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