adb21d53134ea3199f5fa3b7e5a40fce029f2704
[m17n/m17n-lib.git] / src / fontset.c
1 /* fontset.c -- fontset module.
2    Copyright (C) 2003, 2004
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
8    The m17n library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public License
10    as published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    The m17n library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21    02111-1307, USA.  */
22
23 /***en
24     @addtogroup m17nFontset
25     @brief A fontset is an object that maps a character to fonts.
26
27     A @e fontset is an object of the type @c MFontset.  When drawing an
28     M-text, a fontset provides rules to select a font for each
29     character in the M-text according to the following information.
30
31     @li The script character property of a character.
32     @li The language text property of a character.
33     @li The charset text property of a character.
34
35     The documentation of mdraw_text () describes how that information is
36     used.  */
37
38 /***ja @addtogroup m17nFontset 
39
40     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ïʸ»ú¤«¤é¥Õ¥©¥ó¥È¤Ø¤ÎÂбþÉÕ¤±¤ò¹Ô¤¦¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤¢¤ë.
41
42     @e ¥Õ¥©¥ó¥È¥»¥Ã¥È ¤Ï @c MFontset ·¿¤Î¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤¢¤ë¡£M-text 
43     ¤Îɽ¼¨¤ÎºÝ¡¢¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ï°Ê²¼¤Î¾ðÊó¤òÍѤ¤¤Æ M-text 
44     Ãæ¤Î¸Ä¡¹¤Îʸ»ú¤Ë¤É¤Î¥Õ¥©¥ó¥È¤òÍѤ¤¤ë¤«·è¤á¤ëµ¬Â§¤òÍ¿¤¨¤ë¡£
45
46     @li Ê¸»ú¤Îʸ»ú¥×¥í¥Ñ¥Æ¥£ "¥¹¥¯¥ê¥×¥È"
47     @li Ê¸»ú¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£ "¸À¸ì"
48     @li Ê¸»ú¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£ "ʸ»ú¥»¥Ã¥È"
49
50     ¤³¤ì¤é¤Î¾ðÊ󤬤ɤΤ褦¤ËÍѤ¤¤é¤ì¤ë¤«¤Ï mdraw_text () ¤ÎÀâÌÀ¤ò»²¾È¤Î¤³¤È¡£
51
52     */
53
54 /*=*/
55
56 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
57 /*** @addtogroup m17nInternal
58      @{ */
59
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <ctype.h>
64
65 #include "config.h"
66 #include "m17n-gui.h"
67 #include "m17n-misc.h"
68 #include "internal.h"
69 #include "symbol.h"
70 #include "plist.h"
71 #include "character.h"
72 #include "charset.h"
73 #include "internal-gui.h"
74 #include "font.h"
75 #include "fontset.h"
76
77 static int mdebug_flag = MDEBUG_FONTSET;
78
79 static M17NObjectArray fontset_table;
80
81 struct MFontset
82 {
83   M17NObject control;
84
85   /* Name of the fontset.  */
86   MSymbol name;
87
88   /* Initialized to 0, and incremented by one each time the fontset is
89      modified.  */
90   unsigned tick;
91
92   /* Database from which to load the contents of the fontset.  Once
93      loaded, this member is set to NULL.  */
94   MDatabase *mdb;
95
96   /* SCRIPT vs PER-LANGUAGE (which is a plist LANGUAGE vs FONT-GROUP) */
97   MPlist *per_script;
98
99   /* CHARSET vs FONT-GROUP */
100   MPlist *per_charset;
101
102   /* FONT-GROUP */
103   MPlist *fallback;
104 };
105
106 static MFontset *default_fontset;
107
108 static MPlist *fontset_list;
109
110 struct MRealizedFontset
111 {
112   /* Fontset from which the realized fontset is realized.  */
113   MFontset *fontset;
114
115   /* Initialized to <fontset>->tick.  */
116   unsigned tick;
117
118   /* Font spec that must be satisfied, or NULL.  */
119   MFont *spec;
120
121   /* Font spec requested by a face.  */
122   MFont request;
123
124   /* The frame on which the realized fontset is realized.  */
125   MFrame *frame;
126
127   MPlist *per_script;
128
129   MPlist *per_charset;
130
131   MPlist *fallback;
132 };
133
134
135 static MPlist *
136 load_font_group (MPlist *plist, MPlist *elt)
137 {
138   MPLIST_DO (elt, elt)
139     {
140       /* ELT ::= ( FONT-SPEC [ LAYOUTER ] ) ...  */
141       MPlist *elt2;
142       MFont *font;
143       MSymbol layouter_name;
144
145       if (! MPLIST_PLIST_P (elt))
146         MWARNING (MERROR_FONTSET);
147       elt2 = MPLIST_PLIST (elt);
148       if (! MPLIST_PLIST_P (elt2))
149         MWARNING (MERROR_FONTSET);
150       MSTRUCT_CALLOC (font, MERROR_FONTSET);
151       mfont__set_spec_from_plist (font, MPLIST_PLIST (elt2));
152       elt2 = MPLIST_NEXT (elt2);
153       layouter_name = Mt;
154       if (MPLIST_SYMBOL_P (elt2))
155         layouter_name = MPLIST_SYMBOL (elt2);
156       if (layouter_name == Mnil)
157         layouter_name = Mt;
158       plist = mplist_add (plist, layouter_name, font);
159       continue;
160     warning:
161       /* ANSI-C requires some statement after a label.  */
162       continue;
163     }
164   return plist;
165 }
166
167 /* Load FONTSET->per_script from the data in FONTSET->mdb.  */
168
169 static void
170 load_fontset_contents (MFontset *fontset)
171 {
172   MPlist *per_script, *per_charset, *font_group;
173   MPlist *fontset_def, *plist;
174
175   fontset->per_script = per_script = mplist ();
176   fontset->per_charset = per_charset = mplist ();
177   fontset->fallback = mplist ();
178   if (! (fontset_def = (MPlist *) mdatabase_load (fontset->mdb)))
179     return;
180
181   MPLIST_DO (plist, fontset_def)
182     {
183       /* PLIST ::=   ( SCRIPT ( LANGUAGE ( FONT-SPEC [LAYOUTER]) ... ) ... )
184                    | ( CHARSET ( FONT-SPEC [LAYOUTER] ) ...)
185                    | ( nil ( FONT-SPEC [LAYOUTER] ) ...)
186          FONT-SPEC :: = ( ... ) */
187       MPlist *elt;
188       MSymbol sym;
189
190       if (! MPLIST_PLIST_P (plist))
191         MWARNING (MERROR_FONTSET);
192       elt = MPLIST_PLIST (plist);
193       if (! MPLIST_SYMBOL_P (elt))
194         MWARNING (MERROR_FONTSET);
195       sym = MPLIST_SYMBOL (elt);
196       elt = MPLIST_NEXT (elt);
197       if (! MPLIST_PLIST_P (elt))
198         MWARNING (MERROR_FONTSET);
199       if (sym == Mnil)
200         load_font_group (fontset->fallback, elt);
201       else if (MPLIST_PLIST_P (MPLIST_PLIST (elt)))
202         {
203           /* SYM is a charset.  */
204           font_group = mplist ();
205           per_charset = mplist_add (per_charset, sym, font_group);
206           load_font_group (font_group, elt);
207         }
208       else
209         {
210           /* SYM is a script */
211           MPlist *per_lang = mplist ();
212
213           per_script = mplist_add (per_script, sym, per_lang);
214           MPLIST_DO (elt, elt)
215             {
216               /* ELT ::= ( LANGUAGE FONT-DEF ...) ... */
217               MPlist *elt2;
218               MSymbol lang;
219
220               if (! MPLIST_PLIST_P (elt))
221                 MWARNING (MERROR_FONTSET);
222               elt2 = MPLIST_PLIST (elt);
223               if (! MPLIST_SYMBOL_P (elt2))
224                 MWARNING (MERROR_FONTSET);
225               lang = MPLIST_SYMBOL (elt2);
226               if (lang == Mnil)
227                 lang = Mt;
228               font_group = mplist ();
229               mplist_add (per_lang, lang, font_group);
230               elt2 = MPLIST_NEXT (elt2);
231               load_font_group (font_group, elt2);
232             }
233         }
234       continue;
235
236     warning:
237       /* ANSI-C requires some statement after a label.  */
238       continue;
239     }
240
241   M17N_OBJECT_UNREF (fontset_def);
242   fontset->mdb = NULL;
243 }
244
245 static void
246 free_fontset (void *object)
247 {
248   MFontset *fontset = (MFontset *) object;
249   MPlist *plist, *pl, *p;
250
251   if (fontset->per_script)
252     {
253       MPLIST_DO (plist, fontset->per_script)
254         {
255           MPLIST_DO (pl, MPLIST_PLIST (plist))
256             {
257               MPLIST_DO (p, MPLIST_PLIST (pl))
258                 free (MPLIST_VAL (p));
259               p = MPLIST_PLIST (pl);
260               M17N_OBJECT_UNREF (p);
261             }
262           pl = MPLIST_PLIST (plist);
263           M17N_OBJECT_UNREF (pl);
264         }
265       M17N_OBJECT_UNREF (fontset->per_script);
266     }
267   if (fontset->per_charset)
268     {
269       MPLIST_DO (pl, fontset->per_charset)
270         {
271           MPLIST_DO (p, MPLIST_PLIST (pl))
272             free (MPLIST_VAL (p));
273           p = MPLIST_PLIST (p);
274           M17N_OBJECT_UNREF (p);
275         }
276       M17N_OBJECT_UNREF (fontset->per_charset);
277     }
278   if (fontset->fallback)
279     {
280       MPLIST_DO (p, fontset->fallback)
281         free (MPLIST_VAL (p));
282       M17N_OBJECT_UNREF (fontset->fallback);
283     }
284
285   plist = mplist_find_by_key (fontset_list, fontset->name);
286   if (! plist)
287     mdebug_hook ();
288   mplist_pop (plist);
289   if (MPLIST_TAIL_P (fontset_list))
290     {
291       M17N_OBJECT_UNREF (fontset_list);
292       fontset_list = NULL;
293     }
294   M17N_OBJECT_UNREGISTER (fontset_table, fontset);
295   free (object);
296 }
297
298 static void
299 realize_fontset_elements (MFrame *frame, MRealizedFontset *realized)
300 {
301   MFontset *fontset = realized->fontset;
302   MPlist *per_script, *per_charset, *font_group;
303   MPlist *plist, *pl, *p;
304
305   realized->per_script = per_script = mplist ();
306   /* The actual elements of per_script are realized on demand.  */
307 #if 0
308   MPLIST_DO (plist, fontset->per_script)
309     {
310       per_lang = mplist ();
311       per_script = mplist_add (per_script, MPLIST_KEY (plist), per_lang);
312       MPLIST_DO (pl, MPLIST_PLIST (plist))
313         {
314           font_group = mplist ();
315           per_lang = mplist_add (per_lang, MPLIST_KEY (pl), font_group);
316           MPLIST_DO (p, MPLIST_PLIST (pl))
317             font_group = mplist_add (font_group,
318                                      MPLIST_KEY (p), MPLIST_VAL (p));
319         }
320     }
321 #endif
322
323   realized->per_charset = per_charset = mplist ();
324   MPLIST_DO (pl, fontset->per_charset)
325     {
326       font_group = mplist ();
327       per_charset = mplist_add (per_charset, MPLIST_KEY (plist), font_group);
328       MPLIST_DO (p, MPLIST_PLIST (pl))
329         font_group = mplist_add (font_group, MPLIST_KEY (p), MPLIST_VAL (p));
330     }
331   realized->fallback = font_group = mplist ();
332   MPLIST_DO (p, fontset->fallback)
333     font_group = mplist_add (font_group, MPLIST_KEY (p), MPLIST_VAL (p));
334 }
335
336
337 /* Return a plist of fonts for SCRIPT in FONTSET.  The returned list
338    is acutally a plist of languages vs font groups (which is a plist).
339    If SCRIPT is nil, return a plist of fallback fonts.  If FONTSET
340    doesn't record any fonts for SCRIPT, generate a proper font spec
341    lists for X backend and FreeType backend.  */
342
343 MPlist *
344 get_per_script (MFontset *fontset, MSymbol script)
345 {
346   MPlist *plist;
347
348   if (script == Mnil)
349     return fontset->fallback;
350   plist = mplist_get (fontset->per_script, script);
351   if (! plist)
352     {
353       int len = MSYMBOL_NAMELEN (script);
354       char *cap = alloca (8 + len + 1);
355       MSymbol capability;
356       MFont *font;
357       MPlist *pl, *p;
358
359       sprintf (cap, ":script=%s", MSYMBOL_NAME (script));
360       capability = msymbol (cap);
361
362       pl = mplist ();
363       MPLIST_DO (p, fontset->fallback)
364         {
365           font = mfont_copy (MPLIST_VAL (p));
366           mfont_put_prop (font, Mregistry, Municode_bmp);
367           font->source = MFONT_SOURCE_FT;
368           font->capability = capability;
369           mplist_add (pl, Mt, font);
370
371           font = mfont_copy (MPLIST_VAL (p));
372           mfont_put_prop (font, Mregistry, Miso10646_1);
373           font->source = MFONT_SOURCE_X;
374           font->capability = capability;
375           mplist_add (pl, Mt, font);
376         }
377       plist = mplist ();
378       mplist_add (plist, Mt, pl);
379       mplist_add (fontset->per_script, script, plist);
380     }
381   return plist;
382 }
383
384 static void
385 free_realized_fontset_elements (MRealizedFontset *realized)
386 {
387   MPlist *plist, *pl, *p;
388   MFont *font;
389   MFontList *font_list;
390
391   if (realized->per_script)
392     {
393       MPLIST_DO (plist, realized->per_script)
394         {
395           MPLIST_DO (pl, MPLIST_PLIST (plist))
396             {
397               MPLIST_DO (p, MPLIST_PLIST (pl))
398                 {
399                   font = MPLIST_VAL (p);
400                   if (font->type == MFONT_TYPE_OBJECT)
401                     {
402                       font_list = (MFontList *) font;
403                       free (font_list->fonts);
404                       free (font_list);
405                     }
406                   /* This is to avoid freeing rfont again by the later
407                      M17N_OBJECT_UNREF (p) */
408                   MPLIST_KEY (p) = Mt;
409                 }
410               p = MPLIST_PLIST (pl);
411               M17N_OBJECT_UNREF (p);
412             }
413           pl = MPLIST_PLIST (plist);
414           M17N_OBJECT_UNREF (pl);
415         }
416       M17N_OBJECT_UNREF (realized->per_script);
417     }
418   if (realized->per_charset)
419     {
420       MPLIST_DO (plist, realized->per_charset)
421         {
422           MPLIST_DO (pl, MPLIST_PLIST (plist))
423             {
424               font = MPLIST_VAL (pl);
425               if (font->type == MFONT_TYPE_OBJECT)
426                 {
427                   font_list = (MFontList *) font;
428                   free (font_list->fonts);
429                   free (font_list);
430                 }
431               MPLIST_KEY (pl) = Mt;
432             }
433           pl = MPLIST_PLIST (plist);
434           M17N_OBJECT_UNREF (pl);
435         }
436       M17N_OBJECT_UNREF (realized->per_charset);
437     }
438   if (realized->fallback)
439     {
440       MPLIST_DO (plist, realized->fallback)
441         {
442           font = MPLIST_VAL (plist);
443           if (font->type == MFONT_TYPE_OBJECT)
444             {
445               font_list = (MFontList *) font;
446               free (font_list->fonts);
447               free (font_list);
448             }
449           MPLIST_KEY (plist) = Mt;
450         }
451       M17N_OBJECT_UNREF (realized->fallback);
452     }
453 }
454
455 static void
456 update_fontset_elements (MRealizedFontset *realized)
457 {
458   free_realized_fontset_elements (realized);
459   realize_fontset_elements (realized->frame, realized);
460 }
461
462
463 \f
464
465 /* Internal API */
466
467 int
468 mfont__fontset_init ()
469 {
470   M17N_OBJECT_ADD_ARRAY (fontset_table, "Fontset");
471
472   Mfontset = msymbol ("fontset");
473   Mfontset->managing_key = 1;
474   fontset_list = mplist ();
475   default_fontset = mfontset ("default");
476   if (! default_fontset->mdb)
477     {
478       MFont font;
479
480       MFONT_INIT (&font);
481       mfont_put_prop (&font, Mregistry, msymbol ("iso8859-1"));
482       mfontset_modify_entry (default_fontset, Mnil, Mnil, Mnil,
483                              &font, Mnil, 1);
484       mfont_put_prop (&font, Mregistry, msymbol ("iso10646-1"));
485       mfontset_modify_entry (default_fontset, Mnil, Mnil, Mnil,
486                              &font, Mnil, 1);
487     }
488   return 0;
489 }
490
491
492 void
493 mfont__fontset_fini ()
494 {
495   M17N_OBJECT_UNREF (default_fontset);
496   default_fontset = NULL;
497 }
498
499
500 MRealizedFontset *
501 mfont__realize_fontset (MFrame *frame, MFontset *fontset,
502                         MFace *face, MFont *spec)
503 {
504   MRealizedFontset *realized;
505   MFont request;
506   MPlist *plist;
507
508   if (fontset->mdb)
509     load_fontset_contents (fontset);
510
511   MFONT_INIT (&request);
512   mfont__set_spec_from_face (&request, face);
513   if (request.size <= 0)
514     {
515       mdebug_hook ();
516       request.size = 120;
517     }
518   MPLIST_DO (plist, frame->realized_fontset_list)
519     {
520       realized = (MRealizedFontset *) MPLIST_VAL (plist);
521       if (fontset->name == MPLIST_KEY (plist)
522           && ! memcmp (&request, &realized->request, sizeof (MFont))
523           && (realized->spec
524               ? (spec && ! memcmp (spec, &realized->spec, sizeof (MFont)))
525               : ! spec))
526         return realized;
527     }
528
529   MSTRUCT_CALLOC (realized, MERROR_FONTSET);
530   realized->fontset = fontset;
531   M17N_OBJECT_REF (fontset);
532   realized->tick = fontset->tick;
533   if (spec)
534     {
535       MSTRUCT_CALLOC (realized->spec, MERROR_FONTSET);
536       *realized->spec = *spec;
537     }
538   realized->request = request;
539   realized->frame = frame;
540   realize_fontset_elements (frame, realized);
541   mplist_add (frame->realized_fontset_list, fontset->name, realized);
542   return realized;
543 }
544
545
546 void
547 mfont__free_realized_fontset (MRealizedFontset *realized)
548 {
549   free_realized_fontset_elements (realized);
550   M17N_OBJECT_UNREF (realized->fontset);
551   if (realized->spec)
552     free (realized->spec);
553   free (realized);
554 }
555
556
557 static MRealizedFont *
558 try_font_list (MFrame *frame, MFontList *font_list, MFont *request,
559                MSymbol layouter, MGlyph *g, int *num, int all, int exact)
560 {
561   int i, j;
562   MFont *font;
563   MRealizedFont *rfont;
564
565   for (i = 0; i < font_list->nfonts; i++)
566     {
567       if (font_list->fonts[i].font->type == MFONT_TYPE_SPEC)
568         MFATAL (MERROR_FONT);
569       if (exact)
570         {
571           if (font_list->fonts[i].score > 0)
572             break;
573         }
574       else
575         {
576           if (font_list->fonts[i].score == 0)
577             continue;
578         }
579       font = font_list->fonts[i].font;
580       if (font->type == MFONT_TYPE_FAILURE)
581         continue;
582       /* Check if this font can display all glyphs.  */
583       for (j = 0; j < *num; j++)
584         {
585           int c = g[j].type == GLYPH_CHAR ? g[j].g.c : ' ';
586           MFLT *flt;
587           MCharTable *coverage;
588
589           if (layouter != Mt
590               ? ((flt = mflt_get (layouter))
591                  ? (coverage = mflt_coverage (flt),
592                     ! mchartable_lookup (coverage, c))
593                  : 0)
594               : ! mfont__has_char (frame, font, &font_list->object, c))
595             break;
596         }
597       if (j == 0 && *num > 0)
598         continue;
599       if (j == *num || !all)
600         {
601           MCharTable *coverage = NULL;
602
603           /* We found a font that can display the requested range of
604              glyphs.  */
605           if (font->type == MFONT_TYPE_REALIZED)
606             rfont = (MRealizedFont *) font;
607           else
608             {
609               rfont = mfont__open (frame, font, &font_list->object);
610               if (! rfont)
611                 continue;
612               font_list->fonts[i].font = (MFont *) rfont;
613             }
614           rfont->layouter = layouter == Mt ? Mnil : layouter;
615           if (rfont->layouter)
616             {
617               MFLT *flt = mflt_get (rfont->layouter);
618
619               if (flt)
620                 coverage = mflt_coverage (flt);
621             }
622           *num = j;
623           for (j = 0; j < *num; j++)
624             {
625               int c = g[j].type == GLYPH_CHAR ? g[j].g.c : ' ';
626
627               g[j].g.code = (coverage
628                              ? (unsigned ) mchartable_lookup (coverage, c)
629                              : mfont__encode_char (frame, (MFont *) rfont,
630                                                    &font_list->object, c));
631             }
632           return rfont;
633         }
634     }
635   return NULL;
636 }
637
638
639 static MRealizedFont *
640 try_font_group (MRealizedFontset *realized, MFont *request,
641                 MPlist *font_group, MGlyph *g, int *num, int size)
642 {
643   MFrame *frame = realized->frame;
644   MFont *font;
645   MFontList *font_list;
646   MRealizedFont *rfont;
647   MPlist *plist;
648   MSymbol layouter;
649   int best_score = -1, worst_score;
650
651   for (plist = font_group; ! MPLIST_TAIL_P (plist); )
652     {
653       int this_score;
654
655       layouter = MPLIST_KEY (plist);
656       font = MPLIST_VAL (plist);
657       if (font->type == MFONT_TYPE_SPEC)
658         {
659           /* We have not yet made this entry a MFontList.  */
660           if (realized->spec)
661             {
662               MFont this = *font;
663               
664               if (mfont__merge (&this, realized->spec, 1) < 0)
665                 {
666                   mplist_pop (plist);
667                   continue;
668                 }
669               font_list = mfont__list (frame, &this, &this, size);
670             }
671           else
672             font_list = mfont__list (frame, font, request, size);
673           if (! font_list)
674             {
675               /* As there's no font matching this spec, remove this
676                  element from the font group.  */
677               mplist_pop (plist);
678               continue;
679             }
680           MPLIST_VAL (plist) = font_list;
681         }
682       else
683         font_list = (MFontList *) font;
684
685       this_score = font_list->fonts[0].score;
686       if ((this_score == 0)
687           && (rfont = try_font_list (frame, font_list, request,
688                                      layouter, g, num, 1, 1)))
689         return rfont;
690       if (best_score < 0)
691         {
692           best_score = worst_score = this_score;
693           plist = MPLIST_NEXT (plist);
694         }
695       else if (this_score >= worst_score)
696         {
697           worst_score = this_score;
698           plist = MPLIST_NEXT (plist);
699         }
700       else
701         {
702           MPlist *pl;
703
704           MPLIST_DO (pl, font_group)
705             if (this_score < ((MFontList *) MPLIST_VAL (pl))->fonts[0].score)
706               break;
707           mplist_pop (plist);
708           mplist_push (pl, layouter, font_list);
709         }
710     }
711
712   /* We couldn't find an exact matching font that can display all
713      glyphs.  Find one that can at least display all glyphs.  */
714   MPLIST_DO (plist, font_group)
715     {
716       rfont = try_font_list (frame, MPLIST_VAL (plist), request,
717                              MPLIST_KEY (plist), g, num, 1, 0);
718       if (rfont)
719         return rfont;
720     }
721
722   /* We couldn't find a font that can display all glyphs.  Find an
723      exact matching font that can at least display the first
724      glyph.  */
725   MPLIST_DO (plist, font_group)
726     {
727       rfont = try_font_list (frame, MPLIST_VAL (plist), request,
728                              MPLIST_KEY (plist), g, num, 0, 1);
729       if (rfont)
730         return rfont;
731     }
732
733   /* Find any font that can at least display the first glyph.  */
734   MPLIST_DO (plist, font_group)
735     {
736       rfont = try_font_list (frame, MPLIST_VAL (plist), request,
737                              MPLIST_KEY (plist), g, num, 0, 0);
738       if (rfont)
739         return rfont;
740     }
741
742   return NULL;
743 }
744
745 MRealizedFont *
746 mfont__lookup_fontset (MRealizedFontset *realized, MGlyph *g, int *num,
747                        MSymbol script, MSymbol language, MSymbol charset,
748                        int size, int ignore_fallback)
749 {
750   MCharset *preferred_charset = (charset == Mnil ? NULL : MCHARSET (charset));
751   MPlist *per_charset, *per_script, *per_lang;
752   MPlist *plist;
753   MRealizedFont *rfont = NULL;
754
755   if (MDEBUG_FLAG ())
756     {
757       int i;
758
759       MDEBUG_PRINT1 (" [FONTSET] fontset looking up for %s:",
760                      script ? script->name : "none");
761       for (i = 0; i < *num; i++)
762         MDEBUG_PRINT1 (" U+%04X", g[i].g.c);
763       MDEBUG_PRINT ("\n");
764     }
765
766   if (realized->tick != realized->fontset->tick)
767     update_fontset_elements (realized);
768
769   if (preferred_charset
770       && (per_charset = mplist_get (realized->per_charset, charset)) != NULL
771       && (rfont = try_font_group (realized, &realized->request, per_charset,
772                                   g, num, size)))
773     goto done;
774
775   if (script != Mnil)
776     {
777       MFont request = realized->request;
778
779       if (script != Mlatin)
780         /* This is not appropriate for non-Latin scripts.  */
781         request.property[MFONT_REGISTRY] = 0;
782
783       per_script = mplist_get (realized->per_script, script);
784       if (! per_script)
785         {
786           per_script = mplist_copy (get_per_script (realized->fontset, script));
787           /* PER_SCRIPT ::= (LANGUAGE:(LAYOUTER:FONT-SPEC ...) ...) */
788           MPLIST_DO (plist, per_script)
789             MPLIST_VAL (plist) = mplist_copy (MPLIST_VAL (plist));
790           mplist_add (realized->per_script, script, per_script);
791         }
792
793       /* We prefer font groups in this order:
794           (1) group matching with LANGUAGE if LANGUAGE is not Mnil
795           (2) group for generic language
796           (3) group not matching with LANGUAGE  */
797       if (language == Mnil)
798         language = Mt;
799       if ((per_lang = mplist_get (per_script, language))
800           && (rfont = try_font_group (realized, &request, per_lang,
801                                       g, num, size)))
802         goto done;
803
804       if (per_lang && *num > 1)
805         *num = 1;
806       if (language == Mt)
807         {
808           /* Try the above (3) */
809           MPLIST_DO (plist, per_script)
810             if (MPLIST_KEY (plist) != language
811                 && (rfont = try_font_group (realized, &request,
812                                             MPLIST_PLIST (plist),
813                                             g, num, size)))
814               goto done;
815         }
816       else
817         {
818           /* At first try the above (2) */
819           if ((per_lang = mplist_get (per_script, Mt))
820               && (rfont = try_font_group (realized, &request, per_lang,
821                                           g, num, size)))
822             goto done;
823
824           if (per_lang && *num > 1)
825             *num = 1;
826           /* Then try the above (3) */
827           MPLIST_DO (plist, per_script)
828             if (MPLIST_KEY (plist) != language
829                 && MPLIST_KEY (plist) != Mt
830                 && (rfont = try_font_group (realized, &request,
831                                             MPLIST_PLIST (plist),
832                                             g, num, size)))
833               goto done;
834         }
835       if (ignore_fallback)
836         goto done;
837     }
838
839   if (language != Mnil)
840     /* Find a font group for this language from all scripts.  */
841     MPLIST_DO (plist, realized->per_script)
842       {
843         MFont request = realized->request;
844
845         if (MPLIST_KEY (plist) != Mlatin)
846           request.property[MFONT_FOUNDRY]
847             = request.property[MFONT_FAMILY]
848             = request.property[MFONT_FAMILY] = 0;
849         if ((per_lang = mplist_get (MPLIST_PLIST (plist), language))
850             && (rfont = try_font_group (realized, &request, per_lang,
851                                         g, num, size)))
852           goto done;
853       }
854
855   /* Try fallback fonts.  */
856   rfont = try_font_group (realized, &realized->request,
857                           realized->fallback, g, num, size);
858  done:
859   if (MDEBUG_FLAG ())
860     {
861       if (rfont)
862         {
863           MSymbol family = mfont_get_prop (rfont->font, Mfamily);
864           MDEBUG_PRINT1 (" [FONTSET] found %s\n", family->name);
865         }
866       else
867         MDEBUG_PRINT (" [FONTSET] not found\n");
868     }
869
870   return rfont;
871 }
872
873 MRealizedFont *
874 get_font_from_group (MFrame *frame, MPlist *plist, MFont *font)
875 {
876   MRealizedFont *rfont;
877
878   MPLIST_DO (plist, plist)
879     {
880       MFont spec = *(MFont *) MPLIST_VAL (plist);
881       if (mfont__merge (&spec, font, 1) < 0)
882         continue;
883       if (font->type == MFONT_TYPE_SPEC)
884         rfont = (MRealizedFont *) mfont_find (frame, &spec, NULL, 0);
885       else if (font->type == MFONT_TYPE_OBJECT)
886         rfont = mfont__open (frame, font, &spec);
887       else
888         rfont = (MRealizedFont *) font;
889       if (rfont
890           && (spec.capability == Mnil
891               || mfont__check_capability (rfont, spec.capability) == 0))
892         {
893           rfont->layouter
894             = MPLIST_KEY (plist) == Mt ? Mnil : MPLIST_KEY (plist);
895           return rfont;
896         }
897     }
898   return NULL;
899 }
900
901 MRealizedFont *
902 mfontset__get_font (MFrame *frame, MFontset *fontset,
903                     MSymbol script, MSymbol language, MFont *font,
904                     int *best)
905 {
906   MPlist *per_script, *per_lang;
907   MRealizedFont *rfont;
908
909   if (best)
910     *best = 0;
911
912   if (language == Mnil)
913     language = Mt;
914
915   if (script != Mnil)
916     {
917       per_script = get_per_script (fontset, script);
918       if ((per_lang = mplist_get (per_script, language))
919           && (rfont = get_font_from_group (frame, per_lang, font)))
920         {
921           if (best)
922             *best = 1;
923           return rfont;
924         }
925       if (best)
926         *best = per_lang ? 0 : 1;
927       if (language == Mt)
928         {
929           MPLIST_DO (per_script, per_script)
930             if (MPLIST_KEY (per_script) != language
931                 && (rfont = get_font_from_group (frame,
932                                                  MPLIST_PLIST (per_script),
933                                                  font)))
934               return rfont;
935         }
936       else
937         {
938           if ((per_lang = mplist_get (per_script, Mt))
939               && (rfont = get_font_from_group (frame, per_lang, font)))
940             return rfont;
941           if (best)
942             *best = 0;
943           MPLIST_DO (per_script, per_script)
944             if (MPLIST_KEY (per_script) != language
945                 && MPLIST_KEY (per_script) != Mt
946                 && (rfont = get_font_from_group (frame,
947                                                  MPLIST_PLIST (per_script),
948                                                  font)))
949               return rfont;
950         }
951     }
952
953   if (language != Mt)
954     MPLIST_DO (per_script, fontset->per_script)
955       {
956         if ((per_lang = mplist_get (MPLIST_PLIST (per_script), language))
957             && (rfont = get_font_from_group (frame, per_lang, font)))
958           {
959             if (best)
960               *best = 1;
961             return rfont;
962           }
963       }
964
965   if (best)
966     *best = 0;
967   if ((rfont = get_font_from_group (frame, fontset->fallback, font)))
968     return rfont;
969   return NULL;
970 }
971
972
973 /*** @} */
974 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
975
976 \f
977 /* External API */
978
979 /*** @addtogroup m17nFontset */
980 /*** @{ */
981
982 /*=*/
983 /***en
984     @brief Return a fontset.
985
986     The mfontset () function returns a pointer to a fontset object of
987     name $NAME.  If $NAME is @c NULL, it returns a pointer to the
988     default fontset.
989
990     If no fontset has the name $NAME, a new one is created.  At that
991     time, if there exists a data \<@c fontset, $NAME\> in the m17n
992     database, the fontset contents are initialized according to the
993     data.  If no such data exists, the fontset contents are left
994     vacant.
995
996     The macro M17N_INIT () creates the default fontset.  An
997     application program can modify it before the first call of 
998     mframe ().
999
1000     @return
1001     This function returns a pointer to the found or newly created
1002     fontset.  */
1003 /***ja 
1004     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤òÊÖ¤¹.
1005
1006     ´Ø¿ô mfontset () ¤Ï̾Á° $NAME ¤ò»ý¤Ä¥Õ¥©¥ó¥È¥»¥Ã¥È¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£ 
1007     $NAME ¤¬ @c NULL ¤Ê¤é¤Ð¡¢¥Ç¥Õ¥©¥ë¥È¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
1008
1009     $NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¥Õ¥©¥ó¥È¥»¥Ã¥È¤¬¤Ê¤±¤ì¤Ð¡¢¿·¤·¤¤¤â¤Î¤¬ºî¤é¤ì¤ë¡£¤½¤ÎºÝ¡¢
1010     m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë \<@c fontset, $NAME\> 
1011     ¤È¤¤¤¦¥Ç¡¼¥¿¤¬¤¢¤ì¤Ð¡¢¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ï¤½¤Î¥Ç¡¼¥¿¤Ë±è¤Ã¤Æ½é´ü²½¤µ¤ì¤ë¡£
1012     ¤Ê¤±¤ì¤Ð¡¢¶õ¤Î¤Þ¤Þ¤Ë¤µ¤ì¤ë¡£
1013
1014     ¥Þ¥¯¥í M17N_INIT () ¤Ï¥Ç¥Õ¥©¥ë¥È¤Î¥Õ¥©¥ó¥È¥»¥Ã¥È¤òºî¤ë¡£¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï
1015     mframe () ¤ò½é¤á¤Æ¸Æ¤Ö¤Þ¤Ç¤Î´Ö¤Ï¥Ç¥Õ¥©¥ë¥È¥Õ¥©¥ó¥È¥»¥Ã¥È¤òÊѹ¹¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë¡£
1016
1017     @return
1018     ¤³¤Î´Ø¿ô¤Ï¸«¤Ä¤«¤Ã¤¿¡¢¤¢¤ë¤¤¤Ïºî¤Ã¤¿¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
1019      */
1020
1021 MFontset *
1022 mfontset (char *name)
1023 {
1024   MSymbol sym;
1025   MFontset *fontset;
1026
1027   if (! name)
1028     {
1029       fontset = default_fontset;
1030       M17N_OBJECT_REF (fontset);
1031     }
1032   else
1033     {
1034       sym = msymbol (name);
1035       fontset = mplist_get (fontset_list, sym);
1036       if (fontset)
1037         M17N_OBJECT_REF (fontset);
1038       else
1039         {
1040           M17N_OBJECT (fontset, free_fontset, MERROR_FONTSET);
1041           M17N_OBJECT_REGISTER (fontset_table, fontset);
1042           fontset->name = sym;
1043           fontset->mdb = mdatabase_find (Mfontset, sym, Mnil, Mnil);
1044           if (! fontset->mdb)
1045             {
1046               fontset->per_script = mplist ();
1047               fontset->per_charset = mplist ();
1048               fontset->fallback = mplist ();
1049             }
1050           mplist_put (fontset_list, sym, fontset);
1051         }
1052     }
1053   return fontset;
1054 }
1055
1056 /*=*/
1057
1058 /***en
1059     @brief Return the name of a fontset.
1060
1061     The mfontset_name () function returns the name of fontset $FONTSET.  */
1062 /***ja
1063     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î̾Á°¤òÊÖ¤¹.
1064
1065     ´Ø¿ô mfontset_name () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤Î̾Á°¤òÊÖ¤¹¡£  */
1066 MSymbol
1067 mfontset_name (MFontset *fontset)
1068 {
1069   return fontset->name;
1070 }
1071
1072 /*=*/
1073
1074 /***en
1075     @brief Make a copy of a fontset.
1076
1077     The mfontset_copy () function makes a copy of fontset $FONTSET, gives it a
1078     name $NAME, and returns a pointer to the created copy.  $NAME must
1079     not be a name of existing fontset.  In such case, this function
1080     returns NULL without making a copy.  */
1081 /***ja
1082     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î¥³¥Ô¡¼¤òºî¤ë.
1083
1084     ´Ø¿ô mfontset_copy () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤Î¥³¥Ô¡¼¤òºî¤Ã¤Æ¡¢Ì¾Á°
1085     $NAME ¤òÍ¿¤¨¡¢¤½¤Î¥³¥Ô¡¼¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£$NAME 
1086     ¤Ï´û¸¤Î¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î̾Á°¤Ç¤¢¤Ã¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤½¤Î¤è¤¦¤Ê¾ì¹ç¤Ë¤Ï¥³¥Ô¡¼¤òºî¤é¤º¤Ë
1087     NULL ¤òÊÖ¤¹¡£  */
1088
1089 MFontset *
1090 mfontset_copy (MFontset *fontset, char *name)
1091 {
1092   MSymbol sym = msymbol (name);
1093   MFontset *copy = mplist_get (fontset_list, sym);
1094   MPlist *plist, *pl, *p;
1095
1096   if (copy)
1097     return NULL;
1098   M17N_OBJECT (copy, free_fontset, MERROR_FONTSET);
1099   M17N_OBJECT_REGISTER (fontset_table, copy);
1100   copy->name = sym;
1101
1102   if (fontset->mdb)
1103     load_fontset_contents (fontset);
1104
1105   if (fontset->per_script)
1106     {
1107       copy->per_script = mplist ();
1108       MPLIST_DO (plist, fontset->per_script)
1109         {
1110           MPlist *per_lang = mplist ();
1111
1112           mplist_add (copy->per_script, MPLIST_KEY (plist), per_lang);
1113           MPLIST_DO (pl, MPLIST_PLIST (plist))
1114             {
1115               MPlist *font_group = mplist ();
1116
1117               per_lang = mplist_add (per_lang, MPLIST_KEY (pl), font_group);
1118               MPLIST_DO (p, MPLIST_PLIST (pl))
1119                 font_group = mplist_add (font_group, MPLIST_KEY (p),
1120                                          mfont_copy (MPLIST_VAL (p)));
1121             }
1122         }
1123     }
1124   if (fontset->per_charset)
1125     {
1126       MPlist *per_charset = mplist ();
1127
1128       copy->per_charset = per_charset;
1129       MPLIST_DO (pl, fontset->per_charset)
1130         {
1131           MPlist *font_group = mplist ();
1132
1133           per_charset = mplist_add (per_charset, MPLIST_KEY (pl), font_group);
1134           MPLIST_DO (p, MPLIST_PLIST (pl))
1135             font_group = mplist_add (font_group, MPLIST_KEY (p),
1136                                      mfont_copy (MPLIST_VAL (p)));
1137         }
1138     }
1139   if (fontset->fallback)
1140     {
1141       MPlist *font_group = mplist ();
1142
1143       copy->fallback = font_group;
1144       MPLIST_DO (p, fontset->fallback)
1145         font_group = mplist_add (font_group, MPLIST_KEY (p),
1146                                  mfont_copy (MPLIST_VAL (p)));
1147     }                            
1148
1149   mplist_put (fontset_list, sym, copy);
1150   return copy;
1151 }
1152
1153 /*=*/
1154
1155 /***en
1156     @brief Modify the contents of a fontset.
1157
1158     The mfontset_modify_entry () function associates, in fontset
1159     $FONTSET, a copy of $FONT with the $SCRIPT / $LANGUAGE pair or
1160     with $CHARSET.
1161
1162     Each font in a fontset is associated with a particular
1163     script/language pair, with a particular charset, or with the
1164     symbol @c Mnil.  The fonts that are associated with the same item
1165     make a group.
1166
1167     If $SCRIPT is not @c Mnil, it must be a symbol identifying a
1168     script.  In this case, $LANGUAGE is either a symbol identifying a
1169     language or @c Mnil, and $FONT is associated with the $SCRIPT /
1170     $LANGUAGE pair.
1171
1172     If $CHARSET is not @c Mnil, it must be a symbol representing a
1173     charset object.  In this case, $FONT is associated with that
1174     charset.
1175
1176     If both $SCRIPT and $CHARSET are not @c Mnil, two copies of $FONT
1177     are created.  Then one is associated with the $SCRIPT / $LANGUAGE
1178     pair and the other with that charset.
1179
1180     If both $SCRIPT and $CHARSET are @c Mnil, $FONT is associated with
1181     @c Mnil.  This kind of fonts are called @e fallback @e fonts.
1182
1183     The argument $HOW specifies the priority of $FONT.  If $HOW is
1184     positive, $FONT has the highest priority in the group of fonts
1185     that are associated with the same item.  If $HOW is negative,
1186     $FONT has the lowest priority.  If $HOW is zero, $FONT becomes the
1187     only available font for the associated item; all the other fonts
1188     are removed from the group.
1189
1190     If $LAYOUTER_NAME is not @c Mnil, it must be a symbol representing
1191     a @ref mdbFLT (font layout table).  In that case, if $FONT is
1192     selected for drawing an M-text, that font layout table is used to
1193     generate a glyph code sequence from a character sequence.
1194
1195     @return
1196     If the operation was successful, mfontset_modify_entry () returns 0.
1197     Otherwise it returns -1 and assigns an error code to the external
1198     variable #merror_code.  */
1199
1200 /***ja
1201     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤ÎÆâÍƤòÊѹ¹¤¹¤ë.
1202
1203     ´Ø¿ô mfontset_modify_entry () ¤Ï¡¢$LANGUAGE ¤È $SCRIPT ¤ÎÁȤ߹ç¤ï¤»¡¢¤Þ¤¿¤Ï
1204     $CHARSET ¤ËÂФ·¤Æ $FONT ¤Î¥³¥Ô¡¼¤ò»È¤¦¤è¤¦¤Ë¡¢¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤òÀßÄꤹ¤ë¡£
1205
1206     ¥Õ¥©¥ó¥È¥»¥Ã¥ÈÃæ¤Î³Æ¥Õ¥©¥ó¥È¤Ï¡¢ÆÃÄê¤Î¥¹¥¯¥ê¥×¥È¤È¸À¸ì¤Î¥Ú¥¢¡¢ÆÃÄê¤Îʸ»ú¥»¥Ã¥È¡¢¥·¥ó¥Ü¥ë
1207     @c Mnil ¤Î¤¤¤º¤ì¤«¤È´ØÏ¢ÉÕ¤±¤é¤ì¤Æ¤¤¤ë¡£Æ±¤¸¤â¤Î¤È´ØÏ¢ÉÕ¤±¤é¤ì¤¿¥Õ¥©¥ó¥È¤Ï¥°¥ë¡¼¥×¤ò¹½À®¤¹¤ë¡£
1208
1209     $SCRIPT ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢¥¹¥¯¥ê¥×¥È¤òÆÃÄꤹ¤ë¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
1210     ¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¾ì¹ç¤Ë¤Ï¡¢$LANGUAGE ¤Ï¸À¸ì¤òÆÃÄꤹ¤ë¥·¥ó¥Ü¥ë¤« @c
1211     Mnil ¤Ç¤¢¤ê¡¢$FONT ¤Ïthe $SCRIPT / $LANGUAGE ¥Ú¥¢¤Ë´ØÏ¢ÉÕ¤±¤é¤ì¤ë¡£
1212
1213     $CHARSET ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢Ê¸»ú¥»¥Ã¥È¥ª¥Ö¥¸¥§¥¯¥È¤òɽ¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
1214     ¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¾ì¹ç¤Ë¤Ï $FONT ¤Ï¤½¤Îʸ»ú¥»¥Ã¥È¤È´ØÏ¢ÉÕ¤±¤é¤ì¤ë¡£
1215
1216     $SCRIPT ¤È $CHARSET ¤ÎÁÐÊý¤¬ @c Mnil ¤Ç¤Ê¤¤¾ì¹ç¤Ë¤Ï $FONT 
1217     ¤Î¥³¥Ô¡¼¤¬£²¤Äºî¤é¤ì¡¢¤½¤ì¤¾¤ì $SCRIPT / $LANGUAGE 
1218     ¥Ú¥¢¤Èʸ»ú¥»¥Ã¥È¤Ë´ØÏ¢ÉÕ¤±¤é¤ì¤ë¡£
1219
1220     $SCRIPT ¤È $CHARSET ¤ÎÁÐÊý¤¬ @c Mnil ¤Ê¤é¤Ð¡¢ $FONT ¤Ï @c Mnil 
1221     ¤È´ØÏ¢ÉÕ¤±¤é¤ì¤ë¡£¤³¤Î¼ï¤Î¥Õ¥©¥ó¥È¤Ï @e fallback @e font ¤È¸Æ¤Ð¤ì¤ë¡£
1222
1223     °ú¿ô $HOW ¤Ï $FONT ¤ÎÍ¥ÀèÅÙ¤ò»ØÄꤹ¤ë¡£$HOW ¤¬Àµ¤Ê¤é¤Ð¡¢$FONT 
1224     ¤ÏƱ¤¸¤â¤Î¤È´ØÏ¢ÉÕ¤±¤é¤ì¤¿¥°¥ë¡¼¥×Ãæ¤ÇºÇ¹â¤ÎÍ¥ÀèÅÙ¤ò»ý¤Ä¡£$HOW 
1225     ¤¬Éé¤Ê¤é¤Ð¡¢ºÇÄã¤ÎÍ¥ÀèÅÙ¤ò»ý¤Ä¡£$HOW ¤¬ 0 ¤Ê¤é¤Ð¡¢$FONT 
1226     ¤Ï´ØÏ¢ÉÕ¤±¤é¤ì¤¿¤â¤Î¤ËÂФ¹¤ëÍ£°ì¤ÎÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤È¤Ê¤ê¡¢Â¾¤Î¥Õ¥©¥ó¥È¤Ï¥°¥ë¡¼¥×¤«¤é¼è¤ê½ü¤«¤ì¤ë¡£
1227
1228     $LAYOUTER_NAME ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢@ref mdbFLT 
1229     ¡Ê¥Õ¥©¥ó¥È¥ì¥¤¥¢¥¦¥È¥Æ¡¼¥Ö¥ë¡Ë¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£¥·¥ó¥Ü¥ë¤Ç¤¢¤ì¤Ð¡¢$FONT ¤òÍѤ¤¤Æ
1230     M-text ¤òɽ¼¨¤¹¤ëºÝ¤Ë¤Ï¡¢¤½¤Î¥Õ¥©¥ó¥È¥ì¥¤¥¢¥¦¥È¥Æ¡¼¥Ö¥ë¤ò»È¤Ã¤Æʸ»úÎ󤫤饰¥ê¥Õ¥³¡¼¥ÉÎó¤òÀ¸À®¤¹¤ë¡£
1231
1232     @return 
1233     ½èÍý¤¬À®¸ù¤·¤¿¤È¤­¡¢mfontset_modify_entry () ¤Ï 0 ¤òÊÖ¤¹¡£
1234     ¼ºÇÔ¤·¤¿¤È¤­¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
1235
1236 /***
1237     @errors
1238     @c MERROR_SYMBOL  */
1239
1240 int
1241 mfontset_modify_entry (MFontset *fontset,
1242                        MSymbol script, MSymbol language, MSymbol charset,
1243                        MFont *spec, MSymbol layouter_name,
1244                        int how)
1245 {
1246   MPlist *per_lang, *plist[3];
1247   MFont *font = NULL;
1248   int i;
1249
1250   if (fontset->mdb)
1251     load_fontset_contents (fontset);
1252
1253   i = 0;
1254   if (script != Mnil)
1255     {
1256       if (language == Mnil)
1257         language = Mt;
1258       per_lang = mplist_get (fontset->per_script, script);
1259       if (! per_lang)
1260         mplist_add (fontset->per_script, script, per_lang = mplist ());
1261       plist[i] = mplist_get (per_lang, language);
1262       if (! plist[i])
1263         mplist_add (per_lang, language, plist[i] = mplist ());
1264       i++;
1265     }
1266   if (charset != Mnil)
1267     {
1268       plist[i] = mplist_get (fontset->per_charset, charset);
1269       if (! plist[i])
1270         mplist_add (fontset->per_charset, charset, plist[i] = mplist ());
1271       i++;
1272     }
1273   if (script == Mnil && charset == Mnil)
1274     {
1275       plist[i++] = fontset->fallback;
1276     }
1277
1278   if (layouter_name == Mnil)
1279     layouter_name = Mt;
1280   for (i--; i >= 0; i--)
1281     {
1282       font = mfont_copy (spec);
1283       font->type = MFONT_TYPE_SPEC;
1284       if (how == 1)
1285         mplist_push (plist[i], layouter_name, font);
1286       else if (how == -1)
1287         mplist_add (plist[i], layouter_name, font);
1288       else
1289         {
1290           MPlist *pl;
1291
1292           MPLIST_DO (pl, plist[i])
1293             free (MPLIST_VAL (pl));
1294           mplist_set (plist[i], Mnil, NULL);
1295           mplist_add (plist[i], layouter_name, font);
1296         }
1297     }
1298
1299   fontset->tick++;
1300   return 0;
1301 }
1302
1303 /*=*/
1304
1305 /***en
1306     @brief Lookup a fontset.
1307
1308     The mfontset_lookup () function lookups $FONTSET and returns a
1309     plist that describes the contents of $FONTSET corresponding to the
1310     specified script, language, and charset.
1311
1312     If $SCRIPT is @c Mt, keys of the returned plist are script name
1313     symbols for which some fonts are specified and values are NULL.
1314
1315     If $SCRIPT is a script name symbol, the returned plist is decided
1316     by $LANGUAGE.
1317     
1318     @li If $LANGUAGE is @c Mt, keys of the plist are language name
1319     symbols for which some fonts are specified and values are NULL.  A
1320     key may be @c Mt which means some fallback fonts are specified for
1321     the script.
1322
1323     @li If $LANGUAGE is a language name symbol, the plist is a @c
1324     FONT-GROUP for the specified script and language.  @c FONT-GROUP
1325     is a plist whose keys are FLT (FontLayoutTable) name symbols (@c
1326     Mt if no FLT is associated with the font) and values are pointers
1327     to #MFont.
1328
1329     @li If $LANGUAGE is @c Mnil, the plist is fallback @c FONT-GROUP
1330     for the script. 
1331
1332     If $SCRIPT is @c Mnil, the returned plist is decided as below.
1333
1334     @li If $CHARSET is @c Mt, keys of the returned plist are charset name
1335     symbols for which some fonts are specified and values are NULL.
1336
1337     @li If $CHARSET is a charset name symbol, the plist is a @c FONT-GROUP for
1338     the charset.
1339
1340     @li If $CHARSET is @c Mnil, the plist is a fallback @c FONT-GROUP.
1341
1342     @return
1343     It returns a plist describing the contents of a fontset.  The
1344     plist should be freed by m17n_object_unref ().  */
1345 /***ja
1346     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤ò¸¡º÷¤¹¤ë.
1347
1348     ´Ø¿ô mfontset_lookup () ¤Ï $FONTSET ¤ò¸¡º÷¤·¡¢$FONTSET 
1349     ¤ÎÆâÍƤΤ¦¤Á»ØÄꤷ¤¿¥¹¥¯¥ê¥×¥È¡¢¸À¸ì¡¢Ê¸»ú¥»¥Ã¥È¤ËÂбþ¤¹¤ëÉôʬ¤òɽ¤¹
1350     plist ¤òÊÖ¤¹¡£
1351
1352     $SCRIPT ¤¬ @c Mt ¤Ê¤é¤Ð¡¢ÊÖ¤¹ plist 
1353     ¤Î¥­¡¼¤Ï¥Õ¥©¥ó¥È¤¬»ØÄꤵ¤ì¤Æ¤¤¤ë¥¹¥¯¥ê¥×¥È̾¤Î¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢ÃͤÏ
1354     NULL ¤Ç¤¢¤ë¡£
1355
1356     $SCRIPT ¤¬¥¹¥¯¥ê¥×¥È̾¤Î¥·¥ó¥Ü¥ë¤Ç¤¢¤ì¤Ð¡¢ÊÖ¤¹ 
1357     plist ¤Ï $LANGUAGE¤Ë¤è¤Ã¤ÆÄê¤Þ¤ë¡£
1358     
1359     @li $LANGUAGE ¤¬ @c Mt ¤Ê¤é¤Ð¡¢plist 
1360     ¤Î¥­¡¼¤Ï¥Õ¥©¥ó¥È¤¬»ØÄꤵ¤ì¤Æ¤¤¤ë¸À¸ì̾¤Î¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢ÃͤÏ
1361     NULL ¤Ç¤¢¤ë¡£¥­¡¼¤Ï @c Mt
1362     ¤Ç¤¢¤ë¤³¤È¤â¤¢¤ê¡¢¤½¤Î¾ì¹ç¤½¤Î¥¹¥¯¥ê¥×¥È¤Ë¥Õ¥©¡¼¥ë¥Ð¥Ã¥¯¥Õ¥©¥ó¥È¤¬¤¢¤ë¤³¤È¤ò°ÕÌ£¤¹¤ë¡£
1363
1364     @li $LANGUAGE ¤¬¸À¸ì̾¤Î¥·¥ó¥Ü¥ë¤Ê¤é¤Ð¡¢plist ¤Ï»ØÄê¤Î¥¹¥¯¥ê¥×¥È¤È¸À¸ì¤ËÂФ¹¤ë
1365     @c FONT-GROUP ¤Ç¤¢¤ë¡£@c FONT-GROUP ¤È¤Ï¡¢¥­¡¼¤¬ FLT
1366     (FontLayoutTable) Ì¾¤Î¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢Ãͤ¬ #MFont 
1367     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¤è¤¦¤Ê plist ¤Ç¤¢¤ë¡£¤¿¤À¤·¥Õ¥©¥ó¥È¤Ë FLT 
1368     ¤¬ÂбþÉÕ¤±¤é¤ì¤Æ¤¤¤Ê¤¤»þ¤Ë¤Ï¡¢¥­¡¼¤Ï @c Mt ¤Ë¤Ê¤ë¡£
1369
1370     @li $LANGUAGE ¤¬ @c Mnil ¤Ê¤é¤Ð¡¢plist ¤Ï¤½¤Î¥¹¥¯¥ê¥×¥ÈÍѤΥե©¡¼¥ë¥Ð¥Ã¥¯
1371     @c FONT-GROUP ¤Ç¤¢¤ë¡£
1372
1373     $SCRIPT ¤¬ @c Mnil ¤Ê¤é¤Ð¡¢ÊÖ¤¹ plist ¤Ï°Ê²¼¤Î¤è¤¦¤ËÄê¤Þ¤ë¡£
1374
1375     @li $CHARSET ¤¬ @c Mt ¤Ê¤é¤Ð¡¢plist 
1376     ¤Î¥­¡¼¤Ï¥Õ¥©¥ó¥È¤¬»ØÄꤵ¤ì¤Æ¤¤¤ëʸ»ú¥»¥Ã¥È̾¤Î¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢ÃͤÏ
1377     NULL ¤Ç¤¢¤ë¡£
1378
1379     @li $CHARSET ¤¬Ê¸»ú¥»¥Ã¥È̾¤Î¥·¥ó¥Ü¥ë¤Ê¤é¤Ð¡¢plist ¤Ï¤½¤Îʸ»ú¥»¥Ã¥ÈÍѤΠ
1380     @c FONT-GROUP ¤Ç¤¢¤ë¡£
1381
1382     @li $CHARSET ¤¬ @c Mnil ¤Ê¤é¤Ð¡¢plist ¤Ï¥Õ¥©¡¼¥ë¥Ð¥Ã¥¯ @c FONT-GROUP ¤Ç¤¢¤ë¡£
1383
1384     @return
1385     ¤³¤Î´Ø¿ô¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È¤ÎÆâÍƤòɽ¤¹ plist ¤òÊÖ¤¹¡£
1386     plist ¤Ï m17n_object_unref () ¤Ç²òÊü¤µ¤ì¤ë¤Ù¤­¤Ç¤¢¤ë¡£  */
1387
1388 MPlist *
1389 mfontset_lookup (MFontset *fontset,
1390                  MSymbol script, MSymbol language, MSymbol charset)
1391 {
1392   MPlist *plist = mplist (), *pl, *p;
1393
1394   if (fontset->mdb)
1395     load_fontset_contents (fontset);
1396   if (script == Mt)
1397     {
1398       if (! fontset->per_script)
1399         return plist;
1400       p = plist;
1401       MPLIST_DO (pl, fontset->per_script)
1402         p = mplist_add (p, MPLIST_KEY (pl), NULL);
1403       return plist;
1404     }
1405   if (script != Mnil)
1406     {
1407       pl = get_per_script (fontset, script);
1408       if (MPLIST_TAIL_P (pl))
1409         return plist;
1410       if (language == Mt)
1411         {
1412           p = plist;
1413           MPLIST_DO (pl, pl)
1414             p = mplist_add (p, MPLIST_KEY (pl), NULL);
1415           return plist;
1416         }
1417       if (language == Mnil)
1418         language = Mt;
1419       pl = mplist_get (pl, language);
1420     }
1421   else if (charset != Mnil)
1422     {
1423       if (! fontset->per_charset)
1424         return plist;
1425       if (charset == Mt)
1426         {
1427           p = plist;
1428           MPLIST_DO (pl, fontset->per_charset)
1429             p = mplist_add (p, MPLIST_KEY (pl), NULL);
1430           return plist;
1431         }
1432       pl = mplist_get (fontset->per_charset, charset);
1433     }
1434   else
1435     pl = fontset->fallback;
1436   if (! pl)
1437     return plist;
1438   return mplist_copy (pl);
1439 }
1440
1441
1442 /*** @} */
1443
1444 /*** @addtogroup m17nDebug */
1445 /*=*/
1446 /*** @{  */
1447
1448 /***en
1449     @brief Dump a fontset.
1450
1451     The mdebug_dump_fontset () function prints fontset $FONTSET in a human readable
1452     way to the stderr.  $INDENT specifies how many columns to indent
1453     the lines but the first one.
1454
1455     @return
1456     This function returns $FONTSET.  */
1457 /***ja
1458     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤ò¥À¥ó¥×¤¹¤ë.
1459
1460     ´Ø¿ô mdebug_dump_face () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤ò stderr 
1461     ¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£ $INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
1462
1463     @return
1464     ¤³¤Î´Ø¿ô¤Ï $FONTSET ¤òÊÖ¤¹¡£  */
1465
1466 MFontset *
1467 mdebug_dump_fontset (MFontset *fontset, int indent)
1468 {
1469   char *prefix = (char *) alloca (indent + 1);
1470   MPlist *plist, *pl, *p;
1471
1472   memset (prefix, 32, indent);
1473   prefix[indent] = 0;
1474
1475   fprintf (stderr, "(fontset %s", fontset->name->name);
1476   if (fontset->per_script)
1477     MPLIST_DO (plist, fontset->per_script)
1478       {
1479         fprintf (stderr, "\n  %s(%s", prefix, MPLIST_KEY (plist)->name);
1480         MPLIST_DO (pl, MPLIST_PLIST (plist))
1481           {
1482             fprintf (stderr, "\n    %s(%s", prefix, MPLIST_KEY (pl)->name);
1483             MPLIST_DO (p, MPLIST_PLIST (pl))
1484               {
1485                 fprintf (stderr, "\n      %s(0x%X %s ", prefix,
1486                          (unsigned) MPLIST_VAL (p),
1487                          MPLIST_KEY (p)->name);
1488                 mdebug_dump_font (MPLIST_VAL (p));
1489                 fprintf (stderr, ")");
1490               }
1491             fprintf (stderr, ")");
1492           }
1493         fprintf (stderr, ")");
1494       }
1495   if (fontset->per_charset)
1496     MPLIST_DO (pl, fontset->per_charset)
1497       {
1498         fprintf (stderr, "\n  %s(%s", prefix, MPLIST_KEY (pl)->name);
1499         MPLIST_DO (p, MPLIST_PLIST (pl))
1500           {
1501             fprintf (stderr, "\n    %s(%s ", prefix, MPLIST_KEY (p)->name);
1502             mdebug_dump_font (MPLIST_VAL (p));
1503             fprintf (stderr, ")");
1504           }
1505         fprintf (stderr, ")");
1506       }
1507
1508   if (fontset->fallback)
1509     MPLIST_DO (p, fontset->fallback)
1510       {
1511         fprintf (stderr, "\n  %s(%s ", prefix, MPLIST_KEY (p)->name);
1512         mdebug_dump_font (MPLIST_VAL (p));
1513         fprintf (stderr, ")");
1514       }
1515
1516   fprintf (stderr, ")");
1517   return fontset;
1518 }
1519
1520 /*** @} */
1521
1522 /*
1523   Local Variables:
1524   coding: euc-japan
1525   End:
1526 */