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