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