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