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