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