Update FSF postal address.
[m17n/m17n-lib.git] / src / fontset.c
1 /* fontset.c -- fontset module.
2    Copyright (C) 2003, 2004
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
8    The m17n library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public License
10    as published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    The m17n library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21    02111-1307, USA.  */
22
23 /***en
24     @addtogroup m17nFontset
25     @brief A fontset is an object that maps a character to fonts.
26
27     A @e fontset is an object of the type @c MFontset.  When drawing an
28     M-text, a fontset provides rules to select a font for each
29     character in the M-text according to the following information.
30
31     @li The script character property of a character.
32     @li The language text property of a character.
33     @li The charset text property of a character.
34
35     The documentation of mdraw_text () describes how that information is
36     used.  */
37
38 /***ja @addtogroup m17nFontset 
39
40     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ïʸ»ú¤«¤é¥Õ¥©¥ó¥È¤Ø¤ÎÂбþÉÕ¤±¤ò¹Ô¤¦¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤¢¤ë.
41
42     @e ¥Õ¥©¥ó¥È¥»¥Ã¥È ¤Ï @c MFontset ·¿¤Î¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤¢¤ë¡£M-text 
43     ¤Îɽ¼¨¤ÎºÝ¡¢¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ï°Ê²¼¤Î¾ðÊó¤òÍѤ¤¤Æ M-text 
44     Ãæ¤Î¸Ä¡¹¤Îʸ»ú¤Ë¤É¤Î¥Õ¥©¥ó¥È¤òÍѤ¤¤ë¤«·è¤á¤ëµ¬Â§¤òÍ¿¤¨¤ë¡£
45
46     @li Ê¸»ú¤Îʸ»ú¥×¥í¥Ñ¥Æ¥£ "¥¹¥¯¥ê¥×¥È"
47     @li Ê¸»ú¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£ "¸À¸ì"
48     @li Ê¸»ú¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£ "ʸ»ú¥»¥Ã¥È"
49
50     ¤³¤ì¤é¤Î¾ðÊ󤬤ɤΤ褦¤ËÍѤ¤¤é¤ì¤ë¤«¤Ï mdraw_text () ¤ÎÀâÌÀ¤ò»²¾È¤Î¤³¤È¡£
51
52     */
53
54 /*=*/
55
56 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
57 /*** @addtogroup m17nInternal
58      @{ */
59
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <ctype.h>
64
65 #include "config.h"
66 #include "m17n-gui.h"
67 #include "m17n-misc.h"
68 #include "internal.h"
69 #include "symbol.h"
70 #include "plist.h"
71 #include "character.h"
72 #include "charset.h"
73 #include "internal-gui.h"
74 #include "font.h"
75 #include "fontset.h"
76
77 static 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         /* This is not appropriate for non-Latin scripts.  */
753         request.property[MFONT_REGISTRY] = 0;
754
755       per_script = mplist_get (realized->per_script, script);
756       if (! per_script)
757         {
758           per_script = mplist_copy (get_per_script (realized->fontset, script));
759           /* PER_SCRIPT ::= (LANGUAGE:(LAYOUTER:FONT-SPEC ...) ...) */
760           MPLIST_DO (plist, per_script)
761             MPLIST_VAL (plist) = mplist_copy (MPLIST_VAL (plist));
762           mplist_add (realized->per_script, script, per_script);
763         }
764
765       /* We prefer font groups in this order:
766           (1) group matching with LANGUAGE if LANGUAGE is not Mnil
767           (2) group for generic language
768           (3) group not matching with LANGUAGE  */
769       if (language == Mnil)
770         language = Mt;
771       if ((per_lang = mplist_get (per_script, language))
772           && (rfont = try_font_group (realized, &request, per_lang,
773                                       g, num, size)))
774         return rfont;
775
776       if (per_lang && *num > 1)
777         *num = 1;
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           if (per_lang && *num > 1)
797             *num = 1;
798           /* Then try the above (3) */
799           MPLIST_DO (plist, per_script)
800             if (MPLIST_KEY (plist) != language
801                 && MPLIST_KEY (plist) != Mt
802                 && (rfont = try_font_group (realized, &request,
803                                             MPLIST_PLIST (plist),
804                                             g, num, size)))
805               return rfont;
806         }
807       if (ignore_fallback)
808         return NULL;
809     }
810
811   if (language != Mnil)
812     /* Find a font group for this language from all scripts.  */
813     MPLIST_DO (plist, realized->per_script)
814       {
815         MFont request = realized->request;
816
817         if (MPLIST_KEY (plist) != Mlatin)
818           request.property[MFONT_FOUNDRY]
819             = request.property[MFONT_FAMILY]
820             = request.property[MFONT_FAMILY] = 0;
821         if ((per_lang = mplist_get (MPLIST_PLIST (plist), language))
822             && (rfont = try_font_group (realized, &request, per_lang,
823                                         g, num, size)))
824           return rfont;
825       }
826
827   /* Try fallback fonts.  */
828   if ((rfont = try_font_group (realized, &realized->request,
829                                realized->fallback, g, num, size)))
830     return rfont;
831
832   return NULL;
833
834   /* At last try all fonts.  */
835   MPLIST_DO (per_script, realized->per_script)
836     {
837       MPLIST_DO (per_lang, MPLIST_PLIST (per_script))
838         if ((rfont = try_font_group (realized, &realized->request,
839                                      MPLIST_PLIST (per_lang), g, num, size)))
840           return rfont;
841     }
842   MPLIST_DO (per_charset, realized->per_charset)
843     if ((rfont = try_font_group (realized, &realized->request,
844                                  MPLIST_PLIST (per_charset), g, num, size)))
845       return rfont;
846
847   return NULL;
848 }
849
850 MRealizedFont *
851 get_font_from_group (MFrame *frame, MPlist *plist, MFont *font)
852 {
853   MRealizedFont *rfont;
854
855   MPLIST_DO (plist, plist)
856     {
857       MFont spec = *(MFont *) MPLIST_VAL (plist);
858       if (mfont__merge (&spec, font, 1) < 0)
859         continue;
860       if (font->type == MFONT_TYPE_SPEC)
861         rfont = (MRealizedFont *) mfont_find (frame, &spec, NULL, 0);
862       else if (font->type == MFONT_TYPE_OBJECT)
863         rfont = mfont__open (frame, font, &spec);
864       else
865         rfont = (MRealizedFont *) font;
866       if (rfont
867           && (spec.capability == Mnil
868               || mfont__check_capability (rfont, spec.capability) == 0))
869         {
870           rfont->layouter
871             = MPLIST_KEY (plist) == Mt ? Mnil : MPLIST_KEY (plist);
872           return rfont;
873         }
874     }
875   return NULL;
876 }
877
878 MRealizedFont *
879 mfontset__get_font (MFrame *frame, MFontset *fontset,
880                     MSymbol script, MSymbol language, MFont *font,
881                     int *best)
882 {
883   MPlist *per_script, *per_lang;
884   MRealizedFont *rfont;
885
886   if (best)
887     *best = 0;
888
889   if (language == Mnil)
890     language = Mt;
891
892   if (script != Mnil)
893     {
894       per_script = get_per_script (fontset, script);
895       if ((per_lang = mplist_get (per_script, language))
896           && (rfont = get_font_from_group (frame, per_lang, font)))
897         {
898           if (best)
899             *best = 1;
900           return rfont;
901         }
902       if (best)
903         *best = per_lang ? 0 : 1;
904       if (language == Mt)
905         {
906           MPLIST_DO (per_script, per_script)
907             if (MPLIST_KEY (per_script) != language
908                 && (rfont = get_font_from_group (frame,
909                                                  MPLIST_PLIST (per_script),
910                                                  font)))
911               return rfont;
912         }
913       else
914         {
915           if ((per_lang = mplist_get (per_script, Mt))
916               && (rfont = get_font_from_group (frame, per_lang, font)))
917             return rfont;
918           if (best)
919             *best = 0;
920           MPLIST_DO (per_script, per_script)
921             if (MPLIST_KEY (per_script) != language
922                 && MPLIST_KEY (per_script) != Mt
923                 && (rfont = get_font_from_group (frame,
924                                                  MPLIST_PLIST (per_script),
925                                                  font)))
926               return rfont;
927         }
928     }
929
930   if (language != Mt)
931     MPLIST_DO (per_script, fontset->per_script)
932       {
933         if ((per_lang = mplist_get (MPLIST_PLIST (per_script), language))
934             && (rfont = get_font_from_group (frame, per_lang, font)))
935           {
936             if (best)
937               *best = 1;
938             return rfont;
939           }
940       }
941
942   if (best)
943     *best = 0;
944   if ((rfont = get_font_from_group (frame, fontset->fallback, font)))
945     return rfont;
946   return NULL;
947 }
948
949
950 /*** @} */
951 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
952
953 \f
954 /* External API */
955
956 /*** @addtogroup m17nFontset */
957 /*** @{ */
958
959 /*=*/
960 /***en
961     @brief Return a fontset.
962
963     The mfontset () function returns a pointer to a fontset object of
964     name $NAME.  If $NAME is @c NULL, it returns a pointer to the
965     default fontset.
966
967     If no fontset has the name $NAME, a new one is created.  At that
968     time, if there exists a data \<@c fontset, $NAME\> in the m17n
969     database, the fontset contents are initialized according to the
970     data.  If no such data exists, the fontset contents are left
971     vacant.
972
973     The macro M17N_INIT () creates the default fontset.  An
974     application program can modify it before the first call of 
975     mframe ().
976
977     @return
978     This function returns a pointer to the found or newly created
979     fontset.  */
980 /***ja 
981     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤òÊÖ¤¹.
982
983     ´Ø¿ô mfontset () ¤Ï̾Á° $NAME ¤ò»ý¤Ä¥Õ¥©¥ó¥È¥»¥Ã¥È¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£ 
984     $NAME ¤¬ @c NULL ¤Ê¤é¤Ð¡¢¥Ç¥Õ¥©¥ë¥È¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
985
986     $NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¥Õ¥©¥ó¥È¥»¥Ã¥È¤¬¤Ê¤±¤ì¤Ð¡¢¿·¤·¤¤¤â¤Î¤¬ºî¤é¤ì¤ë¡£¤½¤ÎºÝ¡¢
987     m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë \<@c fontset, $NAME\> 
988     ¤È¤¤¤¦¥Ç¡¼¥¿¤¬¤¢¤ì¤Ð¡¢¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ï¤½¤Î¥Ç¡¼¥¿¤Ë±è¤Ã¤Æ½é´ü²½¤µ¤ì¤ë¡£
989     ¤Ê¤±¤ì¤Ð¡¢¶õ¤Î¤Þ¤Þ¤Ë¤µ¤ì¤ë¡£
990
991     ¥Þ¥¯¥í M17N_INIT () ¤Ï¥Ç¥Õ¥©¥ë¥È¤Î¥Õ¥©¥ó¥È¥»¥Ã¥È¤òºî¤ë¡£¥¢¥×¥ê¥±¡¼¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï
992     mframe () ¤ò½é¤á¤Æ¸Æ¤Ö¤Þ¤Ç¤Î´Ö¤Ï¥Ç¥Õ¥©¥ë¥È¥Õ¥©¥ó¥È¥»¥Ã¥È¤òÊѹ¹¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë¡£
993
994     @return
995     ¤³¤Î´Ø¿ô¤Ï¸«¤Ä¤«¤Ã¤¿¡¢¤¢¤ë¤¤¤Ïºî¤Ã¤¿¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
996      */
997
998 MFontset *
999 mfontset (char *name)
1000 {
1001   MSymbol sym;
1002   MFontset *fontset;
1003
1004   if (! name)
1005     {
1006       fontset = default_fontset;
1007       M17N_OBJECT_REF (fontset);
1008     }
1009   else
1010     {
1011       sym = msymbol (name);
1012       fontset = mplist_get (fontset_list, sym);
1013       if (fontset)
1014         M17N_OBJECT_REF (fontset);
1015       else
1016         {
1017           M17N_OBJECT (fontset, free_fontset, MERROR_FONTSET);
1018           M17N_OBJECT_REGISTER (fontset_table, fontset);
1019           fontset->name = sym;
1020           fontset->mdb = mdatabase_find (Mfontset, sym, Mnil, Mnil);
1021           if (! fontset->mdb)
1022             {
1023               fontset->per_script = mplist ();
1024               fontset->per_charset = mplist ();
1025               fontset->fallback = mplist ();
1026             }
1027           mplist_put (fontset_list, sym, fontset);
1028         }
1029     }
1030   return fontset;
1031 }
1032
1033 /*=*/
1034
1035 /***en
1036     @brief Return the name of a fontset.
1037
1038     The mfontset_name () function returns the name of fontset $FONTSET.  */
1039 /***ja
1040     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î̾Á°¤òÊÖ¤¹.
1041
1042     ´Ø¿ô mfontset_name () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤Î̾Á°¤òÊÖ¤¹¡£  */
1043 MSymbol
1044 mfontset_name (MFontset *fontset)
1045 {
1046   return fontset->name;
1047 }
1048
1049 /*=*/
1050
1051 /***en
1052     @brief Make a copy of a fontset.
1053
1054     The mfontset_copy () function makes a copy of fontset $FONTSET, gives it a
1055     name $NAME, and returns a pointer to the created copy.  $NAME must
1056     not be a name of existing fontset.  In such case, this function
1057     returns NULL without making a copy.  */
1058 /***ja
1059     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î¥³¥Ô¡¼¤òºî¤ë.
1060
1061     ´Ø¿ô mfontset_copy () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤Î¥³¥Ô¡¼¤òºî¤Ã¤Æ¡¢Ì¾Á°
1062     $NAME ¤òÍ¿¤¨¡¢¤½¤Î¥³¥Ô¡¼¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£$NAME 
1063     ¤Ï´û¸¤Î¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î̾Á°¤Ç¤¢¤Ã¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤½¤Î¤è¤¦¤Ê¾ì¹ç¤Ë¤Ï¥³¥Ô¡¼¤òºî¤é¤º¤Ë
1064     NULL ¤òÊÖ¤¹¡£  */
1065
1066 MFontset *
1067 mfontset_copy (MFontset *fontset, char *name)
1068 {
1069   MSymbol sym = msymbol (name);
1070   MFontset *copy = mplist_get (fontset_list, sym);
1071   MPlist *plist, *pl, *p;
1072
1073   if (copy)
1074     return NULL;
1075   M17N_OBJECT (copy, free_fontset, MERROR_FONTSET);
1076   M17N_OBJECT_REGISTER (fontset_table, copy);
1077   copy->name = sym;
1078
1079   if (fontset->mdb)
1080     load_fontset_contents (fontset);
1081
1082   if (fontset->per_script)
1083     {
1084       copy->per_script = mplist ();
1085       MPLIST_DO (plist, fontset->per_script)
1086         {
1087           MPlist *per_lang = mplist ();
1088
1089           mplist_add (copy->per_script, MPLIST_KEY (plist), per_lang);
1090           MPLIST_DO (pl, MPLIST_PLIST (plist))
1091             {
1092               MPlist *font_group = mplist ();
1093
1094               per_lang = mplist_add (per_lang, MPLIST_KEY (pl), font_group);
1095               MPLIST_DO (p, MPLIST_PLIST (pl))
1096                 font_group = mplist_add (font_group, MPLIST_KEY (p),
1097                                          mfont_copy (MPLIST_VAL (p)));
1098             }
1099         }
1100     }
1101   if (fontset->per_charset)
1102     {
1103       MPlist *per_charset = mplist ();
1104
1105       copy->per_charset = per_charset;
1106       MPLIST_DO (pl, fontset->per_charset)
1107         {
1108           MPlist *font_group = mplist ();
1109
1110           per_charset = mplist_add (per_charset, MPLIST_KEY (pl), font_group);
1111           MPLIST_DO (p, MPLIST_PLIST (pl))
1112             font_group = mplist_add (font_group, MPLIST_KEY (p),
1113                                      mfont_copy (MPLIST_VAL (p)));
1114         }
1115     }
1116   if (fontset->fallback)
1117     {
1118       MPlist *font_group = mplist ();
1119
1120       copy->fallback = font_group;
1121       MPLIST_DO (p, fontset->fallback)
1122         font_group = mplist_add (font_group, MPLIST_KEY (p),
1123                                  mfont_copy (MPLIST_VAL (p)));
1124     }                            
1125
1126   mplist_put (fontset_list, sym, copy);
1127   return copy;
1128 }
1129
1130 /*=*/
1131
1132 /***en
1133     @brief Modify the contents of a fontset.
1134
1135     The mfontset_modify_entry () function associates, in fontset
1136     $FONTSET, a copy of $FONT with the $SCRIPT / $LANGUAGE pair or
1137     with $CHARSET.
1138
1139     Each font in a fontset is associated with a particular
1140     script/language pair, with a particular charset, or with the
1141     symbol @c Mnil.  The fonts that are associated with the same item
1142     make a group.
1143
1144     If $SCRIPT is not @c Mnil, it must be a symbol identifying a
1145     script.  In this case, $LANGUAGE is either a symbol identifying a
1146     language or @c Mnil, and $FONT is associated with the $SCRIPT /
1147     $LANGUAGE pair.
1148
1149     If $CHARSET is not @c Mnil, it must be a symbol representing a
1150     charset object.  In this case, $FONT is associated with that
1151     charset.
1152
1153     If both $SCRIPT and $CHARSET are not @c Mnil, two copies of $FONT
1154     are created.  Then one is associated with the $SCRIPT / $LANGUAGE
1155     pair and the other with that charset.
1156
1157     If both $SCRIPT and $CHARSET are @c Mnil, $FONT is associated with
1158     @c Mnil.  This kind of fonts are called @e fallback @e fonts.
1159
1160     The argument $HOW specifies the priority of $FONT.  If $HOW is
1161     positive, $FONT has the highest priority in the group of fonts
1162     that are associated with the same item.  If $HOW is negative,
1163     $FONT has the lowest priority.  If $HOW is zero, $FONT becomes the
1164     only available font for the associated item; all the other fonts
1165     are removed from the group.
1166
1167     If $LAYOUTER_NAME is not @c Mnil, it must be a symbol representing
1168     a @ref flt (font layout table).  In that case, if $FONT is
1169     selected for drawing an M-text, that font layout table is used to
1170     generate a glyph code sequence from a character sequence.
1171
1172     @return
1173     If the operation was successful, mfontset_modify_entry () returns 0.
1174     Otherwise it returns -1 and assigns an error code to the external
1175     variable #merror_code.  */
1176
1177 /***ja
1178     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤ÎÆâÍƤòÊѹ¹¤¹¤ë.
1179
1180     ´Ø¿ô mfontset_modify_entry () ¤Ï¡¢$LANGUAGE ¤È $SCRIPT ¤ÎÁȤ߹ç¤ï¤»¡¢¤Þ¤¿¤Ï
1181     $CHARSET ¤ËÂФ·¤Æ $FONT ¤Î¥³¥Ô¡¼¤ò»È¤¦¤è¤¦¤Ë¡¢¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤òÀßÄꤹ¤ë¡£
1182
1183     ¥Õ¥©¥ó¥È¥»¥Ã¥ÈÃæ¤Î³Æ¥Õ¥©¥ó¥È¤Ï¡¢ÆÃÄê¤Î¥¹¥¯¥ê¥×¥È¤È¸À¸ì¤Î¥Ú¥¢¡¢ÆÃÄê¤Îʸ»ú¥»¥Ã¥È¡¢¥·¥ó¥Ü¥ë
1184     @c Mnil ¤Î¤¤¤º¤ì¤«¤È´ØÏ¢ÉÕ¤±¤é¤ì¤Æ¤¤¤ë¡£Æ±¤¸¤â¤Î¤È´ØÏ¢ÉÕ¤±¤é¤ì¤¿¥Õ¥©¥ó¥È¤Ï¥°¥ë¡¼¥×¤ò¹½À®¤¹¤ë¡£
1185
1186     $SCRIPT ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢¥¹¥¯¥ê¥×¥È¤òÆÃÄꤹ¤ë¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
1187     ¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¾ì¹ç¤Ë¤Ï¡¢$LANGUAGE ¤Ï¸À¸ì¤òÆÃÄꤹ¤ë¥·¥ó¥Ü¥ë¤« @c
1188     Mnil ¤Ç¤¢¤ê¡¢$FONT ¤Ïthe $SCRIPT / $LANGUAGE ¥Ú¥¢¤Ë´ØÏ¢ÉÕ¤±¤é¤ì¤ë¡£
1189
1190     $CHARSET ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢Ê¸»ú¥»¥Ã¥È¥ª¥Ö¥¸¥§¥¯¥È¤òɽ¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
1191     ¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¾ì¹ç¤Ë¤Ï $FONT ¤Ï¤½¤Îʸ»ú¥»¥Ã¥È¤È´ØÏ¢ÉÕ¤±¤é¤ì¤ë¡£
1192
1193     $SCRIPT ¤È $CHARSET ¤ÎÁÐÊý¤¬ @c Mnil ¤Ç¤Ê¤¤¾ì¹ç¤Ë¤Ï $FONT 
1194     ¤Î¥³¥Ô¡¼¤¬£²¤Äºî¤é¤ì¡¢¤½¤ì¤¾¤ì $SCRIPT / $LANGUAGE 
1195     ¥Ú¥¢¤Èʸ»ú¥»¥Ã¥È¤Ë´ØÏ¢ÉÕ¤±¤é¤ì¤ë¡£
1196
1197     $SCRIPT ¤È $CHARSET ¤ÎÁÐÊý¤¬ @c Mnil ¤Ê¤é¤Ð¡¢ $FONT ¤Ï @c Mnil 
1198     ¤È´ØÏ¢ÉÕ¤±¤é¤ì¤ë¡£¤³¤Î¼ï¤Î¥Õ¥©¥ó¥È¤Ï @e fallback @e font ¤È¸Æ¤Ð¤ì¤ë¡£
1199
1200     °ú¿ô $HOW ¤Ï $FONT ¤ÎÍ¥ÀèÅÙ¤ò»ØÄꤹ¤ë¡£$HOW ¤¬Àµ¤Ê¤é¤Ð¡¢$FONT 
1201     ¤ÏƱ¤¸¤â¤Î¤È´ØÏ¢ÉÕ¤±¤é¤ì¤¿¥°¥ë¡¼¥×Ãæ¤ÇºÇ¹â¤ÎÍ¥ÀèÅÙ¤ò»ý¤Ä¡£$HOW 
1202     ¤¬Éé¤Ê¤é¤Ð¡¢ºÇÄã¤ÎÍ¥ÀèÅÙ¤ò»ý¤Ä¡£$HOW ¤¬ 0 ¤Ê¤é¤Ð¡¢$FONT 
1203     ¤Ï´ØÏ¢ÉÕ¤±¤é¤ì¤¿¤â¤Î¤ËÂФ¹¤ëÍ£°ì¤ÎÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤È¤Ê¤ê¡¢Â¾¤Î¥Õ¥©¥ó¥È¤Ï¥°¥ë¡¼¥×¤«¤é¼è¤ê½ü¤«¤ì¤ë¡£
1204
1205     $LAYOUTER_NAME ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢@ref flt 
1206     ¡Ê¥Õ¥©¥ó¥È¥ì¥¤¥¢¥¦¥È¥Æ¡¼¥Ö¥ë¡Ë¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£¥·¥ó¥Ü¥ë¤Ç¤¢¤ì¤Ð¡¢$FONT ¤òÍѤ¤¤Æ
1207     M-text ¤òɽ¼¨¤¹¤ëºÝ¤Ë¤Ï¡¢¤½¤Î¥Õ¥©¥ó¥È¥ì¥¤¥¢¥¦¥È¥Æ¡¼¥Ö¥ë¤ò»È¤Ã¤Æʸ»úÎ󤫤饰¥ê¥Õ¥³¡¼¥ÉÎó¤òÀ¸À®¤¹¤ë¡£
1208
1209     @return 
1210     ½èÍý¤¬À®¸ù¤·¤¿¤È¤­¡¢mfontset_modify_entry () ¤Ï 0 ¤òÊÖ¤¹¡£
1211     ¼ºÇÔ¤·¤¿¤È¤­¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤òÀßÄꤹ¤ë¡£  */
1212
1213 /***
1214     @errors
1215     @c MERROR_SYMBOL  */
1216
1217 int
1218 mfontset_modify_entry (MFontset *fontset,
1219                        MSymbol script, MSymbol language, MSymbol charset,
1220                        MFont *spec, MSymbol layouter_name,
1221                        int how)
1222 {
1223   MPlist *per_lang, *plist[3];
1224   MFont *font = NULL;
1225   int i;
1226
1227   if (fontset->mdb)
1228     load_fontset_contents (fontset);
1229
1230   i = 0;
1231   if (script != Mnil)
1232     {
1233       if (language == Mnil)
1234         language = Mt;
1235       per_lang = mplist_get (fontset->per_script, script);
1236       if (! per_lang)
1237         mplist_add (fontset->per_script, script, per_lang = mplist ());
1238       plist[i] = mplist_get (per_lang, language);
1239       if (! plist[i])
1240         mplist_add (per_lang, language, plist[i] = mplist ());
1241       i++;
1242     }
1243   if (charset != Mnil)
1244     {
1245       plist[i] = mplist_get (fontset->per_charset, charset);
1246       if (! plist[i])
1247         mplist_add (fontset->per_charset, charset, plist[i] = mplist ());
1248       i++;
1249     }
1250   if (script == Mnil && charset == Mnil)
1251     {
1252       plist[i++] = fontset->fallback;
1253     }
1254
1255   if (layouter_name == Mnil)
1256     layouter_name = Mt;
1257   for (i--; i >= 0; i--)
1258     {
1259       font = mfont_copy (spec);
1260       font->type = MFONT_TYPE_SPEC;
1261       if (how == 1)
1262         mplist_push (plist[i], layouter_name, font);
1263       else if (how == -1)
1264         mplist_add (plist[i], layouter_name, font);
1265       else
1266         {
1267           MPlist *pl;
1268
1269           MPLIST_DO (pl, plist[i])
1270             free (MPLIST_VAL (pl));
1271           mplist_set (plist[i], Mnil, NULL);
1272           mplist_add (plist[i], layouter_name, font);
1273         }
1274     }
1275
1276   fontset->tick++;
1277   return 0;
1278 }
1279
1280 /*=*/
1281
1282 /***en
1283     @brief Lookup a fontset.
1284
1285     The mfontset_lookup () function lookups $FONTSET and returns a
1286     plist that describes the contents of $FONTSET corresponding to the
1287     specified script, language, and charset.
1288
1289     If $SCRIPT is @c Mt, keys of the returned plist are script name
1290     symbols for which some fonts are specified and values are NULL.
1291
1292     If $SCRIPT is a script name symbol, the returned plist is decided
1293     by $LANGUAGE.
1294     
1295     @li If $LANGUAGE is @c Mt, keys of the plist are language name
1296     symbols for which some fonts are specified and values are NULL.  A
1297     key may be @c Mt which means some fallback fonts are specified for
1298     the script.
1299
1300     @li If $LANGUAGE is a language name symbol, the plist is a @c
1301     FONT-GROUP for the specified script and language.  @c FONT-GROUP
1302     is a plist whose keys are FLT (FontLayoutTable) name symbols (@c
1303     Mt if no FLT is associated with the font) and values are pointers
1304     to #MFont.
1305
1306     @li If $LANGUAGE is @c Mnil, the plist is fallback @c FONT-GROUP
1307     for the script. 
1308
1309     If $SCRIPT is @c Mnil, the returned plist is decided as below.
1310
1311     @li If $CHARSET is @c Mt, keys of the returned plist are charset name
1312     symbols for which some fonts are specified and values are NULL.
1313
1314     @li If $CHARSET is a charset name symbol, the plist is a @c FONT-GROUP for
1315     the charset.
1316
1317     @li If $CHARSET is @c Mnil, the plist is a fallback @c FONT-GROUP.
1318
1319     @return
1320     It returns a plist describing the contents of a fontset.  The
1321     plist should be freed by m17n_object_unref ().  */
1322 /***ja
1323     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤ò¸¡º÷¤¹¤ë.
1324
1325     ´Ø¿ô mfontset_lookup () ¤Ï $FONTSET ¤ò¸¡º÷¤·¡¢$FONTSET 
1326     ¤ÎÆâÍƤΤ¦¤Á»ØÄꤷ¤¿¥¹¥¯¥ê¥×¥È¡¢¸À¸ì¡¢Ê¸»ú¥»¥Ã¥È¤ËÂбþ¤¹¤ëÉôʬ¤òɽ¤¹
1327     plist ¤òÊÖ¤¹¡£
1328
1329     $SCRIPT ¤¬ @c Mt ¤Ê¤é¤Ð¡¢ÊÖ¤¹ plist 
1330     ¤Î¥­¡¼¤Ï¥Õ¥©¥ó¥È¤¬»ØÄꤵ¤ì¤Æ¤¤¤ë¥¹¥¯¥ê¥×¥È̾¤Î¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢ÃͤÏ
1331     NULL ¤Ç¤¢¤ë¡£
1332
1333     $SCRIPT ¤¬¥¹¥¯¥ê¥×¥È̾¤Î¥·¥ó¥Ü¥ë¤Ç¤¢¤ì¤Ð¡¢ÊÖ¤¹ 
1334     plist ¤Ï $LANGUAGE¤Ë¤è¤Ã¤ÆÄê¤Þ¤ë¡£
1335     
1336     @li $LANGUAGE ¤¬ @c Mt ¤Ê¤é¤Ð¡¢plist 
1337     ¤Î¥­¡¼¤Ï¥Õ¥©¥ó¥È¤¬»ØÄꤵ¤ì¤Æ¤¤¤ë¸À¸ì̾¤Î¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢ÃͤÏ
1338     NULL ¤Ç¤¢¤ë¡£¥­¡¼¤Ï @c Mt
1339     ¤Ç¤¢¤ë¤³¤È¤â¤¢¤ê¡¢¤½¤Î¾ì¹ç¤½¤Î¥¹¥¯¥ê¥×¥È¤Ë¥Õ¥©¡¼¥ë¥Ð¥Ã¥¯¥Õ¥©¥ó¥È¤¬¤¢¤ë¤³¤È¤ò°ÕÌ£¤¹¤ë¡£
1340
1341     @li $LANGUAGE ¤¬¸À¸ì̾¤Î¥·¥ó¥Ü¥ë¤Ê¤é¤Ð¡¢plist ¤Ï»ØÄê¤Î¥¹¥¯¥ê¥×¥È¤È¸À¸ì¤ËÂФ¹¤ë
1342     @c FONT-GROUP ¤Ç¤¢¤ë¡£@c FONT-GROUP ¤È¤Ï¡¢¥­¡¼¤¬ FLT
1343     (FontLayoutTable) Ì¾¤Î¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢Ãͤ¬ #MFont 
1344     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤Ç¤¢¤ë¤è¤¦¤Ê plist ¤Ç¤¢¤ë¡£¤¿¤À¤·¥Õ¥©¥ó¥È¤Ë FLT 
1345     ¤¬ÂбþÉÕ¤±¤é¤ì¤Æ¤¤¤Ê¤¤»þ¤Ë¤Ï¡¢¥­¡¼¤Ï @c Mt ¤Ë¤Ê¤ë¡£
1346
1347     @li $LANGUAGE ¤¬ @c Mnil ¤Ê¤é¤Ð¡¢plist ¤Ï¤½¤Î¥¹¥¯¥ê¥×¥ÈÍѤΥե©¡¼¥ë¥Ð¥Ã¥¯
1348     @c FONT-GROUP ¤Ç¤¢¤ë¡£
1349
1350     $SCRIPT ¤¬ @c Mnil ¤Ê¤é¤Ð¡¢ÊÖ¤¹ plist ¤Ï°Ê²¼¤Î¤è¤¦¤ËÄê¤Þ¤ë¡£
1351
1352     @li $CHARSET ¤¬ @c Mt ¤Ê¤é¤Ð¡¢plist 
1353     ¤Î¥­¡¼¤Ï¥Õ¥©¥ó¥È¤¬»ØÄꤵ¤ì¤Æ¤¤¤ëʸ»ú¥»¥Ã¥È̾¤Î¥·¥ó¥Ü¥ë¤Ç¤¢¤ê¡¢ÃͤÏ
1354     NULL ¤Ç¤¢¤ë¡£
1355
1356     @li $CHARSET ¤¬Ê¸»ú¥»¥Ã¥È̾¤Î¥·¥ó¥Ü¥ë¤Ê¤é¤Ð¡¢plist ¤Ï¤½¤Îʸ»ú¥»¥Ã¥ÈÍѤΠ
1357     @c FONT-GROUP ¤Ç¤¢¤ë¡£
1358
1359     @li $CHARSET ¤¬ @c Mnil ¤Ê¤é¤Ð¡¢plist ¤Ï¥Õ¥©¡¼¥ë¥Ð¥Ã¥¯ @c FONT-GROUP ¤Ç¤¢¤ë¡£
1360
1361     @return
1362     ¤³¤Î´Ø¿ô¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È¤ÎÆâÍƤòɽ¤¹ plist ¤òÊÖ¤¹¡£
1363     plist ¤Ï m17n_object_unref () ¤Ç²òÊü¤µ¤ì¤ë¤Ù¤­¤Ç¤¢¤ë¡£  */
1364
1365 MPlist *
1366 mfontset_lookup (MFontset *fontset,
1367                  MSymbol script, MSymbol language, MSymbol charset)
1368 {
1369   MPlist *plist = mplist (), *pl, *p;
1370
1371   if (fontset->mdb)
1372     load_fontset_contents (fontset);
1373   if (script == Mt)
1374     {
1375       if (! fontset->per_script)
1376         return plist;
1377       p = plist;
1378       MPLIST_DO (pl, fontset->per_script)
1379         p = mplist_add (p, MPLIST_KEY (pl), NULL);
1380       return plist;
1381     }
1382   if (script != Mnil)
1383     {
1384       pl = get_per_script (fontset, script);
1385       if (MPLIST_TAIL_P (pl))
1386         return plist;
1387       if (language == Mt)
1388         {
1389           p = plist;
1390           MPLIST_DO (pl, pl)
1391             p = mplist_add (p, MPLIST_KEY (pl), NULL);
1392           return plist;
1393         }
1394       if (language == Mnil)
1395         language = Mt;
1396       pl = mplist_get (pl, language);
1397     }
1398   else if (charset != Mnil)
1399     {
1400       if (! fontset->per_charset)
1401         return plist;
1402       if (charset == Mt)
1403         {
1404           p = plist;
1405           MPLIST_DO (pl, fontset->per_charset)
1406             p = mplist_add (p, MPLIST_KEY (pl), NULL);
1407           return plist;
1408         }
1409       pl = mplist_get (fontset->per_charset, charset);
1410     }
1411   else
1412     pl = fontset->fallback;
1413   if (! pl)
1414     return plist;
1415   return mplist_copy (pl);
1416 }
1417
1418
1419 /*** @} */
1420
1421 /*** @addtogroup m17nDebug */
1422 /*=*/
1423 /*** @{  */
1424
1425 /***en
1426     @brief Dump a fontset.
1427
1428     The mdebug_dump_fontset () function prints fontset $FONTSET in a human readable
1429     way to the stderr.  $INDENT specifies how many columns to indent
1430     the lines but the first one.
1431
1432     @return
1433     This function returns $FONTSET.  */
1434 /***ja
1435     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤ò¥À¥ó¥×¤¹¤ë.
1436
1437     ´Ø¿ô mdebug_dump_face () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤ò stderr 
1438     ¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£ $INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
1439
1440     @return
1441     ¤³¤Î´Ø¿ô¤Ï $FONTSET ¤òÊÖ¤¹¡£  */
1442
1443 MFontset *
1444 mdebug_dump_fontset (MFontset *fontset, int indent)
1445 {
1446   char *prefix = (char *) alloca (indent + 1);
1447   MPlist *plist, *pl, *p;
1448
1449   memset (prefix, 32, indent);
1450   prefix[indent] = 0;
1451
1452   fprintf (stderr, "(fontset %s", fontset->name->name);
1453   if (fontset->per_script)
1454     MPLIST_DO (plist, fontset->per_script)
1455       {
1456         fprintf (stderr, "\n  %s(%s", prefix, MPLIST_KEY (plist)->name);
1457         MPLIST_DO (pl, MPLIST_PLIST (plist))
1458           {
1459             fprintf (stderr, "\n    %s(%s", prefix, MPLIST_KEY (pl)->name);
1460             MPLIST_DO (p, MPLIST_PLIST (pl))
1461               {
1462                 fprintf (stderr, "\n      %s(0x%X %s ", prefix,
1463                          (unsigned) MPLIST_VAL (p),
1464                          MPLIST_KEY (p)->name);
1465                 mdebug_dump_font (MPLIST_VAL (p));
1466                 fprintf (stderr, ")");
1467               }
1468             fprintf (stderr, ")");
1469           }
1470         fprintf (stderr, ")");
1471       }
1472   if (fontset->per_charset)
1473     MPLIST_DO (pl, fontset->per_charset)
1474       {
1475         fprintf (stderr, "\n  %s(%s", prefix, MPLIST_KEY (pl)->name);
1476         MPLIST_DO (p, MPLIST_PLIST (pl))
1477           {
1478             fprintf (stderr, "\n    %s(%s ", prefix, MPLIST_KEY (p)->name);
1479             mdebug_dump_font (MPLIST_VAL (p));
1480             fprintf (stderr, ")");
1481           }
1482         fprintf (stderr, ")");
1483       }
1484
1485   if (fontset->fallback)
1486     MPLIST_DO (p, fontset->fallback)
1487       {
1488         fprintf (stderr, "\n  %s(%s ", prefix, MPLIST_KEY (p)->name);
1489         mdebug_dump_font (MPLIST_VAL (p));
1490         fprintf (stderr, ")");
1491       }
1492
1493   fprintf (stderr, ")");
1494   return fontset;
1495 }
1496
1497 /*** @} */
1498
1499 /*
1500   Local Variables:
1501   coding: euc-japan
1502   End:
1503 */