(mfont__lookup_fontset): Delete local variable
[m17n/m17n-lib.git] / src / fontset.c
1 /* fontset.c -- fontset module.
2    Copyright (C) 2003, 2004
3      National Institute of Advanced Industrial Science and Technology (AIST)
4      Registration Number H15PRO112
5
6    This file is part of the m17n library.
7
8    The m17n library is free software; you can redistribute it and/or
9    modify it under the terms of the GNU Lesser General Public License
10    as published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    The m17n library is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with the m17n library; if not, write to the Free
20    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21    02111-1307, USA.  */
22
23 /***en
24     @addtogroup m17nFontset
25     @brief A fontset is an object that maps a character to fonts.
26
27     A @e fontset is an object of the type @c MFontset.  When drawing an
28     M-text, a fontset provides rules to select a font for each
29     character in the M-text according to the following information.
30
31     @li The script character property of a character.
32     @li The language text property of a character.
33     @li The charset text property of a character.
34
35     The documentation of mdraw_text () describes how that information is
36     used.  */
37
38 /***ja @addtogroup m17nFontset 
39
40     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ïʸ»ú¤«¤é¥Õ¥©¥ó¥È¤Ø¤ÎÂбþÉÕ¤±¤ò¹Ô¤¦¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤¢¤ë.
41
42     @e ¥Õ¥©¥ó¥È¥»¥Ã¥È ¤Ï @c MFontset ·¿¤Î¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤¢¤ë¡£M-text ¤ò
43     É½¼¨¤¹¤ëºÝ¡¢¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ï M-text Ãæ¤Î¸Ä¡¹¤Îʸ»ú¤ËÂФ·¤Æ¤É¤Î¥Õ¥©
44     ¥ó¥È¤òÍѤ¤¤ë¤«¤Îµ¬Â§¤ò¡¢°Ê²¼¤Î¾ðÊó¤Ë½¾¤Ã¤ÆÍ¿¤¨¤ë¡£
45
46     @li Ê¸»ú¤Îʸ»ú¥×¥í¥Ñ¥Æ¥£ "¥¹¥¯¥ê¥×¥È"
47     @li Ê¸»ú¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£ "¸À¸ì"
48     @li Ê¸»ú¤Î¥Æ¥­¥¹¥È¥×¥í¥Ñ¥Æ¥£ "ʸ»ú¥»¥Ã¥È"
49
50     ¤³¤ì¤é¤Î¾ðÊ󤬤ɤΤ褦¤ËÍѤ¤¤é¤ì¤ë¤«¤Ï mdraw_text () ¤ÎÀâÌÀ¤ò»²¾È
51     ¤Î¤³¤È¡£
52
53     */
54
55 /*=*/
56
57 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
58 /*** @addtogroup m17nInternal
59      @{ */
60
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <ctype.h>
65
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 struct MFontset
78 {
79   M17NObject control;
80
81   /* Name of the fontset.  */
82   MSymbol name;
83
84   /* Initialized to 0, and incremented by one each time the fontset is
85      modified.  */
86   unsigned tick;
87
88   /* Database from which to load the contents of the fontset.  Once
89      loaded, this member is set to NULL.  */
90   MDatabase *mdb;
91
92   /* SCRIPT vs PER-LANGUAGE (which is a plist LANGUAGE vs FONT-GROUP) */
93   MPlist *per_script;
94
95   /* CHARSET vs FONT-GROUP */
96   MPlist *per_charset;
97
98   /* FONT-GROUP */
99   MPlist *fallback;
100
101   /* Plist of Mt vs font specs. */
102   MPlist *font_spec_list;
103 };
104
105 static MFontset *default_fontset;
106
107 static MPlist *fontset_list;
108
109 struct MRealizedFontset
110 {
111   /* Fontset from which the realized fontset is realized.  */
112   MFontset *fontset;
113
114   /* Initialized to <fontset>->tick.  */
115   unsigned tick;
116
117   /* Font spec extracted from a face.  */
118   MFont spec;
119
120   /* The frame on which the realized fontset is realized.  */
121   MFrame *frame;
122
123   MPlist *per_script;
124
125   MPlist *per_charset;
126
127   MPlist *fallback;
128 };
129
130
131 static MPlist *
132 load_font_group (MPlist *plist, MPlist *elt, MPlist *spec_list)
133 {
134   MPLIST_DO (elt, elt)
135     {
136       /* ELT ::= ( FONT-SPEC-LIST [ LAYOUTER ] ) ...  */
137       MPlist *elt2, *p;
138       MFont font, *spec = NULL;
139       MSymbol layouter_name;
140
141       if (! MPLIST_PLIST_P (elt))
142         MWARNING (MERROR_FONTSET);
143       elt2 = MPLIST_PLIST (elt);
144       if (! MPLIST_PLIST_P (elt2))
145         MWARNING (MERROR_FONTSET);
146       mfont__set_spec_from_plist (&font, MPLIST_PLIST (elt2));
147       MPLIST_DO (p, spec_list)
148         {
149           if (! memcmp (MPLIST_VAL (p), &font, sizeof (MFont)))
150             {
151               spec = MPLIST_VAL (p);
152               break;
153             }
154         }
155       if (! spec)
156         {
157           MSTRUCT_MALLOC (spec, MERROR_FONTSET);
158           *spec = font;
159           mplist_add (spec_list, Mt, spec);
160         }
161       elt2 = MPLIST_NEXT (elt2);
162       layouter_name = Mt;
163       if (MPLIST_SYMBOL_P (elt2))
164         layouter_name = MPLIST_SYMBOL (elt2);
165       if (layouter_name == Mnil)
166         layouter_name = Mt;
167       plist = mplist_add (plist, layouter_name, spec);
168       continue;
169     warning:
170       /* ANSI-C requires some statement after a label.  */
171       continue;
172     }
173   return plist;
174 }
175
176 /* Load FONTSET->per_script from the data in FONTSET->mdb.  */
177
178 static void
179 load_fontset_contents (MFontset *fontset)
180 {
181   MPlist *per_script, *per_charset, *fallback, *spec_list, *font_group;
182   MSymbol script, lang;
183   MPlist *fontset_def, *plist;
184
185   fontset->per_script = per_script = mplist ();
186   fontset->per_charset = per_charset = mplist ();
187   fontset->fallback = fallback = mplist ();
188   fontset->font_spec_list = spec_list = mplist ();
189   if (! (fontset_def = (MPlist *) mdatabase_load (fontset->mdb)))
190     return;
191
192   MPLIST_DO (plist, fontset_def)
193     {
194       /* PLIST ::= ( SCRIPT ( LANGUAGE FONT-SPEC-ELT ... ) ... )
195                    | (CHARSET FONT-SPEC-ELT ...)
196                    | FONT-SPEC-ELT  */
197       MPlist *elt;
198
199       if (! MPLIST_PLIST_P (plist))
200         MWARNING (MERROR_FONTSET);
201       elt = MPLIST_PLIST (plist);
202       if (! MPLIST_SYMBOL_P (elt))
203         MWARNING (MERROR_FONTSET);
204       script = MPLIST_SYMBOL (elt);
205       elt = MPLIST_NEXT (elt);
206       if (! MPLIST_PLIST_P (elt))
207         MWARNING (MERROR_FONTSET);
208       if (script == Mnil)
209         fallback = load_font_group (fallback, elt, spec_list);
210       else if (MPLIST_PLIST_P (MPLIST_PLIST (elt)))
211         {
212           font_group = mplist_find_by_key (fontset->per_charset, script);
213           if (! font_group)
214             {
215               font_group = mplist ();
216               per_charset = mplist_add (per_charset, script, font_group);
217             }
218           load_font_group (font_group, elt, spec_list);
219         }
220       else
221         {
222           MPlist *per_lang = mplist_find_by_key (fontset->per_script, script);
223
224           if (! per_lang)
225             {
226               per_lang = mplist ();
227               per_script = mplist_add (per_script, script, per_lang);
228             }
229
230           MPLIST_DO (elt, elt)
231             {
232               /* ELT ::= ( LANGUAGE FONT-DEF ...) ... */
233               MPlist *elt2;
234
235               if (! MPLIST_PLIST_P (elt))
236                 MWARNING (MERROR_FONTSET);
237               elt2 = MPLIST_PLIST (elt);
238               if (! MPLIST_SYMBOL_P (elt2))
239                 MWARNING (MERROR_FONTSET);
240               lang = MPLIST_SYMBOL (elt2);
241               if (lang == Mnil)
242                 lang = Mt;
243               font_group = mplist_find_by_key (per_lang, lang);
244               if (! font_group)
245                 {
246                   font_group = mplist ();
247                   mplist_add (per_lang, lang, font_group);
248                 }
249               elt2 = MPLIST_NEXT (elt2);
250               load_font_group (font_group, elt2, spec_list);
251             }
252         }
253       continue;
254
255     warning:
256       /* ANSI-C requires some statement after a label.  */
257       continue;
258     }
259
260   M17N_OBJECT_UNREF (fontset_def);
261   fontset->mdb = NULL;
262 }
263
264 static void
265 free_fontset (void *object)
266 {
267   MFontset *fontset = (MFontset *) object;
268   MPlist *plist, *pl, *p;
269
270   if (fontset->per_script)
271     {
272       MPLIST_DO (plist, fontset->per_script)
273         {
274           MPLIST_DO (pl, MPLIST_PLIST (plist))
275             {
276               p = MPLIST_PLIST (pl);
277               M17N_OBJECT_UNREF (p);
278             }
279           pl = MPLIST_PLIST (plist);
280           M17N_OBJECT_UNREF (pl);
281         }
282       M17N_OBJECT_UNREF (fontset->per_script);
283     }
284   if (fontset->per_charset)
285     {
286       MPLIST_DO (plist, fontset->per_charset)
287         {
288           pl = MPLIST_PLIST (plist);
289           M17N_OBJECT_UNREF (pl);
290         }
291       M17N_OBJECT_UNREF (fontset->per_charset);
292     }
293   if (fontset->fallback)
294     M17N_OBJECT_UNREF (fontset->fallback);
295   plist = mplist_find_by_key (fontset_list, fontset->name);
296   if (! plist)
297     mdebug_hook ();
298   mplist_pop (plist);
299   if (fontset->font_spec_list)
300     {
301       if (((M17NObject *) (fontset->font_spec_list))->ref_count == 1)
302         MPLIST_DO (plist, fontset->font_spec_list)
303           free (MPLIST_VAL (plist));
304       M17N_OBJECT_UNREF (fontset->font_spec_list);
305     }
306   free (object);
307 }
308
309 static void
310 realize_font_group (MFrame *frame, MFont *request, MPlist *font_group,
311                     int size)
312 {
313   MPlist *plist = MPLIST_VAL (font_group), *pl, *p;
314
315   mplist_set (font_group, Mnil, NULL);
316   MPLIST_DO (pl, plist)
317     {
318       MSymbol layouter = MPLIST_KEY (pl);
319       MFont this_request = *request;
320       MRealizedFont *rfont;
321
322       mfont__resize (MPLIST_VAL (pl), &this_request);
323       rfont = mfont__select (frame, MPLIST_VAL (pl), &this_request,
324                              size, layouter == Mt ? Mnil : layouter);
325
326       if (rfont)
327         {
328           MPLIST_DO (p, font_group)
329             if (((MRealizedFont *) (MPLIST_VAL (p)))->score > rfont->score)
330               break;
331           mplist_push (p, Mt, rfont);
332         }
333     }
334 }
335
336 \f
337
338 /* Internal API */
339
340 int
341 mfont__fontset_init ()
342 {
343   Mfontset = msymbol ("fontset");
344   Mfontset->managing_key = 1;
345   fontset_list = mplist ();
346   default_fontset = mfontset ("default");
347   if (! default_fontset->mdb)
348     {
349       MFont font;
350
351       MFONT_INIT (&font);
352       mfont_put_prop (&font, Mregistry, msymbol ("iso8859-1"));
353       mfontset_modify_entry (default_fontset, Mnil, Mnil, Mnil,
354                              &font, Mnil, 1);
355       mfont_put_prop (&font, Mregistry, msymbol ("iso10646-1"));
356       mfontset_modify_entry (default_fontset, Mnil, Mnil, Mnil,
357                              &font, Mnil, 1);
358     }
359   return 0;
360 }
361
362
363 void
364 mfont__fontset_fini ()
365 {
366   while (! MPLIST_TAIL_P (fontset_list))
367     free_fontset ((MFontset *) MPLIST_VAL (fontset_list));
368   M17N_OBJECT_UNREF (fontset_list);
369   fontset_list = NULL;
370 }
371
372
373 MRealizedFontset *
374 mfont__realize_fontset (MFrame *frame, MFontset *fontset, MFace *face)
375 {
376   MRealizedFontset *realized;
377   MFont request;
378   MPlist *per_script, *per_lang, *per_charset, *font_group;
379   MPlist *plist, *pl, *p;
380
381   if (fontset->mdb)
382     load_fontset_contents (fontset);
383
384   mfont__set_spec_from_face (&request, face);
385   if (request.property[MFONT_SIZE] <= 0)
386     {
387       mdebug_hook ();
388       request.property[MFONT_SIZE] = 120;
389     }
390   MPLIST_DO (p, frame->realized_fontset_list)
391     {
392       realized = (MRealizedFontset *) MPLIST_VAL (p);
393       if (fontset->name == MPLIST_KEY (p)
394           && ! memcmp (&request, &realized->spec, sizeof (request)))
395         return realized;
396     }
397
398   MSTRUCT_MALLOC (realized, MERROR_FONTSET);
399   realized->fontset = fontset;
400   realized->tick = fontset->tick;
401   realized->spec = request;
402   realized->frame = frame;
403   realized->per_script = per_script = mplist ();
404   MPLIST_DO (plist, fontset->per_script)
405     {
406       per_lang = mplist ();
407       per_script = mplist_add (per_script, MPLIST_KEY (plist), per_lang);
408       MPLIST_DO (pl, MPLIST_PLIST (plist))
409         {
410           font_group = mplist ();
411           mplist_add (font_group, Mplist, MPLIST_VAL (pl));
412           per_lang = mplist_add (per_lang, MPLIST_KEY (pl), font_group);
413         }
414     }
415
416   realized->per_charset = per_charset = mplist ();
417   MPLIST_DO (plist, fontset->per_charset)
418     {
419       font_group = mplist ();
420       mplist_add (font_group, Mplist, MPLIST_VAL (plist));
421       per_charset = mplist_add (per_charset, MPLIST_KEY (plist), font_group);
422     }
423
424   realized->fallback = mplist ();
425   mplist_add (realized->fallback, Mplist, fontset->fallback);
426
427   mplist_add (frame->realized_fontset_list, fontset->name, realized);
428   return realized;
429 }
430
431
432 void
433 mfont__free_realized_fontset (MRealizedFontset *realized)
434 {
435   MPlist *plist, *pl, *p;
436   MRealizedFont *rfont;
437
438   if (realized->per_script)
439     {
440       MPLIST_DO (plist, realized->per_script)
441         {
442           MPLIST_DO (pl, MPLIST_PLIST (plist))
443             {
444               MPLIST_DO (p, MPLIST_PLIST (pl))
445                 if ((rfont = MPLIST_VAL (p)) && ! rfont->frame)
446                   free (rfont);
447               p = MPLIST_PLIST (pl);
448               M17N_OBJECT_UNREF (p);
449             }
450           pl = MPLIST_PLIST (plist);
451           M17N_OBJECT_UNREF (pl);
452         }
453       M17N_OBJECT_UNREF (realized->per_script);
454     }
455   if (realized->per_charset)
456     {
457       MPLIST_DO (plist, realized->per_charset)
458         {
459           MPLIST_DO (pl, MPLIST_PLIST (plist))
460             if ((rfont = MPLIST_VAL (pl)) && ! rfont->frame)
461               free (rfont);
462           pl = MPLIST_PLIST (plist);
463           M17N_OBJECT_UNREF (pl);
464         }
465       M17N_OBJECT_UNREF (realized->per_charset);
466     }
467   if (realized->fallback)
468     {
469       MPLIST_DO (plist, realized->fallback)
470         if ((rfont = MPLIST_VAL (plist)) && ! rfont->frame)
471           free (rfont);
472       M17N_OBJECT_UNREF (realized->fallback);
473     }
474
475   free (realized);
476 }
477
478
479 MRealizedFont *
480 mfont__lookup_fontset (MRealizedFontset *realized, MGlyph *g, int *num,
481                        MSymbol script, MSymbol language, MSymbol charset,
482                        int size)
483 {
484   MFrame *frame = realized->frame;
485   MCharset *preferred_charset = (charset == Mnil ? NULL : MCHARSET (charset));
486   MPlist *per_charset, *per_script, *per_lang;
487   MPlist *font_groups[256], *plist;
488   int n_font_group = 0;
489   MRealizedFont *rfont;
490   int i;
491
492   if (preferred_charset
493       && (per_charset = mplist_get (realized->per_charset, charset)) != NULL)
494     font_groups[n_font_group++] = per_charset;
495   if (script != Mnil
496       && ((per_script = mplist_find_by_key (realized->per_script, script))
497           != NULL))
498     {
499       /* The first loop is for matching language (if any), and the second
500          loop is for non-matching languages.  */
501       if (language == Mnil)
502         language = Mt;
503       for (i = 0; i < 2; i++)
504         {
505           MPLIST_DO (per_lang, MPLIST_PLIST (per_script))
506             if ((MPLIST_KEY (per_lang) == language) != i)
507               font_groups[n_font_group++] = MPLIST_PLIST (per_lang);
508         }
509     }
510   font_groups[n_font_group++] = realized->fallback;
511
512   if (n_font_group == 1)
513     {
514       /* As we only have a fallback font group, try all the other
515          fonts too.  */
516       MPLIST_DO (per_script, realized->per_script)
517         MPLIST_DO (per_lang, MPLIST_PLIST (per_script))
518           font_groups[n_font_group++] = MPLIST_PLIST (per_lang);
519       MPLIST_DO (per_charset, realized->per_charset)
520         font_groups[n_font_group++] = MPLIST_PLIST (per_charset);
521     }
522
523   for (i = 0; i < n_font_group; i++)
524     {
525       int j;
526       
527       if (MPLIST_PLIST_P (font_groups[i]))
528         realize_font_group (frame, &realized->spec, font_groups[i], size);
529
530       MPLIST_DO (plist, font_groups[i])
531         {
532           rfont = (MRealizedFont *) MPLIST_VAL (plist);
533           if (rfont->status < 0)
534             continue;
535           /* Check if this font can display all glyphs.  */
536           for (j = 0; j < *num; j++)
537             {
538               g[j].code = mfont__encode_char (rfont, g[j].c);
539               if (g[j].code == MCHAR_INVALID_CODE)
540                 break;
541             }
542           if (j == *num)
543             {
544               if (rfont->status > 0
545                   || mfont__open (rfont) == 0)
546                 /* We found a font that can display all glyphs.  */
547                 break;
548             }
549         }
550       if (! MPLIST_TAIL_P (plist))
551         break;
552     }
553
554   if (i < n_font_group) 
555     return rfont;
556
557   /* We couldn't find a font that can display all glyphs.  Find one
558      that can display at least the first glyph.  */
559   for (i = 0; i < n_font_group; i++)
560     {
561       MPLIST_DO (plist, font_groups[i])
562         {
563           rfont = (MRealizedFont *) MPLIST_VAL (plist);
564           if (rfont->status < 0)
565             continue;
566           g->code = mfont__encode_char (rfont, g->c);
567           if (g->code != MCHAR_INVALID_CODE)
568             {
569               if (rfont->status > 0
570                   || mfont__open (rfont) == 0)
571                 break;
572             }
573         }
574       if (! MPLIST_TAIL_P (plist))
575         break;
576     }
577   return (i < n_font_group ? rfont : NULL);
578 }
579
580 /*** @} */
581 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
582
583 \f
584 /* External API */
585
586 /*** @addtogroup m17nFontset */
587 /*** @{ */
588
589 /*=*/
590 /***en
591     @brief Return a fontset.
592
593     The mfontset () function returns a pointer to a fontset object of
594     name $NAME.  If $NAME is @c NULL, it returns a pointer to the
595     default fontset.
596
597     If no fontset has the name $NAME, a new one is created.  At that
598     time, if there exists a data \<@c fontset, $NAME\> in the m17n
599     database, the fontset contents are initialized according to the
600     data.  If no such data exists, the fontset contents are left
601     vacant.
602
603     The macro M17N_INIT () creates the default fontset.  An
604     application program can modify it before the first call of 
605     mframe ().
606
607     @return
608     This function returns a pointer to the found or newly created
609     fontset.  */
610 /***ja 
611     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤òÊÖ¤¹.
612
613     ´Ø¿ô mfontset () ¤Ï̾Á° $NAME ¤ò»ý¤Ä¥Õ¥©¥ó¥È¥»¥Ã¥È¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î
614     ¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£ $NAME ¤¬ @c NULL ¤Ê¤é¤Ð¡¢¥Ç¥Õ¥©¥ë¥È¥Õ¥©¥ó¥È¥»¥Ã¥È
615     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
616
617     $NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¥Õ¥©¥ó¥È¥»¥Ã¥È¤¬¤Ê¤±¤ì¤Ð¡¢¿·¤·¤¤¤â¤Î¤¬ºî¤é¤ì
618     ¤ë¡£¤½¤ÎºÝ¡¢m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë \<@c fontset, $NAME\> ¤È¤¤¤¦¥Ç¡¼¥¿
619     ¤¬¤¢¤ì¤Ð¡¢¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ï¤½¤Î¥Ç¡¼¥¿¤Ë±è¤Ã¤Æ½é´ü²½¤µ¤ì¤ë¡£¤Ê¤±¤ì¤Ð¡¢
620     ¶õ¤Î¤Þ¤Þ¤Ë¤µ¤ì¤ë¡£
621
622     ¥Þ¥¯¥í M17N_INIT () ¤Ï¥Ç¥Õ¥©¥ë¥È¤Î¥Õ¥©¥ó¥È¥»¥Ã¥È¤òºî¤ë¡£¥¢¥×¥ê¥±¡¼
623     ¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï mframe () ¤ò½é¤á¤Æ¸Æ¤Ö¤Þ¤Ç¤Ï¥Ç¥Õ¥©¥ë¥È¥Õ¥©¥ó¥È
624     ¥»¥Ã¥È¤òÊѹ¹¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë¡£
625
626     @return
627     ¤³¤Î´Ø¿ô¤Ï¸«¤Ä¤«¤Ã¤¿¡¢¤¢¤ë¤¤¤Ïºî¤Ã¤¿¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
628      */
629
630 MFontset *
631 mfontset (char *name)
632 {
633   MSymbol sym;
634   MFontset *fontset;
635
636   if (! name)
637     fontset = default_fontset;
638   else
639     {
640       sym = msymbol (name);
641       fontset = mplist_get (fontset_list, sym);
642       if (! fontset)
643         {
644           M17N_OBJECT (fontset, free_fontset, MERROR_FONTSET);
645           fontset->name = sym;
646           fontset->mdb = mdatabase_find (Mfontset, sym, Mnil, Mnil);
647           if (! fontset->mdb)
648             {
649               fontset->per_script = mplist ();
650               fontset->per_charset = mplist ();
651               fontset->fallback = mplist ();
652             }
653           mplist_put (fontset_list, sym, fontset);
654         }
655     }
656   M17N_OBJECT_REF (fontset);
657   return fontset;
658 }
659
660 /*=*/
661
662 /***en
663     @brief Return the name of a fontset.
664
665     The mfontset_name () function returns the name of fontset $FONTSET.  */
666 /***ja
667     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î̾Á°¤òÊÖ¤¹.
668
669     ´Ø¿ô mfontset_name () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤Î̾Á°¤òÊÖ¤¹¡£  */
670 MSymbol
671 mfontset_name (MFontset *fontset)
672 {
673   return fontset->name;
674 }
675
676 /*=*/
677
678 /***en
679     @brief Make a copy of a fontset.
680
681     The mfontset_copy () function makes a copy of fontset $FONTSET, gives it a
682     name $NAME, and returns a pointer to the created copy.  $NAME must
683     not be a name of existing fontset.  In such case, this function
684     returns NULL without making a copy.  */
685 /***ja
686     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î¥³¥Ô¡¼¤òºî¤ë.
687
688     ´Ø¿ô mfontset_copy () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤Î¥³¥Ô¡¼¤òºî¤Ã¤Æ¡¢
689     Ì¾Á° $NAME ¤òÍ¿¤¨¡¢¤½¤Î¥³¥Ô¡¼¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£$NAME ¤Ï´û¸¤Î
690     ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î̾Á°¤Ç¤¢¤Ã¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤½¤Î¾ì¹ç¤Ë¤Ï¥³¥Ô¡¼¤òºî¤é¤º
691     NULL ¤òÊÖ¤¹¡£  */
692
693 MFontset *
694 mfontset_copy (MFontset *fontset, char *name)
695 {
696   MSymbol sym = msymbol (name);
697   MFontset *copy = mplist_get (fontset_list, sym);
698   MPlist *plist, *pl;
699
700   if (copy)
701     return NULL;
702   M17N_OBJECT (copy, free_fontset, MERROR_FONTSET);
703   copy->name = sym;
704
705   if (fontset->per_script)
706     {
707       copy->per_script = mplist ();
708       MPLIST_DO (plist, fontset->per_script)
709         {
710           MPlist *new = mplist ();
711
712           MPLIST_DO (pl, MPLIST_PLIST (plist))
713             mplist_add (new, MPLIST_KEY (pl), mplist_copy (MPLIST_PLIST (pl)));
714           mplist_add (copy->per_script, MPLIST_KEY (plist), new);
715         }
716     }
717   if (fontset->per_charset)
718     {
719       copy->per_charset = mplist ();
720       MPLIST_DO (plist, fontset->per_charset)
721         mplist_add (copy->per_charset, MPLIST_KEY (plist),
722                     mplist_copy (MPLIST_PLIST (plist)));
723     }
724   if (fontset->fallback)
725     copy->fallback = mplist_copy (fontset->fallback);
726
727   copy->font_spec_list = fontset->font_spec_list;
728   M17N_OBJECT_REF (copy->font_spec_list);
729
730   mplist_put (fontset_list, sym, copy);
731   M17N_OBJECT_REF (copy);
732   return copy;
733 }
734
735 /*=*/
736
737 /***en
738     @brief Modify the contents of a fontset.
739
740     The mfontset_modify_entry () function associates, in fontset
741     $FONTSET, a copy of $FONT with the $SCRIPT / $LANGUAGE pair or
742     with $CHARSET.
743
744     Each font in a fontset is associated with a particular
745     script/language pair, with a particular charset, or with the
746     symbol @c Mnil.  The fonts that are associated with the same item
747     make a group.
748
749     If $SCRIPT is not @c Mnil, it must be a symbol identifying a
750     script.  In this case, $LANGUAGE is either a symbol identifying a
751     language or @c Mnil, and $FONT is associated with the $SCRIPT /
752     $LANGUAGE pair.
753
754     If $CHARSET is not @c Mnil, it must be a symbol representing a
755     charset object.  In this case, $FONT is associated with that
756     charset.
757
758     If both $SCRIPT and $CHARSET are not @c Mnil, two copies of $FONT
759     are created.  Then one is associated with the $SCRIPT / $LANGUAGE
760     pair and the other with that charset.
761
762     If both $SCRIPT and $CHARSET are @c Mnil, $FONT is associated with
763     @c Mnil.  This kind of fonts are called @e fallback @e fonts.
764
765     The argument $HOW specifies the priority of $FONT.  If $HOW is
766     positive, $FONT has the highest priority in the group of fonts
767     that are associated with the same item.  If $HOW is negative,
768     $FONT has the lowest priority.  If $HOW is zero, $FONT becomes the
769     only available font for the associated item; all the other fonts
770     are removed from the group.
771
772     If $LAYOUTER_NAME is not @c Mnil, it must be a symbol
773     representing a @ref flt.  In that case, if $FONT is selected for
774     drawing an M-text, that font layout table is used to generate a
775     glyph code sequence from a character sequence.
776
777     @return
778     If the operation was successful, mfontset_modify_entry () returns 0.
779     Otherwise it returns -1 and assigns an error code to the external
780     variable #merror_code.  */
781
782 /***ja
783     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤ÎÆâÍƤòÊѹ¹¤¹¤ë.
784
785     ´Ø¿ô mfontset_modify_entry () ¤Ï¡¢$LANGUAGE ¤È $SCRIPT ¤ÎÁȤ߹ç¤ï
786     ¤»¤Þ¤¿¤Ï $CHARSET ¤ËÂФ·¤Æ $FONT ¤Î¥³¥Ô¡¼¤ò»È¤¦¤è¤¦¤Ë¡¢¥Õ¥©¥ó¥È¥»¥Ã
787     ¥È $FONTSET ¤òÀßÄꤹ¤ë¡£
788
789     ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î³Æ¥Õ¥©¥ó¥È¤Ï¡¢ÆÃÄê¤Î¥¹¥¯¥ê¥×¥È¤È¸À¸ì¤Î¥Ú¥¢¡¢ÆÃÄê¤Î
790     Ê¸»ú¥»¥Ã¥È¡¢¥·¥ó¥Ü¥ë @c Mnil ¤Î¤¤¤º¤ì¤«¤È´ØÏ¢ÉÕ¤±¤é¤ì¤Æ¤¤¤ë¡£Æ±¤¸
791     ¤â¤Î¤È´ØÏ¢ÉÕ¤±¤é¤ì¤¿¥Õ¥©¥ó¥È¤Ï¥°¥ë¡¼¥×¤ò¹½À®¤¹¤ë¡£
792
793     $SCRIPT ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢¥¹¥¯¥ê¥×¥È¤òÆÃÄꤹ¤ë¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
794     ¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¾ì¹ç¤Ë¤Ï¡¢$LANGUAGE ¤Ï¸À¸ì¤òÆÃÄꤹ¤ë¥·¥ó¥Ü¥ë¤« @c
795     Mnil ¤Ç¤¢¤ê¡¢$FONT ¤Ïthe $SCRIPT / $LANGUAGE ¥Ú¥¢¤Ë´ØÏ¢ÉÕ¤±¤é¤ì¤ë¡£
796
797     $CHARSET ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢Ê¸»ú¥»¥Ã¥È¥ª¥Ö¥¸¥§¥¯¥È¤òɽ¤¹¥·¥ó¥Ü¥ë
798     ¤Ç¤¢¤ë¡£¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¾ì¹ç¤Ë¤Ï $FONT ¤Ï¤½¤Îʸ»ú¥»¥Ã¥È¤È´ØÏ¢ÉÕ¤±¤é¤ì
799     ¤ë¡£
800
801     $SCRIPT ¤È $CHARSET ¤ÎÁÐÊý¤¬ @c Mnil ¤Ç¤Ê¤¤¾ì¹ç¤Ë¤Ï $FONT ¤Î¥³¥Ô¡¼
802     ¤¬£²¤Äºî¤é¤ì¡¢¤½¤ì¤¾¤ì $SCRIPT / $LANGUAGE ¥Ú¥¢¤Èʸ»ú¥»¥Ã¥È¤Ë´ØÏ¢
803     ÉÕ¤±¤é¤ì¤ë¡£
804
805     $SCRIPT ¤È $CHARSET ¤ÎÁÐÊý¤¬ @c Mnil ¤Ê¤é¤Ð¡¢ $FONT ¤Ï @c Mnil ¤È
806     ´ØÏ¢ÉÕ¤±¤é¤ì¤ë¡£¤³¤Î¼ï¤Î¥Õ¥©¥ó¥È¤Ï @e fallback @e font ¤È¸Æ¤Ð¤ì¤ë¡£
807
808     °ú¿ô $HOW ¤Ï $FONT ¤ÎÍ¥ÀèÅÙ¤ò»ØÄꤹ¤ë¡£$HOW ¤¬Àµ¤Ê¤é¤Ð¡¢$FONT ¤ÏƱ
809     ¤¸¤â¤Î¤È´ØÏ¢ÉÕ¤±¤é¤ì¤¿¥°¥ë¡¼¥×Ãæ¤ÇºÇ¹â¤ÎÍ¥ÀèÅÙ¤ò»ý¤Ä¡£$HOW ¤¬Éé¤Ê
810     ¤é¤Ð¡¢ºÇÄã¤ÎÍ¥ÀèÅÙ¤ò»ý¤Ä¡£$HOW ¤¬ 0 ¤Ê¤é¤Ð¡¢$FONT ¤Ï´ØÏ¢ÉÕ¤±¤é¤ì¤¿
811     ¤â¤Î¤ËÂФ¹¤ëÍ£°ì¤ÎÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤È¤Ê¤ê¡¢Â¾¤Î¥Õ¥©¥ó¥È¤Ï¥°¥ë¡¼¥×
812     ¤«¤é¼è¤ê½ü¤«¤ì¤ë¡£
813
814     $LAYOUTER_NAME ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢@ref flt ¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
815     ¥·¥ó¥Ü¥ë¤Ç¤¢¤ì¤Ð¡¢$FONT ¤òÍѤ¤¤ÆM-text ¤òɽ¼¨¤¹¤ëºÝ¤Ë¤Ï¡¢¤½¤Î FONT
816     LAYOUT TABLE ¤ò»È¤Ã¤Æʸ»úÎ󤫤饰¥ê¥Õ¥³¡¼¥ÉÎó¤òÀ¸À®¤¹¤ë¡£
817
818     @return 
819     ½èÍý¤¬À®¸ù¤·¤¿¤È¤­¡¢mfontset_modify_entry () ¤Ï 0 ¤òÊÖ¤¹¡£
820     ¼ºÇÔ¤·¤¿¤È¤­¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤ò
821     ÀßÄꤹ¤ë¡£  */
822
823 /***
824     @errors
825     @c MERROR_SYMBOL  */
826
827 int
828 mfontset_modify_entry (MFontset *fontset,
829                        MSymbol script, MSymbol language, MSymbol charset,
830                        MFont *spec, MSymbol layouter_name,
831                        int how)
832 {
833   MPlist *per_lang, *plist[3], *pl;
834   MFont *font = NULL;
835   int i;
836
837   if (fontset->mdb)
838     load_fontset_contents (fontset);
839
840   MPLIST_DO (pl, fontset->font_spec_list)
841     {
842       if (! memcmp (MPLIST_VAL (pl), spec, sizeof (MFont)))
843         {
844           font = MPLIST_VAL (pl);
845           break;
846         }
847     }
848   if (! font)
849     {
850       font = mfont ();
851       *font = *spec;
852       mplist_add (fontset->font_spec_list, Mt, font);
853     }
854
855   i = 0;
856   if (script != Mnil)
857     {
858       if (language == Mnil)
859         language = Mt;
860       per_lang = mplist_get (fontset->per_script, script);
861       if (! per_lang)
862         mplist_add (fontset->per_script, script, per_lang = mplist ());
863       plist[i] = mplist_get (per_lang, language);
864       if (! plist[i])
865         mplist_add (per_lang, language, plist[i] = mplist ());
866       i++;
867     }
868   if (charset != Mnil)
869     {
870       plist[i] = mplist_get (fontset->per_charset, charset);
871       if (! plist[i])
872         mplist_add (fontset->per_charset, charset, plist[i] = mplist ());
873       i++;
874     }
875   if (script == Mnil && charset == Mnil)
876     {
877       plist[i++] = fontset->fallback;
878     }
879
880   if (layouter_name == Mnil)
881     layouter_name = Mt;
882   for (i--; i >= 0; i--)
883     {
884       if (how == -1)
885         mplist_push (plist[i], layouter_name, font);
886       else if (how == 1)
887         mplist_add (plist[i], layouter_name, font);
888       else
889         {
890           mplist_set (plist[i], Mnil, NULL);
891           mplist_add (plist[i], layouter_name, font);
892         }
893     }
894
895   return 0;
896 }
897
898 /*** @} */
899
900 /*** @addtogroup m17nDebug */
901 /*=*/
902 /*** @{  */
903
904 /***en
905     @brief Dump a fontset.
906
907     The mdebug_dump_fontset () function prints fontset $FONTSET in a human readable
908     way to the stderr.  $INDENT specifies how many columns to indent
909     the lines but the first one.
910
911     @return
912     This function returns $FONTSET.  */
913 /***ja
914     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤ò¥À¥ó¥×¤¹¤ë.
915
916     ´Ø¿ô mdebug_dump_face () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤ò stderr ¤Ë¿Í
917     ´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£ $INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ
918     ¤ë¡£
919
920     @return
921     ¤³¤Î´Ø¿ô¤Ï $FONTSET ¤òÊÖ¤¹¡£  */
922
923 MFontset *
924 mdebug_dump_fontset (MFontset *fontset, int indent)
925 {
926   char *prefix = (char *) alloca (indent + 1);
927   MPlist *plist, *pl, *p;
928
929   memset (prefix, 32, indent);
930   prefix[indent] = 0;
931
932   fprintf (stderr, "(fontset %s", fontset->name->name);
933   if (fontset->per_script)
934     MPLIST_DO (plist, fontset->per_script)
935       {
936         fprintf (stderr, "\n  %s(%s", prefix, MPLIST_KEY (plist)->name);
937         MPLIST_DO (pl, MPLIST_PLIST (plist))
938           {
939             fprintf (stderr, "\n    %s(%s", prefix, MPLIST_KEY (pl)->name);
940             MPLIST_DO (p, MPLIST_PLIST (pl))
941               {
942                 fprintf (stderr, "\n      %s(%s ", prefix,
943                          MPLIST_KEY (p)->name);
944                 mdebug_dump_font (MPLIST_VAL (p));
945                 fprintf (stderr, ")");
946               }
947             fprintf (stderr, ")");
948           }
949         fprintf (stderr, ")");
950       }
951   if (fontset->per_charset)
952     MPLIST_DO (pl, fontset->per_charset)
953       {
954         fprintf (stderr, "\n  %s(%s", prefix, MPLIST_KEY (pl)->name);
955         MPLIST_DO (p, MPLIST_PLIST (pl))
956           {
957             fprintf (stderr, "\n    %s(%s ", prefix, MPLIST_KEY (p)->name);
958             mdebug_dump_font (MPLIST_VAL (p));
959             fprintf (stderr, ")");
960           }
961         fprintf (stderr, ")");
962       }
963
964   if (fontset->fallback)
965     MPLIST_DO (p, fontset->fallback)
966       {
967         fprintf (stderr, "\n  %s(%s ", prefix, MPLIST_KEY (p)->name);
968         mdebug_dump_font (MPLIST_VAL (p));
969         fprintf (stderr, ")");
970       }
971
972   fprintf (stderr, ")");
973   return fontset;
974 }
975
976 /*** @} */
977
978 /*
979   Local Variables:
980   coding: euc-japan
981   End:
982 */