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