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