/* fontset.c -- fontset module.
- Copyright (C) 2003, 2004
+ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
National Institute of Advanced Industrial Science and Technology (AIST)
Registration Number H15PRO112
You should have received a copy of the GNU Lesser General Public
License along with the m17n library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
02111-1307, USA. */
/***en
#include "font.h"
#include "fontset.h"
+static int mdebug_flag = MDEBUG_FONTSET;
+
+static M17NObjectArray fontset_table;
+
struct MFontset
{
M17NObject control;
/* FONT-GROUP */
MPlist *fallback;
-
- /* Plist of Mt vs font specs. */
- MPlist *font_spec_list;
};
static MFontset *default_fontset;
/* Initialized to <fontset>->tick. */
unsigned tick;
- /* Font spec extracted from a face. */
- MFont spec;
+ /* Font spec that must be satisfied, or NULL. */
+ MFont *spec;
+
+ /* Font spec requested by a face. */
+ MFont request;
/* The frame on which the realized fontset is realized. */
MFrame *frame;
static MPlist *
-load_font_group (MPlist *plist, MPlist *elt, MPlist *spec_list)
+load_font_group (MPlist *plist, MPlist *elt)
{
MPLIST_DO (elt, elt)
{
- /* ELT ::= ( FONT-SPEC-LIST [ LAYOUTER ] ) ... */
- MPlist *elt2, *p;
- MFont font, *spec = NULL;
+ /* ELT ::= ( FONT-SPEC [ LAYOUTER ] ) ... */
+ MPlist *elt2;
+ MFont *font;
MSymbol layouter_name;
if (! MPLIST_PLIST_P (elt))
elt2 = MPLIST_PLIST (elt);
if (! MPLIST_PLIST_P (elt2))
MWARNING (MERROR_FONTSET);
- mfont__set_spec_from_plist (&font, MPLIST_PLIST (elt2));
- MPLIST_DO (p, spec_list)
- {
- if (! memcmp (MPLIST_VAL (p), &font, sizeof (MFont)))
- {
- spec = MPLIST_VAL (p);
- break;
- }
- }
- if (! spec)
- {
- MSTRUCT_MALLOC (spec, MERROR_FONTSET);
- *spec = font;
- mplist_add (spec_list, Mt, spec);
- }
+ MSTRUCT_CALLOC (font, MERROR_FONTSET);
+ mfont__set_spec_from_plist (font, MPLIST_PLIST (elt2));
elt2 = MPLIST_NEXT (elt2);
layouter_name = Mt;
if (MPLIST_SYMBOL_P (elt2))
layouter_name = MPLIST_SYMBOL (elt2);
if (layouter_name == Mnil)
layouter_name = Mt;
- plist = mplist_add (plist, layouter_name, spec);
+ plist = mplist_add (plist, layouter_name, font);
continue;
warning:
/* ANSI-C requires some statement after a label. */
static void
load_fontset_contents (MFontset *fontset)
{
- MPlist *per_script, *per_charset, *fallback, *spec_list, *font_group;
- MSymbol script, lang;
+ MPlist *per_script, *per_charset, *font_group;
MPlist *fontset_def, *plist;
fontset->per_script = per_script = mplist ();
fontset->per_charset = per_charset = mplist ();
- fontset->fallback = fallback = mplist ();
- fontset->font_spec_list = spec_list = mplist ();
+ fontset->fallback = mplist ();
if (! (fontset_def = (MPlist *) mdatabase_load (fontset->mdb)))
return;
MPLIST_DO (plist, fontset_def)
{
- /* PLIST ::= ( SCRIPT ( LANGUAGE FONT-SPEC-ELT ... ) ... )
- | (CHARSET FONT-SPEC-ELT ...)
- | FONT-SPEC-ELT */
+ /* PLIST ::= ( SCRIPT ( LANGUAGE ( FONT-SPEC [LAYOUTER]) ... ) ... )
+ | ( CHARSET ( FONT-SPEC [LAYOUTER] ) ...)
+ | ( nil ( FONT-SPEC [LAYOUTER] ) ...)
+ FONT-SPEC :: = ( ... ) */
MPlist *elt;
+ MSymbol sym;
if (! MPLIST_PLIST_P (plist))
MWARNING (MERROR_FONTSET);
elt = MPLIST_PLIST (plist);
if (! MPLIST_SYMBOL_P (elt))
MWARNING (MERROR_FONTSET);
- script = MPLIST_SYMBOL (elt);
+ sym = MPLIST_SYMBOL (elt);
elt = MPLIST_NEXT (elt);
if (! MPLIST_PLIST_P (elt))
MWARNING (MERROR_FONTSET);
- if (script == Mnil)
- fallback = load_font_group (fallback, elt, spec_list);
+ if (sym == Mnil)
+ load_font_group (fontset->fallback, elt);
else if (MPLIST_PLIST_P (MPLIST_PLIST (elt)))
{
- font_group = mplist_find_by_key (fontset->per_charset, script);
- if (! font_group)
- {
- font_group = mplist ();
- per_charset = mplist_add (per_charset, script, font_group);
- }
- load_font_group (font_group, elt, spec_list);
+ /* SYM is a charset. */
+ font_group = mplist ();
+ per_charset = mplist_add (per_charset, sym, font_group);
+ load_font_group (font_group, elt);
}
else
{
- MPlist *per_lang = mplist_find_by_key (fontset->per_script, script);
-
- if (! per_lang)
- {
- per_lang = mplist ();
- per_script = mplist_add (per_script, script, per_lang);
- }
+ /* SYM is a script */
+ MPlist *per_lang = mplist ();
+ per_script = mplist_add (per_script, sym, per_lang);
MPLIST_DO (elt, elt)
{
/* ELT ::= ( LANGUAGE FONT-DEF ...) ... */
MPlist *elt2;
+ MSymbol lang;
if (! MPLIST_PLIST_P (elt))
MWARNING (MERROR_FONTSET);
lang = MPLIST_SYMBOL (elt2);
if (lang == Mnil)
lang = Mt;
- font_group = mplist_find_by_key (per_lang, lang);
- if (! font_group)
- {
- font_group = mplist ();
- mplist_add (per_lang, lang, font_group);
- }
+ font_group = mplist ();
+ mplist_add (per_lang, lang, font_group);
elt2 = MPLIST_NEXT (elt2);
- load_font_group (font_group, elt2, spec_list);
+ load_font_group (font_group, elt2);
}
}
continue;
{
MPLIST_DO (pl, MPLIST_PLIST (plist))
{
+ MPLIST_DO (p, MPLIST_PLIST (pl))
+ free (MPLIST_VAL (p));
p = MPLIST_PLIST (pl);
M17N_OBJECT_UNREF (p);
}
}
if (fontset->per_charset)
{
- MPLIST_DO (plist, fontset->per_charset)
+ MPLIST_DO (pl, fontset->per_charset)
{
- pl = MPLIST_PLIST (plist);
- M17N_OBJECT_UNREF (pl);
+ MPLIST_DO (p, MPLIST_PLIST (pl))
+ free (MPLIST_VAL (p));
+ p = MPLIST_PLIST (p);
+ M17N_OBJECT_UNREF (p);
}
M17N_OBJECT_UNREF (fontset->per_charset);
}
if (fontset->fallback)
- M17N_OBJECT_UNREF (fontset->fallback);
+ {
+ MPLIST_DO (p, fontset->fallback)
+ free (MPLIST_VAL (p));
+ M17N_OBJECT_UNREF (fontset->fallback);
+ }
+
plist = mplist_find_by_key (fontset_list, fontset->name);
if (! plist)
mdebug_hook ();
mplist_pop (plist);
- if (fontset->font_spec_list)
+ if (MPLIST_TAIL_P (fontset_list))
{
- if (((M17NObject *) (fontset->font_spec_list))->ref_count == 1)
- MPLIST_DO (plist, fontset->font_spec_list)
- free (MPLIST_VAL (plist));
- M17N_OBJECT_UNREF (fontset->font_spec_list);
+ M17N_OBJECT_UNREF (fontset_list);
+ fontset_list = NULL;
}
+ M17N_OBJECT_UNREGISTER (fontset_table, fontset);
free (object);
}
static void
-realize_font_group (MFrame *frame, MFont *request, MPlist *font_group,
- int size)
-{
- MPlist *plist = MPLIST_VAL (font_group), *pl, *p;
-
- mplist_set (font_group, Mnil, NULL);
- MPLIST_DO (pl, plist)
- {
- MSymbol layouter = MPLIST_KEY (pl);
- MFont this_request = *request;
- MRealizedFont *rfont;
-
- mfont__resize (MPLIST_VAL (pl), &this_request);
- rfont = mfont__select (frame, MPLIST_VAL (pl), &this_request,
- size, layouter == Mt ? Mnil : layouter);
-
- if (rfont)
- {
- MPLIST_DO (p, font_group)
- if (((MRealizedFont *) (MPLIST_VAL (p)))->score > rfont->score)
- break;
- mplist_push (p, Mt, rfont);
- }
- }
-}
-
-static void
-realize_fontset_elements (MFrame *frame, MRealizedFontset *realized,
- MFontset *fontset, MFont *request)
+realize_fontset_elements (MFrame *frame, MRealizedFontset *realized)
{
- MPlist *per_script, *per_lang, *per_charset, *font_group;
- MPlist *plist, *pl;
+ MFontset *fontset = realized->fontset;
+ MPlist *per_script, *per_charset, *font_group;
+ MPlist *plist, *p;
- realized->fontset = fontset;
- realized->tick = fontset->tick;
- realized->spec = *request;
- realized->frame = frame;
realized->per_script = per_script = mplist ();
+ /* The actual elements of per_script are realized on demand. */
+#if 0
MPLIST_DO (plist, fontset->per_script)
{
+ MPlist *pl;
+
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);
+ MPLIST_DO (p, MPLIST_PLIST (pl))
+ font_group = mplist_add (font_group,
+ MPLIST_KEY (p), MPLIST_VAL (p));
}
}
+#endif
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);
+ MPLIST_DO (p, MPLIST_PLIST (plist))
+ font_group = mplist_add (font_group, MPLIST_KEY (p), MPLIST_VAL (p));
}
+ realized->fallback = font_group = mplist ();
+ MPLIST_DO (p, fontset->fallback)
+ font_group = mplist_add (font_group, MPLIST_KEY (p), MPLIST_VAL (p));
+}
- realized->fallback = mplist ();
- mplist_add (realized->fallback, Mplist, fontset->fallback);
+/* Return a plist of fonts for SCRIPT in FONTSET. The returned list
+ is acutally a plist of languages vs font groups (which is a plist).
+ If SCRIPT is nil, return a plist of fallback fonts. If FONTSET
+ doesn't record any fonts for SCRIPT, generate a proper font spec
+ lists for X backend and FreeType backend. */
+
+MPlist *
+get_per_script (MFontset *fontset, MSymbol script)
+{
+ MPlist *plist;
+
+ if (script == Mnil)
+ return fontset->fallback;
+ plist = mplist_get (fontset->per_script, script);
+ if (! plist)
+ {
+ int len = MSYMBOL_NAMELEN (script);
+ char *cap = alloca (8 + len + 1);
+ MSymbol capability;
+ MFont *font;
+ MPlist *pl, *p;
+
+ sprintf (cap, ":script=%s", MSYMBOL_NAME (script));
+ capability = msymbol (cap);
+
+ pl = mplist ();
+ MPLIST_DO (p, fontset->fallback)
+ {
+ font = mfont_copy (MPLIST_VAL (p));
+ mfont_put_prop (font, Mregistry, Municode_bmp);
+ font->source = MFONT_SOURCE_FT;
+ font->capability = capability;
+ mplist_add (pl, Mt, font);
+
+ font = mfont_copy (MPLIST_VAL (p));
+ mfont_put_prop (font, Mregistry, Miso10646_1);
+ font->source = MFONT_SOURCE_X;
+ font->capability = capability;
+ mplist_add (pl, Mt, font);
+ }
+ plist = mplist ();
+ mplist_add (plist, Mt, pl);
+ mplist_add (fontset->per_script, script, plist);
+ }
+ return plist;
}
static void
free_realized_fontset_elements (MRealizedFontset *realized)
{
MPlist *plist, *pl, *p;
- MRealizedFont *rfont;
+ MFont *font;
+ MFontList *font_list;
if (realized->per_script)
{
MPLIST_DO (pl, MPLIST_PLIST (plist))
{
MPLIST_DO (p, MPLIST_PLIST (pl))
- if ((rfont = MPLIST_VAL (p)) && ! rfont->frame)
- free (rfont);
+ {
+ font = MPLIST_VAL (p);
+ if (font->type == MFONT_TYPE_OBJECT)
+ {
+ font_list = (MFontList *) font;
+ free (font_list->fonts);
+ free (font_list);
+ }
+ /* This is to avoid freeing rfont again by the later
+ M17N_OBJECT_UNREF (p) */
+ MPLIST_KEY (p) = Mt;
+ }
p = MPLIST_PLIST (pl);
M17N_OBJECT_UNREF (p);
}
MPLIST_DO (plist, realized->per_charset)
{
MPLIST_DO (pl, MPLIST_PLIST (plist))
- if ((rfont = MPLIST_VAL (pl)) && ! rfont->frame)
- free (rfont);
+ {
+ font = MPLIST_VAL (pl);
+ if (font->type == MFONT_TYPE_OBJECT)
+ {
+ font_list = (MFontList *) font;
+ free (font_list->fonts);
+ free (font_list);
+ }
+ MPLIST_KEY (pl) = Mt;
+ }
pl = MPLIST_PLIST (plist);
M17N_OBJECT_UNREF (pl);
}
if (realized->fallback)
{
MPLIST_DO (plist, realized->fallback)
- if ((rfont = MPLIST_VAL (plist)) && ! rfont->frame)
- free (rfont);
+ {
+ font = MPLIST_VAL (plist);
+ if (font->type == MFONT_TYPE_OBJECT)
+ {
+ font_list = (MFontList *) font;
+ free (font_list->fonts);
+ free (font_list);
+ }
+ MPLIST_KEY (plist) = Mt;
+ }
M17N_OBJECT_UNREF (realized->fallback);
}
}
update_fontset_elements (MRealizedFontset *realized)
{
free_realized_fontset_elements (realized);
- realize_fontset_elements (realized->frame, realized, realized->fontset,
- &realized->spec);
+ realize_fontset_elements (realized->frame, realized);
}
int
mfont__fontset_init ()
{
+ M17N_OBJECT_ADD_ARRAY (fontset_table, "Fontset");
+
Mfontset = msymbol ("fontset");
Mfontset->managing_key = 1;
fontset_list = mplist ();
void
mfont__fontset_fini ()
{
- while (! MPLIST_TAIL_P (fontset_list))
- free_fontset ((MFontset *) MPLIST_VAL (fontset_list));
- M17N_OBJECT_UNREF (fontset_list);
- fontset_list = NULL;
+ M17N_OBJECT_UNREF (default_fontset);
+ default_fontset = NULL;
}
MRealizedFontset *
-mfont__realize_fontset (MFrame *frame, MFontset *fontset, MFace *face)
+mfont__realize_fontset (MFrame *frame, MFontset *fontset,
+ MFace *face, MFont *spec)
{
MRealizedFontset *realized;
MFont request;
if (fontset->mdb)
load_fontset_contents (fontset);
+ MFONT_INIT (&request);
mfont__set_spec_from_face (&request, face);
- if (request.property[MFONT_SIZE] <= 0)
+ if (request.size <= 0)
{
mdebug_hook ();
- request.property[MFONT_SIZE] = 120;
+ request.size = 120;
}
MPLIST_DO (plist, frame->realized_fontset_list)
{
realized = (MRealizedFontset *) MPLIST_VAL (plist);
if (fontset->name == MPLIST_KEY (plist)
- && ! memcmp (&request, &realized->spec, sizeof (request)))
+ && ! memcmp (&request, &realized->request, sizeof (MFont))
+ && (realized->spec
+ ? (spec && ! memcmp (spec, &realized->spec, sizeof (MFont)))
+ : ! spec))
return realized;
}
- MSTRUCT_MALLOC (realized, MERROR_FONTSET);
- realize_fontset_elements (frame, realized, fontset, &request);
+ MSTRUCT_CALLOC (realized, MERROR_FONTSET);
+ realized->fontset = fontset;
+ M17N_OBJECT_REF (fontset);
+ realized->tick = fontset->tick;
+ if (spec)
+ {
+ MSTRUCT_CALLOC (realized->spec, MERROR_FONTSET);
+ *realized->spec = *spec;
+ }
+ realized->request = request;
+ realized->frame = frame;
+ realize_fontset_elements (frame, realized);
mplist_add (frame->realized_fontset_list, fontset->name, realized);
return realized;
}
mfont__free_realized_fontset (MRealizedFontset *realized)
{
free_realized_fontset_elements (realized);
+ M17N_OBJECT_UNREF (realized->fontset);
+ if (realized->spec)
+ free (realized->spec);
free (realized);
}
static MRealizedFont *
-try_font_group (MRealizedFontset *realized,
- MPlist *font_group, MGlyph *g, int *num, int size)
+try_font_list (MFrame *frame, MFontList *font_list, MFont *request,
+ MSymbol layouter, MGlyph *g, int *num, int all, int exact)
{
- MFrame *frame = realized->frame;
+ int i, j;
+ MFont *font;
MRealizedFont *rfont;
- MPlist *plist;
- int i;
- if (MPLIST_PLIST_P (font_group))
- realize_font_group (frame, &realized->spec, font_group, size);
-
- MPLIST_DO (plist, font_group)
+ for (i = 0; i < font_list->nfonts; i++)
{
- rfont = (MRealizedFont *) MPLIST_VAL (plist);
- if (rfont->status < 0)
+ if (font_list->fonts[i].font->type == MFONT_TYPE_SPEC)
+ MFATAL (MERROR_FONT);
+ if (exact)
+ {
+ if (font_list->fonts[i].score > 0)
+ break;
+ }
+ else
+ {
+ if (font_list->fonts[i].score == 0)
+ continue;
+ }
+ font = font_list->fonts[i].font;
+ if (font->type == MFONT_TYPE_FAILURE)
continue;
/* Check if this font can display all glyphs. */
- for (i = 0; i < *num; i++)
+ for (j = 0; j < *num; j++)
{
- g[i].code = mfont__encode_char (rfont,
- g[i].type == GLYPH_CHAR ? g[i].c
- : ' ');
- if (g[i].code == MCHAR_INVALID_CODE)
+ int c = g[j].type == GLYPH_CHAR ? g[j].g.c : ' ';
+ MFLT *flt;
+ MCharTable *coverage;
+
+ if (layouter != Mt
+ ? ((flt = mflt_get (layouter))
+ ? (coverage = mflt_coverage (flt),
+ ! mchartable_lookup (coverage, c))
+ : 0)
+ : ! mfont__has_char (frame, font, &font_list->object, c))
break;
}
- if (i == *num)
+ if (j == 0 && *num > 0)
+ continue;
+ if (j == *num || !all)
{
- if (rfont->status > 0
- || mfont__open (rfont) == 0)
- /* We found a font that can display all glyphs. */
- return rfont;
+ MCharTable *coverage = NULL;
+
+ /* We found a font that can display the requested range of
+ glyphs. */
+ if (font->type == MFONT_TYPE_REALIZED)
+ rfont = (MRealizedFont *) font;
+ else
+ {
+ rfont = mfont__open (frame, font, &font_list->object);
+ if (! rfont)
+ continue;
+ font_list->fonts[i].font = (MFont *) rfont;
+ }
+ rfont->layouter = layouter == Mt ? Mnil : layouter;
+ if (rfont->layouter)
+ {
+ MFLT *flt = mflt_get (rfont->layouter);
+
+ if (flt)
+ coverage = mflt_coverage (flt);
+ }
+ *num = j;
+ for (j = 0; j < *num; j++)
+ {
+ int c = g[j].type == GLYPH_CHAR ? g[j].g.c : ' ';
+
+ g[j].g.code = (coverage
+ ? (unsigned ) mchartable_lookup (coverage, c)
+ : mfont__encode_char (frame, (MFont *) rfont,
+ &font_list->object, c));
+ }
+ return rfont;
}
}
+ return NULL;
+}
- /* 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)
+
+static MRealizedFont *
+try_font_group (MRealizedFontset *realized, MFont *request,
+ MPlist *font_group, MGlyph *g, int *num, int size)
+{
+ MFrame *frame = realized->frame;
+ MFont *font;
+ MFontList *font_list;
+ MRealizedFont *rfont;
+ MPlist *plist;
+ MSymbol layouter;
+ int best_score = -1, worst_score;
+
+ for (plist = font_group; ! MPLIST_TAIL_P (plist); )
{
- 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)
+ int this_score;
+
+ layouter = MPLIST_KEY (plist);
+ font = MPLIST_VAL (plist);
+ if (font->type == MFONT_TYPE_SPEC)
{
- if (rfont->status > 0
- || mfont__open (rfont) == 0)
+ /* We have not yet made this entry a MFontList. */
+ if (realized->spec)
{
- /* Ok, let's use this font. Check how many more
- characters it supports. */
- int i;
-
- for (i = 1; i < *num; i++)
+ MFont this = *font;
+
+ if (mfont__merge (&this, realized->spec, 1) < 0)
{
- g[i].code = mfont__encode_char (rfont,
- g[i].type == GLYPH_CHAR
- ? g[i].c : ' ');
- if (g[i].code == MCHAR_INVALID_CODE)
- break;
+ mplist_pop (plist);
+ continue;
}
- *num = i;
- return rfont;
+ font_list = mfont__list (frame, &this, &this, size);
}
+ else
+ font_list = mfont__list (frame, font, request, size);
+ if (! font_list)
+ {
+ /* As there's no font matching this spec, remove this
+ element from the font group. */
+ mplist_pop (plist);
+ continue;
+ }
+ MPLIST_VAL (plist) = font_list;
+ }
+ else
+ font_list = (MFontList *) font;
+
+ this_score = font_list->fonts[0].score;
+ if ((this_score == 0)
+ && (rfont = try_font_list (frame, font_list, request,
+ layouter, g, num, 1, 1)))
+ return rfont;
+ if (best_score < 0)
+ {
+ best_score = worst_score = this_score;
+ plist = MPLIST_NEXT (plist);
}
+ else if (this_score >= worst_score)
+ {
+ worst_score = this_score;
+ plist = MPLIST_NEXT (plist);
+ }
+ else
+ {
+ MPlist *pl;
+
+ MPLIST_DO (pl, font_group)
+ if (this_score < ((MFontList *) MPLIST_VAL (pl))->fonts[0].score)
+ break;
+ mplist_pop (plist);
+ mplist_push (pl, layouter, font_list);
+ }
+ }
+
+ /* We couldn't find an exact matching font that can display all
+ glyphs. Find one that can at least display all glyphs. */
+ MPLIST_DO (plist, font_group)
+ {
+ rfont = try_font_list (frame, MPLIST_VAL (plist), request,
+ MPLIST_KEY (plist), g, num, 1, 0);
+ if (rfont)
+ return rfont;
+ }
+
+ /* We couldn't find a font that can display all glyphs. Find an
+ exact matching font that can at least display the first
+ glyph. */
+ MPLIST_DO (plist, font_group)
+ {
+ rfont = try_font_list (frame, MPLIST_VAL (plist), request,
+ MPLIST_KEY (plist), g, num, 0, 1);
+ if (rfont)
+ return rfont;
+ }
+
+ /* Find any font that can at least display the first glyph. */
+ MPLIST_DO (plist, font_group)
+ {
+ rfont = try_font_list (frame, MPLIST_VAL (plist), request,
+ MPLIST_KEY (plist), g, num, 0, 0);
+ if (rfont)
+ return rfont;
}
return NULL;
MRealizedFont *
mfont__lookup_fontset (MRealizedFontset *realized, MGlyph *g, int *num,
MSymbol script, MSymbol language, MSymbol charset,
- int size)
+ int size, int ignore_fallback)
{
MCharset *preferred_charset = (charset == Mnil ? NULL : MCHARSET (charset));
MPlist *per_charset, *per_script, *per_lang;
MPlist *plist;
MRealizedFont *rfont = NULL;
+ if (MDEBUG_FLAG ())
+ {
+ int i;
+
+ MDEBUG_PRINT1 (" [FONTSET] fontset looking up for %s:",
+ script ? script->name : "none");
+ for (i = 0; i < *num; i++)
+ MDEBUG_PRINT1 (" U+%04X", g[i].g.c);
+ MDEBUG_PRINT ("\n");
+ }
+
if (realized->tick != realized->fontset->tick)
update_fontset_elements (realized);
if (preferred_charset
&& (per_charset = mplist_get (realized->per_charset, charset)) != NULL
- && (rfont = try_font_group (realized, per_charset, g, num, size)))
- return rfont;
+ && (rfont = try_font_group (realized, &realized->request, per_charset,
+ g, num, size)))
+ goto done;
- if (script != Mnil
- && (per_script = mplist_get (realized->per_script, script)))
+ if (script != Mnil)
{
+ MFont request = realized->request;
+
+ if (script != Mlatin)
+ /* This is not appropriate for non-Latin scripts. */
+ request.property[MFONT_REGISTRY] = 0;
+
+ per_script = mplist_get (realized->per_script, script);
+ if (! per_script)
+ {
+ per_script = mplist_copy (get_per_script (realized->fontset, script));
+ /* PER_SCRIPT ::= (LANGUAGE:(LAYOUTER:FONT-SPEC ...) ...) */
+ MPLIST_DO (plist, per_script)
+ MPLIST_VAL (plist) = mplist_copy (MPLIST_VAL (plist));
+ mplist_add (realized->per_script, script, per_script);
+ }
+
/* We prefer font groups in this order:
(1) group matching with LANGUAGE if LANGUAGE is not Mnil
(2) group for generic language
if (language == Mnil)
language = Mt;
if ((per_lang = mplist_get (per_script, language))
- && (rfont = try_font_group (realized, per_lang, g, num, size)))
- return rfont;
+ && (rfont = try_font_group (realized, &request, per_lang,
+ g, num, size)))
+ goto done;
+ if (per_lang && *num > 1)
+ *num = 1;
if (language == Mt)
{
/* Try the above (3) */
MPLIST_DO (plist, per_script)
if (MPLIST_KEY (plist) != language
- && (rfont = try_font_group (realized, MPLIST_PLIST (plist),
+ && (rfont = try_font_group (realized, &request,
+ MPLIST_PLIST (plist),
g, num, size)))
- return rfont;
+ goto done;
}
else
{
/* 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;
+ && (rfont = try_font_group (realized, &request, per_lang,
+ g, num, size)))
+ goto done;
+ if (per_lang && *num > 1)
+ *num = 1;
/* 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),
+ && (rfont = try_font_group (realized, &request,
+ MPLIST_PLIST (plist),
g, num, size)))
- return rfont;
+ goto done;
}
+ if (ignore_fallback)
+ goto done;
}
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;
+ {
+ MFont request = realized->request;
+
+ if (MPLIST_KEY (plist) != Mlatin)
+ request.property[MFONT_FOUNDRY]
+ = request.property[MFONT_FAMILY]
+ = request.property[MFONT_FAMILY] = 0;
+ if ((per_lang = mplist_get (MPLIST_PLIST (plist), language))
+ && (rfont = try_font_group (realized, &request, per_lang,
+ g, num, size)))
+ goto done;
+ }
/* Try fallback fonts. */
- if ((rfont = try_font_group (realized, realized->fallback, g, num, size)))
- return rfont;
+ rfont = try_font_group (realized, &realized->request,
+ realized->fallback, g, num, size);
+ done:
+ if (MDEBUG_FLAG ())
+ {
+ if (rfont)
+ {
+ MSymbol family = mfont_get_prop (rfont->font, Mfamily);
+ MDEBUG_PRINT1 (" [FONTSET] found %s\n", family->name);
+ }
+ else
+ MDEBUG_PRINT (" [FONTSET] not found\n");
+ }
+
+ return rfont;
+}
+
+MRealizedFont *
+get_font_from_group (MFrame *frame, MPlist *plist, MFont *font)
+{
+ MRealizedFont *rfont;
+
+ MPLIST_DO (plist, plist)
+ {
+ MFont spec = *(MFont *) MPLIST_VAL (plist);
+ if (mfont__merge (&spec, font, 1) < 0)
+ continue;
+ if (font->type == MFONT_TYPE_SPEC)
+ rfont = (MRealizedFont *) mfont_find (frame, &spec, NULL, 0);
+ else if (font->type == MFONT_TYPE_OBJECT)
+ rfont = mfont__open (frame, font, &spec);
+ else
+ rfont = (MRealizedFont *) font;
+ if (rfont
+ && (spec.capability == Mnil
+ || mfont__check_capability (rfont, spec.capability) == 0))
+ {
+ rfont->layouter
+ = MPLIST_KEY (plist) == Mt ? Mnil : MPLIST_KEY (plist);
+ return rfont;
+ }
+ }
+ return NULL;
+}
+
+MRealizedFont *
+mfontset__get_font (MFrame *frame, MFontset *fontset,
+ MSymbol script, MSymbol language, MFont *font,
+ int *best)
+{
+ MPlist *per_script, *per_lang;
+ MRealizedFont *rfont;
+
+ if (best)
+ *best = 0;
- /* At last try all fonts. */
- MPLIST_DO (per_script, realized->per_script)
+ if (language == Mnil)
+ language = Mt;
+
+ if (script != Mnil)
{
- MPLIST_DO (per_lang, MPLIST_PLIST (per_script))
- if ((rfont = try_font_group (realized, MPLIST_PLIST (per_lang),
- g, num, size)))
+ per_script = get_per_script (fontset, script);
+ if ((per_lang = mplist_get (per_script, language))
+ && (rfont = get_font_from_group (frame, per_lang, font)))
+ {
+ if (best)
+ *best = 1;
return rfont;
+ }
+ if (best)
+ *best = per_lang ? 0 : 1;
+ if (language == Mt)
+ {
+ MPLIST_DO (per_script, per_script)
+ if (MPLIST_KEY (per_script) != language
+ && (rfont = get_font_from_group (frame,
+ MPLIST_PLIST (per_script),
+ font)))
+ return rfont;
+ }
+ else
+ {
+ if ((per_lang = mplist_get (per_script, Mt))
+ && (rfont = get_font_from_group (frame, per_lang, font)))
+ return rfont;
+ if (best)
+ *best = 0;
+ MPLIST_DO (per_script, per_script)
+ if (MPLIST_KEY (per_script) != language
+ && MPLIST_KEY (per_script) != Mt
+ && (rfont = get_font_from_group (frame,
+ MPLIST_PLIST (per_script),
+ font)))
+ return rfont;
+ }
}
- MPLIST_DO (per_charset, realized->per_charset)
- if ((rfont = try_font_group (realized, MPLIST_PLIST (per_charset),
- g, num, size)))
- return rfont;
+ if (language != Mt)
+ MPLIST_DO (per_script, fontset->per_script)
+ {
+ if ((per_lang = mplist_get (MPLIST_PLIST (per_script), language))
+ && (rfont = get_font_from_group (frame, per_lang, font)))
+ {
+ if (best)
+ *best = 1;
+ return rfont;
+ }
+ }
+
+ if (best)
+ *best = 0;
+ if ((rfont = get_font_from_group (frame, fontset->fallback, font)))
+ return rfont;
return NULL;
}
+
/*** @} */
#endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
MFontset *fontset;
if (! name)
- fontset = default_fontset;
+ {
+ fontset = default_fontset;
+ M17N_OBJECT_REF (fontset);
+ }
else
{
sym = msymbol (name);
fontset = mplist_get (fontset_list, sym);
- if (! fontset)
+ if (fontset)
+ M17N_OBJECT_REF (fontset);
+ else
{
M17N_OBJECT (fontset, free_fontset, MERROR_FONTSET);
+ M17N_OBJECT_REGISTER (fontset_table, 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);
}
}
- M17N_OBJECT_REF (fontset);
return fontset;
}
{
MSymbol sym = msymbol (name);
MFontset *copy = mplist_get (fontset_list, sym);
- MPlist *plist, *pl;
+ MPlist *plist, *pl, *p;
if (copy)
return NULL;
M17N_OBJECT (copy, free_fontset, MERROR_FONTSET);
+ M17N_OBJECT_REGISTER (fontset_table, copy);
copy->name = sym;
if (fontset->mdb)
copy->per_script = mplist ();
MPLIST_DO (plist, fontset->per_script)
{
- MPlist *new = mplist ();
+ MPlist *per_lang = mplist ();
+ mplist_add (copy->per_script, MPLIST_KEY (plist), per_lang);
MPLIST_DO (pl, MPLIST_PLIST (plist))
- mplist_add (new, MPLIST_KEY (pl), mplist_copy (MPLIST_PLIST (pl)));
- mplist_add (copy->per_script, MPLIST_KEY (plist), new);
+ {
+ MPlist *font_group = mplist ();
+
+ per_lang = mplist_add (per_lang, MPLIST_KEY (pl), font_group);
+ MPLIST_DO (p, MPLIST_PLIST (pl))
+ font_group = mplist_add (font_group, MPLIST_KEY (p),
+ mfont_copy (MPLIST_VAL (p)));
+ }
}
}
if (fontset->per_charset)
{
- copy->per_charset = mplist ();
- MPLIST_DO (plist, fontset->per_charset)
- mplist_add (copy->per_charset, MPLIST_KEY (plist),
- mplist_copy (MPLIST_PLIST (plist)));
+ MPlist *per_charset = mplist ();
+
+ copy->per_charset = per_charset;
+ MPLIST_DO (pl, fontset->per_charset)
+ {
+ MPlist *font_group = mplist ();
+
+ per_charset = mplist_add (per_charset, MPLIST_KEY (pl), font_group);
+ MPLIST_DO (p, MPLIST_PLIST (pl))
+ font_group = mplist_add (font_group, MPLIST_KEY (p),
+ mfont_copy (MPLIST_VAL (p)));
+ }
}
if (fontset->fallback)
- copy->fallback = mplist_copy (fontset->fallback);
+ {
+ MPlist *font_group = mplist ();
- copy->font_spec_list = fontset->font_spec_list;
- M17N_OBJECT_REF (copy->font_spec_list);
+ copy->fallback = font_group;
+ MPLIST_DO (p, fontset->fallback)
+ font_group = mplist_add (font_group, MPLIST_KEY (p),
+ mfont_copy (MPLIST_VAL (p)));
+ }
mplist_put (fontset_list, sym, copy);
- M17N_OBJECT_REF (copy);
return copy;
}
are removed from the group.
If $LAYOUTER_NAME is not @c Mnil, it must be a symbol representing
- a @ref flt (font layout table). In that case, if $FONT is
+ a @ref mdbFLT (font layout table). In that case, if $FONT is
selected for drawing an M-text, that font layout table is used to
generate a glyph code sequence from a character sequence.
¤¬Éé¤Ê¤é¤Ð¡¢ºÇÄã¤ÎÍ¥ÀèÅÙ¤ò»ý¤Ä¡£$HOW ¤¬ 0 ¤Ê¤é¤Ð¡¢$FONT
¤Ï´ØÏ¢ÉÕ¤±¤é¤ì¤¿¤â¤Î¤ËÂФ¹¤ëÍ£°ì¤ÎÍøÍѲÄǽ¤Ê¥Õ¥©¥ó¥È¤È¤Ê¤ê¡¢Â¾¤Î¥Õ¥©¥ó¥È¤Ï¥°¥ë¡¼¥×¤«¤é¼è¤ê½ü¤«¤ì¤ë¡£
- $LAYOUTER_NAME ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢@ref flt
+ $LAYOUTER_NAME ¤Ï @c Mnil ¤Ç¤¢¤ë¤«¡¢@ref mdbFLT
¡Ê¥Õ¥©¥ó¥È¥ì¥¤¥¢¥¦¥È¥Æ¡¼¥Ö¥ë¡Ë¤ò¼¨¤¹¥·¥ó¥Ü¥ë¤Ç¤¢¤ë¡£¥·¥ó¥Ü¥ë¤Ç¤¢¤ì¤Ð¡¢$FONT ¤òÍѤ¤¤Æ
M-text ¤òɽ¼¨¤¹¤ëºÝ¤Ë¤Ï¡¢¤½¤Î¥Õ¥©¥ó¥È¥ì¥¤¥¢¥¦¥È¥Æ¡¼¥Ö¥ë¤ò»È¤Ã¤Æʸ»úÎ󤫤饰¥ê¥Õ¥³¡¼¥ÉÎó¤òÀ¸À®¤¹¤ë¡£
MFont *spec, MSymbol layouter_name,
int how)
{
- MPlist *per_lang, *plist[3], *pl;
+ MPlist *per_lang, *plist[3];
MFont *font = NULL;
int i;
if (fontset->mdb)
load_fontset_contents (fontset);
- 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 ();
- *font = *spec;
- mplist_add (fontset->font_spec_list, Mt, font);
- }
-
i = 0;
if (script != Mnil)
{
layouter_name = Mt;
for (i--; i >= 0; i--)
{
+ font = mfont_copy (spec);
+ font->type = MFONT_TYPE_SPEC;
if (how == 1)
mplist_push (plist[i], layouter_name, font);
else if (how == -1)
mplist_add (plist[i], layouter_name, font);
else
{
+ MPlist *pl;
+
+ MPLIST_DO (pl, plist[i])
+ free (MPLIST_VAL (pl));
mplist_set (plist[i], Mnil, NULL);
mplist_add (plist[i], layouter_name, font);
}
}
if (script != Mnil)
{
- if (! fontset->per_script)
- return plist;
- pl = mplist_get (fontset->per_script, script);
- if (! pl)
+ pl = get_per_script (fontset, script);
+ if (MPLIST_TAIL_P (pl))
return plist;
if (language == Mt)
{
/***en
@brief Dump a fontset.
- The mdebug_dump_fontset () function prints fontset $FONTSET in a human readable
- way to the stderr. $INDENT specifies how many columns to indent
- the lines but the first one.
+ The mdebug_dump_fontset () function prints fontset $FONTSET in a
+ human readable way to the stderr or to what specified by the
+ environment variable MDEBUG_OUTPUT_FILE. $INDENT specifies how
+ many columns to indent the lines but the first one.
@return
This function returns $FONTSET. */
/***ja
@brief ¥Õ¥©¥ó¥È¥»¥Ã¥È¤ò¥À¥ó¥×¤¹¤ë.
- ´Ø¿ô mdebug_dump_face () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤ò stderr
- ¤Ë¿Í´Ö¤Ë²ÄÆɤʷÁ¤Ç°õºþ¤¹¤ë¡£ $INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
+ ´Ø¿ô mdebug_dump_face () ¤Ï¥Õ¥©¥ó¥È¥»¥Ã¥È $FONTSET ¤òɸ½à¥¨¥é¡¼½ÐÎÏ
+ ¤â¤·¤¯¤Ï´Ä¶ÊÑ¿ô MDEBUG_DUMP_FONT ¤Ç»ØÄꤵ¤ì¤¿¥Õ¥¡¥¤¥ë¤Ë¿Í´Ö¤Ë²ÄÆÉ
+ ¤Ê·Á¤Ç½ÐÎϤ¹¤ë¡£ $INDENT ¤Ï£²¹ÔÌܰʹߤΥ¤¥ó¥Ç¥ó¥È¤ò»ØÄꤹ¤ë¡£
@return
¤³¤Î´Ø¿ô¤Ï $FONTSET ¤òÊÖ¤¹¡£ */
memset (prefix, 32, indent);
prefix[indent] = 0;
- fprintf (stderr, "(fontset %s", fontset->name->name);
+ fprintf (mdebug__output, "(fontset %s", fontset->name->name);
if (fontset->per_script)
MPLIST_DO (plist, fontset->per_script)
{
- fprintf (stderr, "\n %s(%s", prefix, MPLIST_KEY (plist)->name);
+ fprintf (mdebug__output, "\n %s(%s", prefix, MPLIST_KEY (plist)->name);
MPLIST_DO (pl, MPLIST_PLIST (plist))
{
- fprintf (stderr, "\n %s(%s", prefix, MPLIST_KEY (pl)->name);
+ fprintf (mdebug__output, "\n %s(%s", prefix,
+ MPLIST_KEY (pl)->name);
MPLIST_DO (p, MPLIST_PLIST (pl))
{
- fprintf (stderr, "\n %s(%s ", prefix,
+ fprintf (mdebug__output, "\n %s(0x%X %s ", prefix,
+ (unsigned) MPLIST_VAL (p),
MPLIST_KEY (p)->name);
mdebug_dump_font (MPLIST_VAL (p));
- fprintf (stderr, ")");
+ fprintf (mdebug__output, ")");
}
- fprintf (stderr, ")");
+ fprintf (mdebug__output, ")");
}
- fprintf (stderr, ")");
+ fprintf (mdebug__output, ")");
}
if (fontset->per_charset)
MPLIST_DO (pl, fontset->per_charset)
{
- fprintf (stderr, "\n %s(%s", prefix, MPLIST_KEY (pl)->name);
+ fprintf (mdebug__output, "\n %s(%s", prefix, MPLIST_KEY (pl)->name);
MPLIST_DO (p, MPLIST_PLIST (pl))
{
- fprintf (stderr, "\n %s(%s ", prefix, MPLIST_KEY (p)->name);
+ fprintf (mdebug__output, "\n %s(%s ", prefix,
+ MPLIST_KEY (p)->name);
mdebug_dump_font (MPLIST_VAL (p));
- fprintf (stderr, ")");
+ fprintf (mdebug__output, ")");
}
- fprintf (stderr, ")");
+ fprintf (mdebug__output, ")");
}
if (fontset->fallback)
MPLIST_DO (p, fontset->fallback)
{
- fprintf (stderr, "\n %s(%s ", prefix, MPLIST_KEY (p)->name);
+ fprintf (mdebug__output, "\n %s(%s ", prefix, MPLIST_KEY (p)->name);
mdebug_dump_font (MPLIST_VAL (p));
- fprintf (stderr, ")");
+ fprintf (mdebug__output, ")");
}
- fprintf (stderr, ")");
+ fprintf (mdebug__output, ")");
return fontset;
}