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