(realize_fontset_elements)
[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 static void
337 realize_fontset_elements (MFrame *frame, MRealizedFontset *realized,
338                           MFontset *fontset, MFont *request)
339 {
340   MPlist *per_script, *per_lang, *per_charset, *font_group;
341   MPlist *plist, *pl;
342
343   realized->fontset = fontset;
344   realized->tick = fontset->tick;
345   realized->spec = *request;
346   realized->frame = frame;
347   realized->per_script = per_script = mplist ();
348   MPLIST_DO (plist, fontset->per_script)
349     {
350       per_lang = mplist ();
351       per_script = mplist_add (per_script, MPLIST_KEY (plist), per_lang);
352       MPLIST_DO (pl, MPLIST_PLIST (plist))
353         {
354           font_group = mplist ();
355           mplist_add (font_group, Mplist, MPLIST_VAL (pl));
356           per_lang = mplist_add (per_lang, MPLIST_KEY (pl), font_group);
357         }
358     }
359
360   realized->per_charset = per_charset = mplist ();
361   MPLIST_DO (plist, fontset->per_charset)
362     {
363       font_group = mplist ();
364       mplist_add (font_group, Mplist, MPLIST_VAL (plist));
365       per_charset = mplist_add (per_charset, MPLIST_KEY (plist), font_group);
366     }
367
368   realized->fallback = mplist ();
369   mplist_add (realized->fallback, Mplist, fontset->fallback);
370
371 }
372
373 static void
374 free_realized_fontset_elements (MRealizedFontset *realized)
375 {
376   MPlist *plist, *pl, *p;
377   MRealizedFont *rfont;
378
379   if (realized->per_script)
380     {
381       MPLIST_DO (plist, realized->per_script)
382         {
383           MPLIST_DO (pl, MPLIST_PLIST (plist))
384             {
385               MPLIST_DO (p, MPLIST_PLIST (pl))
386                 if ((rfont = MPLIST_VAL (p)) && ! rfont->frame)
387                   free (rfont);
388               p = MPLIST_PLIST (pl);
389               M17N_OBJECT_UNREF (p);
390             }
391           pl = MPLIST_PLIST (plist);
392           M17N_OBJECT_UNREF (pl);
393         }
394       M17N_OBJECT_UNREF (realized->per_script);
395     }
396   if (realized->per_charset)
397     {
398       MPLIST_DO (plist, realized->per_charset)
399         {
400           MPLIST_DO (pl, MPLIST_PLIST (plist))
401             if ((rfont = MPLIST_VAL (pl)) && ! rfont->frame)
402               free (rfont);
403           pl = MPLIST_PLIST (plist);
404           M17N_OBJECT_UNREF (pl);
405         }
406       M17N_OBJECT_UNREF (realized->per_charset);
407     }
408   if (realized->fallback)
409     {
410       MPLIST_DO (plist, realized->fallback)
411         if ((rfont = MPLIST_VAL (plist)) && ! rfont->frame)
412           free (rfont);
413       M17N_OBJECT_UNREF (realized->fallback);
414     }
415 }
416
417 static void
418 update_fontset_elements (MRealizedFontset *realized)
419 {
420   free_realized_fontset_elements (realized);
421   realize_fontset_elements (realized->frame, realized, realized->fontset,
422                             &realized->spec);
423 }
424
425
426 \f
427
428 /* Internal API */
429
430 int
431 mfont__fontset_init ()
432 {
433   Mfontset = msymbol ("fontset");
434   Mfontset->managing_key = 1;
435   fontset_list = mplist ();
436   default_fontset = mfontset ("default");
437   if (! default_fontset->mdb)
438     {
439       MFont font;
440
441       MFONT_INIT (&font);
442       mfont_put_prop (&font, Mregistry, msymbol ("iso8859-1"));
443       mfontset_modify_entry (default_fontset, Mnil, Mnil, Mnil,
444                              &font, Mnil, 1);
445       mfont_put_prop (&font, Mregistry, msymbol ("iso10646-1"));
446       mfontset_modify_entry (default_fontset, Mnil, Mnil, Mnil,
447                              &font, Mnil, 1);
448     }
449   return 0;
450 }
451
452
453 void
454 mfont__fontset_fini ()
455 {
456   while (! MPLIST_TAIL_P (fontset_list))
457     free_fontset ((MFontset *) MPLIST_VAL (fontset_list));
458   M17N_OBJECT_UNREF (fontset_list);
459   fontset_list = NULL;
460 }
461
462
463 MRealizedFontset *
464 mfont__realize_fontset (MFrame *frame, MFontset *fontset, MFace *face)
465 {
466   MRealizedFontset *realized;
467   MFont request;
468   MPlist *plist;
469
470   if (fontset->mdb)
471     load_fontset_contents (fontset);
472
473   mfont__set_spec_from_face (&request, face);
474   if (request.property[MFONT_SIZE] <= 0)
475     {
476       mdebug_hook ();
477       request.property[MFONT_SIZE] = 120;
478     }
479   MPLIST_DO (plist, frame->realized_fontset_list)
480     {
481       realized = (MRealizedFontset *) MPLIST_VAL (plist);
482       if (fontset->name == MPLIST_KEY (plist)
483           && ! memcmp (&request, &realized->spec, sizeof (request)))
484         return realized;
485     }
486
487   MSTRUCT_MALLOC (realized, MERROR_FONTSET);
488   realize_fontset_elements (frame, realized, fontset, &request);
489   mplist_add (frame->realized_fontset_list, fontset->name, realized);
490   return realized;
491 }
492
493
494 void
495 mfont__free_realized_fontset (MRealizedFontset *realized)
496 {
497   free_realized_fontset_elements (realized);
498   free (realized);
499 }
500
501
502 MRealizedFont *
503 mfont__lookup_fontset (MRealizedFontset *realized, MGlyph *g, int *num,
504                        MSymbol script, MSymbol language, MSymbol charset,
505                        int size)
506 {
507   MFrame *frame = realized->frame;
508   MCharset *preferred_charset = (charset == Mnil ? NULL : MCHARSET (charset));
509   MPlist *per_charset, *per_script, *per_lang;
510   MPlist *font_groups[256], *plist;
511   int n_font_group = 0;
512   MRealizedFont *rfont;
513   int i;
514
515   if (realized->tick != realized->fontset->tick)
516     update_fontset_elements (realized);
517
518   if (preferred_charset
519       && (per_charset = mplist_get (realized->per_charset, charset)) != NULL)
520     font_groups[n_font_group++] = per_charset;
521   if (script != Mnil
522       && ((per_script = mplist_find_by_key (realized->per_script, script))
523           != NULL))
524     {
525       /* We prefer font groups in this order:
526           (1) group matching LANGUAGE
527           (2) group for generic LANGUAGE
528           (3) group non-matching LANGUAGE  */
529       if (language == Mnil)
530         language = Mt;
531       per_lang = mplist_find_by_key (MPLIST_PLIST (per_script), language);
532       if (per_lang)
533         {
534           font_groups[n_font_group++] = MPLIST_PLIST (per_lang);
535           if (language == Mt)
536             {
537               MPLIST_DO (per_lang, MPLIST_PLIST (per_script))
538                 if (MPLIST_KEY (per_lang) != language)
539                   font_groups[n_font_group++] = MPLIST_PLIST (per_lang);
540             }
541         }
542       if (language != Mt)
543         {
544           plist = mplist_get (MPLIST_PLIST (per_script), Mt);
545           if (plist)
546             font_groups[n_font_group++] = plist;
547         }
548       MPLIST_DO (per_lang, MPLIST_PLIST (per_script))
549         if (MPLIST_KEY (per_lang) != language
550             && MPLIST_KEY (per_lang) != Mt)
551           font_groups[n_font_group++] = MPLIST_PLIST (per_lang);
552     }
553   font_groups[n_font_group++] = realized->fallback;
554
555   if (n_font_group == 1)
556     {
557       /* As we only have a fallback font group, try all the other
558          fonts too.  */
559       MPLIST_DO (per_script, realized->per_script)
560         MPLIST_DO (per_lang, MPLIST_PLIST (per_script))
561           font_groups[n_font_group++] = MPLIST_PLIST (per_lang);
562       MPLIST_DO (per_charset, realized->per_charset)
563         font_groups[n_font_group++] = MPLIST_PLIST (per_charset);
564     }
565
566   for (i = 0; i < n_font_group; i++)
567     {
568       int j;
569       
570       if (MPLIST_PLIST_P (font_groups[i]))
571         realize_font_group (frame, &realized->spec, font_groups[i], size);
572
573       MPLIST_DO (plist, font_groups[i])
574         {
575           rfont = (MRealizedFont *) MPLIST_VAL (plist);
576           if (rfont->status < 0)
577             continue;
578           /* Check if this font can display all glyphs.  */
579           for (j = 0; j < *num; j++)
580             {
581               g[j].code = mfont__encode_char (rfont, g[j].c);
582               if (g[j].code == MCHAR_INVALID_CODE)
583                 break;
584             }
585           if (j == *num)
586             {
587               if (rfont->status > 0
588                   || mfont__open (rfont) == 0)
589                 /* We found a font that can display all glyphs.  */
590                 break;
591             }
592         }
593       if (! MPLIST_TAIL_P (plist))
594         break;
595     }
596
597   if (i < n_font_group) 
598     return rfont;
599
600   /* We couldn't find a font that can display all glyphs.  Find one
601      that can display at least the first glyph.  */
602   for (i = 0; i < n_font_group; i++)
603     {
604       MPLIST_DO (plist, font_groups[i])
605         {
606           rfont = (MRealizedFont *) MPLIST_VAL (plist);
607           if (rfont->status < 0)
608             continue;
609           g->code = mfont__encode_char (rfont, g->c);
610           if (g->code != MCHAR_INVALID_CODE)
611             {
612               if (rfont->status > 0
613                   || mfont__open (rfont) == 0)
614                 break;
615             }
616         }
617       if (! MPLIST_TAIL_P (plist))
618         break;
619     }
620   return (i < n_font_group ? rfont : NULL);
621 }
622
623 /*** @} */
624 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
625
626 \f
627 /* External API */
628
629 /*** @addtogroup m17nFontset */
630 /*** @{ */
631
632 /*=*/
633 /***en
634     @brief Return a fontset.
635
636     The mfontset () function returns a pointer to a fontset object of
637     name $NAME.  If $NAME is @c NULL, it returns a pointer to the
638     default fontset.
639
640     If no fontset has the name $NAME, a new one is created.  At that
641     time, if there exists a data \<@c fontset, $NAME\> in the m17n
642     database, the fontset contents are initialized according to the
643     data.  If no such data exists, the fontset contents are left
644     vacant.
645
646     The macro M17N_INIT () creates the default fontset.  An
647     application program can modify it before the first call of 
648     mframe ().
649
650     @return
651     This function returns a pointer to the found or newly created
652     fontset.  */
653 /***ja 
654     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤òÊÖ¤¹.
655
656     ´Ø¿ô mfontset () ¤Ï̾Á° $NAME ¤ò»ý¤Ä¥Õ¥©¥ó¥È¥»¥Ã¥È¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î
657     ¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£ $NAME ¤¬ @c NULL ¤Ê¤é¤Ð¡¢¥Ç¥Õ¥©¥ë¥È¥Õ¥©¥ó¥È¥»¥Ã¥È
658     ¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
659
660     $NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä¥Õ¥©¥ó¥È¥»¥Ã¥È¤¬¤Ê¤±¤ì¤Ð¡¢¿·¤·¤¤¤â¤Î¤¬ºî¤é¤ì
661     ¤ë¡£¤½¤ÎºÝ¡¢m17n ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë \<@c fontset, $NAME\> ¤È¤¤¤¦¥Ç¡¼¥¿
662     ¤¬¤¢¤ì¤Ð¡¢¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ï¤½¤Î¥Ç¡¼¥¿¤Ë±è¤Ã¤Æ½é´ü²½¤µ¤ì¤ë¡£¤Ê¤±¤ì¤Ð¡¢
663     ¶õ¤Î¤Þ¤Þ¤Ë¤µ¤ì¤ë¡£
664
665     ¥Þ¥¯¥í M17N_INIT () ¤Ï¥Ç¥Õ¥©¥ë¥È¤Î¥Õ¥©¥ó¥È¥»¥Ã¥È¤òºî¤ë¡£¥¢¥×¥ê¥±¡¼
666     ¥·¥ç¥ó¥×¥í¥°¥é¥à¤Ï mframe () ¤ò½é¤á¤Æ¸Æ¤Ö¤Þ¤Ç¤Ï¥Ç¥Õ¥©¥ë¥È¥Õ¥©¥ó¥È
667     ¥»¥Ã¥È¤òÊѹ¹¤¹¤ë¤³¤È¤¬¤Ç¤­¤ë¡£
668
669     @return
670     ¤³¤Î´Ø¿ô¤Ï¸«¤Ä¤«¤Ã¤¿¡¢¤¢¤ë¤¤¤Ïºî¤Ã¤¿¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£
671      */
672
673 MFontset *
674 mfontset (char *name)
675 {
676   MSymbol sym;
677   MFontset *fontset;
678
679   if (! name)
680     fontset = default_fontset;
681   else
682     {
683       sym = msymbol (name);
684       fontset = mplist_get (fontset_list, sym);
685       if (! fontset)
686         {
687           M17N_OBJECT (fontset, free_fontset, MERROR_FONTSET);
688           fontset->name = sym;
689           fontset->mdb = mdatabase_find (Mfontset, sym, Mnil, Mnil);
690           if (! fontset->mdb)
691             {
692               fontset->per_script = mplist ();
693               fontset->per_charset = mplist ();
694               fontset->fallback = mplist ();
695             }
696           mplist_put (fontset_list, sym, fontset);
697         }
698     }
699   M17N_OBJECT_REF (fontset);
700   return fontset;
701 }
702
703 /*=*/
704
705 /***en
706     @brief Return the name of a fontset.
707
708     The mfontset_name () function returns the name of fontset $FONTSET.  */
709 /***ja
710     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î̾Á°¤òÊÖ¤¹.
711
712     ´Ø¿ô mfontset_name () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤Î̾Á°¤òÊÖ¤¹¡£  */
713 MSymbol
714 mfontset_name (MFontset *fontset)
715 {
716   return fontset->name;
717 }
718
719 /*=*/
720
721 /***en
722     @brief Make a copy of a fontset.
723
724     The mfontset_copy () function makes a copy of fontset $FONTSET, gives it a
725     name $NAME, and returns a pointer to the created copy.  $NAME must
726     not be a name of existing fontset.  In such case, this function
727     returns NULL without making a copy.  */
728 /***ja
729     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î¥³¥Ô¡¼¤òºî¤ë.
730
731     ´Ø¿ô mfontset_copy () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤Î¥³¥Ô¡¼¤òºî¤Ã¤Æ¡¢
732     Ì¾Á° $NAME ¤òÍ¿¤¨¡¢¤½¤Î¥³¥Ô¡¼¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£$NAME ¤Ï´û¸¤Î
733     ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î̾Á°¤Ç¤¢¤Ã¤Æ¤Ï¤Ê¤é¤Ê¤¤¡£¤½¤Î¾ì¹ç¤Ë¤Ï¥³¥Ô¡¼¤òºî¤é¤º
734     NULL ¤òÊÖ¤¹¡£  */
735
736 MFontset *
737 mfontset_copy (MFontset *fontset, char *name)
738 {
739   MSymbol sym = msymbol (name);
740   MFontset *copy = mplist_get (fontset_list, sym);
741   MPlist *plist, *pl;
742
743   if (copy)
744     return NULL;
745   M17N_OBJECT (copy, free_fontset, MERROR_FONTSET);
746   copy->name = sym;
747
748   if (fontset->per_script)
749     {
750       copy->per_script = mplist ();
751       MPLIST_DO (plist, fontset->per_script)
752         {
753           MPlist *new = mplist ();
754
755           MPLIST_DO (pl, MPLIST_PLIST (plist))
756             mplist_add (new, MPLIST_KEY (pl), mplist_copy (MPLIST_PLIST (pl)));
757           mplist_add (copy->per_script, MPLIST_KEY (plist), new);
758         }
759     }
760   if (fontset->per_charset)
761     {
762       copy->per_charset = mplist ();
763       MPLIST_DO (plist, fontset->per_charset)
764         mplist_add (copy->per_charset, MPLIST_KEY (plist),
765                     mplist_copy (MPLIST_PLIST (plist)));
766     }
767   if (fontset->fallback)
768     copy->fallback = mplist_copy (fontset->fallback);
769
770   copy->font_spec_list = fontset->font_spec_list;
771   M17N_OBJECT_REF (copy->font_spec_list);
772
773   mplist_put (fontset_list, sym, copy);
774   M17N_OBJECT_REF (copy);
775   return copy;
776 }
777
778 /*=*/
779
780 /***en
781     @brief Modify the contents of a fontset.
782
783     The mfontset_modify_entry () function associates, in fontset
784     $FONTSET, a copy of $FONT with the $SCRIPT / $LANGUAGE pair or
785     with $CHARSET.
786
787     Each font in a fontset is associated with a particular
788     script/language pair, with a particular charset, or with the
789     symbol @c Mnil.  The fonts that are associated with the same item
790     make a group.
791
792     If $SCRIPT is not @c Mnil, it must be a symbol identifying a
793     script.  In this case, $LANGUAGE is either a symbol identifying a
794     language or @c Mnil, and $FONT is associated with the $SCRIPT /
795     $LANGUAGE pair.
796
797     If $CHARSET is not @c Mnil, it must be a symbol representing a
798     charset object.  In this case, $FONT is associated with that
799     charset.
800
801     If both $SCRIPT and $CHARSET are not @c Mnil, two copies of $FONT
802     are created.  Then one is associated with the $SCRIPT / $LANGUAGE
803     pair and the other with that charset.
804
805     If both $SCRIPT and $CHARSET are @c Mnil, $FONT is associated with
806     @c Mnil.  This kind of fonts are called @e fallback @e fonts.
807
808     The argument $HOW specifies the priority of $FONT.  If $HOW is
809     positive, $FONT has the highest priority in the group of fonts
810     that are associated with the same item.  If $HOW is negative,
811     $FONT has the lowest priority.  If $HOW is zero, $FONT becomes the
812     only available font for the associated item; all the other fonts
813     are removed from the group.
814
815     If $LAYOUTER_NAME is not @c Mnil, it must be a symbol
816     representing a @ref flt.  In that case, if $FONT is selected for
817     drawing an M-text, that font layout table is used to generate a
818     glyph code sequence from a character sequence.
819
820     @return
821     If the operation was successful, mfontset_modify_entry () returns 0.
822     Otherwise it returns -1 and assigns an error code to the external
823     variable #merror_code.  */
824
825 /***ja
826     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤ÎÆâÍƤòÊѹ¹¤¹¤ë.
827
828     ´Ø¿ô mfontset_modify_entry () ¤Ï¡¢$LANGUAGE ¤È $SCRIPT ¤ÎÁȤ߹ç¤ï
829     ¤»¤Þ¤¿¤Ï $CHARSET ¤ËÂФ·¤Æ $FONT ¤Î¥³¥Ô¡¼¤ò»È¤¦¤è¤¦¤Ë¡¢¥Õ¥©¥ó¥È¥»¥Ã
830     ¥È $FONTSET ¤òÀßÄꤹ¤ë¡£
831
832     ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Î³Æ¥Õ¥©¥ó¥È¤Ï¡¢ÆÃÄê¤Î¥¹¥¯¥ê¥×¥È¤È¸À¸ì¤Î¥Ú¥¢¡¢ÆÃÄê¤Î
833     Ê¸»ú¥»¥Ã¥È¡¢¥·¥ó¥Ü¥ë @c Mnil ¤Î¤¤¤º¤ì¤«¤È´ØÏ¢ÉÕ¤±¤é¤ì¤Æ¤¤¤ë¡£Æ±¤¸
834     ¤â¤Î¤È´ØÏ¢ÉÕ¤±¤é¤ì¤¿¥Õ¥©¥ó¥È¤Ï¥°¥ë¡¼¥×¤ò¹½À®¤¹¤ë¡£
835
836     $SCRIPT ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢¥¹¥¯¥ê¥×¥È¤òÆÃÄꤹ¤ë¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
837     ¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¾ì¹ç¤Ë¤Ï¡¢$LANGUAGE ¤Ï¸À¸ì¤òÆÃÄꤹ¤ë¥·¥ó¥Ü¥ë¤« @c
838     Mnil ¤Ç¤¢¤ê¡¢$FONT ¤Ïthe $SCRIPT / $LANGUAGE ¥Ú¥¢¤Ë´ØÏ¢ÉÕ¤±¤é¤ì¤ë¡£
839
840     $CHARSET ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢Ê¸»ú¥»¥Ã¥È¥ª¥Ö¥¸¥§¥¯¥È¤òɽ¤¹¥·¥ó¥Ü¥ë
841     ¤Ç¤¢¤ë¡£¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¾ì¹ç¤Ë¤Ï $FONT ¤Ï¤½¤Îʸ»ú¥»¥Ã¥È¤È´ØÏ¢ÉÕ¤±¤é¤ì
842     ¤ë¡£
843
844     $SCRIPT ¤È $CHARSET ¤ÎÁÐÊý¤¬ @c Mnil ¤Ç¤Ê¤¤¾ì¹ç¤Ë¤Ï $FONT ¤Î¥³¥Ô¡¼
845     ¤¬£²¤Äºî¤é¤ì¡¢¤½¤ì¤¾¤ì $SCRIPT / $LANGUAGE ¥Ú¥¢¤Èʸ»ú¥»¥Ã¥È¤Ë´ØÏ¢
846     ÉÕ¤±¤é¤ì¤ë¡£
847
848     $SCRIPT ¤È $CHARSET ¤ÎÁÐÊý¤¬ @c Mnil ¤Ê¤é¤Ð¡¢ $FONT ¤Ï @c Mnil ¤È
849     ´ØÏ¢ÉÕ¤±¤é¤ì¤ë¡£¤³¤Î¼ï¤Î¥Õ¥©¥ó¥È¤Ï @e fallback @e font ¤È¸Æ¤Ð¤ì¤ë¡£
850
851     °ú¿ô $HOW ¤Ï $FONT ¤ÎÍ¥ÀèÅÙ¤ò»ØÄꤹ¤ë¡£$HOW ¤¬Àµ¤Ê¤é¤Ð¡¢$FONT ¤ÏƱ
852     ¤¸¤â¤Î¤È´ØÏ¢ÉÕ¤±¤é¤ì¤¿¥°¥ë¡¼¥×Ãæ¤ÇºÇ¹â¤ÎÍ¥ÀèÅÙ¤ò»ý¤Ä¡£$HOW ¤¬Éé¤Ê
853     ¤é¤Ð¡¢ºÇÄã¤ÎÍ¥ÀèÅÙ¤ò»ý¤Ä¡£$HOW ¤¬ 0 ¤Ê¤é¤Ð¡¢$FONT ¤Ï´ØÏ¢ÉÕ¤±¤é¤ì¤¿
854     ¤â¤Î¤ËÂФ¹¤ëÍ£°ì¤ÎÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤È¤Ê¤ê¡¢Â¾¤Î¥Õ¥©¥ó¥È¤Ï¥°¥ë¡¼¥×
855     ¤«¤é¼è¤ê½ü¤«¤ì¤ë¡£
856
857     $LAYOUTER_NAME ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢@ref flt ¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
858     ¥·¥ó¥Ü¥ë¤Ç¤¢¤ì¤Ð¡¢$FONT ¤òÍѤ¤¤ÆM-text ¤òɽ¼¨¤¹¤ëºÝ¤Ë¤Ï¡¢¤½¤Î FONT
859     LAYOUT TABLE ¤ò»È¤Ã¤Æʸ»úÎ󤫤饰¥ê¥Õ¥³¡¼¥ÉÎó¤òÀ¸À®¤¹¤ë¡£
860
861     @return 
862     ½èÍý¤¬À®¸ù¤·¤¿¤È¤­¡¢mfontset_modify_entry () ¤Ï 0 ¤òÊÖ¤¹¡£
863     ¼ºÇÔ¤·¤¿¤È¤­¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô #merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤ò
864     ÀßÄꤹ¤ë¡£  */
865
866 /***
867     @errors
868     @c MERROR_SYMBOL  */
869
870 int
871 mfontset_modify_entry (MFontset *fontset,
872                        MSymbol script, MSymbol language, MSymbol charset,
873                        MFont *spec, MSymbol layouter_name,
874                        int how)
875 {
876   MPlist *per_lang, *plist[3], *pl;
877   MFont *font = NULL;
878   int i;
879
880   if (fontset->mdb)
881     load_fontset_contents (fontset);
882
883   if (! fontset->font_spec_list)
884     fontset->font_spec_list = mplist ();
885   else
886     MPLIST_DO (pl, fontset->font_spec_list)
887       {
888         if (! memcmp (MPLIST_VAL (pl), spec, sizeof (MFont)))
889           {
890             font = MPLIST_VAL (pl);
891             break;
892           }
893       }
894   if (! font)
895     {
896       font = mfont ();
897       *font = *spec;
898       mplist_add (fontset->font_spec_list, Mt, font);
899     }
900
901   i = 0;
902   if (script != Mnil)
903     {
904       if (language == Mnil)
905         language = Mt;
906       per_lang = mplist_get (fontset->per_script, script);
907       if (! per_lang)
908         mplist_add (fontset->per_script, script, per_lang = mplist ());
909       plist[i] = mplist_get (per_lang, language);
910       if (! plist[i])
911         mplist_add (per_lang, language, plist[i] = mplist ());
912       i++;
913     }
914   if (charset != Mnil)
915     {
916       plist[i] = mplist_get (fontset->per_charset, charset);
917       if (! plist[i])
918         mplist_add (fontset->per_charset, charset, plist[i] = mplist ());
919       i++;
920     }
921   if (script == Mnil && charset == Mnil)
922     {
923       plist[i++] = fontset->fallback;
924     }
925
926   if (layouter_name == Mnil)
927     layouter_name = Mt;
928   for (i--; i >= 0; i--)
929     {
930       if (how == -1)
931         mplist_push (plist[i], layouter_name, font);
932       else if (how == 1)
933         mplist_add (plist[i], layouter_name, font);
934       else
935         {
936           mplist_set (plist[i], Mnil, NULL);
937           mplist_add (plist[i], layouter_name, font);
938         }
939     }
940
941   fontset->tick++;
942   return 0;
943 }
944
945 /*=*/
946
947 /***en
948     @brief Lookup a fontset.
949
950     The mfontset_lookup () function lookups $FONTSET and returns a
951     plist that describes the contents of $FONTSET corresponding to the
952     specified script, language, and charset.
953
954     If $SCRIPT is @c Mt, keys of the returned plist are script name
955     symbols for which some fonts are specified and values are NULL.
956
957     If $SCIRPT is a script symbol, the returned plist is decided by
958     $LANGUAGE.
959
960     If $LANGUAGE is @c Mt, keys of the plist are language name symbols
961     for which some fonts are specified and values are NULL.  A key may
962     be @c Mt which means some fallback fonts are specified for the
963     script.
964
965     If $LANGUAGE is a language name symbol, the plist is a @c
966     FONT-GROUP for the specified script and langauge.
967
968     If $LANGAUGE is @c Mt, the plist is fallback @c FONT-GROUP for the
969     script.
970
971     If $SCRIPT is @c Mnil, the returned plist is decided as below.
972
973     If $CHARSET is @c Mt, keys of the returned plist are charset name
974     symbols for which some fonts are specified and values are NULL.
975
976     If $CHARSET is a charset symbol, the plist is a @c FONT-GROUP for
977     the charset.
978
979     If $CHARSET is @c Mnil, the plist is a fallback @c FONT-GROUP.
980
981     @c FONT-GROUP is a plist whose keys are FLT name symbols (@c Mt if
982     no FLT is associated with the font) and values are pointers to
983     #MFont.
984
985     @return
986     It returns a plist describing the contents of a fontset.  The
987     plist should be freed by m17n_object_unref ().  */
988
989 MPlist *
990 mfontset_lookup (MFontset *fontset,
991                  MSymbol script, MSymbol language, MSymbol charset)
992 {
993   MPlist *plist = mplist (), *pl, *p;
994
995   if (fontset->mdb)
996     load_fontset_contents (fontset);
997   if (script == Mt)
998     {
999       if (! fontset->per_script)
1000         return plist;
1001       p = plist;
1002       MPLIST_DO (pl, fontset->per_script)
1003         p = mplist_add (p, MPLIST_KEY (pl), NULL);
1004       return plist;
1005     }
1006   if (script != Mnil)
1007     {
1008       if (! fontset->per_script)
1009         return plist;
1010       pl = mplist_get (fontset->per_script, script);
1011       if (! pl)
1012         return plist;
1013       if (language == Mt)
1014         {
1015           p = plist;
1016           MPLIST_DO (pl, pl)
1017             p = mplist_add (p, MPLIST_KEY (pl), NULL);
1018           return plist;
1019         }
1020       if (language == Mnil)
1021         language = Mt;
1022       pl = mplist_get (pl, language);
1023     }
1024   else if (charset != Mnil)
1025     {
1026       if (! fontset->per_charset)
1027         return plist;
1028       if (charset == Mt)
1029         {
1030           p = plist;
1031           MPLIST_DO (pl, fontset->per_charset)
1032             p = mplist_add (p, MPLIST_KEY (pl), NULL);
1033           return plist;
1034         }
1035       pl = mplist_get (fontset->per_charset, charset);
1036     }
1037   else
1038     pl = fontset->fallback;
1039   if (! pl)
1040     return plist;
1041   return mplist_copy (pl);
1042 }
1043
1044
1045 /*** @} */
1046
1047 /*** @addtogroup m17nDebug */
1048 /*=*/
1049 /*** @{  */
1050
1051 /***en
1052     @brief Dump a fontset.
1053
1054     The mdebug_dump_fontset () function prints fontset $FONTSET in a human readable
1055     way to the stderr.  $INDENT specifies how many columns to indent
1056     the lines but the first one.
1057
1058     @return
1059     This function returns $FONTSET.  */
1060 /***ja
1061     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤ò¥À¥ó¥×¤¹¤ë.
1062
1063     ´Ø¿ô mdebug_dump_face () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤ò stderr ¤Ë¿Í
1064     ´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£ $INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ
1065     ¤ë¡£
1066
1067     @return
1068     ¤³¤Î´Ø¿ô¤Ï $FONTSET ¤òÊÖ¤¹¡£  */
1069
1070 MFontset *
1071 mdebug_dump_fontset (MFontset *fontset, int indent)
1072 {
1073   char *prefix = (char *) alloca (indent + 1);
1074   MPlist *plist, *pl, *p;
1075
1076   memset (prefix, 32, indent);
1077   prefix[indent] = 0;
1078
1079   fprintf (stderr, "(fontset %s", fontset->name->name);
1080   if (fontset->per_script)
1081     MPLIST_DO (plist, fontset->per_script)
1082       {
1083         fprintf (stderr, "\n  %s(%s", prefix, MPLIST_KEY (plist)->name);
1084         MPLIST_DO (pl, MPLIST_PLIST (plist))
1085           {
1086             fprintf (stderr, "\n    %s(%s", prefix, MPLIST_KEY (pl)->name);
1087             MPLIST_DO (p, MPLIST_PLIST (pl))
1088               {
1089                 fprintf (stderr, "\n      %s(%s ", prefix,
1090                          MPLIST_KEY (p)->name);
1091                 mdebug_dump_font (MPLIST_VAL (p));
1092                 fprintf (stderr, ")");
1093               }
1094             fprintf (stderr, ")");
1095           }
1096         fprintf (stderr, ")");
1097       }
1098   if (fontset->per_charset)
1099     MPLIST_DO (pl, fontset->per_charset)
1100       {
1101         fprintf (stderr, "\n  %s(%s", prefix, MPLIST_KEY (pl)->name);
1102         MPLIST_DO (p, MPLIST_PLIST (pl))
1103           {
1104             fprintf (stderr, "\n    %s(%s ", prefix, MPLIST_KEY (p)->name);
1105             mdebug_dump_font (MPLIST_VAL (p));
1106             fprintf (stderr, ")");
1107           }
1108         fprintf (stderr, ")");
1109       }
1110
1111   if (fontset->fallback)
1112     MPLIST_DO (p, fontset->fallback)
1113       {
1114         fprintf (stderr, "\n  %s(%s ", prefix, MPLIST_KEY (p)->name);
1115         mdebug_dump_font (MPLIST_VAL (p));
1116         fprintf (stderr, ")");
1117       }
1118
1119   fprintf (stderr, ")");
1120   return fontset;
1121 }
1122
1123 /*** @} */
1124
1125 /*
1126   Local Variables:
1127   coding: euc-japan
1128   End:
1129 */