#include <string.h>
#include <ctype.h>
+#include "config.h"
#include "m17n-gui.h"
#include "m17n-misc.h"
#include "internal.h"
}
}
+static void
+realize_fontset_elements (MFrame *frame, MRealizedFontset *realized,
+ MFontset *fontset, MFont *request)
+{
+ MPlist *per_script, *per_lang, *per_charset, *font_group;
+ MPlist *plist, *pl;
+
+ realized->fontset = fontset;
+ realized->tick = fontset->tick;
+ realized->spec = *request;
+ realized->frame = frame;
+ realized->per_script = per_script = mplist ();
+ MPLIST_DO (plist, fontset->per_script)
+ {
+ per_lang = mplist ();
+ per_script = mplist_add (per_script, MPLIST_KEY (plist), per_lang);
+ MPLIST_DO (pl, MPLIST_PLIST (plist))
+ {
+ font_group = mplist ();
+ mplist_add (font_group, Mplist, MPLIST_VAL (pl));
+ per_lang = mplist_add (per_lang, MPLIST_KEY (pl), font_group);
+ }
+ }
+
+ realized->per_charset = per_charset = mplist ();
+ MPLIST_DO (plist, fontset->per_charset)
+ {
+ font_group = mplist ();
+ mplist_add (font_group, Mplist, MPLIST_VAL (plist));
+ per_charset = mplist_add (per_charset, MPLIST_KEY (plist), font_group);
+ }
+
+ realized->fallback = mplist ();
+ mplist_add (realized->fallback, Mplist, fontset->fallback);
+
+}
+
+static void
+free_realized_fontset_elements (MRealizedFontset *realized)
+{
+ MPlist *plist, *pl, *p;
+ MRealizedFont *rfont;
+
+ if (realized->per_script)
+ {
+ MPLIST_DO (plist, realized->per_script)
+ {
+ MPLIST_DO (pl, MPLIST_PLIST (plist))
+ {
+ MPLIST_DO (p, MPLIST_PLIST (pl))
+ if ((rfont = MPLIST_VAL (p)) && ! rfont->frame)
+ free (rfont);
+ p = MPLIST_PLIST (pl);
+ M17N_OBJECT_UNREF (p);
+ }
+ pl = MPLIST_PLIST (plist);
+ M17N_OBJECT_UNREF (pl);
+ }
+ M17N_OBJECT_UNREF (realized->per_script);
+ }
+ if (realized->per_charset)
+ {
+ MPLIST_DO (plist, realized->per_charset)
+ {
+ MPLIST_DO (pl, MPLIST_PLIST (plist))
+ if ((rfont = MPLIST_VAL (pl)) && ! rfont->frame)
+ free (rfont);
+ pl = MPLIST_PLIST (plist);
+ M17N_OBJECT_UNREF (pl);
+ }
+ M17N_OBJECT_UNREF (realized->per_charset);
+ }
+ if (realized->fallback)
+ {
+ MPLIST_DO (plist, realized->fallback)
+ if ((rfont = MPLIST_VAL (plist)) && ! rfont->frame)
+ free (rfont);
+ M17N_OBJECT_UNREF (realized->fallback);
+ }
+}
+
+static void
+update_fontset_elements (MRealizedFontset *realized)
+{
+ free_realized_fontset_elements (realized);
+ realize_fontset_elements (realized->frame, realized, realized->fontset,
+ &realized->spec);
+}
+
+
\f
/* Internal API */
{
MRealizedFontset *realized;
MFont request;
- MPlist *per_script, *per_lang, *per_charset, *font_group;
- MPlist *plist, *pl, *p;
+ MPlist *plist;
if (fontset->mdb)
load_fontset_contents (fontset);
mdebug_hook ();
request.property[MFONT_SIZE] = 120;
}
- MPLIST_DO (p, frame->realized_fontset_list)
+ MPLIST_DO (plist, frame->realized_fontset_list)
{
- realized = (MRealizedFontset *) MPLIST_VAL (p);
- if (fontset->name == MPLIST_KEY (p)
+ realized = (MRealizedFontset *) MPLIST_VAL (plist);
+ if (fontset->name == MPLIST_KEY (plist)
&& ! memcmp (&request, &realized->spec, sizeof (request)))
return realized;
}
MSTRUCT_MALLOC (realized, MERROR_FONTSET);
- realized->fontset = fontset;
- realized->tick = fontset->tick;
- realized->spec = request;
- realized->frame = frame;
- realized->per_script = per_script = mplist ();
- MPLIST_DO (plist, fontset->per_script)
- {
- per_lang = mplist ();
- per_script = mplist_add (per_script, MPLIST_KEY (plist), per_lang);
- MPLIST_DO (pl, MPLIST_PLIST (plist))
- {
- font_group = mplist ();
- mplist_add (font_group, Mplist, MPLIST_VAL (pl));
- per_lang = mplist_add (per_lang, MPLIST_KEY (pl), font_group);
- }
- }
-
- realized->per_charset = per_charset = mplist ();
- MPLIST_DO (plist, fontset->per_charset)
- {
- font_group = mplist ();
- mplist_add (font_group, Mplist, MPLIST_VAL (plist));
- per_charset = mplist_add (per_charset, MPLIST_KEY (plist), font_group);
- }
-
- realized->fallback = mplist ();
- mplist_add (realized->fallback, Mplist, fontset->fallback);
-
+ realize_fontset_elements (frame, realized, fontset, &request);
mplist_add (frame->realized_fontset_list, fontset->name, realized);
return realized;
}
void
mfont__free_realized_fontset (MRealizedFontset *realized)
{
- MPlist *plist, *pl, *p;
+ free_realized_fontset_elements (realized);
+ free (realized);
+}
+
+
+static MRealizedFont *
+try_font_group (MRealizedFontset *realized,
+ MPlist *font_group, MGlyph *g, int *num, int size)
+{
+ MFrame *frame = realized->frame;
MRealizedFont *rfont;
+ MPlist *plist;
+ int i;
- if (realized->per_script)
+ if (MPLIST_PLIST_P (font_group))
+ realize_font_group (frame, &realized->spec, font_group, size);
+
+ MPLIST_DO (plist, font_group)
{
- MPLIST_DO (plist, realized->per_script)
+ rfont = (MRealizedFont *) MPLIST_VAL (plist);
+ if (rfont->status < 0)
+ continue;
+ /* Check if this font can display all glyphs. */
+ for (i = 0; i < *num; i++)
{
- MPLIST_DO (pl, MPLIST_PLIST (plist))
- {
- MPLIST_DO (p, MPLIST_PLIST (pl))
- if ((rfont = MPLIST_VAL (p)) && ! rfont->frame)
- free (rfont);
- p = MPLIST_PLIST (pl);
- M17N_OBJECT_UNREF (p);
- }
- pl = MPLIST_PLIST (plist);
- M17N_OBJECT_UNREF (pl);
+ g[i].code = mfont__encode_char (rfont,
+ g[i].type == GLYPH_CHAR ? g[i].c
+ : ' ');
+ if (g[i].code == MCHAR_INVALID_CODE)
+ break;
}
- M17N_OBJECT_UNREF (realized->per_script);
- }
- if (realized->per_charset)
- {
- MPLIST_DO (plist, realized->per_charset)
+ if (i == *num)
{
- MPLIST_DO (pl, MPLIST_PLIST (plist))
- if ((rfont = MPLIST_VAL (pl)) && ! rfont->frame)
- free (rfont);
- pl = MPLIST_PLIST (plist);
- M17N_OBJECT_UNREF (pl);
+ if (rfont->status > 0
+ || mfont__open (rfont) == 0)
+ /* We found a font that can display all glyphs. */
+ return rfont;
}
- M17N_OBJECT_UNREF (realized->per_charset);
}
- if (realized->fallback)
+
+ /* We couldn't find a font that can display all glyphs. Find one
+ that can display at least the first glyph. */
+ MPLIST_DO (plist, font_group)
{
- MPLIST_DO (plist, realized->fallback)
- if ((rfont = MPLIST_VAL (plist)) && ! rfont->frame)
- free (rfont);
- M17N_OBJECT_UNREF (realized->fallback);
+ rfont = (MRealizedFont *) MPLIST_VAL (plist);
+ if (rfont->status < 0)
+ continue;
+ g->code = mfont__encode_char (rfont,
+ g->type == GLYPH_CHAR ? g->c : ' ');
+ if (g->code != MCHAR_INVALID_CODE)
+ {
+ if (rfont->status > 0
+ || mfont__open (rfont) == 0)
+ {
+ /* Ok, let's use this font. Check how many more
+ characters it supports. */
+ int i;
+
+ for (i = 1; i < *num; i++)
+ {
+ g[i].code = mfont__encode_char (rfont,
+ g[i].type == GLYPH_CHAR
+ ? g[i].c : ' ');
+ if (g[i].code == MCHAR_INVALID_CODE)
+ break;
+ }
+ *num = i;
+ return rfont;
+ }
+ }
}
- free (realized);
+ return NULL;
}
-
MRealizedFont *
mfont__lookup_fontset (MRealizedFontset *realized, MGlyph *g, int *num,
MSymbol script, MSymbol language, MSymbol charset,
int size)
{
- MFrame *frame = realized->frame;
MCharset *preferred_charset = (charset == Mnil ? NULL : MCHARSET (charset));
- MPlist *per_charset, *per_script, *per_lang, *font_group;
- MPlist *font_groups[256], *plist;
- int n_font_group = 0;
- MRealizedFont *first = NULL, *rfont;
- int first_len;
- int i;
+ MPlist *per_charset, *per_script, *per_lang;
+ MPlist *plist;
+ MRealizedFont *rfont = NULL;
+
+ if (realized->tick != realized->fontset->tick)
+ update_fontset_elements (realized);
if (preferred_charset
- && (per_charset = mplist_get (realized->per_charset, charset)) != NULL)
- font_groups[n_font_group++] = per_charset;
+ && (per_charset = mplist_get (realized->per_charset, charset)) != NULL
+ && (rfont = try_font_group (realized, per_charset, g, num, size)))
+ return rfont;
+
if (script != Mnil
- && ((per_script = mplist_find_by_key (realized->per_script, script))
- != NULL))
+ && (per_script = mplist_get (realized->per_script, script)))
{
- /* The first loop is for matching language (if any), and the second
- loop is for non-matching languages. */
+ /* We prefer font groups in this order:
+ (1) group matching with LANGUAGE if LANGUAGE is not Mnil
+ (2) group for generic language
+ (3) group not matching with LANGUAGE */
if (language == Mnil)
language = Mt;
- for (i = 0; i < 2; i++)
- {
- MPLIST_DO (per_lang, MPLIST_PLIST (per_script))
- if ((MPLIST_KEY (per_lang) == language) != i)
- font_groups[n_font_group++] = MPLIST_PLIST (per_lang);
- }
- }
- font_groups[n_font_group++] = realized->fallback;
-
- if (n_font_group == 1)
- {
- /* As we only have a fallback font group, try all the other
- fonts too. */
- MPLIST_DO (per_script, realized->per_script)
- MPLIST_DO (per_lang, MPLIST_PLIST (per_script))
- font_groups[n_font_group++] = MPLIST_PLIST (per_lang);
- MPLIST_DO (per_charset, realized->per_charset)
- font_groups[n_font_group++] = MPLIST_PLIST (per_charset);
- }
-
- for (i = 0; i < n_font_group; i++)
- {
- int j;
-
- if (MPLIST_PLIST_P (font_groups[i]))
- realize_font_group (frame, &realized->spec, font_groups[i], size);
+ if ((per_lang = mplist_get (per_script, language))
+ && (rfont = try_font_group (realized, per_lang, g, num, size)))
+ return rfont;
- MPLIST_DO (plist, font_groups[i])
- {
- rfont = (MRealizedFont *) MPLIST_VAL (plist);
- g->code = mfont__encode_char (rfont, g->c);
- if (g->code != MCHAR_INVALID_CODE)
- break;
- }
- if (MPLIST_TAIL_P (plist))
- continue;
- for (j = 1; j < *num; j++)
+ if (language == Mt)
{
- g[j].code = mfont__encode_char (rfont, g[j].c);
- if (g[j].code == MCHAR_INVALID_CODE)
- break;
+ /* Try the above (3) */
+ MPLIST_DO (plist, per_script)
+ if (MPLIST_KEY (plist) != language
+ && (rfont = try_font_group (realized, MPLIST_PLIST (plist),
+ g, num, size)))
+ return rfont;
}
- if (! first)
- first = rfont, first_len = j;
- if (j == *num)
- /* We found a font that can display all requested
- characters. */
- break;
-
- MPLIST_DO (plist, MPLIST_NEXT (plist))
+ else
{
- rfont = (MRealizedFont *) MPLIST_VAL (plist);
- for (j = 0; j < *num; j++)
- {
- g[j].code = mfont__encode_char (rfont, g[j].c);
- if (g[j].code == MCHAR_INVALID_CODE)
- break;
- }
- if (j == *num)
- break;
+ /* At first try the above (2) */
+ if ((per_lang = mplist_get (per_script, Mt))
+ && (rfont = try_font_group (realized, per_lang, g, num, size)))
+ return rfont;
+
+ /* Then try the above (3) */
+ MPLIST_DO (plist, per_script)
+ if (MPLIST_KEY (plist) != language
+ && MPLIST_KEY (plist) != Mt
+ && (rfont = try_font_group (realized, MPLIST_PLIST (plist),
+ g, num, size)))
+ return rfont;
}
- if (! MPLIST_TAIL_P (plist))
- break;
}
- if (i == n_font_group)
- {
- if (! first)
- return NULL;
- rfont = first, *num = first_len;
- for (i = 0; i < *num; i++)
- g[i].code = mfont__encode_char (rfont, g[i].c);
- }
- if (! rfont->status
- && mfont__open (rfont) < 0)
+ if (language != Mnil)
+ /* Find a font group for this language from all scripts. */
+ MPLIST_DO (plist, realized->per_script)
+ if ((per_lang = mplist_get (MPLIST_PLIST (plist), language))
+ && (rfont = try_font_group (realized, per_lang, g, num, size)))
+ return rfont;
+
+ /* Try fallback fonts. */
+ if ((rfont = try_font_group (realized, realized->fallback, g, num, size)))
+ return rfont;
+
+ /* At last try all fonts. */
+ MPLIST_DO (per_script, realized->per_script)
{
- MPLIST_VAL (font_group) = NULL;
- return NULL;
+ MPLIST_DO (per_lang, MPLIST_PLIST (per_script))
+ if ((rfont = try_font_group (realized, MPLIST_PLIST (per_lang),
+ g, num, size)))
+ return rfont;
}
- return rfont;
+ MPLIST_DO (per_charset, realized->per_charset)
+ if ((rfont = try_font_group (realized, MPLIST_PLIST (per_charset),
+ g, num, size)))
+ return rfont;
+
+ return NULL;
}
/*** @} */
MFontset *fontset;
if (! name)
- return default_fontset;
- sym = msymbol (name);
- fontset = mplist_get (fontset_list, sym);
- if (fontset)
- return fontset;
- M17N_OBJECT (fontset, free_fontset, MERROR_FONTSET);
- fontset->name = sym;
- fontset->mdb = mdatabase_find (Mfontset, sym, Mnil, Mnil);
- if (! fontset->mdb)
+ fontset = default_fontset;
+ else
{
- fontset->per_script = mplist ();
- fontset->per_charset = mplist ();
- fontset->fallback = mplist ();
+ sym = msymbol (name);
+ fontset = mplist_get (fontset_list, sym);
+ if (! fontset)
+ {
+ M17N_OBJECT (fontset, free_fontset, MERROR_FONTSET);
+ fontset->name = sym;
+ fontset->mdb = mdatabase_find (Mfontset, sym, Mnil, Mnil);
+ if (! fontset->mdb)
+ {
+ fontset->per_script = mplist ();
+ fontset->per_charset = mplist ();
+ fontset->fallback = mplist ();
+ fontset->font_spec_list = mplist ();
+ }
+ mplist_put (fontset_list, sym, fontset);
+ }
}
- mplist_put (fontset_list, sym, fontset);
M17N_OBJECT_REF (fontset);
return fontset;
}
M17N_OBJECT (copy, free_fontset, MERROR_FONTSET);
copy->name = sym;
+ if (fontset->mdb)
+ load_fontset_contents (fontset);
+
if (fontset->per_script)
{
copy->per_script = mplist ();
if (fontset->mdb)
load_fontset_contents (fontset);
- MPLIST_DO (pl, fontset->font_spec_list)
- {
- if (! memcmp (MPLIST_VAL (pl), spec, sizeof (MFont)))
- {
- font = MPLIST_VAL (pl);
- break;
- }
- }
+ if (! fontset->font_spec_list)
+ fontset->font_spec_list = mplist ();
+ else
+ MPLIST_DO (pl, fontset->font_spec_list)
+ {
+ if (! memcmp (MPLIST_VAL (pl), spec, sizeof (MFont)))
+ {
+ font = MPLIST_VAL (pl);
+ break;
+ }
+ }
if (! font)
{
font = mfont ();
layouter_name = Mt;
for (i--; i >= 0; i--)
{
- if (how == -1)
+ if (how == 1)
mplist_push (plist[i], layouter_name, font);
- else if (how == 1)
+ else if (how == -1)
mplist_add (plist[i], layouter_name, font);
else
{
}
}
+ fontset->tick++;
return 0;
}
+/*=*/
+
+/***en
+ @brief Lookup a fontset.
+
+ The mfontset_lookup () function lookups $FONTSET and returns a
+ plist that describes the contents of $FONTSET corresponding to the
+ specified script, language, and charset.
+
+ If $SCRIPT is @c Mt, keys of the returned plist are script name
+ symbols for which some fonts are specified and values are NULL.
+
+ If $SCIRPT is a script symbol, the returned plist is decided by
+ $LANGUAGE.
+
+ If $LANGUAGE is @c Mt, keys of the plist are language name symbols
+ for which some fonts are specified and values are NULL. A key may
+ be @c Mt which means some fallback fonts are specified for the
+ script.
+
+ If $LANGUAGE is a language name symbol, the plist is a @c
+ FONT-GROUP for the specified script and langauge.
+
+ If $LANGAUGE is @c Mt, the plist is fallback @c FONT-GROUP for the
+ script.
+
+ If $SCRIPT is @c Mnil, the returned plist is decided as below.
+
+ If $CHARSET is @c Mt, keys of the returned plist are charset name
+ symbols for which some fonts are specified and values are NULL.
+
+ If $CHARSET is a charset symbol, the plist is a @c FONT-GROUP for
+ the charset.
+
+ If $CHARSET is @c Mnil, the plist is a fallback @c FONT-GROUP.
+
+ @c FONT-GROUP is a plist whose keys are FLT name symbols (@c Mt if
+ no FLT is associated with the font) and values are pointers to
+ #MFont.
+
+ @return
+ It returns a plist describing the contents of a fontset. The
+ plist should be freed by m17n_object_unref (). */
+
+MPlist *
+mfontset_lookup (MFontset *fontset,
+ MSymbol script, MSymbol language, MSymbol charset)
+{
+ MPlist *plist = mplist (), *pl, *p;
+
+ if (fontset->mdb)
+ load_fontset_contents (fontset);
+ if (script == Mt)
+ {
+ if (! fontset->per_script)
+ return plist;
+ p = plist;
+ MPLIST_DO (pl, fontset->per_script)
+ p = mplist_add (p, MPLIST_KEY (pl), NULL);
+ return plist;
+ }
+ if (script != Mnil)
+ {
+ if (! fontset->per_script)
+ return plist;
+ pl = mplist_get (fontset->per_script, script);
+ if (! pl)
+ return plist;
+ if (language == Mt)
+ {
+ p = plist;
+ MPLIST_DO (pl, pl)
+ p = mplist_add (p, MPLIST_KEY (pl), NULL);
+ return plist;
+ }
+ if (language == Mnil)
+ language = Mt;
+ pl = mplist_get (pl, language);
+ }
+ else if (charset != Mnil)
+ {
+ if (! fontset->per_charset)
+ return plist;
+ if (charset == Mt)
+ {
+ p = plist;
+ MPLIST_DO (pl, fontset->per_charset)
+ p = mplist_add (p, MPLIST_KEY (pl), NULL);
+ return plist;
+ }
+ pl = mplist_get (fontset->per_charset, charset);
+ }
+ else
+ pl = fontset->fallback;
+ if (! pl)
+ return plist;
+ return mplist_copy (pl);
+}
+
+
/*** @} */
/*** @addtogroup m17nDebug */