(try_font_group): New function.
[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 "config.h"
67 #include "m17n-gui.h"
68 #include "m17n-misc.h"
69 #include "internal.h"
70 #include "symbol.h"
71 #include "plist.h"
72 #include "character.h"
73 #include "charset.h"
74 #include "internal-gui.h"
75 #include "font.h"
76 #include "fontset.h"
77
78 struct MFontset
79 {
80   M17NObject control;
81
82   /* Name of the fontset.  */
83   MSymbol name;
84
85   /* Initialized to 0, and incremented by one each time the fontset is
86      modified.  */
87   unsigned tick;
88
89   /* Database from which to load the contents of the fontset.  Once
90      loaded, this member is set to NULL.  */
91   MDatabase *mdb;
92
93   /* SCRIPT vs PER-LANGUAGE (which is a plist LANGUAGE vs FONT-GROUP) */
94   MPlist *per_script;
95
96   /* CHARSET vs FONT-GROUP */
97   MPlist *per_charset;
98
99   /* FONT-GROUP */
100   MPlist *fallback;
101
102   /* Plist of Mt vs font specs. */
103   MPlist *font_spec_list;
104 };
105
106 static MFontset *default_fontset;
107
108 static MPlist *fontset_list;
109
110 struct MRealizedFontset
111 {
112   /* Fontset from which the realized fontset is realized.  */
113   MFontset *fontset;
114
115   /* Initialized to <fontset>->tick.  */
116   unsigned tick;
117
118   /* Font spec extracted from a face.  */
119   MFont spec;
120
121   /* The frame on which the realized fontset is realized.  */
122   MFrame *frame;
123
124   MPlist *per_script;
125
126   MPlist *per_charset;
127
128   MPlist *fallback;
129 };
130
131
132 static MPlist *
133 load_font_group (MPlist *plist, MPlist *elt, MPlist *spec_list)
134 {
135   MPLIST_DO (elt, elt)
136     {
137       /* ELT ::= ( FONT-SPEC-LIST [ LAYOUTER ] ) ...  */
138       MPlist *elt2, *p;
139       MFont font, *spec = NULL;
140       MSymbol layouter_name;
141
142       if (! MPLIST_PLIST_P (elt))
143         MWARNING (MERROR_FONTSET);
144       elt2 = MPLIST_PLIST (elt);
145       if (! MPLIST_PLIST_P (elt2))
146         MWARNING (MERROR_FONTSET);
147       mfont__set_spec_from_plist (&font, MPLIST_PLIST (elt2));
148       MPLIST_DO (p, spec_list)
149         {
150           if (! memcmp (MPLIST_VAL (p), &font, sizeof (MFont)))
151             {
152               spec = MPLIST_VAL (p);
153               break;
154             }
155         }
156       if (! spec)
157         {
158           MSTRUCT_MALLOC (spec, MERROR_FONTSET);
159           *spec = font;
160           mplist_add (spec_list, Mt, spec);
161         }
162       elt2 = MPLIST_NEXT (elt2);
163       layouter_name = Mt;
164       if (MPLIST_SYMBOL_P (elt2))
165         layouter_name = MPLIST_SYMBOL (elt2);
166       if (layouter_name == Mnil)
167         layouter_name = Mt;
168       plist = mplist_add (plist, layouter_name, spec);
169       continue;
170     warning:
171       /* ANSI-C requires some statement after a label.  */
172       continue;
173     }
174   return plist;
175 }
176
177 /* Load FONTSET->per_script from the data in FONTSET->mdb.  */
178
179 static void
180 load_fontset_contents (MFontset *fontset)
181 {
182   MPlist *per_script, *per_charset, *fallback, *spec_list, *font_group;
183   MSymbol script, lang;
184   MPlist *fontset_def, *plist;
185
186   fontset->per_script = per_script = mplist ();
187   fontset->per_charset = per_charset = mplist ();
188   fontset->fallback = fallback = mplist ();
189   fontset->font_spec_list = spec_list = mplist ();
190   if (! (fontset_def = (MPlist *) mdatabase_load (fontset->mdb)))
191     return;
192
193   MPLIST_DO (plist, fontset_def)
194     {
195       /* PLIST ::= ( SCRIPT ( LANGUAGE FONT-SPEC-ELT ... ) ... )
196                    | (CHARSET FONT-SPEC-ELT ...)
197                    | FONT-SPEC-ELT  */
198       MPlist *elt;
199
200       if (! MPLIST_PLIST_P (plist))
201         MWARNING (MERROR_FONTSET);
202       elt = MPLIST_PLIST (plist);
203       if (! MPLIST_SYMBOL_P (elt))
204         MWARNING (MERROR_FONTSET);
205       script = MPLIST_SYMBOL (elt);
206       elt = MPLIST_NEXT (elt);
207       if (! MPLIST_PLIST_P (elt))
208         MWARNING (MERROR_FONTSET);
209       if (script == Mnil)
210         fallback = load_font_group (fallback, elt, spec_list);
211       else if (MPLIST_PLIST_P (MPLIST_PLIST (elt)))
212         {
213           font_group = mplist_find_by_key (fontset->per_charset, script);
214           if (! font_group)
215             {
216               font_group = mplist ();
217               per_charset = mplist_add (per_charset, script, font_group);
218             }
219           load_font_group (font_group, elt, spec_list);
220         }
221       else
222         {
223           MPlist *per_lang = mplist_find_by_key (fontset->per_script, script);
224
225           if (! per_lang)
226             {
227               per_lang = mplist ();
228               per_script = mplist_add (per_script, script, per_lang);
229             }
230
231           MPLIST_DO (elt, elt)
232             {
233               /* ELT ::= ( LANGUAGE FONT-DEF ...) ... */
234               MPlist *elt2;
235
236               if (! MPLIST_PLIST_P (elt))
237                 MWARNING (MERROR_FONTSET);
238               elt2 = MPLIST_PLIST (elt);
239               if (! MPLIST_SYMBOL_P (elt2))
240                 MWARNING (MERROR_FONTSET);
241               lang = MPLIST_SYMBOL (elt2);
242               if (lang == Mnil)
243                 lang = Mt;
244               font_group = mplist_find_by_key (per_lang, lang);
245               if (! font_group)
246                 {
247                   font_group = mplist ();
248                   mplist_add (per_lang, lang, font_group);
249                 }
250               elt2 = MPLIST_NEXT (elt2);
251               load_font_group (font_group, elt2, spec_list);
252             }
253         }
254       continue;
255
256     warning:
257       /* ANSI-C requires some statement after a label.  */
258       continue;
259     }
260
261   M17N_OBJECT_UNREF (fontset_def);
262   fontset->mdb = NULL;
263 }
264
265 static void
266 free_fontset (void *object)
267 {
268   MFontset *fontset = (MFontset *) object;
269   MPlist *plist, *pl, *p;
270
271   if (fontset->per_script)
272     {
273       MPLIST_DO (plist, fontset->per_script)
274         {
275           MPLIST_DO (pl, MPLIST_PLIST (plist))
276             {
277               p = MPLIST_PLIST (pl);
278               M17N_OBJECT_UNREF (p);
279             }
280           pl = MPLIST_PLIST (plist);
281           M17N_OBJECT_UNREF (pl);
282         }
283       M17N_OBJECT_UNREF (fontset->per_script);
284     }
285   if (fontset->per_charset)
286     {
287       MPLIST_DO (plist, fontset->per_charset)
288         {
289           pl = MPLIST_PLIST (plist);
290           M17N_OBJECT_UNREF (pl);
291         }
292       M17N_OBJECT_UNREF (fontset->per_charset);
293     }
294   if (fontset->fallback)
295     M17N_OBJECT_UNREF (fontset->fallback);
296   plist = mplist_find_by_key (fontset_list, fontset->name);
297   if (! plist)
298     mdebug_hook ();
299   mplist_pop (plist);
300   if (fontset->font_spec_list)
301     {
302       if (((M17NObject *) (fontset->font_spec_list))->ref_count == 1)
303         MPLIST_DO (plist, fontset->font_spec_list)
304           free (MPLIST_VAL (plist));
305       M17N_OBJECT_UNREF (fontset->font_spec_list);
306     }
307   free (object);
308 }
309
310 static void
311 realize_font_group (MFrame *frame, MFont *request, MPlist *font_group,
312                     int size)
313 {
314   MPlist *plist = MPLIST_VAL (font_group), *pl, *p;
315
316   mplist_set (font_group, Mnil, NULL);
317   MPLIST_DO (pl, plist)
318     {
319       MSymbol layouter = MPLIST_KEY (pl);
320       MFont this_request = *request;
321       MRealizedFont *rfont;
322
323       mfont__resize (MPLIST_VAL (pl), &this_request);
324       rfont = mfont__select (frame, MPLIST_VAL (pl), &this_request,
325                              size, layouter == Mt ? Mnil : layouter);
326
327       if (rfont)
328         {
329           MPLIST_DO (p, font_group)
330             if (((MRealizedFont *) (MPLIST_VAL (p)))->score > rfont->score)
331               break;
332           mplist_push (p, Mt, rfont);
333         }
334     }
335 }
336
337 static void
338 realize_fontset_elements (MFrame *frame, MRealizedFontset *realized,
339                           MFontset *fontset, MFont *request)
340 {
341   MPlist *per_script, *per_lang, *per_charset, *font_group;
342   MPlist *plist, *pl;
343
344   realized->fontset = fontset;
345   realized->tick = fontset->tick;
346   realized->spec = *request;
347   realized->frame = frame;
348   realized->per_script = per_script = mplist ();
349   MPLIST_DO (plist, fontset->per_script)
350     {
351       per_lang = mplist ();
352       per_script = mplist_add (per_script, MPLIST_KEY (plist), per_lang);
353       MPLIST_DO (pl, MPLIST_PLIST (plist))
354         {
355           font_group = mplist ();
356           mplist_add (font_group, Mplist, MPLIST_VAL (pl));
357           per_lang = mplist_add (per_lang, MPLIST_KEY (pl), font_group);
358         }
359     }
360
361   realized->per_charset = per_charset = mplist ();
362   MPLIST_DO (plist, fontset->per_charset)
363     {
364       font_group = mplist ();
365       mplist_add (font_group, Mplist, MPLIST_VAL (plist));
366       per_charset = mplist_add (per_charset, MPLIST_KEY (plist), font_group);
367     }
368
369   realized->fallback = mplist ();
370   mplist_add (realized->fallback, Mplist, fontset->fallback);
371
372 }
373
374 static void
375 free_realized_fontset_elements (MRealizedFontset *realized)
376 {
377   MPlist *plist, *pl, *p;
378   MRealizedFont *rfont;
379
380   if (realized->per_script)
381     {
382       MPLIST_DO (plist, realized->per_script)
383         {
384           MPLIST_DO (pl, MPLIST_PLIST (plist))
385             {
386               MPLIST_DO (p, MPLIST_PLIST (pl))
387                 if ((rfont = MPLIST_VAL (p)) && ! rfont->frame)
388                   free (rfont);
389               p = MPLIST_PLIST (pl);
390               M17N_OBJECT_UNREF (p);
391             }
392           pl = MPLIST_PLIST (plist);
393           M17N_OBJECT_UNREF (pl);
394         }
395       M17N_OBJECT_UNREF (realized->per_script);
396     }
397   if (realized->per_charset)
398     {
399       MPLIST_DO (plist, realized->per_charset)
400         {
401           MPLIST_DO (pl, MPLIST_PLIST (plist))
402             if ((rfont = MPLIST_VAL (pl)) && ! rfont->frame)
403               free (rfont);
404           pl = MPLIST_PLIST (plist);
405           M17N_OBJECT_UNREF (pl);
406         }
407       M17N_OBJECT_UNREF (realized->per_charset);
408     }
409   if (realized->fallback)
410     {
411       MPLIST_DO (plist, realized->fallback)
412         if ((rfont = MPLIST_VAL (plist)) && ! rfont->frame)
413           free (rfont);
414       M17N_OBJECT_UNREF (realized->fallback);
415     }
416 }
417
418 static void
419 update_fontset_elements (MRealizedFontset *realized)
420 {
421   free_realized_fontset_elements (realized);
422   realize_fontset_elements (realized->frame, realized, realized->fontset,
423                             &realized->spec);
424 }
425
426
427 \f
428
429 /* Internal API */
430
431 int
432 mfont__fontset_init ()
433 {
434   Mfontset = msymbol ("fontset");
435   Mfontset->managing_key = 1;
436   fontset_list = mplist ();
437   default_fontset = mfontset ("default");
438   if (! default_fontset->mdb)
439     {
440       MFont font;
441
442       MFONT_INIT (&font);
443       mfont_put_prop (&font, Mregistry, msymbol ("iso8859-1"));
444       mfontset_modify_entry (default_fontset, Mnil, Mnil, Mnil,
445                              &font, Mnil, 1);
446       mfont_put_prop (&font, Mregistry, msymbol ("iso10646-1"));
447       mfontset_modify_entry (default_fontset, Mnil, Mnil, Mnil,
448                              &font, Mnil, 1);
449     }
450   return 0;
451 }
452
453
454 void
455 mfont__fontset_fini ()
456 {
457   while (! MPLIST_TAIL_P (fontset_list))
458     free_fontset ((MFontset *) MPLIST_VAL (fontset_list));
459   M17N_OBJECT_UNREF (fontset_list);
460   fontset_list = NULL;
461 }
462
463
464 MRealizedFontset *
465 mfont__realize_fontset (MFrame *frame, MFontset *fontset, MFace *face)
466 {
467   MRealizedFontset *realized;
468   MFont request;
469   MPlist *plist;
470
471   if (fontset->mdb)
472     load_fontset_contents (fontset);
473
474   mfont__set_spec_from_face (&request, face);
475   if (request.property[MFONT_SIZE] <= 0)
476     {
477       mdebug_hook ();
478       request.property[MFONT_SIZE] = 120;
479     }
480   MPLIST_DO (plist, frame->realized_fontset_list)
481     {
482       realized = (MRealizedFontset *) MPLIST_VAL (plist);
483       if (fontset->name == MPLIST_KEY (plist)
484           && ! memcmp (&request, &realized->spec, sizeof (request)))
485         return realized;
486     }
487
488   MSTRUCT_MALLOC (realized, MERROR_FONTSET);
489   realize_fontset_elements (frame, realized, fontset, &request);
490   mplist_add (frame->realized_fontset_list, fontset->name, realized);
491   return realized;
492 }
493
494
495 void
496 mfont__free_realized_fontset (MRealizedFontset *realized)
497 {
498   free_realized_fontset_elements (realized);
499   free (realized);
500 }
501
502
503 static MRealizedFont *
504 try_font_group (MRealizedFontset *realized,
505                 MPlist *font_group, MGlyph *g, int *num, int size)
506 {
507   MFrame *frame = realized->frame;
508   MRealizedFont *rfont;
509   MPlist *plist;
510   int i;
511
512   if (MPLIST_PLIST_P (font_group))
513     realize_font_group (frame, &realized->spec, font_group, size);
514
515   MPLIST_DO (plist, font_group)
516     {
517       rfont = (MRealizedFont *) MPLIST_VAL (plist);
518       if (rfont->status < 0)
519         continue;
520       /* Check if this font can display all glyphs.  */
521       for (i = 0; i < *num; i++)
522         {
523           g[i].code = mfont__encode_char (rfont,
524                                           g[i].type == GLYPH_CHAR ? g[i].c
525                                           : ' ');
526           if (g[i].code == MCHAR_INVALID_CODE)
527             break;
528         }
529       if (i == *num)
530         {
531           if (rfont->status > 0
532               || mfont__open (rfont) == 0)
533             /* We found a font that can display all glyphs.  */
534             return rfont;
535         }
536     }
537
538   /* We couldn't find a font that can display all glyphs.  Find one
539      that can display at least the first glyph.  */
540   MPLIST_DO (plist, font_group)
541     {
542       rfont = (MRealizedFont *) MPLIST_VAL (plist);
543       if (rfont->status < 0)
544         continue;
545       g->code = mfont__encode_char (rfont,
546                                     g->type == GLYPH_CHAR ? g->c : ' ');
547       if (g->code != MCHAR_INVALID_CODE)
548         {
549           if (rfont->status > 0
550               || mfont__open (rfont) == 0)
551             {
552               /* Ok, let's use this font.  Check how many more
553                  characters it supports.  */
554               int i;
555
556               for (i = 1; i < *num; i++)
557                 {
558                   g[i].code = mfont__encode_char (rfont,
559                                                   g[i].type == GLYPH_CHAR
560                                                   ? g[i].c : ' ');
561                   if (g[i].code == MCHAR_INVALID_CODE)
562                     break;
563                 }
564               *num = i;
565               return rfont;
566             }
567         }
568     }
569
570   return NULL;
571 }
572
573 MRealizedFont *
574 mfont__lookup_fontset (MRealizedFontset *realized, MGlyph *g, int *num,
575                        MSymbol script, MSymbol language, MSymbol charset,
576                        int size)
577 {
578   MCharset *preferred_charset = (charset == Mnil ? NULL : MCHARSET (charset));
579   MPlist *per_charset, *per_script, *per_lang;
580   MPlist *plist;
581   MRealizedFont *rfont = NULL;
582
583   if (realized->tick != realized->fontset->tick)
584     update_fontset_elements (realized);
585
586   if (preferred_charset
587       && (per_charset = mplist_get (realized->per_charset, charset)) != NULL
588       && (rfont = try_font_group (realized, per_charset, g, num, size)))
589     return rfont;
590
591   if (script != Mnil
592       && (per_script = mplist_get (realized->per_script, script)))
593     {
594       /* We prefer font groups in this order:
595           (1) group matching with LANGUAGE if LANGUAGE is not Mnil
596           (2) group for generic language
597           (3) group not matching with LANGUAGE  */
598       if (language == Mnil)
599         language = Mt;
600       if ((per_lang = mplist_get (per_script, language))
601           && (rfont = try_font_group (realized, per_lang, g, num, size)))
602         return rfont;
603
604       if (language == Mt)
605         {
606           /* Try the above (3) */
607           MPLIST_DO (plist, per_script)
608             if (MPLIST_KEY (plist) != language
609                 && (rfont = try_font_group (realized, MPLIST_PLIST (plist),
610                                             g, num, size)))
611               return rfont;
612         }
613       else
614         {
615           /* At first try the above (2) */
616           if ((per_lang = mplist_get (per_script, Mt))
617               && (rfont = try_font_group (realized, per_lang, g, num, size)))
618             return rfont;
619
620           /* Then try the above (3) */
621           MPLIST_DO (plist, per_script)
622             if (MPLIST_KEY (plist) != language
623                 && MPLIST_KEY (plist) != Mt
624                 && (rfont = try_font_group (realized, MPLIST_PLIST (plist),
625                                             g, num, size)))
626               return rfont;
627         }
628     }
629
630   if (language != Mnil)
631     /* Find a font group for this language from all scripts.  */
632     MPLIST_DO (plist, realized->per_script)
633       if ((per_lang = mplist_get (MPLIST_PLIST (plist), language))
634           && (rfont = try_font_group (realized, per_lang, g, num, size)))
635         return rfont;
636
637   /* Try fallback fonts.  */
638   if ((rfont = try_font_group (realized, realized->fallback, g, num, size)))
639     return rfont;
640
641   /* At last try all fonts.  */
642   MPLIST_DO (per_script, realized->per_script)
643     {
644       MPLIST_DO (per_lang, MPLIST_PLIST (per_script))
645         if ((rfont = try_font_group (realized, MPLIST_PLIST (per_lang),
646                                      g, num, size)))
647           return rfont;
648     }
649   MPLIST_DO (per_charset, realized->per_charset)
650     if ((rfont = try_font_group (realized, MPLIST_PLIST (per_charset),
651                                  g, num, size)))
652       return rfont;
653
654   return NULL;
655 }
656
657 /*** @} */
658 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
659
660 \f
661 /* External API */
662
663 /*** @addtogroup m17nFontset */
664 /*** @{ */
665
666 /*=*/
667 /***en
668     @brief Return a fontset.
669
670     The mfontset () function returns a pointer to a fontset object of
671     name $NAME.  If $NAME is @c NULL, it returns a pointer to the
672     default fontset.
673
674     If no fontset has the name $NAME, a new one is created.  At that
675     time, if there exists a data \<@c fontset, $NAME\> in the m17n
676     database, the fontset contents are initialized according to the
677     data.  If no such data exists, the fontset contents are left
678     vacant.
679
680     The macro M17N_INIT () creates the default fontset.  An
681     application program can modify it before the first call of 
682     mframe ().
683
684     @return
685     This function returns a pointer to the found or newly created
686     fontset.  */
687 /***ja 
688     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤òÊÖ¤¹.
689
690     ´Ø¿ô mfontset () ¤Ï̾Á° $NAME ¤ò»ý¤Ä¥Õ¥©¥ó¥È¥»¥Ã¥È¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î
691     ¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£ $NAME ¤¬ @c NULL ¤Ê¤é¤Ð¡¢¥Ç¥Õ¥©¥ë¥È¥Õ¥©¥ó¥È¥»¥Ã¥È
692     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
693
694     $NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¥Õ¥©¥ó¥È¥»¥Ã¥È¤¬¤Ê¤±¤ì¤Ð¡¢¿·¤·¤¤¤â¤Î¤¬ºî¤é¤ì
695     ¤ë¡£¤½¤ÎºÝ¡¢m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë \<@c fontset, $NAME\> ¤È¤¤¤¦¥Ç¡¼¥¿
696     ¤¬¤¢¤ì¤Ð¡¢¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ï¤½¤Î¥Ç¡¼¥¿¤Ë±è¤Ã¤Æ½é´ü²½¤µ¤ì¤ë¡£¤Ê¤±¤ì¤Ð¡¢
697     ¶õ¤Î¤Þ¤Þ¤Ë¤µ¤ì¤ë¡£
698
699     ¥Þ¥¯¥í M17N_INIT () ¤Ï¥Ç¥Õ¥©¥ë¥È¤Î¥Õ¥©¥ó¥È¥»¥Ã¥È¤òºî¤ë¡£¥¢¥×¥ê¥±¡¼
700     ¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï mframe () ¤ò½é¤á¤Æ¸Æ¤Ö¤Þ¤Ç¤Ï¥Ç¥Õ¥©¥ë¥È¥Õ¥©¥ó¥È
701     ¥»¥Ã¥È¤òÊѹ¹¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë¡£
702
703     @return
704     ¤³¤Î´Ø¿ô¤Ï¸«¤Ä¤«¤Ã¤¿¡¢¤¢¤ë¤¤¤Ïºî¤Ã¤¿¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
705      */
706
707 MFontset *
708 mfontset (char *name)
709 {
710   MSymbol sym;
711   MFontset *fontset;
712
713   if (! name)
714     fontset = default_fontset;
715   else
716     {
717       sym = msymbol (name);
718       fontset = mplist_get (fontset_list, sym);
719       if (! fontset)
720         {
721           M17N_OBJECT (fontset, free_fontset, MERROR_FONTSET);
722           fontset->name = sym;
723           fontset->mdb = mdatabase_find (Mfontset, sym, Mnil, Mnil);
724           if (! fontset->mdb)
725             {
726               fontset->per_script = mplist ();
727               fontset->per_charset = mplist ();
728               fontset->fallback = mplist ();
729               fontset->font_spec_list = mplist ();
730             }
731           mplist_put (fontset_list, sym, fontset);
732         }
733     }
734   M17N_OBJECT_REF (fontset);
735   return fontset;
736 }
737
738 /*=*/
739
740 /***en
741     @brief Return the name of a fontset.
742
743     The mfontset_name () function returns the name of fontset $FONTSET.  */
744 /***ja
745     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î̾Á°¤òÊÖ¤¹.
746
747     ´Ø¿ô mfontset_name () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤Î̾Á°¤òÊÖ¤¹¡£  */
748 MSymbol
749 mfontset_name (MFontset *fontset)
750 {
751   return fontset->name;
752 }
753
754 /*=*/
755
756 /***en
757     @brief Make a copy of a fontset.
758
759     The mfontset_copy () function makes a copy of fontset $FONTSET, gives it a
760     name $NAME, and returns a pointer to the created copy.  $NAME must
761     not be a name of existing fontset.  In such case, this function
762     returns NULL without making a copy.  */
763 /***ja
764     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î¥³¥Ô¡¼¤òºî¤ë.
765
766     ´Ø¿ô mfontset_copy () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤Î¥³¥Ô¡¼¤òºî¤Ã¤Æ¡¢
767     Ì¾Á° $NAME ¤òÍ¿¤¨¡¢¤½¤Î¥³¥Ô¡¼¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£$NAME ¤Ï´û¸¤Î
768     ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î̾Á°¤Ç¤¢¤Ã¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤½¤Î¾ì¹ç¤Ë¤Ï¥³¥Ô¡¼¤òºî¤é¤º
769     NULL ¤òÊÖ¤¹¡£  */
770
771 MFontset *
772 mfontset_copy (MFontset *fontset, char *name)
773 {
774   MSymbol sym = msymbol (name);
775   MFontset *copy = mplist_get (fontset_list, sym);
776   MPlist *plist, *pl;
777
778   if (copy)
779     return NULL;
780   M17N_OBJECT (copy, free_fontset, MERROR_FONTSET);
781   copy->name = sym;
782
783   if (fontset->mdb)
784     load_fontset_contents (fontset);
785
786   if (fontset->per_script)
787     {
788       copy->per_script = mplist ();
789       MPLIST_DO (plist, fontset->per_script)
790         {
791           MPlist *new = mplist ();
792
793           MPLIST_DO (pl, MPLIST_PLIST (plist))
794             mplist_add (new, MPLIST_KEY (pl), mplist_copy (MPLIST_PLIST (pl)));
795           mplist_add (copy->per_script, MPLIST_KEY (plist), new);
796         }
797     }
798   if (fontset->per_charset)
799     {
800       copy->per_charset = mplist ();
801       MPLIST_DO (plist, fontset->per_charset)
802         mplist_add (copy->per_charset, MPLIST_KEY (plist),
803                     mplist_copy (MPLIST_PLIST (plist)));
804     }
805   if (fontset->fallback)
806     copy->fallback = mplist_copy (fontset->fallback);
807
808   copy->font_spec_list = fontset->font_spec_list;
809   M17N_OBJECT_REF (copy->font_spec_list);
810
811   mplist_put (fontset_list, sym, copy);
812   M17N_OBJECT_REF (copy);
813   return copy;
814 }
815
816 /*=*/
817
818 /***en
819     @brief Modify the contents of a fontset.
820
821     The mfontset_modify_entry () function associates, in fontset
822     $FONTSET, a copy of $FONT with the $SCRIPT / $LANGUAGE pair or
823     with $CHARSET.
824
825     Each font in a fontset is associated with a particular
826     script/language pair, with a particular charset, or with the
827     symbol @c Mnil.  The fonts that are associated with the same item
828     make a group.
829
830     If $SCRIPT is not @c Mnil, it must be a symbol identifying a
831     script.  In this case, $LANGUAGE is either a symbol identifying a
832     language or @c Mnil, and $FONT is associated with the $SCRIPT /
833     $LANGUAGE pair.
834
835     If $CHARSET is not @c Mnil, it must be a symbol representing a
836     charset object.  In this case, $FONT is associated with that
837     charset.
838
839     If both $SCRIPT and $CHARSET are not @c Mnil, two copies of $FONT
840     are created.  Then one is associated with the $SCRIPT / $LANGUAGE
841     pair and the other with that charset.
842
843     If both $SCRIPT and $CHARSET are @c Mnil, $FONT is associated with
844     @c Mnil.  This kind of fonts are called @e fallback @e fonts.
845
846     The argument $HOW specifies the priority of $FONT.  If $HOW is
847     positive, $FONT has the highest priority in the group of fonts
848     that are associated with the same item.  If $HOW is negative,
849     $FONT has the lowest priority.  If $HOW is zero, $FONT becomes the
850     only available font for the associated item; all the other fonts
851     are removed from the group.
852
853     If $LAYOUTER_NAME is not @c Mnil, it must be a symbol
854     representing a @ref flt.  In that case, if $FONT is selected for
855     drawing an M-text, that font layout table is used to generate a
856     glyph code sequence from a character sequence.
857
858     @return
859     If the operation was successful, mfontset_modify_entry () returns 0.
860     Otherwise it returns -1 and assigns an error code to the external
861     variable #merror_code.  */
862
863 /***ja
864     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤ÎÆâÍƤòÊѹ¹¤¹¤ë.
865
866     ´Ø¿ô mfontset_modify_entry () ¤Ï¡¢$LANGUAGE ¤È $SCRIPT ¤ÎÁȤ߹ç¤ï
867     ¤»¤Þ¤¿¤Ï $CHARSET ¤ËÂФ·¤Æ $FONT ¤Î¥³¥Ô¡¼¤ò»È¤¦¤è¤¦¤Ë¡¢¥Õ¥©¥ó¥È¥»¥Ã
868     ¥È $FONTSET ¤òÀßÄꤹ¤ë¡£
869
870     ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î³Æ¥Õ¥©¥ó¥È¤Ï¡¢ÆÃÄê¤Î¥¹¥¯¥ê¥×¥È¤È¸À¸ì¤Î¥Ú¥¢¡¢ÆÃÄê¤Î
871     Ê¸»ú¥»¥Ã¥È¡¢¥·¥ó¥Ü¥ë @c Mnil ¤Î¤¤¤º¤ì¤«¤È´ØÏ¢ÉÕ¤±¤é¤ì¤Æ¤¤¤ë¡£Æ±¤¸
872     ¤â¤Î¤È´ØÏ¢ÉÕ¤±¤é¤ì¤¿¥Õ¥©¥ó¥È¤Ï¥°¥ë¡¼¥×¤ò¹½À®¤¹¤ë¡£
873
874     $SCRIPT ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢¥¹¥¯¥ê¥×¥È¤òÆÃÄꤹ¤ë¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
875     ¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¾ì¹ç¤Ë¤Ï¡¢$LANGUAGE ¤Ï¸À¸ì¤òÆÃÄꤹ¤ë¥·¥ó¥Ü¥ë¤« @c
876     Mnil ¤Ç¤¢¤ê¡¢$FONT ¤Ïthe $SCRIPT / $LANGUAGE ¥Ú¥¢¤Ë´ØÏ¢ÉÕ¤±¤é¤ì¤ë¡£
877
878     $CHARSET ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢Ê¸»ú¥»¥Ã¥È¥ª¥Ö¥¸¥§¥¯¥È¤òɽ¤¹¥·¥ó¥Ü¥ë
879     ¤Ç¤¢¤ë¡£¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¾ì¹ç¤Ë¤Ï $FONT ¤Ï¤½¤Îʸ»ú¥»¥Ã¥È¤È´ØÏ¢ÉÕ¤±¤é¤ì
880     ¤ë¡£
881
882     $SCRIPT ¤È $CHARSET ¤ÎÁÐÊý¤¬ @c Mnil ¤Ç¤Ê¤¤¾ì¹ç¤Ë¤Ï $FONT ¤Î¥³¥Ô¡¼
883     ¤¬£²¤Äºî¤é¤ì¡¢¤½¤ì¤¾¤ì $SCRIPT / $LANGUAGE ¥Ú¥¢¤Èʸ»ú¥»¥Ã¥È¤Ë´ØÏ¢
884     ÉÕ¤±¤é¤ì¤ë¡£
885
886     $SCRIPT ¤È $CHARSET ¤ÎÁÐÊý¤¬ @c Mnil ¤Ê¤é¤Ð¡¢ $FONT ¤Ï @c Mnil ¤È
887     ´ØÏ¢ÉÕ¤±¤é¤ì¤ë¡£¤³¤Î¼ï¤Î¥Õ¥©¥ó¥È¤Ï @e fallback @e font ¤È¸Æ¤Ð¤ì¤ë¡£
888
889     °ú¿ô $HOW ¤Ï $FONT ¤ÎÍ¥ÀèÅÙ¤ò»ØÄꤹ¤ë¡£$HOW ¤¬Àµ¤Ê¤é¤Ð¡¢$FONT ¤ÏƱ
890     ¤¸¤â¤Î¤È´ØÏ¢ÉÕ¤±¤é¤ì¤¿¥°¥ë¡¼¥×Ãæ¤ÇºÇ¹â¤ÎÍ¥ÀèÅÙ¤ò»ý¤Ä¡£$HOW ¤¬Éé¤Ê
891     ¤é¤Ð¡¢ºÇÄã¤ÎÍ¥ÀèÅÙ¤ò»ý¤Ä¡£$HOW ¤¬ 0 ¤Ê¤é¤Ð¡¢$FONT ¤Ï´ØÏ¢ÉÕ¤±¤é¤ì¤¿
892     ¤â¤Î¤ËÂФ¹¤ëÍ£°ì¤ÎÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤È¤Ê¤ê¡¢Â¾¤Î¥Õ¥©¥ó¥È¤Ï¥°¥ë¡¼¥×
893     ¤«¤é¼è¤ê½ü¤«¤ì¤ë¡£
894
895     $LAYOUTER_NAME ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢@ref flt ¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
896     ¥·¥ó¥Ü¥ë¤Ç¤¢¤ì¤Ð¡¢$FONT ¤òÍѤ¤¤ÆM-text ¤òɽ¼¨¤¹¤ëºÝ¤Ë¤Ï¡¢¤½¤Î FONT
897     LAYOUT TABLE ¤ò»È¤Ã¤Æʸ»úÎ󤫤饰¥ê¥Õ¥³¡¼¥ÉÎó¤òÀ¸À®¤¹¤ë¡£
898
899     @return 
900     ½èÍý¤¬À®¸ù¤·¤¿¤È¤­¡¢mfontset_modify_entry () ¤Ï 0 ¤òÊÖ¤¹¡£
901     ¼ºÇÔ¤·¤¿¤È¤­¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤ò
902     ÀßÄꤹ¤ë¡£  */
903
904 /***
905     @errors
906     @c MERROR_SYMBOL  */
907
908 int
909 mfontset_modify_entry (MFontset *fontset,
910                        MSymbol script, MSymbol language, MSymbol charset,
911                        MFont *spec, MSymbol layouter_name,
912                        int how)
913 {
914   MPlist *per_lang, *plist[3], *pl;
915   MFont *font = NULL;
916   int i;
917
918   if (fontset->mdb)
919     load_fontset_contents (fontset);
920
921   if (! fontset->font_spec_list)
922     fontset->font_spec_list = mplist ();
923   else
924     MPLIST_DO (pl, fontset->font_spec_list)
925       {
926         if (! memcmp (MPLIST_VAL (pl), spec, sizeof (MFont)))
927           {
928             font = MPLIST_VAL (pl);
929             break;
930           }
931       }
932   if (! font)
933     {
934       font = mfont ();
935       *font = *spec;
936       mplist_add (fontset->font_spec_list, Mt, font);
937     }
938
939   i = 0;
940   if (script != Mnil)
941     {
942       if (language == Mnil)
943         language = Mt;
944       per_lang = mplist_get (fontset->per_script, script);
945       if (! per_lang)
946         mplist_add (fontset->per_script, script, per_lang = mplist ());
947       plist[i] = mplist_get (per_lang, language);
948       if (! plist[i])
949         mplist_add (per_lang, language, plist[i] = mplist ());
950       i++;
951     }
952   if (charset != Mnil)
953     {
954       plist[i] = mplist_get (fontset->per_charset, charset);
955       if (! plist[i])
956         mplist_add (fontset->per_charset, charset, plist[i] = mplist ());
957       i++;
958     }
959   if (script == Mnil && charset == Mnil)
960     {
961       plist[i++] = fontset->fallback;
962     }
963
964   if (layouter_name == Mnil)
965     layouter_name = Mt;
966   for (i--; i >= 0; i--)
967     {
968       if (how == 1)
969         mplist_push (plist[i], layouter_name, font);
970       else if (how == -1)
971         mplist_add (plist[i], layouter_name, font);
972       else
973         {
974           mplist_set (plist[i], Mnil, NULL);
975           mplist_add (plist[i], layouter_name, font);
976         }
977     }
978
979   fontset->tick++;
980   return 0;
981 }
982
983 /*=*/
984
985 /***en
986     @brief Lookup a fontset.
987
988     The mfontset_lookup () function lookups $FONTSET and returns a
989     plist that describes the contents of $FONTSET corresponding to the
990     specified script, language, and charset.
991
992     If $SCRIPT is @c Mt, keys of the returned plist are script name
993     symbols for which some fonts are specified and values are NULL.
994
995     If $SCIRPT is a script symbol, the returned plist is decided by
996     $LANGUAGE.
997
998     If $LANGUAGE is @c Mt, keys of the plist are language name symbols
999     for which some fonts are specified and values are NULL.  A key may
1000     be @c Mt which means some fallback fonts are specified for the
1001     script.
1002
1003     If $LANGUAGE is a language name symbol, the plist is a @c
1004     FONT-GROUP for the specified script and langauge.
1005
1006     If $LANGAUGE is @c Mt, the plist is fallback @c FONT-GROUP for the
1007     script.
1008
1009     If $SCRIPT is @c Mnil, the returned plist is decided as below.
1010
1011     If $CHARSET is @c Mt, keys of the returned plist are charset name
1012     symbols for which some fonts are specified and values are NULL.
1013
1014     If $CHARSET is a charset symbol, the plist is a @c FONT-GROUP for
1015     the charset.
1016
1017     If $CHARSET is @c Mnil, the plist is a fallback @c FONT-GROUP.
1018
1019     @c FONT-GROUP is a plist whose keys are FLT name symbols (@c Mt if
1020     no FLT is associated with the font) and values are pointers to
1021     #MFont.
1022
1023     @return
1024     It returns a plist describing the contents of a fontset.  The
1025     plist should be freed by m17n_object_unref ().  */
1026
1027 MPlist *
1028 mfontset_lookup (MFontset *fontset,
1029                  MSymbol script, MSymbol language, MSymbol charset)
1030 {
1031   MPlist *plist = mplist (), *pl, *p;
1032
1033   if (fontset->mdb)
1034     load_fontset_contents (fontset);
1035   if (script == Mt)
1036     {
1037       if (! fontset->per_script)
1038         return plist;
1039       p = plist;
1040       MPLIST_DO (pl, fontset->per_script)
1041         p = mplist_add (p, MPLIST_KEY (pl), NULL);
1042       return plist;
1043     }
1044   if (script != Mnil)
1045     {
1046       if (! fontset->per_script)
1047         return plist;
1048       pl = mplist_get (fontset->per_script, script);
1049       if (! pl)
1050         return plist;
1051       if (language == Mt)
1052         {
1053           p = plist;
1054           MPLIST_DO (pl, pl)
1055             p = mplist_add (p, MPLIST_KEY (pl), NULL);
1056           return plist;
1057         }
1058       if (language == Mnil)
1059         language = Mt;
1060       pl = mplist_get (pl, language);
1061     }
1062   else if (charset != Mnil)
1063     {
1064       if (! fontset->per_charset)
1065         return plist;
1066       if (charset == Mt)
1067         {
1068           p = plist;
1069           MPLIST_DO (pl, fontset->per_charset)
1070             p = mplist_add (p, MPLIST_KEY (pl), NULL);
1071           return plist;
1072         }
1073       pl = mplist_get (fontset->per_charset, charset);
1074     }
1075   else
1076     pl = fontset->fallback;
1077   if (! pl)
1078     return plist;
1079   return mplist_copy (pl);
1080 }
1081
1082
1083 /*** @} */
1084
1085 /*** @addtogroup m17nDebug */
1086 /*=*/
1087 /*** @{  */
1088
1089 /***en
1090     @brief Dump a fontset.
1091
1092     The mdebug_dump_fontset () function prints fontset $FONTSET in a human readable
1093     way to the stderr.  $INDENT specifies how many columns to indent
1094     the lines but the first one.
1095
1096     @return
1097     This function returns $FONTSET.  */
1098 /***ja
1099     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤ò¥À¥ó¥×¤¹¤ë.
1100
1101     ´Ø¿ô mdebug_dump_face () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤ò stderr ¤Ë¿Í
1102     ´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£ $INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ
1103     ¤ë¡£
1104
1105     @return
1106     ¤³¤Î´Ø¿ô¤Ï $FONTSET ¤òÊÖ¤¹¡£  */
1107
1108 MFontset *
1109 mdebug_dump_fontset (MFontset *fontset, int indent)
1110 {
1111   char *prefix = (char *) alloca (indent + 1);
1112   MPlist *plist, *pl, *p;
1113
1114   memset (prefix, 32, indent);
1115   prefix[indent] = 0;
1116
1117   fprintf (stderr, "(fontset %s", fontset->name->name);
1118   if (fontset->per_script)
1119     MPLIST_DO (plist, fontset->per_script)
1120       {
1121         fprintf (stderr, "\n  %s(%s", prefix, MPLIST_KEY (plist)->name);
1122         MPLIST_DO (pl, MPLIST_PLIST (plist))
1123           {
1124             fprintf (stderr, "\n    %s(%s", prefix, MPLIST_KEY (pl)->name);
1125             MPLIST_DO (p, MPLIST_PLIST (pl))
1126               {
1127                 fprintf (stderr, "\n      %s(%s ", prefix,
1128                          MPLIST_KEY (p)->name);
1129                 mdebug_dump_font (MPLIST_VAL (p));
1130                 fprintf (stderr, ")");
1131               }
1132             fprintf (stderr, ")");
1133           }
1134         fprintf (stderr, ")");
1135       }
1136   if (fontset->per_charset)
1137     MPLIST_DO (pl, fontset->per_charset)
1138       {
1139         fprintf (stderr, "\n  %s(%s", prefix, MPLIST_KEY (pl)->name);
1140         MPLIST_DO (p, MPLIST_PLIST (pl))
1141           {
1142             fprintf (stderr, "\n    %s(%s ", prefix, MPLIST_KEY (p)->name);
1143             mdebug_dump_font (MPLIST_VAL (p));
1144             fprintf (stderr, ")");
1145           }
1146         fprintf (stderr, ")");
1147       }
1148
1149   if (fontset->fallback)
1150     MPLIST_DO (p, fontset->fallback)
1151       {
1152         fprintf (stderr, "\n  %s(%s ", prefix, MPLIST_KEY (p)->name);
1153         mdebug_dump_font (MPLIST_VAL (p));
1154         fprintf (stderr, ")");
1155       }
1156
1157   fprintf (stderr, ")");
1158   return fontset;
1159 }
1160
1161 /*** @} */
1162
1163 /*
1164   Local Variables:
1165   coding: euc-japan
1166   End:
1167 */