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