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