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