Change /***ja to /***oldja
[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     - The script character property of a character.
32     - The language text property of a character.
33     - The charset text property of a character.
34
35     The documentation of mdraw_text () describes how that information is
36     used.  */
37
38 /***oldja
39     @addtogroup m17nFontset
40     @brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ï°ìÄê¤Î¥¹¥¿¥¤¥ë¤ò¶¦Í­¤¹¤ë¥Õ¥©¥ó¥È¤Î½¸¹ç¤Ç¤¢¤ë
41
42     @e ¥Õ¥©¥ó¥È¥»¥Ã¥È ¤Ï @c MFontset ·¿¤Î¥ª¥Ö¥¸¥§¥¯¥È¤Ç¤¢¤ê¡¢Â¿¸À¸ìʸ
43     ½ñ¤Îɽ¼¨¤ÎºÝ¡¢¸«¤«¤±¤Î»÷¤¿¥Õ¥©¥ó¥È¤ò½¸¤á¤Æ°ì´Ó¤·¤Æ¼è¤ê°·¤¦¤¿¤á¤Ë»È
44     ¤ï¤ì¤ë¡£¥Õ¥©¥ó¥È¥»¥Ã¥È¤Ï¤Þ¤¿¡¢¸À¸ì¡¢Ê¸»ú¥»¥Ã¥È¡¢Ê¸»ú¤¬Í¿¤¨¤é¤ì¤¿¤È
45     ¤­¤ËŬÀڤʥե©¥ó¥È¤òÁªÂò¤¹¤ë¤¿¤á¤Î¾ðÊó¤âÊÝ»ý¤·¤Æ¤¤¤ë¡£  */
46
47 /*=*/
48
49 #if !defined (FOR_DOXYGEN) || defined (DOXYGEN_INTERNAL_MODULE)
50 /*** @addtogroup m17nInternal
51      @{ */
52
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <ctype.h>
57
58 #include "m17n-gui.h"
59 #include "m17n-misc.h"
60 #include "internal.h"
61 #include "symbol.h"
62 #include "plist.h"
63 #include "character.h"
64 #include "charset.h"
65 #include "internal-gui.h"
66 #include "font.h"
67 #include "fontset.h"
68
69 struct MFontset
70 {
71   M17NObject control;
72
73   /* Name of the fontset.  */
74   MSymbol name;
75
76   /* Initialized to 0, and incremented by one each time the fontset is
77      modified.  */
78   unsigned tick;
79
80   /* Database from which to load the contents of the fontset.  Once
81      loaded, this member is set to NULL.  */
82   MDatabase *mdb;
83
84   /* SCRIPT vs PER-LANGUAGE (which is a plist LANGUAGE vs FONT-GROUP) */
85   MPlist *per_script;
86
87   /* CHARSET vs FONT-GROUP */
88   MPlist *per_charset;
89
90   /* FONT-GROUP */
91   MPlist *fallback;
92
93   /* Plist of Mt vs font specs. */
94   MPlist *font_spec_list;
95 };
96
97 static MFontset *default_fontset;
98
99 static MPlist *fontset_list;
100
101 struct MRealizedFontset
102 {
103   /* Fontset from which the realized fontset is realized.  */
104   MFontset *fontset;
105
106   /* Initialized to <fontset>->tick.  */
107   unsigned tick;
108
109   /* Font spec extracted from a face.  */
110   MFont spec;
111
112   /* The frame on which the realized fontset is realized.  */
113   MFrame *frame;
114
115   MPlist *per_script;
116
117   MPlist *per_charset;
118
119   MPlist *fallback;
120 };
121
122
123 static MPlist *
124 load_font_group (MPlist *plist, MPlist *elt, MPlist *spec_list)
125 {
126   MPLIST_DO (elt, elt)
127     {
128       /* ELT ::= ( FONT-SPEC-LIST [ LAYOUTER ] ) ...  */
129       MPlist *elt2, *p;
130       MFont font, *spec = NULL;
131       MSymbol layouter_name;
132
133       if (! MPLIST_PLIST_P (elt))
134         MWARNING (MERROR_FONTSET);
135       elt2 = MPLIST_PLIST (elt);
136       if (! MPLIST_PLIST_P (elt2))
137         MWARNING (MERROR_FONTSET);
138       mfont__set_spec_from_plist (&font, MPLIST_PLIST (elt2));
139       MPLIST_DO (p, spec_list)
140         {
141           if (! memcmp (MPLIST_VAL (p), &font, sizeof (MFont)))
142             {
143               spec = MPLIST_VAL (p);
144               break;
145             }
146         }
147       if (! spec)
148         {
149           MSTRUCT_MALLOC (spec, MERROR_FONTSET);
150           *spec = font;
151           mplist_add (spec_list, Mt, spec);
152         }
153       elt2 = MPLIST_NEXT (elt2);
154       layouter_name = Mt;
155       if (MPLIST_SYMBOL_P (elt2))
156         layouter_name = MPLIST_SYMBOL (elt2);
157       if (layouter_name == Mnil)
158         layouter_name = Mt;
159       plist = mplist_add (plist, layouter_name, spec);
160       continue;
161     warning:
162       /* ANSI-C requires some statement after a label.  */
163       continue;
164     }
165   return plist;
166 }
167
168 /* Load FONTSET->per_script from the data in FONTSET->mdb.  */
169
170 static void
171 load_fontset_contents (MFontset *fontset)
172 {
173   MPlist *per_script, *per_charset, *fallback, *spec_list, *font_group;
174   MSymbol script, lang;
175   MPlist *fontset_def, *plist;
176
177   fontset->per_script = per_script = mplist ();
178   fontset->per_charset = per_charset = mplist ();
179   fontset->fallback = fallback = mplist ();
180   fontset->font_spec_list = spec_list = mplist ();
181   if (! (fontset_def = (MPlist *) mdatabase_load (fontset->mdb)))
182     return;
183
184   MPLIST_DO (plist, fontset_def)
185     {
186       /* PLIST ::= ( SCRIPT ( LANGUAGE FONT-SPEC-ELT ... ) ... )
187                    | (CHARSET FONT-SPEC-ELT ...)
188                    | FONT-SPEC-ELT  */
189       MPlist *elt;
190
191       if (! MPLIST_PLIST_P (plist))
192         MWARNING (MERROR_FONTSET);
193       elt = MPLIST_PLIST (plist);
194       if (! MPLIST_SYMBOL_P (elt))
195         MWARNING (MERROR_FONTSET);
196       script = MPLIST_SYMBOL (elt);
197       elt = MPLIST_NEXT (elt);
198       if (! MPLIST_PLIST_P (elt))
199         MWARNING (MERROR_FONTSET);
200       if (script == Mnil)
201         fallback = load_font_group (fallback, elt, spec_list);
202       else if (MPLIST_PLIST_P (MPLIST_PLIST (elt)))
203         {
204           font_group = mplist_find_by_key (fontset->per_charset, script);
205           if (! font_group)
206             {
207               font_group = mplist ();
208               per_charset = mplist_add (per_charset, script, font_group);
209             }
210           load_font_group (font_group, elt, spec_list);
211         }
212       else
213         {
214           MPlist *per_lang = mplist_find_by_key (fontset->per_script, script);
215
216           if (! per_lang)
217             {
218               per_lang = mplist ();
219               per_script = mplist_add (per_script, script, per_lang);
220             }
221
222           MPLIST_DO (elt, elt)
223             {
224               /* ELT ::= ( LANGUAGE FONT-DEF ...) ... */
225               MPlist *elt2;
226
227               if (! MPLIST_PLIST_P (elt))
228                 MWARNING (MERROR_FONTSET);
229               elt2 = MPLIST_PLIST (elt);
230               if (! MPLIST_SYMBOL_P (elt2))
231                 MWARNING (MERROR_FONTSET);
232               lang = MPLIST_SYMBOL (elt2);
233               if (lang == Mnil)
234                 lang = Mt;
235               font_group = mplist_find_by_key (per_lang, lang);
236               if (! font_group)
237                 {
238                   font_group = mplist ();
239                   mplist_add (per_lang, lang, font_group);
240                 }
241               elt2 = MPLIST_NEXT (elt2);
242               load_font_group (font_group, elt2, spec_list);
243             }
244         }
245       continue;
246
247     warning:
248       /* ANSI-C requires some statement after a label.  */
249       continue;
250     }
251
252   M17N_OBJECT_UNREF (fontset_def);
253   fontset->mdb = NULL;
254 }
255
256 static void
257 free_fontset (void *object)
258 {
259   MFontset *fontset = (MFontset *) object;
260   MPlist *plist, *pl, *p;
261
262   if (fontset->per_script)
263     {
264       MPLIST_DO (plist, fontset->per_script)
265         {
266           MPLIST_DO (pl, MPLIST_PLIST (plist))
267             {
268               p = MPLIST_PLIST (pl);
269               M17N_OBJECT_UNREF (p);
270             }
271           pl = MPLIST_PLIST (plist);
272           M17N_OBJECT_UNREF (pl);
273         }
274       M17N_OBJECT_UNREF (fontset->per_script);
275     }
276   if (fontset->per_charset)
277     {
278       MPLIST_DO (plist, fontset->per_charset)
279         {
280           pl = MPLIST_PLIST (plist);
281           M17N_OBJECT_UNREF (pl);
282         }
283       M17N_OBJECT_UNREF (fontset->per_charset);
284     }
285   if (fontset->fallback)
286     M17N_OBJECT_UNREF (fontset->fallback);
287   plist = mplist_find_by_key (fontset_list, fontset->name);
288   if (! plist)
289     mdebug_hook ();
290   mplist_pop (plist);
291   if (fontset->font_spec_list)
292     {
293       if (((M17NObject *) (fontset->font_spec_list))->ref_count == 1)
294         MPLIST_DO (plist, fontset->font_spec_list)
295           free (MPLIST_VAL (plist));
296       M17N_OBJECT_UNREF (fontset->font_spec_list);
297     }
298   free (object);
299 }
300
301 static void
302 realize_font_group (MFrame *frame, MFont *request, MPlist *font_group,
303                     int size)
304 {
305   MPlist *plist = MPLIST_VAL (font_group), *pl, *p;
306
307   mplist_set (font_group, Mnil, NULL);
308   MPLIST_DO (pl, plist)
309     {
310       MSymbol layouter = MPLIST_KEY (pl);
311       MFont this_request = *request;
312       MRealizedFont *rfont;
313
314       mfont__resize (MPLIST_VAL (pl), &this_request);
315       rfont = mfont__select (frame, MPLIST_VAL (pl), &this_request,
316                              size, layouter == Mt ? Mnil : layouter);
317
318       if (rfont)
319         {
320           MPLIST_DO (p, font_group)
321             if (((MRealizedFont *) (MPLIST_VAL (p)))->score > rfont->score)
322               break;
323           mplist_push (p, Mt, rfont);
324         }
325     }
326 }
327
328 \f
329
330 /* Internal API */
331
332 int
333 mfont__fontset_init ()
334 {
335   Mfontset = msymbol ("fontset");
336   Mfontset->managing_key = 1;
337   fontset_list = mplist ();
338   default_fontset = mfontset ("default");
339   if (! default_fontset->mdb)
340     {
341       MFont font;
342
343       MFONT_INIT (&font);
344       mfont_put_prop (&font, Mregistry, msymbol ("iso8859-1"));
345       mfontset_modify_entry (default_fontset, Mnil, Mnil, Mnil,
346                              &font, Mnil, 1);
347       mfont_put_prop (&font, Mregistry, msymbol ("iso10646-1"));
348       mfontset_modify_entry (default_fontset, Mnil, Mnil, Mnil,
349                              &font, Mnil, 1);
350     }
351   return 0;
352 }
353
354
355 void
356 mfont__fontset_fini ()
357 {
358   while (! MPLIST_TAIL_P (fontset_list))
359     free_fontset ((MFontset *) MPLIST_VAL (fontset_list));
360   M17N_OBJECT_UNREF (fontset_list);
361   fontset_list = NULL;
362 }
363
364
365 MRealizedFontset *
366 mfont__realize_fontset (MFrame *frame, MFontset *fontset, MFace *face)
367 {
368   MRealizedFontset *realized;
369   MFont request;
370   MPlist *per_script, *per_lang, *per_charset, *font_group;
371   MPlist *plist, *pl, *p;
372
373   if (fontset->mdb)
374     load_fontset_contents (fontset);
375
376   mfont__set_spec_from_face (&request, face);
377   if (request.property[MFONT_SIZE] <= 0)
378     {
379       mdebug_hook ();
380       request.property[MFONT_SIZE] = 120;
381     }
382   MPLIST_DO (p, frame->realized_fontset_list)
383     {
384       realized = (MRealizedFontset *) MPLIST_VAL (p);
385       if (fontset->name == MPLIST_KEY (p)
386           && ! memcmp (&request, &realized->spec, sizeof (request)))
387         return realized;
388     }
389
390   MSTRUCT_MALLOC (realized, MERROR_FONTSET);
391   realized->fontset = fontset;
392   realized->tick = fontset->tick;
393   realized->spec = request;
394   realized->frame = frame;
395   realized->per_script = per_script = mplist ();
396   MPLIST_DO (plist, fontset->per_script)
397     {
398       per_lang = mplist ();
399       per_script = mplist_add (per_script, MPLIST_KEY (plist), per_lang);
400       MPLIST_DO (pl, MPLIST_PLIST (plist))
401         {
402           font_group = mplist ();
403           mplist_add (font_group, Mplist, MPLIST_VAL (pl));
404           per_lang = mplist_add (per_lang, MPLIST_KEY (pl), font_group);
405         }
406     }
407
408   realized->per_charset = per_charset = mplist ();
409   MPLIST_DO (plist, fontset->per_charset)
410     {
411       font_group = mplist ();
412       mplist_add (font_group, Mplist, MPLIST_VAL (plist));
413       per_charset = mplist_add (per_charset, MPLIST_KEY (plist), font_group);
414     }
415
416   realized->fallback = mplist ();
417   mplist_add (realized->fallback, Mplist, fontset->fallback);
418
419   mplist_add (frame->realized_fontset_list, fontset->name, realized);
420   return realized;
421 }
422
423
424 void
425 mfont__free_realized_fontset (MRealizedFontset *realized)
426 {
427   MPlist *plist, *pl, *p;
428   MRealizedFont *rfont;
429
430   if (realized->per_script)
431     {
432       MPLIST_DO (plist, realized->per_script)
433         {
434           MPLIST_DO (pl, MPLIST_PLIST (plist))
435             {
436               MPLIST_DO (p, MPLIST_PLIST (pl))
437                 if ((rfont = MPLIST_VAL (p)) && ! rfont->frame)
438                   free (rfont);
439               p = MPLIST_PLIST (pl);
440               M17N_OBJECT_UNREF (p);
441             }
442           pl = MPLIST_PLIST (plist);
443           M17N_OBJECT_UNREF (pl);
444         }
445       M17N_OBJECT_UNREF (realized->per_script);
446     }
447   if (realized->per_charset)
448     {
449       MPLIST_DO (plist, realized->per_charset)
450         {
451           MPLIST_DO (pl, MPLIST_PLIST (plist))
452             if ((rfont = MPLIST_VAL (pl)) && ! rfont->frame)
453               free (rfont);
454           pl = MPLIST_PLIST (plist);
455           M17N_OBJECT_UNREF (pl);
456         }
457       M17N_OBJECT_UNREF (realized->per_charset);
458     }
459   if (realized->fallback)
460     {
461       MPLIST_DO (plist, realized->fallback)
462         if ((rfont = MPLIST_VAL (plist)) && ! rfont->frame)
463           free (rfont);
464       M17N_OBJECT_UNREF (realized->fallback);
465     }
466
467   free (realized);
468 }
469
470
471 MRealizedFont *
472 mfont__lookup_fontset (MRealizedFontset *realized, MGlyph *g, int *num,
473                        MSymbol script, MSymbol language, MSymbol charset,
474                        int size)
475 {
476   MFrame *frame = realized->frame;
477   MCharset *preferred_charset = (charset == Mnil ? NULL : MCHARSET (charset));
478   MPlist *per_charset, *per_script, *per_lang, *font_group;
479   MPlist *font_groups[256], *plist;
480   int n_font_group = 0;
481   MRealizedFont *first = NULL, *rfont;
482   int first_len;
483   int i;
484
485   if (preferred_charset
486       && (per_charset = mplist_get (realized->per_charset, charset)) != NULL)
487     font_groups[n_font_group++] = per_charset;
488   if (script != Mnil
489       && ((per_script = mplist_find_by_key (realized->per_script, script))
490           != NULL))
491     {
492       /* The first loop is for matching language (if any), and the second
493          loop is for non-matching languages.  */
494       if (language == Mnil)
495         language = Mt;
496       for (i = 0; i < 2; i++)
497         {
498           MPLIST_DO (per_lang, MPLIST_PLIST (per_script))
499             if ((MPLIST_KEY (per_lang) == language) != i)
500               font_groups[n_font_group++] = MPLIST_PLIST (per_lang);
501         }
502     }
503   font_groups[n_font_group++] = realized->fallback;
504
505   if (n_font_group == 1)
506     {
507       /* As we only have a fallback font group, try all the other
508          fonts too.  */
509       MPLIST_DO (per_script, realized->per_script)
510         MPLIST_DO (per_lang, MPLIST_PLIST (per_script))
511           font_groups[n_font_group++] = MPLIST_PLIST (per_lang);
512       MPLIST_DO (per_charset, realized->per_charset)
513         font_groups[n_font_group++] = MPLIST_PLIST (per_charset);
514     }
515
516   for (i = 0; i < n_font_group; i++)
517     {
518       int j;
519       
520       if (MPLIST_PLIST_P (font_groups[i]))
521         realize_font_group (frame, &realized->spec, font_groups[i], size);
522
523       MPLIST_DO (plist, font_groups[i])
524         {
525           rfont = (MRealizedFont *) MPLIST_VAL (plist);
526           g->code = mfont__encode_char (rfont, g->c);
527           if (g->code != MCHAR_INVALID_CODE)
528             break;
529         }
530       if (MPLIST_TAIL_P (plist))
531         continue;
532       for (j = 1; j < *num; j++)
533         {
534           g[j].code = mfont__encode_char (rfont, g[j].c);
535           if (g[j].code == MCHAR_INVALID_CODE)
536             break;
537         }
538       if (! first)
539         first = rfont, first_len = j;
540       if (j == *num)
541         /* We found a font that can display all requested
542            characters.  */
543         break;
544
545       MPLIST_DO (plist, MPLIST_NEXT (plist))
546         {
547           rfont = (MRealizedFont *) MPLIST_VAL (plist);
548           for (j = 0; j < *num; j++)
549             {
550               g[j].code = mfont__encode_char (rfont, g[j].c);
551               if (g[j].code == MCHAR_INVALID_CODE)
552                 break;
553             }
554           if (j == *num)
555             break;
556         }
557       if (! MPLIST_TAIL_P (plist))
558         break;
559     }
560
561   if (i == n_font_group) 
562     {
563       if (! first)
564         return NULL;
565       rfont = first, *num = first_len;
566       for (i = 0; i < *num; i++)
567         g[i].code = mfont__encode_char (rfont, g[i].c);
568     }
569   if (! rfont->status
570       && mfont__open (rfont) < 0)
571     {
572       MPLIST_VAL (font_group) = NULL;
573       return NULL;
574     }
575   return rfont;
576 }
577
578 /*** @} */
579 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
580
581 \f
582 /* External API */
583
584 /*** @addtogroup m17nFontset */
585 /*** @{ */
586
587 /*=*/
588 /***en
589     @brief Return a fontset.
590
591     The mfontset () function returns a pointer to a fontset object of
592     name $NAME.  If $NAME is @c NULL, it returns a pointer to the
593     default fontset.
594
595     If no fontset has the name $NAME, a new one is created.  At that
596     time, if there exists a data \<@c fontset, $NAME\> in the m17n
597     database, the fontset contents are initialized according to the
598     data.  If no such data exists, the fontset contents are left
599     vacant.
600
601     The macro M17N_INIT () creates the default fontset.  An
602     application program can modify it before the first call of mframe
603     ().
604
605     @return
606     This function returns a pointer to the found or newly created
607     fontset.  */
608
609 MFontset *
610 mfontset (char *name)
611 {
612   MSymbol sym;
613   MFontset *fontset;
614
615   if (! name)
616     return default_fontset;
617   sym = msymbol (name);
618   fontset = mplist_get (fontset_list, sym);
619   if (fontset)
620     return fontset;
621   M17N_OBJECT (fontset, free_fontset, MERROR_FONTSET);
622   fontset->name = sym;
623   fontset->mdb = mdatabase_find (Mfontset, sym, Mnil, Mnil);
624   if (! fontset->mdb)
625     {
626       fontset->per_script = mplist ();
627       fontset->per_charset = mplist ();
628       fontset->fallback = mplist ();
629     }
630   mplist_put (fontset_list, sym, fontset);
631   M17N_OBJECT_REF (fontset);
632   return fontset;
633 }
634
635 /*=*/
636
637 /***en
638     @brief Return the name of a fontset
639
640     The mfontset_name () function returns the name of $FONTSET.  */
641 MSymbol
642 mfontset_name (MFontset *fontset)
643 {
644   return fontset->name;
645 }
646
647 /*=*/
648
649 /***en
650     @brief Make a copy a fontset
651
652     The mfontset_copy () function makes a copy of $FONTSET, gives it a
653     name $NAME, and returns a pointer to the created copy.  $NAME must
654     not be a name of existing fontset.  Otherwise, this function
655     returns NULL without making a copy.  */
656
657 MFontset *
658 mfontset_copy (MFontset *fontset, char *name)
659 {
660   MSymbol sym = msymbol (name);
661   MFontset *copy = mplist_get (fontset_list, sym);
662   MPlist *plist, *pl;
663
664   if (copy)
665     return NULL;
666   M17N_OBJECT (copy, free_fontset, MERROR_FONTSET);
667   copy->name = sym;
668
669   if (fontset->per_script)
670     {
671       copy->per_script = mplist ();
672       MPLIST_DO (plist, fontset->per_script)
673         {
674           MPlist *new = mplist ();
675
676           MPLIST_DO (pl, MPLIST_PLIST (plist))
677             mplist_add (new, MPLIST_KEY (pl), mplist_copy (MPLIST_PLIST (pl)));
678           mplist_add (copy->per_script, MPLIST_KEY (plist), new);
679         }
680     }
681   if (fontset->per_charset)
682     {
683       copy->per_charset = mplist ();
684       MPLIST_DO (plist, fontset->per_charset)
685         mplist_add (copy->per_charset, MPLIST_KEY (plist),
686                     mplist_copy (MPLIST_PLIST (plist)));
687     }
688   if (fontset->fallback)
689     copy->fallback = mplist_copy (fontset->fallback);
690
691   copy->font_spec_list = fontset->font_spec_list;
692   M17N_OBJECT_REF (copy->font_spec_list);
693
694   mplist_put (fontset_list, sym, copy);
695   M17N_OBJECT_REF (copy);
696   return copy;
697 }
698
699 /*=*/
700
701 /***en
702     @brief Modify the contents of a fontset.
703
704     The mfontset_modify_entry () function associates, in $FONTSET, a
705     copy of $FONT with the $SCRIPT / $LANGUAGE pair or with $CHARSET.
706
707     Each font in a fontset is associated with a particular
708     script/language pair, with a particular charset, or with the
709     symbol @c Mnil.  The fonts that are associated with the same item
710     make a group.
711
712     If $SCRIPT is not @c Mnil, it must be a symbol identifying a
713     script.  In this case, $LANGUAGE is either a symbol identifying a
714     language or @c Mnil, and $FONT is associated with the $SCRIPT /
715     $LANGUAGE pair.
716
717     If $CHARSET is not @c Mnil, it must be a symbol representing a
718     charset object.  In this case, $FONT is associated with that
719     charset.
720
721     If both $SCRIPT and $CHARSET are not @c Mnil, two copies of $FONT
722     are created.  Then one is associated with the script/language pair
723     and the other with the charset.
724
725     If both $SCRIPT and $CHARSET are @c Mnil, $FONT is associated
726     with @c Mnil.  This kind of fonts are called <i>fallback
727     fonts</i>.
728
729     The argument $HOW specifies the priority of $FONT.  If $HOW is
730     positive, $FONT has the highest priority in the group of fonts
731     that are associated with the same item.  If $HOW is negative,
732     $FONT has the lowest priority.  If $HOW is zero, $FONT becomes the
733     only available font for the associated item; all the other fonts
734     are removed from the group.
735
736     If $LAYOUTER_NAME is not @c Mnil, it must be a symbol
737     representing a @ref flt.  In that case, if $FONT is selected for
738     drawing an M-text, that font layout table is used to generate a
739     glyph code sequence from a character sequence.
740
741     @return
742     If the operation was successful, mfontset_modify_entry () returns 0.
743     Otherwise it returns -1 and assigns an error code to the external
744     variable @c merror_code.  */
745
746 /***oldja
747     @brief ¸À¸ì¤È¥¹¥¯¥ê¥×¥È¤ÎÁȤ߹ç¤ï¤»¤Ë¥Õ¥©¥ó¥È¤ò´ØÏ¢ÉÕ¤±¤ë
748
749     ´Ø¿ô mfontset_set_language_script () ¤Ï¡¢$LANGUAGE ¤È $SCRIPT ¤ÎÁÈ
750     ¤ß¹ç¤ï¤»¤ËÂФ·¤Æ¥Õ¥©¥ó¥È $FONT ¤ò»È¤¦¤è¤¦¡¢¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET 
751     ¤òÀßÄꤹ¤ë¡£$LANGUAGE ¤È $SCRIPT ¤Ï¡¢¤½¤ì¤¾¤ì¸À¸ì¤È¥¹¥¯¥ê¥×¥È¤ò»Ø
752     Äꤹ¤ë¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
753
754     ¸À¸ì¤È¥¹¥¯¥ê¥×¥È¤ÎÁȤ߹ç¤ï¤»°ì¤Ä¤ËÂФ·¤ÆÊ£¿ô¤Î¥Õ¥©¥ó¥È¤òÀßÄꤹ¤ë¤³
755     ¤È¤â¤Ç¤­¤ë¡£$PREPEND_P ¤¬ 0 °Ê³°¤Ê¤é¤Ð¡¢$FONT ¤Ï¤½¤ÎÁȤ߹ç¤ï¤»¤ËÂÐ
756     ¤·¤ÆºÇÍ¥Àè¤ÇÍѤ¤¤é¤ì¤ë¤â¤Î¤È¤Ê¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢Í¥ÀèÅÙºÇÄã¤Î¥Õ¥©
757     ¥ó¥È¤È¤·¤ÆÅÐÏ¿¤µ¤ì¤ë¡£
758
759     @return
760     ½èÍý¤¬À®¸ù¤·¤¿¤È¤­¡¢mfontset_set_language_script () ¤Ï 0 ¤òÊÖ¤¹¡£
761     ¼ºÇÔ¤·¤¿¤È¤­¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô @c merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤ò
762     ÀßÄꤹ¤ë¡£  */
763
764 /***
765     @errors
766     @c MERROR_SYMBOL  */
767
768 int
769 mfontset_modify_entry (MFontset *fontset,
770                        MSymbol script, MSymbol language, MSymbol charset,
771                        MFont *spec, MSymbol layouter_name,
772                        int how)
773 {
774   MPlist *per_lang, *plist[3], *pl;
775   MFont *font = NULL;
776   int i;
777
778   if (fontset->mdb)
779     load_fontset_contents (fontset);
780
781   MPLIST_DO (pl, fontset->font_spec_list)
782     {
783       if (! memcmp (MPLIST_VAL (pl), spec, sizeof (MFont)))
784         {
785           font = MPLIST_VAL (pl);
786           break;
787         }
788     }
789   if (! font)
790     {
791       font = mfont ();
792       *font = *spec;
793       mplist_add (fontset->font_spec_list, Mt, font);
794     }
795
796   i = 0;
797   if (script != Mnil)
798     {
799       if (language == Mnil)
800         language = Mt;
801       per_lang = mplist_get (fontset->per_script, script);
802       if (! per_lang)
803         mplist_add (fontset->per_script, script, per_lang = mplist ());
804       plist[i] = mplist_get (per_lang, language);
805       if (! plist[i])
806         mplist_add (per_lang, language, plist[i] = mplist ());
807       i++;
808     }
809   if (charset != Mnil)
810     {
811       plist[i] = mplist_get (fontset->per_charset, charset);
812       if (! plist[i])
813         mplist_add (fontset->per_charset, charset, plist[i] = mplist ());
814       i++;
815     }
816   if (script == Mnil && charset == Mnil)
817     {
818       plist[i++] = fontset->fallback;
819     }
820
821   if (layouter_name == Mnil)
822     layouter_name = Mt;
823   for (i--; i >= 0; i--)
824     {
825       if (how == -1)
826         mplist_push (plist[i], layouter_name, font);
827       else if (how == 1)
828         mplist_add (plist[i], layouter_name, font);
829       else
830         {
831           mplist_set (plist[i], Mnil, NULL);
832           mplist_add (plist[i], layouter_name, font);
833         }
834     }
835
836   return 0;
837 }
838
839 /*** @} */
840
841 /*** @addtogroup m17nDebug */
842 /*=*/
843 /*** @{  */
844
845 /***en
846     @brief Dump a fontset
847
848     The mdebug_dump_fontset () function prints $FONTSET in a human readable
849     way to the stderr.  $INDENT specifies how many columns to indent
850     the lines but the first one.
851
852     @return
853     This function returns $FONTSET.  */
854
855 MFontset *
856 mdebug_dump_fontset (MFontset *fontset, int indent)
857 {
858   char *prefix = (char *) alloca (indent + 1);
859   MPlist *plist, *pl, *p;
860
861   memset (prefix, 32, indent);
862   prefix[indent] = 0;
863
864   fprintf (stderr, "(fontset %s", fontset->name->name);
865   if (fontset->per_script)
866     MPLIST_DO (plist, fontset->per_script)
867       {
868         fprintf (stderr, "\n  %s(%s", prefix, MPLIST_KEY (plist)->name);
869         MPLIST_DO (pl, MPLIST_PLIST (plist))
870           {
871             fprintf (stderr, "\n    %s(%s", prefix, MPLIST_KEY (pl)->name);
872             MPLIST_DO (p, MPLIST_PLIST (pl))
873               {
874                 fprintf (stderr, "\n      %s(%s ", prefix,
875                          MPLIST_KEY (p)->name);
876                 mdebug_dump_font (MPLIST_VAL (p));
877                 fprintf (stderr, ")");
878               }
879             fprintf (stderr, ")");
880           }
881         fprintf (stderr, ")");
882       }
883   if (fontset->per_charset)
884     MPLIST_DO (pl, fontset->per_charset)
885       {
886         fprintf (stderr, "\n  %s(%s", prefix, MPLIST_KEY (pl)->name);
887         MPLIST_DO (p, MPLIST_PLIST (pl))
888           {
889             fprintf (stderr, "\n    %s(%s ", prefix, MPLIST_KEY (p)->name);
890             mdebug_dump_font (MPLIST_VAL (p));
891             fprintf (stderr, ")");
892           }
893         fprintf (stderr, ")");
894       }
895
896   if (fontset->fallback)
897     MPLIST_DO (p, fontset->fallback)
898       {
899         fprintf (stderr, "\n  %s(%s ", prefix, MPLIST_KEY (p)->name);
900         mdebug_dump_font (MPLIST_VAL (p));
901         fprintf (stderr, ")");
902       }
903
904   fprintf (stderr, ")");
905   return fontset;
906 }
907
908 /*** @} */
909
910 /*
911   Local Variables:
912   coding: euc-japan
913   End:
914 */