(mfont__lookup_fontset): Fix selection of font groups
[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       /* We prefer font groups in this order:
500           (1) group matching LANGUAGE
501           (2) group for generic LANGUAGE
502           (3) group non-matching LANGUAGE  */
503       if (language == Mnil)
504         language = Mt;
505       per_lang = mplist_find_by_key (MPLIST_PLIST (per_script), language);
506       if (per_lang)
507         {
508           font_groups[n_font_group++] = MPLIST_PLIST (per_lang);
509           if (language == Mt)
510             {
511               MPLIST_DO (per_lang, MPLIST_PLIST (per_script))
512                 if (MPLIST_KEY (per_lang) != language)
513                   font_groups[n_font_group++] = MPLIST_PLIST (per_lang);
514             }
515         }
516       if (language != Mt)
517         {
518           plist = mplist_get (MPLIST_PLIST (per_script), Mt);
519           if (plist)
520             font_groups[n_font_group++] = plist;
521         }
522       MPLIST_DO (per_lang, MPLIST_PLIST (per_script))
523         if (MPLIST_KEY (per_lang) != language
524             && MPLIST_KEY (per_lang) != Mt)
525           font_groups[n_font_group++] = MPLIST_PLIST (per_lang);
526     }
527   font_groups[n_font_group++] = realized->fallback;
528
529   if (n_font_group == 1)
530     {
531       /* As we only have a fallback font group, try all the other
532          fonts too.  */
533       MPLIST_DO (per_script, realized->per_script)
534         MPLIST_DO (per_lang, MPLIST_PLIST (per_script))
535           font_groups[n_font_group++] = MPLIST_PLIST (per_lang);
536       MPLIST_DO (per_charset, realized->per_charset)
537         font_groups[n_font_group++] = MPLIST_PLIST (per_charset);
538     }
539
540   for (i = 0; i < n_font_group; i++)
541     {
542       int j;
543       
544       if (MPLIST_PLIST_P (font_groups[i]))
545         realize_font_group (frame, &realized->spec, font_groups[i], size);
546
547       MPLIST_DO (plist, font_groups[i])
548         {
549           rfont = (MRealizedFont *) MPLIST_VAL (plist);
550           if (rfont->status < 0)
551             continue;
552           /* Check if this font can display all glyphs.  */
553           for (j = 0; j < *num; j++)
554             {
555               g[j].code = mfont__encode_char (rfont, g[j].c);
556               if (g[j].code == MCHAR_INVALID_CODE)
557                 break;
558             }
559           if (j == *num)
560             {
561               if (rfont->status > 0
562                   || mfont__open (rfont) == 0)
563                 /* We found a font that can display all glyphs.  */
564                 break;
565             }
566         }
567       if (! MPLIST_TAIL_P (plist))
568         break;
569     }
570
571   if (i < n_font_group) 
572     return rfont;
573
574   /* We couldn't find a font that can display all glyphs.  Find one
575      that can display at least the first glyph.  */
576   for (i = 0; i < n_font_group; i++)
577     {
578       MPLIST_DO (plist, font_groups[i])
579         {
580           rfont = (MRealizedFont *) MPLIST_VAL (plist);
581           if (rfont->status < 0)
582             continue;
583           g->code = mfont__encode_char (rfont, g->c);
584           if (g->code != MCHAR_INVALID_CODE)
585             {
586               if (rfont->status > 0
587                   || mfont__open (rfont) == 0)
588                 break;
589             }
590         }
591       if (! MPLIST_TAIL_P (plist))
592         break;
593     }
594   return (i < n_font_group ? rfont : NULL);
595 }
596
597 /*** @} */
598 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
599
600 \f
601 /* External API */
602
603 /*** @addtogroup m17nFontset */
604 /*** @{ */
605
606 /*=*/
607 /***en
608     @brief Return a fontset.
609
610     The mfontset () function returns a pointer to a fontset object of
611     name $NAME.  If $NAME is @c NULL, it returns a pointer to the
612     default fontset.
613
614     If no fontset has the name $NAME, a new one is created.  At that
615     time, if there exists a data \<@c fontset, $NAME\> in the m17n
616     database, the fontset contents are initialized according to the
617     data.  If no such data exists, the fontset contents are left
618     vacant.
619
620     The macro M17N_INIT () creates the default fontset.  An
621     application program can modify it before the first call of 
622     mframe ().
623
624     @return
625     This function returns a pointer to the found or newly created
626     fontset.  */
627 /***ja 
628     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤òÊÖ¤¹.
629
630     ´Ø¿ô mfontset () ¤Ï̾Á° $NAME ¤ò»ý¤Ä¥Õ¥©¥ó¥È¥»¥Ã¥È¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î
631     ¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£ $NAME ¤¬ @c NULL ¤Ê¤é¤Ð¡¢¥Ç¥Õ¥©¥ë¥È¥Õ¥©¥ó¥È¥»¥Ã¥È
632     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
633
634     $NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¥Õ¥©¥ó¥È¥»¥Ã¥È¤¬¤Ê¤±¤ì¤Ð¡¢¿·¤·¤¤¤â¤Î¤¬ºî¤é¤ì
635     ¤ë¡£¤½¤ÎºÝ¡¢m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë \<@c fontset, $NAME\> ¤È¤¤¤¦¥Ç¡¼¥¿
636     ¤¬¤¢¤ì¤Ð¡¢¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ï¤½¤Î¥Ç¡¼¥¿¤Ë±è¤Ã¤Æ½é´ü²½¤µ¤ì¤ë¡£¤Ê¤±¤ì¤Ð¡¢
637     ¶õ¤Î¤Þ¤Þ¤Ë¤µ¤ì¤ë¡£
638
639     ¥Þ¥¯¥í M17N_INIT () ¤Ï¥Ç¥Õ¥©¥ë¥È¤Î¥Õ¥©¥ó¥È¥»¥Ã¥È¤òºî¤ë¡£¥¢¥×¥ê¥±¡¼
640     ¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï mframe () ¤ò½é¤á¤Æ¸Æ¤Ö¤Þ¤Ç¤Ï¥Ç¥Õ¥©¥ë¥È¥Õ¥©¥ó¥È
641     ¥»¥Ã¥È¤òÊѹ¹¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë¡£
642
643     @return
644     ¤³¤Î´Ø¿ô¤Ï¸«¤Ä¤«¤Ã¤¿¡¢¤¢¤ë¤¤¤Ïºî¤Ã¤¿¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
645      */
646
647 MFontset *
648 mfontset (char *name)
649 {
650   MSymbol sym;
651   MFontset *fontset;
652
653   if (! name)
654     fontset = default_fontset;
655   else
656     {
657       sym = msymbol (name);
658       fontset = mplist_get (fontset_list, sym);
659       if (! fontset)
660         {
661           M17N_OBJECT (fontset, free_fontset, MERROR_FONTSET);
662           fontset->name = sym;
663           fontset->mdb = mdatabase_find (Mfontset, sym, Mnil, Mnil);
664           if (! fontset->mdb)
665             {
666               fontset->per_script = mplist ();
667               fontset->per_charset = mplist ();
668               fontset->fallback = mplist ();
669             }
670           mplist_put (fontset_list, sym, fontset);
671         }
672     }
673   M17N_OBJECT_REF (fontset);
674   return fontset;
675 }
676
677 /*=*/
678
679 /***en
680     @brief Return the name of a fontset.
681
682     The mfontset_name () function returns the name of fontset $FONTSET.  */
683 /***ja
684     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î̾Á°¤òÊÖ¤¹.
685
686     ´Ø¿ô mfontset_name () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤Î̾Á°¤òÊÖ¤¹¡£  */
687 MSymbol
688 mfontset_name (MFontset *fontset)
689 {
690   return fontset->name;
691 }
692
693 /*=*/
694
695 /***en
696     @brief Make a copy of a fontset.
697
698     The mfontset_copy () function makes a copy of fontset $FONTSET, gives it a
699     name $NAME, and returns a pointer to the created copy.  $NAME must
700     not be a name of existing fontset.  In such case, this function
701     returns NULL without making a copy.  */
702 /***ja
703     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î¥³¥Ô¡¼¤òºî¤ë.
704
705     ´Ø¿ô mfontset_copy () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤Î¥³¥Ô¡¼¤òºî¤Ã¤Æ¡¢
706     Ì¾Á° $NAME ¤òÍ¿¤¨¡¢¤½¤Î¥³¥Ô¡¼¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£$NAME ¤Ï´û¸¤Î
707     ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î̾Á°¤Ç¤¢¤Ã¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤½¤Î¾ì¹ç¤Ë¤Ï¥³¥Ô¡¼¤òºî¤é¤º
708     NULL ¤òÊÖ¤¹¡£  */
709
710 MFontset *
711 mfontset_copy (MFontset *fontset, char *name)
712 {
713   MSymbol sym = msymbol (name);
714   MFontset *copy = mplist_get (fontset_list, sym);
715   MPlist *plist, *pl;
716
717   if (copy)
718     return NULL;
719   M17N_OBJECT (copy, free_fontset, MERROR_FONTSET);
720   copy->name = sym;
721
722   if (fontset->per_script)
723     {
724       copy->per_script = mplist ();
725       MPLIST_DO (plist, fontset->per_script)
726         {
727           MPlist *new = mplist ();
728
729           MPLIST_DO (pl, MPLIST_PLIST (plist))
730             mplist_add (new, MPLIST_KEY (pl), mplist_copy (MPLIST_PLIST (pl)));
731           mplist_add (copy->per_script, MPLIST_KEY (plist), new);
732         }
733     }
734   if (fontset->per_charset)
735     {
736       copy->per_charset = mplist ();
737       MPLIST_DO (plist, fontset->per_charset)
738         mplist_add (copy->per_charset, MPLIST_KEY (plist),
739                     mplist_copy (MPLIST_PLIST (plist)));
740     }
741   if (fontset->fallback)
742     copy->fallback = mplist_copy (fontset->fallback);
743
744   copy->font_spec_list = fontset->font_spec_list;
745   M17N_OBJECT_REF (copy->font_spec_list);
746
747   mplist_put (fontset_list, sym, copy);
748   M17N_OBJECT_REF (copy);
749   return copy;
750 }
751
752 /*=*/
753
754 /***en
755     @brief Modify the contents of a fontset.
756
757     The mfontset_modify_entry () function associates, in fontset
758     $FONTSET, a copy of $FONT with the $SCRIPT / $LANGUAGE pair or
759     with $CHARSET.
760
761     Each font in a fontset is associated with a particular
762     script/language pair, with a particular charset, or with the
763     symbol @c Mnil.  The fonts that are associated with the same item
764     make a group.
765
766     If $SCRIPT is not @c Mnil, it must be a symbol identifying a
767     script.  In this case, $LANGUAGE is either a symbol identifying a
768     language or @c Mnil, and $FONT is associated with the $SCRIPT /
769     $LANGUAGE pair.
770
771     If $CHARSET is not @c Mnil, it must be a symbol representing a
772     charset object.  In this case, $FONT is associated with that
773     charset.
774
775     If both $SCRIPT and $CHARSET are not @c Mnil, two copies of $FONT
776     are created.  Then one is associated with the $SCRIPT / $LANGUAGE
777     pair and the other with that charset.
778
779     If both $SCRIPT and $CHARSET are @c Mnil, $FONT is associated with
780     @c Mnil.  This kind of fonts are called @e fallback @e fonts.
781
782     The argument $HOW specifies the priority of $FONT.  If $HOW is
783     positive, $FONT has the highest priority in the group of fonts
784     that are associated with the same item.  If $HOW is negative,
785     $FONT has the lowest priority.  If $HOW is zero, $FONT becomes the
786     only available font for the associated item; all the other fonts
787     are removed from the group.
788
789     If $LAYOUTER_NAME is not @c Mnil, it must be a symbol
790     representing a @ref flt.  In that case, if $FONT is selected for
791     drawing an M-text, that font layout table is used to generate a
792     glyph code sequence from a character sequence.
793
794     @return
795     If the operation was successful, mfontset_modify_entry () returns 0.
796     Otherwise it returns -1 and assigns an error code to the external
797     variable #merror_code.  */
798
799 /***ja
800     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤ÎÆâÍƤòÊѹ¹¤¹¤ë.
801
802     ´Ø¿ô mfontset_modify_entry () ¤Ï¡¢$LANGUAGE ¤È $SCRIPT ¤ÎÁȤ߹ç¤ï
803     ¤»¤Þ¤¿¤Ï $CHARSET ¤ËÂФ·¤Æ $FONT ¤Î¥³¥Ô¡¼¤ò»È¤¦¤è¤¦¤Ë¡¢¥Õ¥©¥ó¥È¥»¥Ã
804     ¥È $FONTSET ¤òÀßÄꤹ¤ë¡£
805
806     ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î³Æ¥Õ¥©¥ó¥È¤Ï¡¢ÆÃÄê¤Î¥¹¥¯¥ê¥×¥È¤È¸À¸ì¤Î¥Ú¥¢¡¢ÆÃÄê¤Î
807     Ê¸»ú¥»¥Ã¥È¡¢¥·¥ó¥Ü¥ë @c Mnil ¤Î¤¤¤º¤ì¤«¤È´ØÏ¢ÉÕ¤±¤é¤ì¤Æ¤¤¤ë¡£Æ±¤¸
808     ¤â¤Î¤È´ØÏ¢ÉÕ¤±¤é¤ì¤¿¥Õ¥©¥ó¥È¤Ï¥°¥ë¡¼¥×¤ò¹½À®¤¹¤ë¡£
809
810     $SCRIPT ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢¥¹¥¯¥ê¥×¥È¤òÆÃÄꤹ¤ë¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
811     ¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¾ì¹ç¤Ë¤Ï¡¢$LANGUAGE ¤Ï¸À¸ì¤òÆÃÄꤹ¤ë¥·¥ó¥Ü¥ë¤« @c
812     Mnil ¤Ç¤¢¤ê¡¢$FONT ¤Ïthe $SCRIPT / $LANGUAGE ¥Ú¥¢¤Ë´ØÏ¢ÉÕ¤±¤é¤ì¤ë¡£
813
814     $CHARSET ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢Ê¸»ú¥»¥Ã¥È¥ª¥Ö¥¸¥§¥¯¥È¤òɽ¤¹¥·¥ó¥Ü¥ë
815     ¤Ç¤¢¤ë¡£¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¾ì¹ç¤Ë¤Ï $FONT ¤Ï¤½¤Îʸ»ú¥»¥Ã¥È¤È´ØÏ¢ÉÕ¤±¤é¤ì
816     ¤ë¡£
817
818     $SCRIPT ¤È $CHARSET ¤ÎÁÐÊý¤¬ @c Mnil ¤Ç¤Ê¤¤¾ì¹ç¤Ë¤Ï $FONT ¤Î¥³¥Ô¡¼
819     ¤¬£²¤Äºî¤é¤ì¡¢¤½¤ì¤¾¤ì $SCRIPT / $LANGUAGE ¥Ú¥¢¤Èʸ»ú¥»¥Ã¥È¤Ë´ØÏ¢
820     ÉÕ¤±¤é¤ì¤ë¡£
821
822     $SCRIPT ¤È $CHARSET ¤ÎÁÐÊý¤¬ @c Mnil ¤Ê¤é¤Ð¡¢ $FONT ¤Ï @c Mnil ¤È
823     ´ØÏ¢ÉÕ¤±¤é¤ì¤ë¡£¤³¤Î¼ï¤Î¥Õ¥©¥ó¥È¤Ï @e fallback @e font ¤È¸Æ¤Ð¤ì¤ë¡£
824
825     °ú¿ô $HOW ¤Ï $FONT ¤ÎÍ¥ÀèÅÙ¤ò»ØÄꤹ¤ë¡£$HOW ¤¬Àµ¤Ê¤é¤Ð¡¢$FONT ¤ÏƱ
826     ¤¸¤â¤Î¤È´ØÏ¢ÉÕ¤±¤é¤ì¤¿¥°¥ë¡¼¥×Ãæ¤ÇºÇ¹â¤ÎÍ¥ÀèÅÙ¤ò»ý¤Ä¡£$HOW ¤¬Éé¤Ê
827     ¤é¤Ð¡¢ºÇÄã¤ÎÍ¥ÀèÅÙ¤ò»ý¤Ä¡£$HOW ¤¬ 0 ¤Ê¤é¤Ð¡¢$FONT ¤Ï´ØÏ¢ÉÕ¤±¤é¤ì¤¿
828     ¤â¤Î¤ËÂФ¹¤ëÍ£°ì¤ÎÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤È¤Ê¤ê¡¢Â¾¤Î¥Õ¥©¥ó¥È¤Ï¥°¥ë¡¼¥×
829     ¤«¤é¼è¤ê½ü¤«¤ì¤ë¡£
830
831     $LAYOUTER_NAME ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢@ref flt ¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
832     ¥·¥ó¥Ü¥ë¤Ç¤¢¤ì¤Ð¡¢$FONT ¤òÍѤ¤¤ÆM-text ¤òɽ¼¨¤¹¤ëºÝ¤Ë¤Ï¡¢¤½¤Î FONT
833     LAYOUT TABLE ¤ò»È¤Ã¤Æʸ»úÎ󤫤饰¥ê¥Õ¥³¡¼¥ÉÎó¤òÀ¸À®¤¹¤ë¡£
834
835     @return 
836     ½èÍý¤¬À®¸ù¤·¤¿¤È¤­¡¢mfontset_modify_entry () ¤Ï 0 ¤òÊÖ¤¹¡£
837     ¼ºÇÔ¤·¤¿¤È¤­¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤ò
838     ÀßÄꤹ¤ë¡£  */
839
840 /***
841     @errors
842     @c MERROR_SYMBOL  */
843
844 int
845 mfontset_modify_entry (MFontset *fontset,
846                        MSymbol script, MSymbol language, MSymbol charset,
847                        MFont *spec, MSymbol layouter_name,
848                        int how)
849 {
850   MPlist *per_lang, *plist[3], *pl;
851   MFont *font = NULL;
852   int i;
853
854   if (fontset->mdb)
855     load_fontset_contents (fontset);
856
857   if (! fontset->font_spec_list)
858     fontset->font_spec_list = mplist ();
859   else
860     MPLIST_DO (pl, fontset->font_spec_list)
861       {
862         if (! memcmp (MPLIST_VAL (pl), spec, sizeof (MFont)))
863           {
864             font = MPLIST_VAL (pl);
865             break;
866           }
867       }
868   if (! font)
869     {
870       font = mfont ();
871       *font = *spec;
872       mplist_add (fontset->font_spec_list, Mt, font);
873     }
874
875   i = 0;
876   if (script != Mnil)
877     {
878       if (language == Mnil)
879         language = Mt;
880       per_lang = mplist_get (fontset->per_script, script);
881       if (! per_lang)
882         mplist_add (fontset->per_script, script, per_lang = mplist ());
883       plist[i] = mplist_get (per_lang, language);
884       if (! plist[i])
885         mplist_add (per_lang, language, plist[i] = mplist ());
886       i++;
887     }
888   if (charset != Mnil)
889     {
890       plist[i] = mplist_get (fontset->per_charset, charset);
891       if (! plist[i])
892         mplist_add (fontset->per_charset, charset, plist[i] = mplist ());
893       i++;
894     }
895   if (script == Mnil && charset == Mnil)
896     {
897       plist[i++] = fontset->fallback;
898     }
899
900   if (layouter_name == Mnil)
901     layouter_name = Mt;
902   for (i--; i >= 0; i--)
903     {
904       if (how == -1)
905         mplist_push (plist[i], layouter_name, font);
906       else if (how == 1)
907         mplist_add (plist[i], layouter_name, font);
908       else
909         {
910           mplist_set (plist[i], Mnil, NULL);
911           mplist_add (plist[i], layouter_name, font);
912         }
913     }
914
915   return 0;
916 }
917
918 /*** @} */
919
920 /*** @addtogroup m17nDebug */
921 /*=*/
922 /*** @{  */
923
924 /***en
925     @brief Dump a fontset.
926
927     The mdebug_dump_fontset () function prints fontset $FONTSET in a human readable
928     way to the stderr.  $INDENT specifies how many columns to indent
929     the lines but the first one.
930
931     @return
932     This function returns $FONTSET.  */
933 /***ja
934     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤ò¥À¥ó¥×¤¹¤ë.
935
936     ´Ø¿ô mdebug_dump_face () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤ò stderr ¤Ë¿Í
937     ´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£ $INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ
938     ¤ë¡£
939
940     @return
941     ¤³¤Î´Ø¿ô¤Ï $FONTSET ¤òÊÖ¤¹¡£  */
942
943 MFontset *
944 mdebug_dump_fontset (MFontset *fontset, int indent)
945 {
946   char *prefix = (char *) alloca (indent + 1);
947   MPlist *plist, *pl, *p;
948
949   memset (prefix, 32, indent);
950   prefix[indent] = 0;
951
952   fprintf (stderr, "(fontset %s", fontset->name->name);
953   if (fontset->per_script)
954     MPLIST_DO (plist, fontset->per_script)
955       {
956         fprintf (stderr, "\n  %s(%s", prefix, MPLIST_KEY (plist)->name);
957         MPLIST_DO (pl, MPLIST_PLIST (plist))
958           {
959             fprintf (stderr, "\n    %s(%s", prefix, MPLIST_KEY (pl)->name);
960             MPLIST_DO (p, MPLIST_PLIST (pl))
961               {
962                 fprintf (stderr, "\n      %s(%s ", prefix,
963                          MPLIST_KEY (p)->name);
964                 mdebug_dump_font (MPLIST_VAL (p));
965                 fprintf (stderr, ")");
966               }
967             fprintf (stderr, ")");
968           }
969         fprintf (stderr, ")");
970       }
971   if (fontset->per_charset)
972     MPLIST_DO (pl, fontset->per_charset)
973       {
974         fprintf (stderr, "\n  %s(%s", prefix, MPLIST_KEY (pl)->name);
975         MPLIST_DO (p, MPLIST_PLIST (pl))
976           {
977             fprintf (stderr, "\n    %s(%s ", prefix, MPLIST_KEY (p)->name);
978             mdebug_dump_font (MPLIST_VAL (p));
979             fprintf (stderr, ")");
980           }
981         fprintf (stderr, ")");
982       }
983
984   if (fontset->fallback)
985     MPLIST_DO (p, fontset->fallback)
986       {
987         fprintf (stderr, "\n  %s(%s ", prefix, MPLIST_KEY (p)->name);
988         mdebug_dump_font (MPLIST_VAL (p));
989         fprintf (stderr, ")");
990       }
991
992   fprintf (stderr, ")");
993   return fontset;
994 }
995
996 /*** @} */
997
998 /*
999   Local Variables:
1000   coding: euc-japan
1001   End:
1002 */