*** 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     - 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 /***ja
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       MRealizedFont *rfont = mfont__select (frame, MPLIST_VAL (pl), request,
311                                             size);
312
313       if (rfont)
314         {
315           rfont->layouter = MPLIST_KEY (pl);
316           if (rfont->layouter == Mt)
317             rfont->layouter = Mnil;
318           MPLIST_DO (p, font_group)
319             if (((MRealizedFont *) (MPLIST_VAL (p)))->score > rfont->score)
320               break;
321           mplist_push (p, Mt, rfont);
322         }
323     }
324 }
325
326 int
327 check_fontset_element (MFrame *frame, MPlist *element, MGlyph *g, int size)
328 {
329   MRealizedFont *rfont = (MRealizedFont *) MPLIST_VAL (element);
330
331   if (! rfont)
332     /* We have already failed to select this font.  */
333     return 0;
334   if (! rfont->frame)
335     {
336       rfont = mfont__select (frame, &rfont->spec, &rfont->request, size);
337       free (MPLIST_VAL (element));
338       MPLIST_VAL (element) = rfont;
339       if (! rfont)
340         /* No font matches this spec.  */
341         return 0;
342     }
343
344   g->code = mfont__encode_char (rfont, g->c);
345   return (g->code != MCHAR_INVALID_CODE);
346 }
347
348 \f
349
350 /* Internal API */
351
352 int
353 mfont__fontset_init ()
354 {
355   Mfontset = msymbol ("fontset");
356   Mfontset->managing_key = 1;
357   fontset_list = mplist ();
358   default_fontset = mfontset ("default");
359   if (! default_fontset->mdb)
360     {
361       MFont font;
362
363       MFONT_INIT (&font);
364       mfont_put_prop (&font, Mregistry, msymbol ("iso8859-1"));
365       mfontset_modify_entry (default_fontset, Mnil, Mnil, Mnil,
366                              &font, Mnil, 1);
367       mfont_put_prop (&font, Mregistry, msymbol ("iso10646-1"));
368       mfontset_modify_entry (default_fontset, Mnil, Mnil, Mnil,
369                              &font, Mnil, 1);
370     }
371   return 0;
372 }
373
374
375 void
376 mfont__fontset_fini ()
377 {
378   while (! MPLIST_TAIL_P (fontset_list))
379     free_fontset ((MFontset *) MPLIST_VAL (fontset_list));
380   M17N_OBJECT_UNREF (fontset_list);
381   fontset_list = NULL;
382 }
383
384
385 MRealizedFontset *
386 mfont__realize_fontset (MFrame *frame, MFontset *fontset, MFace *face)
387 {
388   MRealizedFontset *realized;
389   MFont request;
390   MPlist *per_script, *per_lang, *per_charset, *font_group;
391   MPlist *plist, *pl, *p;
392
393   if (fontset->mdb)
394     load_fontset_contents (fontset);
395
396   mfont__set_spec_from_face (&request, face);
397   if (request.property[MFONT_SIZE] <= 0)
398     {
399       mdebug_hook ();
400       request.property[MFONT_SIZE] = 120;
401     }
402   MPLIST_DO (p, frame->realized_fontset_list)
403     {
404       realized = (MRealizedFontset *) MPLIST_VAL (p);
405       if (fontset->name == MPLIST_KEY (p)
406           && ! memcmp (&request, &realized->spec, sizeof (request)))
407         return realized;
408     }
409
410   MSTRUCT_MALLOC (realized, MERROR_FONTSET);
411   realized->fontset = fontset;
412   realized->tick = fontset->tick;
413   realized->spec = request;
414   realized->frame = frame;
415   realized->per_script = per_script = mplist ();
416   MPLIST_DO (plist, fontset->per_script)
417     {
418       per_lang = mplist ();
419       per_script = mplist_add (per_script, MPLIST_KEY (plist), per_lang);
420       MPLIST_DO (pl, MPLIST_PLIST (plist))
421         {
422           font_group = mplist ();
423           mplist_add (font_group, Mplist, MPLIST_VAL (pl));
424           per_lang = mplist_add (per_lang, MPLIST_KEY (pl), font_group);
425         }
426     }
427
428   realized->per_charset = per_charset = mplist ();
429   MPLIST_DO (plist, fontset->per_charset)
430     {
431       font_group = mplist ();
432       mplist_add (font_group, Mplist, MPLIST_VAL (plist));
433       per_charset = mplist_add (per_charset, MPLIST_KEY (plist), font_group);
434     }
435
436   realized->fallback = mplist ();
437   mplist_add (realized->fallback, Mplist, fontset->fallback);
438
439   mplist_add (frame->realized_fontset_list, fontset->name, realized);
440   return realized;
441 }
442
443
444 void
445 mfont__free_realized_fontset (MRealizedFontset *realized)
446 {
447   MPlist *plist, *pl, *p;
448   MRealizedFont *rfont;
449
450   if (realized->per_script)
451     {
452       MPLIST_DO (plist, realized->per_script)
453         {
454           MPLIST_DO (pl, MPLIST_PLIST (plist))
455             {
456               MPLIST_DO (p, MPLIST_PLIST (pl))
457                 if ((rfont = MPLIST_VAL (p)) && ! rfont->frame)
458                   free (rfont);
459               p = MPLIST_PLIST (pl);
460               M17N_OBJECT_UNREF (p);
461             }
462           pl = MPLIST_PLIST (plist);
463           M17N_OBJECT_UNREF (pl);
464         }
465       M17N_OBJECT_UNREF (realized->per_script);
466     }
467   if (realized->per_charset)
468     {
469       MPLIST_DO (plist, realized->per_charset)
470         {
471           MPLIST_DO (pl, MPLIST_PLIST (plist))
472             if ((rfont = MPLIST_VAL (pl)) && ! rfont->frame)
473               free (rfont);
474           pl = MPLIST_PLIST (plist);
475           M17N_OBJECT_UNREF (pl);
476         }
477       M17N_OBJECT_UNREF (realized->per_charset);
478     }
479   if (realized->fallback)
480     {
481       MPLIST_DO (plist, realized->fallback)
482         if ((rfont = MPLIST_VAL (plist)) && ! rfont->frame)
483           free (rfont);
484       M17N_OBJECT_UNREF (realized->fallback);
485     }
486
487   free (realized);
488 }
489
490
491 MRealizedFont *
492 mfont__lookup_fontset (MRealizedFontset *realized, MGlyph *g, int *num,
493                        MSymbol script, MSymbol language, MSymbol charset,
494                        int size)
495 {
496   MFrame *frame = realized->frame;
497   MCharset *preferred_charset = (charset == Mnil ? NULL : MCHARSET (charset));
498   MPlist *per_charset, *per_script, *per_lang, *font_group;
499   MPlist *font_groups[256], *plist;
500   int n_font_group = 0;
501   MRealizedFont *first = NULL, *rfont;
502   int first_len;
503   int i;
504
505   if (preferred_charset
506       && (per_charset = mplist_get (realized->per_charset, charset)) != NULL)
507     font_groups[n_font_group++] = per_charset;
508   if (script != Mnil
509       && ((per_script = mplist_find_by_key (realized->per_script, script))
510           != NULL))
511     {
512       /* The first loop is for matching language (if any), and the second
513          loop is for non-matching languages.  */
514       if (language == Mnil)
515         language = Mt;
516       for (i = 0; i < 2; i++)
517         {
518           MPLIST_DO (per_lang, MPLIST_PLIST (per_script))
519             if ((MPLIST_KEY (per_lang) == language) != i)
520               font_groups[n_font_group++] = MPLIST_PLIST (per_lang);
521         }
522     }
523   font_groups[n_font_group++] = realized->fallback;
524
525   if (n_font_group == 1)
526     {
527       /* As we only have a fallback font group, try all the other
528          fonts too.  */
529       MPLIST_DO (per_script, realized->per_script)
530         MPLIST_DO (per_lang, MPLIST_PLIST (per_script))
531           font_groups[n_font_group++] = MPLIST_PLIST (per_lang);
532       MPLIST_DO (per_charset, realized->per_charset)
533         font_groups[n_font_group++] = MPLIST_PLIST (per_charset);
534     }
535
536   for (i = 0; i < n_font_group; i++)
537     {
538       int j;
539       
540       if (MPLIST_PLIST_P (font_groups[i]))
541         realize_font_group (frame, &realized->spec, font_groups[i], size);
542
543       MPLIST_DO (plist, font_groups[i])
544         {
545           rfont = (MRealizedFont *) MPLIST_VAL (plist);
546           g->code = mfont__encode_char (rfont, g->c);
547           if (g->code != MCHAR_INVALID_CODE)
548             break;
549         }
550       if (MPLIST_TAIL_P (plist))
551         continue;
552       for (j = 1; j < *num; j++)
553         {
554           g[j].code = mfont__encode_char (rfont, g[j].c);
555           if (g[j].code == MCHAR_INVALID_CODE)
556             break;
557         }
558       if (! first)
559         first = rfont, first_len = j;
560       if (j == *num)
561         /* We found a font that can display all requested
562            characters.  */
563         break;
564
565       MPLIST_DO (plist, MPLIST_NEXT (plist))
566         {
567           rfont = (MRealizedFont *) MPLIST_VAL (plist);
568           for (j = 0; j < *num; j++)
569             {
570               g[j].code = mfont__encode_char (rfont, g[j].c);
571               if (g[j].code == MCHAR_INVALID_CODE)
572                 break;
573             }
574           if (j == *num)
575             break;
576         }
577       if (! MPLIST_TAIL_P (plist))
578         break;
579     }
580
581   if (i == n_font_group) 
582     {
583       if (! first)
584         return NULL;
585       rfont = first, *num = first_len;
586       for (i = 0; i < *num; i++)
587         g[i].code = mfont__encode_char (rfont, g[i].c);
588     }
589   if (! rfont->status
590       && mfont__open (rfont) < 0)
591     {
592       MPLIST_VAL (font_group) = NULL;
593       return NULL;
594     }
595   return rfont;
596 }
597
598 /*** @} */
599 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
600
601 \f
602 /* External API */
603
604 /*** @addtogroup m17nFontset */
605 /*** @{ */
606
607 /*=*/
608 /***en
609     @brief Return a fontset.
610
611     The mfontset () function returns a pointer to a fontset object of
612     name $NAME.  If $NAME is @c NULL, it returns a pointer to the
613     default fontset.
614
615     If no fontset has the name $NAME, a new one is created.  At that
616     time, if there exists a data \<@c fontset, $NAME\> in the m17n
617     database, the fontset contents are initialized according to the
618     data.  If no such data exists, the fontset contents are left
619     vacant.
620
621     The macro M17N_INIT () creates the default fontset.  An
622     application program can modify it before the first call of mframe
623     ().
624
625     @return
626     This function returns a pointer to the found or newly created
627     fontset.  */
628
629 MFontset *
630 mfontset (char *name)
631 {
632   MSymbol sym;
633   MFontset *fontset;
634
635   if (! name)
636     return default_fontset;
637   sym = msymbol (name);
638   fontset = mplist_get (fontset_list, sym);
639   if (fontset)
640     return fontset;
641   M17N_OBJECT (fontset, free_fontset, MERROR_FONTSET);
642   fontset->name = sym;
643   fontset->mdb = mdatabase_find (Mfontset, sym, Mnil, Mnil);
644   if (! fontset->mdb)
645     {
646       fontset->per_script = mplist ();
647       fontset->per_charset = mplist ();
648       fontset->fallback = mplist ();
649     }
650   mplist_put (fontset_list, sym, fontset);
651   M17N_OBJECT_REF (fontset);
652   return fontset;
653 }
654
655 /*=*/
656
657 /***en
658     @brief Return the name of a fontset
659
660     The mfontset_name () function returns the name of $FONTSET.  */
661 MSymbol
662 mfontset_name (MFontset *fontset)
663 {
664   return fontset->name;
665 }
666
667 /*=*/
668
669 /***en
670     @brief Make a copy a fontset
671
672     The mfontset_copy () function makes a copy of $FONTSET, gives it a
673     name $NAME, and returns a pointer to the created copy.  $NAME must
674     not be a name of existing fontset.  Otherwise, this function
675     returns NULL without making a copy.  */
676
677 MFontset *
678 mfontset_copy (MFontset *fontset, char *name)
679 {
680   MSymbol sym = msymbol (name);
681   MFontset *copy = mplist_get (fontset_list, sym);
682   MPlist *plist, *pl;
683
684   if (copy)
685     return NULL;
686   M17N_OBJECT (copy, free_fontset, MERROR_FONTSET);
687   copy->name = sym;
688
689   if (fontset->per_script)
690     {
691       copy->per_script = mplist ();
692       MPLIST_DO (plist, fontset->per_script)
693         {
694           MPlist *new = mplist ();
695
696           MPLIST_DO (pl, MPLIST_PLIST (plist))
697             mplist_add (new, MPLIST_KEY (pl), mplist_copy (MPLIST_PLIST (pl)));
698           mplist_add (copy->per_script, MPLIST_KEY (plist), new);
699         }
700     }
701   if (fontset->per_charset)
702     {
703       copy->per_charset = mplist ();
704       MPLIST_DO (plist, fontset->per_charset)
705         mplist_add (copy->per_charset, MPLIST_KEY (plist),
706                     mplist_copy (MPLIST_PLIST (plist)));
707     }
708   if (fontset->fallback)
709     copy->fallback = mplist_copy (fontset->fallback);
710
711   copy->font_spec_list = fontset->font_spec_list;
712   M17N_OBJECT_REF (copy->font_spec_list);
713
714   mplist_put (fontset_list, sym, copy);
715   M17N_OBJECT_REF (copy);
716   return copy;
717 }
718
719 /*=*/
720
721 /***en
722     @brief Modify the contents of a fontset.
723
724     The mfontset_modify_entry () function associates, in $FONTSET, a
725     copy of $FONT with the $SCRIPT / $LANGUAGE pair or with $CHARSET.
726
727     Each font in a fontset is associated with a particular
728     script/language pair, with a particular charset, or with the
729     symbol @c Mnil.  The fonts that are associated with the same item
730     make a group.
731
732     If $SCRIPT is not @c Mnil, it must be a symbol identifying a
733     script.  In this case, $LANGUAGE is either a symbol identifying a
734     language or @c Mnil, and $FONT is associated with the $SCRIPT /
735     $LANGUAGE pair.
736
737     If $CHARSET is not @c Mnil, it must be a symbol representing a
738     charset object.  In this case, $FONT is associated with that
739     charset.
740
741     If both $SCRIPT and $CHARSET are not @c Mnil, two copies of $FONT
742     are created.  Then one is associated with the script/language pair
743     and the other with the charset.
744
745     If both $SCRIPT and $CHARSET are @c Mnil, $FONT is associated
746     with @c Mnil.  This kind of fonts are called <i>fallback
747     fonts</i>.
748
749     The argument $HOW specifies the priority of $FONT.  If $HOW is
750     positive, $FONT has the highest priority in the group of fonts
751     that are associated with the same item.  If $HOW is negative,
752     $FONT has the lowest priority.  If $HOW is zero, $FONT becomes the
753     only available font for the associated item; all the other fonts
754     are removed from the group.
755
756     If $LAYOUTER_NAME is not @c Mnil, it must be a symbol
757     representing a @ref flt.  In that case, if $FONT is selected for
758     drawing an M-text, that font layout table is used to generate a
759     glyph code sequence from a character sequence.
760
761     @return
762     If the operation was successful, mfontset_modify_entry () returns 0.
763     Otherwise it returns -1 and assigns an error code to the external
764     variable @c merror_code.  */
765
766 /***ja
767     @brief ¸À¸ì¤È¥¹¥¯¥ê¥×¥È¤ÎÁȤ߹ç¤ï¤»¤Ë¥Õ¥©¥ó¥È¤ò´ØÏ¢ÉÕ¤±¤ë
768
769     ´Ø¿ô mfontset_set_language_script () ¤Ï¡¢$LANGUAGE ¤È $SCRIPT ¤ÎÁÈ
770     ¤ß¹ç¤ï¤»¤ËÂФ·¤Æ¥Õ¥©¥ó¥È $FONT ¤ò»È¤¦¤è¤¦¡¢¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET 
771     ¤òÀßÄꤹ¤ë¡£$LANGUAGE ¤È $SCRIPT ¤Ï¡¢¤½¤ì¤¾¤ì¸À¸ì¤È¥¹¥¯¥ê¥×¥È¤ò»Ø
772     Äꤹ¤ë¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£
773
774     ¸À¸ì¤È¥¹¥¯¥ê¥×¥È¤ÎÁȤ߹ç¤ï¤»°ì¤Ä¤ËÂФ·¤ÆÊ£¿ô¤Î¥Õ¥©¥ó¥È¤òÀßÄꤹ¤ë¤³
775     ¤È¤â¤Ç¤­¤ë¡£$PREPEND_P ¤¬ 0 °Ê³°¤Ê¤é¤Ð¡¢$FONT ¤Ï¤½¤ÎÁȤ߹ç¤ï¤»¤ËÂÐ
776     ¤·¤ÆºÇÍ¥Àè¤ÇÍѤ¤¤é¤ì¤ë¤â¤Î¤È¤Ê¤ë¡£¤½¤¦¤Ç¤Ê¤±¤ì¤Ð¡¢Í¥ÀèÅÙºÇÄã¤Î¥Õ¥©
777     ¥ó¥È¤È¤·¤ÆÅÐÏ¿¤µ¤ì¤ë¡£
778
779     @return
780     ½èÍý¤¬À®¸ù¤·¤¿¤È¤­¡¢mfontset_set_language_script () ¤Ï 0 ¤òÊÖ¤¹¡£
781     ¼ºÇÔ¤·¤¿¤È¤­¤Ï -1 ¤òÊÖ¤·¡¢³°ÉôÊÑ¿ô @c merror_code ¤Ë¥¨¥é¡¼¥³¡¼¥É¤ò
782     ÀßÄꤹ¤ë¡£  */
783
784 /***
785     @errors
786     @c MERROR_SYMBOL  */
787
788 int
789 mfontset_modify_entry (MFontset *fontset,
790                        MSymbol script, MSymbol language, MSymbol charset,
791                        MFont *spec, MSymbol layouter_name,
792                        int how)
793 {
794   MPlist *per_lang, *plist[3], *pl;
795   MFont *font = NULL;
796   int i;
797
798   if (fontset->mdb)
799     load_fontset_contents (fontset);
800
801   MPLIST_DO (pl, fontset->font_spec_list)
802     {
803       if (! memcmp (MPLIST_VAL (pl), spec, sizeof (MFont)))
804         {
805           font = MPLIST_VAL (pl);
806           break;
807         }
808     }
809   if (! font)
810     {
811       font = mfont ();
812       *font = *spec;
813       mplist_add (fontset->font_spec_list, Mt, font);
814     }
815
816   i = 0;
817   if (script != Mnil)
818     {
819       if (language == Mnil)
820         language = Mt;
821       per_lang = mplist_get (fontset->per_script, script);
822       if (! per_lang)
823         mplist_add (fontset->per_script, script, per_lang = mplist ());
824       plist[i] = mplist_get (per_lang, language);
825       if (! plist[i])
826         mplist_add (per_lang, language, plist[i] = mplist ());
827       i++;
828     }
829   if (charset != Mnil)
830     {
831       plist[i] = mplist_get (fontset->per_charset, charset);
832       if (! plist[i])
833         mplist_add (fontset->per_charset, charset, plist[i] = mplist ());
834       i++;
835     }
836   if (script == Mnil && charset == Mnil)
837     {
838       plist[i++] = fontset->fallback;
839     }
840
841   if (layouter_name == Mnil)
842     layouter_name = Mt;
843   for (i--; i >= 0; i--)
844     {
845       if (how == -1)
846         mplist_push (plist[i], layouter_name, font);
847       else if (how == 1)
848         mplist_add (plist[i], layouter_name, font);
849       else
850         {
851           mplist_set (plist[i], Mnil, NULL);
852           mplist_add (plist[i], layouter_name, font);
853         }
854     }
855
856   return 0;
857 }
858
859 /*** @} */
860
861 /*** @addtogroup m17nDebug */
862 /*=*/
863 /*** @{  */
864
865 /***en
866     @brief Dump a fontset
867
868     The mdebug_dump_fontset () function prints $FONTSET in a human readable
869     way to the stderr.  $INDENT specifies how many columns to indent
870     the lines but the first one.
871
872     @return
873     This function returns $FONTSET.  */
874
875 MFontset *
876 mdebug_dump_fontset (MFontset *fontset, int indent)
877 {
878   char *prefix = (char *) alloca (indent + 1);
879   MPlist *plist, *pl, *p;
880
881   memset (prefix, 32, indent);
882   prefix[indent] = 0;
883
884   fprintf (stderr, "(fontset %s", fontset->name->name);
885   if (fontset->per_script)
886     MPLIST_DO (plist, fontset->per_script)
887       {
888         fprintf (stderr, "\n  %s(%s", prefix, MPLIST_KEY (plist)->name);
889         MPLIST_DO (pl, MPLIST_PLIST (plist))
890           {
891             fprintf (stderr, "\n    %s(%s", prefix, MPLIST_KEY (pl)->name);
892             MPLIST_DO (p, MPLIST_PLIST (pl))
893               {
894                 fprintf (stderr, "\n      %s(%s ", prefix,
895                          MPLIST_KEY (p)->name);
896                 mdebug_dump_font (MPLIST_VAL (p));
897                 fprintf (stderr, ")");
898               }
899             fprintf (stderr, ")");
900           }
901         fprintf (stderr, ")");
902       }
903   if (fontset->per_charset)
904     MPLIST_DO (pl, fontset->per_charset)
905       {
906         fprintf (stderr, "\n  %s(%s", prefix, MPLIST_KEY (pl)->name);
907         MPLIST_DO (p, MPLIST_PLIST (pl))
908           {
909             fprintf (stderr, "\n    %s(%s ", prefix, MPLIST_KEY (p)->name);
910             mdebug_dump_font (MPLIST_VAL (p));
911             fprintf (stderr, ")");
912           }
913         fprintf (stderr, ")");
914       }
915
916   if (fontset->fallback)
917     MPLIST_DO (p, fontset->fallback)
918       {
919         fprintf (stderr, "\n  %s(%s ", prefix, MPLIST_KEY (p)->name);
920         mdebug_dump_font (MPLIST_VAL (p));
921         fprintf (stderr, ")");
922       }
923
924   fprintf (stderr, ")");
925   return fontset;
926 }
927
928 /*** @} */
929
930 /*
931   Local Variables:
932   coding: euc-japan
933   End:
934 */