/* m17n-flt.c -- Font Layout Table sub-module.
- Copyright (C) 2003, 2004, 2007
+ Copyright (C) 2003, 2004, 2007, 2008, 2009, 2010
National Institute of Advanced Industrial Science and Technology (AIST)
Registration Number H15PRO112
@brief FLT support for a window system.
This section defines the m17n FLT API concerning character
- layouting facility using FLT (Font Layout Table). */
+ layouting facility using FLT (Font Layout Table). The format of
+ FLT is described in @ref mdbFLT. */
+
+/***ja
+ @addtogroup m17nFLT
+ @brief ¥¦¥£¥ó¥É¥¦¥·¥¹¥Æ¥à¤Î¤¿¤á¤Î FLT ¥µ¥Ý¡¼¥È.
+
+ ¤³¤Î¥»¥¯¥·¥ç¥ó¤Ç¤Ï¡¢FLT (Font Layout Table)
+ ¤òÍѤ¤¤¿Ê¸»ú¥ì¥¤¥¢¥¦¥Èµ¡Ç½¤Ë´Ø¤¹¤ë m17n FLT API ¤òÄêµÁ¤¹¤ë¡£
+ FLT ¤Î·Á¼°¤Ï @ref mdbFLT ¤Ëµ½Ò¤µ¤ì¤Æ¤¤¤ë¡£ */
/*=*/
;; consume nothing.
OTF-COMMAND ::=
- 'otf:''SCRIPT'[':'['LANGSYS'][':'[GSUB-FEATURES][':'GPOS-FEATURES]]]
+ ':otf=''SCRIPT'[':'['LANGSYS'][':'[GSUB-FEATURES][':'GPOS-FEATURES]]]
;; Run the Open Type Layout Table on the current run. Succeed always,
-;; consume nothing.
+;; consume all glyphs in the current range.
SCRIPT ::= OTF-TAG
;; OTF's ScriptTag name (four letters) listed at:
*/
-static int mdebug_flag = MDEBUG_FONT_FLT;
+static int mdebug_flag = MDEBUG_FLT;
MSymbol Mfont, Mlayouter, Mcombining;
enum GlyphInfoMask
{
- CombiningCodeMask = 0xFFFFFFF,
- LeftPaddingMask = 1 << 28,
- RightPaddingMask = 1 << 29
+ CategoryCodeMask = 0x7F,
+ CombiningCodeMask = 0xFFFFFF,
+ CombinedMask = 1 << 28,
+ LeftPaddingMask = 1 << 29,
+ RightPaddingMask = 1 << 30
};
#define SET_GLYPH_INFO(g, mask, ctx, info) \
((g)->internal = (((g)->internal & ~(mask)) | (info)), \
(ctx)->check_mask |= (mask))
+#define GET_CATEGORY_CODE(g) ((g)->internal & CategoryCodeMask)
+#define SET_CATEGORY_CODE(g, code) \
+ ((g)->internal = (((g)->internal & ~(CombiningCodeMask | CombinedMask)) \
+ | (code)))
+#define GET_COMBINED(g) ((g)->internal & CombinedMask)
#define GET_COMBINING_CODE(g) ((g)->internal & CombiningCodeMask)
-#define SET_COMBINING_CODE(g, ctx, code) \
- SET_GLYPH_INFO (g, CombiningCodeMask, ctx, code)
+#define SET_COMBINING_CODE(g, ctx, code) \
+ SET_GLYPH_INFO (g, CombiningCodeMask | CombinedMask, ctx, \
+ (code) | CombinedMask)
#define GET_LEFT_PADDING(g) ((g)->internal & LeftPaddingMask)
#define SET_LEFT_PADDING(g, ctx, flag) \
SET_GLYPH_INFO (g, LeftPaddingMask, ctx, flag)
#define CMD_ID_TO_INDEX(id) (CMD_ID_OFFSET_INDEX - (id))
#define INDEX_TO_CMD_ID(idx) (CMD_ID_OFFSET_INDEX - (idx))
-static MSymbol Mcond, Mrange, Mfont_facility;
+static MSymbol Mcond, Mrange, Mfont_facility, Mequal;
#define GLYPH_CODE_P(code) \
((code) >= GLYPH_CODE_MIN && (code) <= GLYPH_CODE_MAX)
#define UPDATE_CLUSTER_RANGE(ctx, g) \
do { \
- if ((ctx)->cluster_begin_idx >= 0) \
- { \
- if (ctx->cluster_begin_pos > (g)->from) \
- ctx->cluster_begin_pos = (g)->from; \
- if (ctx->cluster_end_pos < (g)->to) \
- ctx->cluster_end_pos = (g)->to; \
- } \
+ if (ctx->cluster_begin_pos > (g)->from) \
+ ctx->cluster_begin_pos = (g)->from; \
+ if (ctx->cluster_end_pos < (g)->to) \
+ ctx->cluster_end_pos = (g)->to; \
} while (0)
enum FontLayoutCmdRuleSrcType
struct {
int from, to;
} range;
- int supported_glyph;
- MFLTOtfSpec otf_spec;
+ struct {
+ int len;
+ MPlist *codes;
+ MFLTOtfSpec otf_spec;
+ } facility;
} src;
int n_cmds;
FontLayoutCmdTypeRule,
FontLayoutCmdTypeCond,
FontLayoutCmdTypeOTF,
+ FontLayoutCmdTypeOTFCategory,
FontLayoutCmdTypeMAX
};
} body;
} FontLayoutCmd;
+typedef struct
+{
+ int size;
+ unsigned int *tag;
+ char *code;
+} FeatureCodeTable;
+
+typedef struct
+{
+ MCharTable *table;
+ FeatureCodeTable feature_table;
+ /* Non-null if the table must be re-configured by OTF specs included
+ in the definition. */
+ MPlist *definition;
+} FontLayoutCategory;
+
typedef struct
{
- MCharTable *category;
+ FontLayoutCategory *category;
int size, inc, used;
FontLayoutCmd *cmds;
} FontLayoutStage;
MSymbol registry;
MFLTOtfSpec otf;
MDatabase *mdb;
- MCharTable *coverage;
+ FontLayoutCategory *coverage;
MPlist *stages;
+ int need_config;
+ /* Font for which coverage or some of categories are configured. */
+ MSymbol font_id;
};
/* Font layout table loader */
static int parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec);
+static void
+apply_otf_feature (MFLTFont *font, MFLTOtfSpec *spec,
+ int from, int to, MCharTable *table, int category)
+{
+ unsigned char *buf;
+ int i;
+
+ if (! mflt_iterate_otf_feature)
+ return;
+ buf = alloca (to + 1 - from);
+ memset (buf, 0, to + 1 - from);
+ if (mflt_iterate_otf_feature (font, spec, from, to, buf) < 0)
+ return;
+ for (i = to - from; i >= 0; i--)
+ if (buf[i])
+ mchartable_set (table, from + i, (void *) category);
+}
+
+static unsigned int gen_otf_tag (char *p, int shift);
+
/* Load a category table from PLIST. PLIST has this form:
PLIST ::= ( FROM-CODE TO-CODE ? CATEGORY-CHAR ) *
*/
-static MCharTable *
-load_category_table (MPlist *plist)
+static FontLayoutCategory *
+load_category_table (MPlist *plist, MFLTFont *font)
{
+ FontLayoutCategory *category;
MCharTable *table;
+ MPlist *feature_table_head = NULL;
+ int feature_table_size = 0;
+ MPlist *p;
+ int need_otf = 0;
table = mchartable (Minteger, (void *) 0);
-
- MPLIST_DO (plist, plist)
+ MPLIST_DO (p, plist)
{
MPlist *elt;
int from, to, category_code;
- if (! MPLIST_PLIST (plist))
- MERROR (MERROR_FONT, NULL);
- elt = MPLIST_PLIST (plist);
+ if (! MPLIST_PLIST_P (p))
+ MERROR_GOTO (MERROR_FLT, end);
+ elt = MPLIST_PLIST (p);
+ if (MPLIST_SYMBOL_P (elt))
+ {
+ MPlist *next;
+
+ if (! mflt_enable_new_feature)
+ {
+ M17N_OBJECT_UNREF (table);
+ return NULL;
+ }
+ next = MPLIST_NEXT (elt);
+ if (! MPLIST_INTEGER_P (next))
+ MERROR_GOTO (MERROR_FLT, end);
+ if (! feature_table_head)
+ feature_table_head = p;
+ feature_table_size++;
+ continue;
+ }
if (! MPLIST_INTEGER_P (elt))
- MERROR (MERROR_FONT, NULL);
+ MERROR_GOTO (MERROR_FLT, end);
from = MPLIST_INTEGER (elt);
elt = MPLIST_NEXT (elt);
if (! MPLIST_INTEGER_P (elt))
- MERROR (MERROR_FONT, NULL);
+ MERROR_GOTO (MERROR_FLT, end);
to = MPLIST_INTEGER (elt);
elt = MPLIST_NEXT (elt);
if (MPLIST_TAIL_P (elt))
category_code = to;
to = from;
}
+ else if (MPLIST_SYMBOL_P (elt))
+ {
+ if (! mflt_enable_new_feature)
+ {
+ M17N_OBJECT_UNREF (table);
+ return NULL;
+ }
+ if (font)
+ {
+ MFLTOtfSpec spec;
+ if (parse_otf_command (MPLIST_SYMBOL (elt), &spec) < 0)
+ MERROR_GOTO (MERROR_FLT, end);
+ elt = MPLIST_NEXT (elt);
+ if (! MPLIST_INTEGER_P (elt))
+ MERROR_GOTO (MERROR_FLT, end);
+ category_code = MPLIST_INTEGER (elt);
+ if (! isalnum (category_code))
+ MERROR_GOTO (MERROR_FLT, end);
+ apply_otf_feature (font, &spec, from, to, table, category_code);
+ }
+ else
+ need_otf = 1;
+ continue;
+ }
else
{
if (! MPLIST_INTEGER_P (elt))
- MERROR (MERROR_FONT, NULL);
+ MERROR_GOTO (MERROR_FLT, end);
category_code = MPLIST_INTEGER (elt);
}
if (! isalnum (category_code))
- MERROR (MERROR_FONT, NULL);
+ MERROR_GOTO (MERROR_FLT, end);
if (from == to)
mchartable_set (table, from, (void *) category_code);
mchartable_set_range (table, from, to, (void *) category_code);
}
- return table;
+ end:
+ category = calloc (1, sizeof (FontLayoutCategory));
+ category->table = table;
+ if (need_otf)
+ {
+ category->definition = plist;
+ M17N_OBJECT_REF (plist);
+ }
+ else
+ category->definition = NULL;
+ if (feature_table_head)
+ {
+ int i = 0;
+ category->feature_table.size = feature_table_size;
+ category->feature_table.tag = malloc (sizeof (unsigned int)
+ * feature_table_size);
+ category->feature_table.code = malloc (feature_table_size);
+
+ MPLIST_DO (p, feature_table_head)
+ {
+ MPlist *elt;
+ MSymbol feature;
+ if (! MPLIST_PLIST_P (p))
+ continue;
+ elt = MPLIST_PLIST (p);
+ if (! MPLIST_SYMBOL_P (elt))
+ continue;
+ feature = MPLIST_SYMBOL (elt);
+ elt = MPLIST_NEXT (elt);
+ if (! MPLIST_INTEGER_P (elt))
+ continue;
+ category->feature_table.tag[i]
+ = gen_otf_tag (MSYMBOL_NAME (feature), 7);
+ category->feature_table.code[i] = MPLIST_INTEGER (elt);
+ i++;
+ }
+ }
+ return category;
+}
+
+#define ref_category_table(CATEGORY) M17N_OBJECT_REF ((CATEGORY)->table)
+
+static void
+unref_category_table (FontLayoutCategory *category)
+{
+ M17N_OBJECT_UNREF (category->table);
+ if (! category->table)
+ {
+ if (category->definition)
+ M17N_OBJECT_UNREF (category->definition);
+ if (category->feature_table.size > 0)
+ {
+ free (category->feature_table.tag);
+ free (category->feature_table.code);
+ }
+ free (category);
+ }
}
static unsigned int
-gen_otf_tag (char *p)
+gen_otf_tag (char *p, int shift)
{
unsigned int tag = 0;
int i;
for (i = 0; i < 4 && *p; i++, p++)
- tag = (tag << 8) | *p;
+ tag = (tag << shift) | *p;
for (; i < 4; i++)
- tag = (tag << 8) | 0x20;
+ tag = (tag << shift) | 0x20;
return tag;
}
{
if (negative++ == 0)
buf[i++] = 0xFFFFFFFF;
- buf[i++] = gen_otf_tag (p + 1), p += 6;
+ buf[i++] = gen_otf_tag (p + 1, 8), p += 6;
}
else
- buf[i++] = gen_otf_tag (p), p += 5;
+ buf[i++] = gen_otf_tag (p, 8), p += 5;
}
buf[i] = 0;
}
+/* SYMBOL's name features[0] for checking for applying
+ features[1] GSUB GPOS GSUB GPOS
+ ------------- ------------------ ------------- ------------
+ SCRIPT [-1,0] [-1,0] any | any all all
+ SCRIPT= NULL [-1,0] none & 1 none all
+ SCRIPT+ [-1,0] NULL 1 & none all none
+ SCRIPT=+ NULL NULL none & none none none
+ SCRIPT=F1 [F1,0] [-1,0] F1 & 1 F1 all
+ SCRIPT+F1 [-1][0] [F1,0] 1 & F1 none F1
+ SCRIPT=F1+ [F1,0] NULL F1 & none F1 none
+ SCRIPT=~F2 [-1,F2,0] [-1,0] ~F2 & 1 all~F2 all
+ SCRIPT=F1,~F2 [F1,-1,F2,0][-1,0] F1&~F2 & 1 F1 (*1) all
+
+ (*1) Invalid specification
+ */
+
static int
parse_otf_command (MSymbol symbol, MFLTOtfSpec *spec)
{
char *str = MSYMBOL_NAME (symbol);
char *end = str + MSYMBOL_NAMELEN (symbol);
unsigned int script, langsys;
- char *gsub, *gpos;
- int gsub_count = 0, gpos_count = 0;
+ char *features[3];
+ int feature_count[2]; /* [0]:GSUB, [1]:GPOS */
+ int i;
char *p;
memset (spec, 0, sizeof (MFLTOtfSpec));
spec->sym = symbol;
- str += 5; /* skip the heading ":otf=" */
- script = gen_otf_tag (str);
+ str += 5; /* skip the heading ":otf=" or ":otf?" */
+ if (str[-1] == '?')
+ {
+ if (! mflt_enable_new_feature)
+ /* The client can't use this command. */
+ return -1;
+ if (! *str)
+ /* This is a spec to reset category codes. */
+ return 0;
+ }
+ spec->script = gen_otf_tag (str, 8);
str += 4;
if (*str == '/')
{
- langsys = gen_otf_tag (str);
+ spec->langsys = gen_otf_tag (str, 8);
str += 4;
}
else
- langsys = 0;
- gsub = str;
+ spec->langsys = 0;
+ features[0] = str;
if (*str != '=')
/* Apply all GSUB features. */
- gsub_count = 1;
+ feature_count[0] = -1;
else
{
p = str + 1;
- str = otf_count_features (p, end, '+', &gsub_count);
+ str = otf_count_features (p, end, '+', feature_count);
if (! str)
MERROR (MERROR_FLT, -1);
}
- gpos = str;
+ features[1] = str;
if (*str != '+')
/* Apply all GPOS features. */
- gpos_count = 1;
+ feature_count[1] = -1;
else
{
p = str + 1;
- str = otf_count_features (p, end, '\0', &gpos_count);
+ str = otf_count_features (p, end, '\0', feature_count + 1);
if (! str)
MERROR (MERROR_FLT, -1);
}
-
- spec->script = script;
- spec->langsys = langsys;
- if (gsub_count > 0)
- {
- spec->features[0] = malloc (sizeof (int) * (gsub_count + 1));
- if (! spec->features[0])
- return -2;
- if (*gsub == '=')
- otf_store_features (gsub + 1, gpos, spec->features[0]);
- else
- spec->features[0][0] = 0xFFFFFFFF, spec->features[0][1] = 0;
- }
- if (gpos_count > 0)
- {
- spec->features[1] = malloc (sizeof (int) * (gpos_count + 1));
- if (! spec->features[1])
- {
- if (spec->features[0])
- free (spec->features[0]);
+ features[2] = str;
+ for (i = 0; i < 2; i++)
+ if (feature_count[i])
+ {
+ spec->features[i] = malloc (sizeof (int)
+ * (feature_count[i] < 0 ? 2
+ : feature_count[i] + 1));
+ if (! spec->features[i])
return -2;
- }
- if (*gpos == '+')
- otf_store_features (gpos + 1, str, spec->features[1]);
- else
- spec->features[1][0] = 0xFFFFFFFF, spec->features[1][1] = 0;
- }
+ if (feature_count[i] > 0)
+ otf_store_features (features[i] + 1, features[i + 1],
+ spec->features[i]);
+ else
+ spec->features[i][0] = 0xFFFFFFFF, spec->features[i][1] = 0;
+ }
+
return 0;
}
result = parse_otf_command (sym, &cmd->body.otf);
if (result == -2)
return result;
- cmd->type = FontLayoutCmdTypeOTF;
+ cmd->type = (name[4] == '?' ? FontLayoutCmdTypeOTFCategory
+ : FontLayoutCmdTypeOTF);
return 0;
}
/* PLIST ::= ( cond ... ) | ( STRING ... ) | ( INTEGER ... )
| ( ( INTEGER INTEGER ) ... )
| ( ( range INTEGER INTEGER ) ... )
+ | ( ( SYMBOL STRING ) ... )
| ( ( font-facilty [ INTEGER ] ) ... )
| ( ( font-facilty OTF-SPEC ) ... ) */
MPlist *elt = MPLIST_PLIST (plist);
}
else if (MPLIST_PLIST_P (elt))
{
- MPlist *pl = MPLIST_PLIST (elt);
+ MPlist *pl = MPLIST_PLIST (elt), *p;
int size = MPLIST_LENGTH (pl);
if (MPLIST_INTEGER_P (pl))
= (unsigned) MPLIST_INTEGER (pl);
}
}
- else if (MPLIST_SYMBOL_P (pl) && size == 3)
- {
- if (MPLIST_SYMBOL (pl) != Mrange)
- MERROR (MERROR_FLT, INVALID_CMD_ID);
- cmd->body.rule.src_type = SRC_RANGE;
- pl = MPLIST_NEXT (pl);
- if (! MPLIST_INTEGER_P (pl))
- MERROR (MERROR_DRAW, INVALID_CMD_ID);
- cmd->body.rule.src.range.from
- = (unsigned) MPLIST_INTEGER (pl);
- pl = MPLIST_NEXT (pl);
- if (! MPLIST_INTEGER_P (pl))
- MERROR (MERROR_DRAW, INVALID_CMD_ID);
- cmd->body.rule.src.range.to
- = (unsigned) MPLIST_INTEGER (pl);
- }
- else if (MPLIST_SYMBOL_P (pl) && size <= 2)
+ else if (MPLIST_SYMBOL_P (pl))
{
- if (MPLIST_SYMBOL (pl) != Mfont_facility)
- MERROR (MERROR_FLT, INVALID_CMD_ID);
- pl = MPLIST_NEXT (pl);
- if (MPLIST_SYMBOL_P (pl))
+ if (MPLIST_SYMBOL (pl) == Mrange)
{
- MSymbol sym = MPLIST_SYMBOL (pl);
- char *otf_spec = MSYMBOL_NAME (sym);
-
- if (otf_spec[0] == ':' && otf_spec[1] == 'o'
- && otf_spec[2] == 't' && otf_spec[3] == 'f')
- parse_otf_command (sym, &cmd->body.rule.src.otf_spec);
- else
+ if (size != 3)
MERROR (MERROR_FLT, INVALID_CMD_ID);
- cmd->body.rule.src_type = SRC_OTF_SPEC;
+ cmd->body.rule.src_type = SRC_RANGE;
+ pl = MPLIST_NEXT (pl);
+ if (! MPLIST_INTEGER_P (pl))
+ MERROR (MERROR_DRAW, INVALID_CMD_ID);
+ cmd->body.rule.src.range.from
+ = (unsigned) MPLIST_INTEGER (pl);
+ pl = MPLIST_NEXT (pl);
+ if (! MPLIST_INTEGER_P (pl))
+ MERROR (MERROR_DRAW, INVALID_CMD_ID);
+ cmd->body.rule.src.range.to
+ = (unsigned) MPLIST_INTEGER (pl);
}
- else
+ else if (MPLIST_SYMBOL (pl) == Mfont_facility)
{
- cmd->body.rule.src_type = SRC_HAS_GLYPH;
- if (MPLIST_INTEGER_P (pl))
- cmd->body.rule.src.supported_glyph
- = MPLIST_INTEGER (pl);
+ FontLayoutCmdRule *rule = &cmd->body.rule;
+
+ pl = MPLIST_NEXT (pl);
+ if (MPLIST_SYMBOL_P (pl))
+ {
+ MSymbol sym = MPLIST_SYMBOL (pl);
+ char *otf_spec = MSYMBOL_NAME (sym);
+
+ if (otf_spec[0] == ':' && otf_spec[1] == 'o'
+ && otf_spec[2] == 't' && otf_spec[3] == 'f')
+ parse_otf_command (sym, &rule->src.facility.otf_spec);
+ else
+ MERROR (MERROR_FLT, INVALID_CMD_ID);
+ rule->src_type = SRC_OTF_SPEC;
+ pl = MPLIST_NEXT (pl);
+ }
+ else if (MPLIST_TAIL_P (pl))
+ MERROR (MERROR_FLT, INVALID_CMD_ID);
else
- cmd->body.rule.src.supported_glyph = -1;
+ rule->src_type = SRC_HAS_GLYPH;
+ rule->src.facility.len = 0;
+ MPLIST_DO (p, pl)
+ {
+ if (! MPLIST_INTEGER_P (p)
+ && (MPLIST_SYMBOL_P (p)
+ ? MPLIST_SYMBOL (p) != Mequal
+ : 1))
+ MERROR (MERROR_FLT, INVALID_CMD_ID);
+ rule->src.facility.len++;
+ }
+ rule->src.facility.codes = pl;
+ M17N_OBJECT_REF (pl);
}
}
else
&& ((name[0] == 'o' && name[1] == 't'
&& name[2] == 'f' && name[3] == ':')
|| (name[0] == ':' && name[1] == 'o' && name[2] == 't'
- && name[3] == 'f' && name[4] == '=')))
+ && name[3] == 'f' && (name[4] == '=' || name[4] == '?'))))
{
result = load_otf_command (&cmd, sym);
if (result < 0)
}
else if (cmd->type == FontLayoutCmdTypeCond)
free (cmd->body.cond.cmd_ids);
- else if (cmd->type == FontLayoutCmdTypeOTF)
+ else if (cmd->type == FontLayoutCmdTypeOTF
+ || cmd->type == FontLayoutCmdTypeOTFCategory)
{
if (cmd->body.otf.features[0])
free (cmd->body.otf.features[0]);
load_flt (MFLT *flt, MPlist *key_list)
{
MPlist *top, *plist, *pl, *p;
- MCharTable *category = NULL;
+ FontLayoutCategory *category = NULL;
MSymbol sym;
if (key_list)
if (sym == Mcategory)
{
if (category)
- M17N_OBJECT_UNREF (category);
+ unref_category_table (category);
else if (flt->coverage)
{
category = flt->coverage;
+ ref_category_table (category);
continue;
}
- category = load_category_table (pl);
+ category = load_category_table (pl, NULL);
+ if (! category)
+ goto err;
if (! flt->coverage)
{
flt->coverage = category;
- M17N_OBJECT_REF (category);
+ ref_category_table (category);
}
+ if (category->definition)
+ flt->need_config = 1;
}
else if (sym == Mgenerator)
{
if (! stage)
break;
stage->category = category;
- M17N_OBJECT_REF (category);
+ M17N_OBJECT_REF (category->table);
if (! flt->stages)
flt->stages = mplist ();
mplist_add (flt->stages, Mt, stage);
}
}
if (category)
- M17N_OBJECT_UNREF (category);
- M17N_OBJECT_UNREF (top);
+ unref_category_table (category);
+ err:
if (! MPLIST_TAIL_P (plist))
{
+ M17N_OBJECT_UNREF (top);
M17N_OBJECT_UNREF (flt->stages);
MERROR (MERROR_FLT, -1);
}
+ M17N_OBJECT_UNREF (top);
return 0;
}
static void
-free_flt_stage (FontLayoutStage *stage)
+free_flt_stage (MFLT *flt, FontLayoutStage *stage)
{
int i;
- M17N_OBJECT_UNREF (stage->category);
- for (i = 0; i < stage->used; i++)
- free_flt_command (stage->cmds + i);
- MLIST_FREE1 (stage, cmds);
+ unref_category_table (stage->category);
+ if (! flt->font_id)
+ {
+ for (i = 0; i < stage->used; i++)
+ free_flt_command (stage->cmds + i);
+ MLIST_FREE1 (stage, cmds);
+ }
free (stage);
}
MFLT *flt = MPLIST_VAL (plist);
if (flt->coverage)
- M17N_OBJECT_UNREF (flt->coverage);
+ unref_category_table (flt->coverage);
if (flt->stages)
{
MPLIST_DO (pl, MPLIST_NEXT (flt->stages))
- free_flt_stage (MPLIST_VAL (pl));
+ free_flt_stage (flt, MPLIST_VAL (pl));
M17N_OBJECT_UNREF (flt->stages);
}
+ free (flt);
+ MPLIST_VAL (plist) = NULL;
}
M17N_OBJECT_UNREF (flt_list);
}
{
if (MPLIST_TAIL_P (flt_list))
{
- flt_min_coverage = mchartable_min_char (flt->coverage);
- flt_max_coverage = mchartable_max_char (flt->coverage);
+ flt_min_coverage = mchartable_min_char (flt->coverage->table);
+ flt_max_coverage = mchartable_max_char (flt->coverage->table);
}
else
{
int c;
- c = mchartable_min_char (flt->coverage);
+ c = mchartable_min_char (flt->coverage->table);
if (flt_min_coverage > c)
flt_min_coverage = c;
- c = mchartable_max_char (flt->coverage);
+ c = mchartable_max_char (flt->coverage->table);
if (flt_max_coverage < c)
flt_max_coverage = c;
}
/* Pointer to the current stage. */
FontLayoutStage *stage;
+ /* Pointer to the category table of the next stage or NULL if none. */
+ FontLayoutCategory *category;
+
/* Pointer to the font. */
MFLTFont *font;
table into this array. An element is a category letter used for
a regular expression matching. */
char *encoded;
+ int encoded_offset;
int *match_indices;
int code_offset;
int cluster_begin_idx;
} FontLayoutContext;
static int run_command (int, int, int, int, FontLayoutContext *);
+static int run_otf (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
+static int try_otf (int, MFLTOtfSpec *, int, int, FontLayoutContext *);
#define NMATCH 20
int consumed;
int i;
int orig_from = from;
+ int need_cluster_update = 0;
- if (rule->src_type == SRC_SEQ)
- {
- int len;
-
- len = rule->src.seq.n_codes;
- if (len > (to - from))
- return 0;
- for (i = 0; i < len; i++)
- if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->code)
- break;
- if (i < len)
- return 0;
- to = from + len;
- if (MDEBUG_FLAG () > 2)
- MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
- rule->src.seq.codes[0]);
- }
- else if (rule->src_type == SRC_RANGE)
- {
- int head;
-
- if (from >= to)
- return 0;
- head = GREF (ctx->in, from)->code;
- if (head < rule->src.range.from || head > rule->src.range.to)
- return 0;
- ctx->code_offset = head - rule->src.range.from;
- to = from + 1;
- if (MDEBUG_FLAG () > 2)
- MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
- rule->src.range.from, rule->src.range.to);
- }
- else if (rule->src_type == SRC_REGEX)
+ if (rule->src_type == SRC_REGEX)
{
regmatch_t pmatch[NMATCH];
char saved_code;
if (from > to)
return 0;
- saved_code = ctx->encoded[to];
- ctx->encoded[to] = '\0';
+ saved_code = ctx->encoded[to - ctx->encoded_offset];
+ ctx->encoded[to - ctx->encoded_offset] = '\0';
result = regexec (&(rule->src.re.preg),
- ctx->encoded + from, NMATCH, pmatch, 0);
+ ctx->encoded + (from - ctx->encoded_offset),
+ NMATCH, pmatch, 0);
if (result == 0 && pmatch[0].rm_so == 0)
{
if (MDEBUG_FLAG () > 2)
MDEBUG_PRINT5 ("\n [FLT] %*s(REGEX \"%s\" \"%s\" %d", depth, "",
rule->src.re.pattern,
- ctx->encoded + from,
+ ctx->encoded + (from - ctx->encoded_offset),
pmatch[0].rm_eo);
- ctx->encoded[to] = saved_code;
+ ctx->encoded[to - ctx->encoded_offset] = saved_code;
for (i = 0; i < NMATCH; i++)
{
if (pmatch[i].rm_so < 0)
}
else
{
- ctx->encoded[to] = saved_code;
+ ctx->encoded[to - ctx->encoded_offset] = saved_code;
return 0;
}
+ need_cluster_update = 1;
+ }
+ else if (rule->src_type == SRC_SEQ)
+ {
+ int len;
+
+ len = rule->src.seq.n_codes;
+ if (len > (to - from))
+ return 0;
+ for (i = 0; i < len; i++)
+ if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->c)
+ break;
+ if (i < len)
+ return 0;
+ to = from + len;
+ if (MDEBUG_FLAG () > 2)
+ MDEBUG_PRINT3 ("\n [FLT] %*s(SEQ 0x%X", depth, "",
+ rule->src.seq.codes[0]);
+ need_cluster_update = 1;
+ }
+ else if (rule->src_type == SRC_RANGE)
+ {
+ int head;
+
+ if (from >= to)
+ return 0;
+ head = GREF (ctx->in, from)->c;
+ if (head < rule->src.range.from || head > rule->src.range.to)
+ return 0;
+ ctx->code_offset = head - rule->src.range.from;
+ to = from + 1;
+ if (MDEBUG_FLAG () > 2)
+ MDEBUG_PRINT4 ("\n [FLT] %*s(RANGE 0x%X-0x%X", depth, "",
+ rule->src.range.from, rule->src.range.to);
+ need_cluster_update = 1;
}
else if (rule->src_type == SRC_INDEX)
{
return 0;
to = ctx->match_indices[rule->src.match_idx * 2 + 1];
if (MDEBUG_FLAG () > 2)
- MDEBUG_PRINT3 ("\n [FLT] %*s(INDEX %d", depth, "", rule->src.match_idx);
+ MDEBUG_PRINT3 ("\n [FLT] %*s(SUBPART %d", depth, "",
+ rule->src.match_idx);
+ need_cluster_update = 1;
}
- else if (rule->src_type == SRC_HAS_GLYPH)
+ else if (rule->src_type == SRC_HAS_GLYPH
+ || rule->src_type == SRC_OTF_SPEC)
{
- int encoded;
- unsigned code;
+ static MFLTGlyphString gstring;
+ MPlist *p;
+ int idx;
+
+ if (rule->src.facility.len > 0)
+ {
+ if (! gstring.glyph_size)
+ {
+ gstring.glyph_size = ctx->in->glyph_size;
+ gstring.glyphs = calloc (rule->src.facility.len,
+ gstring.glyph_size);
+ gstring.allocated = rule->src.facility.len;
+ gstring.used = rule->src.facility.len;
+ }
+ else if (rule->src.facility.len < gstring.allocated)
+ {
+ gstring.glyphs = realloc (gstring.glyphs,
+ gstring.glyph_size
+ * rule->src.facility.len);
+ gstring.allocated = rule->src.facility.len;
+ gstring.used = rule->src.facility.len;
+ }
+
+ for (i = 0, p = rule->src.facility.codes, idx = from;
+ i < rule->src.facility.len; i++, p = MPLIST_NEXT (p))
+ {
+ if (MPLIST_INTEGER_P (p))
+ {
+ GREF (&gstring, i)->c = MPLIST_INTEGER (p);
+ GREF (&gstring, i)->encoded = 0;
+ }
+ else
+ {
+ GREF (&gstring, i)->c = GREF (ctx->in, idx)->code;
+ GREF (&gstring, i)->encoded = GREF (ctx->in, idx)->encoded;
+ idx++;
+ }
+ }
+ }
- if (rule->src.supported_glyph < 0)
+ if (MDEBUG_FLAG () > 2)
{
- if (from >= to)
- return 0;
- code = GREF (ctx->in, from)->code;
- to = from + 1;
- encoded = GREF (ctx->in, from)->encoded;
+ if (rule->src_type == SRC_HAS_GLYPH)
+ MDEBUG_PRINT2 ("\n [FLT] %*s(HAS-GLYPH", depth, "");
+ else
+ MDEBUG_PRINT2 ("\n [FLT] %*s(OTF-SPEC", depth, "");
+ for (i = 0; i < rule->src.facility.len; i++)
+ MDEBUG_PRINT1 (" %04X", GREF (&gstring, i)->code);
}
- else
+ if (ctx->font->get_glyph_id (ctx->font, &gstring, 0,
+ rule->src.facility.len) < 0)
{
- code = rule->src.supported_glyph;
- to = from;
- encoded = 0;
+ MDEBUG_PRINT (") FAIL!");
+ return 0;
}
- if (! encoded)
+ if (rule->src_type == SRC_OTF_SPEC)
{
- static MFLTGlyphString gstring;
+ MFLTOtfSpec *spec = &rule->src.facility.otf_spec;
- if (! gstring.glyph_size)
+ if (! ctx->font->check_otf)
{
- gstring.glyph_size = ctx->in->glyph_size;
- gstring.glyphs = calloc (1, gstring.glyph_size);
- gstring.allocated = 1;
- gstring.used = 1;
+ if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
+ || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
+ return 0;
+ }
+ else
+ {
+ if (rule->src.facility.len == 0)
+ {
+ if (! ctx->font->check_otf (ctx->font, spec))
+ return 0;
+ }
+ else
+ {
+ int prev_out_used = ctx->out->used, out_used;
+ MFLTGlyphAdjustment *adjustment;
+
+ adjustment = alloca ((sizeof *adjustment)
+ * (ctx->out->allocated - ctx->out->used));
+ if (! adjustment)
+ MERROR (MERROR_FLT, -1);
+ memset (adjustment, 0,
+ (sizeof *adjustment)
+ * (ctx->out->allocated - ctx->out->used));
+ ctx->font->drive_otf (ctx->font, &rule->src.facility.otf_spec,
+ &gstring, 0, rule->src.facility.len,
+ ctx->out,
+ adjustment);
+ out_used = ctx->out->used;
+ ctx->out->used = prev_out_used;
+ if (rule->src.facility.len == out_used - prev_out_used)
+ {
+ for (i = prev_out_used; i < out_used; i++)
+ {
+ if (GREF (&gstring, i - prev_out_used)->code
+ != GREF (ctx->out, i)->code)
+ break;
+ if (adjustment[i - prev_out_used].set)
+ break;
+ }
+ if (i == out_used)
+ return 0;
+ }
+ }
}
- gstring.glyphs[0].code = code;
- if (ctx->font->get_glyph_id (ctx->font, &gstring, 0, 1) < 0
- || ! gstring.glyphs[0].encoded)
- return 0;
}
}
- else if (rule->src_type == SRC_OTF_SPEC)
- {
- MFLTOtfSpec *spec = &rule->src.otf_spec;
- if (! ctx->font->check_otf)
+ if (need_cluster_update && ctx->cluster_begin_idx >= 0)
+ {
+ for (i = from; i < to; i++)
{
- if ((spec->features[0] && spec->features[0][0] != 0xFFFFFFFF)
- || (spec->features[1] && spec->features[1][0] != 0xFFFFFFFF))
- return 0;
+ MFLTGlyph *g = GREF (ctx->in, i);
+ UPDATE_CLUSTER_RANGE (ctx, g);
}
- else if (! ctx->font->check_otf (ctx->font, spec))
- return 0;
}
consumed = 0;
return (pos);
}
+static void
+decode_packed_otf_tag (FontLayoutContext *ctx, MFLTGlyphString *gstring,
+ int from, int to, FontLayoutCategory *category)
+{
+ for (; from < to; from++)
+ {
+ MFLTGlyph *g = GREF (gstring, from);
+ unsigned int tag = g->internal & 0xFFFFFFF;
+ char enc;
+
+ if (GET_COMBINED (g))
+ continue;
+ if (! category)
+ {
+ SET_CATEGORY_CODE (g, 0);
+ continue;
+ }
+ enc = '\0';
+ if (tag & 0xFFFFF80)
+ {
+ int i;
+
+ /* Clear the feature tag code. */
+ g->internal &= ~0xFFFFFFF;
+ for (i = 0; i < category->feature_table.size; i++)
+ if (category->feature_table.tag[i] == tag)
+ {
+ enc = category->feature_table.code[i];
+ if (ctx->in == gstring)
+ ctx->encoded[from - ctx->encoded_offset] = enc;
+ break;
+ }
+ }
+ if (! enc)
+ enc = (g->c > 0 ? (int) mchartable_lookup (category->table, g->c)
+ : g->c == 0 ? 1 : ' ');
+ SET_CATEGORY_CODE (g, enc);
+ }
+}
+
static int
run_otf (int depth,
MFLTOtfSpec *otf_spec, int from, int to, FontLayoutContext *ctx)
adjustment);
if (to < 0)
return to;
+ decode_packed_otf_tag (ctx, ctx->out, from_idx, ctx->out->used,
+ ctx->category);
out_len = ctx->out->used - from_idx;
if (otf_spec->features[1])
{
g->xadv += a->xadv;
g->yadv += a->yadv;
}
- if (a->xoff || a->yoff)
+ if (a->xoff || a->yoff || a->back)
{
int j;
MFLTGlyph *gg = PREV (ctx->out, g);
g->xoff = a->xoff;
g->yoff = a->yoff;
+ g->lbearing += a->xoff;
+ g->rbearing += a->xoff;
+ g->ascent -= a->yoff;
+ g->descent -= a->yoff;
while (aa->back > 0)
{
for (j = 0; j < aa->back;
j++, gg = PREV (ctx->out, gg))
- g->xoff -= gg->xadv;
+ {
+ g->xoff -= gg->xadv;
+ g->lbearing -= gg->xadv;
+ g->rbearing -= gg->xadv;
+ }
aa = aa - aa->back;
g->xoff += aa->xoff;
g->yoff += aa->yoff;
+ g->lbearing += aa->xoff;
+ g->rbearing += aa->xoff;
+ g->ascent -= aa->yoff;
+ g->descent -= aa->yoff;
}
}
g->adjusted = 1;
return to;
}
+static int
+try_otf (int depth, MFLTOtfSpec *otf_spec, int from, int to,
+ FontLayoutContext *ctx)
+{
+ MFLTFont *font = ctx->font;
+
+ if (MDEBUG_FLAG () > 2)
+ MDEBUG_PRINT3 ("\n [FLT] %*s%s", depth, "", MSYMBOL_NAME (otf_spec->sym));
+
+ if (! otf_spec->features[0] && ! otf_spec->features[1])
+ {
+ /* Reset categories. */
+ MCharTable *table = ctx->category->table;
+ int i;
+
+ for (i = from; i < to; i++)
+ {
+ MFLTGlyph *g = GREF (ctx->in, i);
+
+ if (! GET_COMBINED (g))
+ {
+ char enc = (GET_ENCODED (g)
+ ? (g->c > 0 ? (int) mchartable_lookup (table, g->c)
+ : 1)
+ : g->code
+ ? (int) mchartable_lookup (table, g->code)
+ : ' ');
+ SET_CATEGORY_CODE (g, enc);
+ ctx->encoded[i - ctx->encoded_offset] = enc;
+ }
+ }
+ return from;
+ }
+
+ if (ctx->stage->category->feature_table.size == 0)
+ return from;
+
+ font->get_glyph_id (font, ctx->in, from, to);
+ if (mflt_try_otf)
+ {
+ to = mflt_try_otf (font, otf_spec, ctx->in, from, to);
+ if (to < 0)
+ return from;
+ decode_packed_otf_tag (ctx, ctx->in, from, to, ctx->stage->category);
+ }
+ return from;
+}
+
static char work[16];
static char *
if (id >= 0)
{
int i;
+ MCharTable *table = ctx->category ? ctx->category->table : NULL;
+ char enc;
/* Direct code (== ctx->code_offset + id) output.
The source is not consumed. */
i = (from < to || from == 0) ? from : from - 1;
GDUP (ctx, i);
g = GREF (ctx->out, ctx->out->used - 1);
- g->code = ctx->code_offset + id;
- SET_ENCODED (g, 0);
- SET_MEASURED (g, 0);
+ g->c = g->code = ctx->code_offset + id;
if (ctx->combining_code)
SET_COMBINING_CODE (g, ctx, ctx->combining_code);
+ else if (table)
+ {
+ enc = (GET_ENCODED (g)
+ ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
+ : g->code
+ ? (int) mchartable_lookup (table, g->code)
+ : ' ');
+ SET_CATEGORY_CODE (g, enc);
+ }
+ SET_ENCODED (g, 0);
+ SET_MEASURED (g, 0);
if (ctx->left_padding)
SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
for (i = from; i < to; i++)
else if (g->to < tmp->to)
g->to = tmp->to;
}
- UPDATE_CLUSTER_RANGE (ctx, g);
+ if (ctx->cluster_begin_idx >= 0)
+ UPDATE_CLUSTER_RANGE (ctx, g);
ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
if (MDEBUG_FLAG () > 2)
MDEBUG_PRINT (")");
to = run_cond (depth, &cmd->body.cond, from, to, ctx);
else if (cmd->type == FontLayoutCmdTypeOTF)
to = run_otf (depth, &cmd->body.otf, from, to, ctx);
+ else if (cmd->type == FontLayoutCmdTypeOTFCategory)
+ to = try_otf (depth, &cmd->body.otf, from, to, ctx);
return to;
}
SET_COMBINING_CODE (g, ctx, ctx->combining_code);
if (ctx->left_padding)
SET_LEFT_PADDING (g, ctx, LeftPaddingMask);
- UPDATE_CLUSTER_RANGE (ctx, g);
+ if (ctx->cluster_begin_idx >= 0)
+ UPDATE_CLUSTER_RANGE (ctx, g);
if (MDEBUG_FLAG () > 2)
{
if (g->c < 0)
MDEBUG_PRINT2 ("\n [FLT] %*s(COPY |)", depth, "");
else
- MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g->code);
+ MDEBUG_PRINT3 ("\n [FLT] %*s(COPY 0x%X)", depth, "", g->c);
}
ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
return (from + 1);
{
int i;
+ if (MDEBUG_FLAG () > 2)
+ MDEBUG_PRINT2 ("\n [FLT] %*s|", depth, "");
i = from < to ? from : from - 1;
GDUP (ctx, i);
g = GREF (ctx->out, ctx->out->used - 1);
g->c = -1, g->code = 0;
g->xadv = g->yadv = 0;
- SET_ENCODED (g, 0);
+ SET_ENCODED (g, 1);
SET_MEASURED (g, 0);
+ SET_CATEGORY_CODE (g, ' ');
return from;
}
int i, j;
MFLTGlyph *g;
MPlist *stages = flt->stages;
+ FontLayoutCategory *prev_category = NULL;
from_pos = GREF (ctx->in, from)->from;
to_pos = GREF (ctx->in, to - 1)->to;
int result;
ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
- table = ctx->stage->category;
+ table = ctx->stage->category->table;
+ stages = MPLIST_NEXT (stages);
+ if (MPLIST_TAIL_P (stages))
+ ctx->category = NULL;
+ else
+ ctx->category = ((FontLayoutStage *) MPLIST_VAL (stages))->category;
ctx->code_offset = ctx->combining_code = ctx->left_padding = 0;
+ ctx->encoded_offset = from;
for (i = from; i < to; i++)
{
MFLTGlyph *g = GREF (ctx->in, i);
- char enc = (GET_ENCODED (g)
- ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
- : g->code
- ? (int) mchartable_lookup (table, g->code)
- : ' ');
+ char enc;
- ctx->encoded[i] = enc;
+ if (GET_COMBINED (g)
+ || (prev_category && prev_category != ctx->stage->category))
+ {
+ enc = (GET_ENCODED (g)
+ ? (g->c > 0 ? (int) mchartable_lookup (table, g->c) : 1)
+ : g->code
+ ? (int) mchartable_lookup (table, g->code)
+ : ' ');
+ if (! GET_COMBINED (g))
+ SET_CATEGORY_CODE (g, enc);
+ }
+ else
+ enc = GET_CATEGORY_CODE (g);
+ ctx->encoded[i - from] = enc;
if (! enc && stage_idx == 0)
{
to = i;
break;
}
}
- ctx->encoded[i] = '\0';
+ ctx->encoded[i - from] = '\0';
ctx->match_indices[0] = from;
ctx->match_indices[1] = to;
for (i = 2; i < NMATCH; i++)
if (MDEBUG_FLAG () > 2)
{
MDEBUG_PRINT2 ("\n [FLT] (STAGE %d \"%s\"", stage_idx,
- ctx->encoded + from);
+ ctx->encoded);
MDEBUG_PRINT (" (");
for (i = from; i < to; i++)
{
if (result < 0)
return result;
- stages = MPLIST_NEXT (stages);
/* If this is the last stage, break the loop. */
if (MPLIST_TAIL_P (stages))
break;
/* Otherwise, prepare for the next stage. */
+ prev_category = ctx->stage->category;
temp = ctx->in;
ctx->in = ctx->out;
if (buf.glyphs)
g = GREF (ctx->out, i);
for (pos = g->from; pos <= g->to; pos++)
- if (g_indices[pos - orig_from] < 0)
- g_indices[pos - orig_from] = i;
+ if (g_indices[pos - from_pos] < 0)
+ g_indices[pos - from_pos] = i;
}
for (i = 0; i < len; i++)
if (g_indices[i] < 0)
ctx->font->get_metrics (ctx->font, ctx->out, 0, ctx->out->used);
/* Handle combining. */
- if (ctx->check_mask & CombiningCodeMask)
+ if (ctx->check_mask & CombinedMask)
{
MFLTGlyph *base = GREF (ctx->out, 0);
int base_height = base->ascent + base->descent;
+ int base_width = base->rbearing - base->lbearing;
int combining_code;
for (i = 1; i < ctx->out->used; i++)
{
if ((g = GREF (ctx->out, i))
+ && GET_COMBINED (g)
&& (combining_code = GET_COMBINING_CODE (g)))
{
int height = g->ascent + g->descent;
+ int width = g->rbearing - g->lbearing;
int base_x, base_y, add_x, add_y, off_x, off_y;
if (base->from > g->from)
off_x = COMBINING_CODE_OFF_X (combining_code);
off_y = COMBINING_CODE_OFF_Y (combining_code);
- g->xoff = ((base->xadv * base_x - g->xadv * add_x) / 2
- + x_ppem * off_x / 100 - base->xadv);
+ g->xoff = ((base_width * base_x - width * add_x) / 2
+ + x_ppem * off_x / 100
+ - (base->xadv - base->lbearing) - g->lbearing);
if (base_y < 3)
g->yoff = base_height * base_y / 2 - base->ascent;
else
g->yoff -= y_ppem * off_y / 100;
if (base->lbearing > base->xadv + g->lbearing + g->xoff)
base->lbearing = base->xadv + g->lbearing + g->xoff;
- if (base->rbearing < base->xadv + g->xadv + g->xoff)
- base->rbearing = base->xadv + g->xadv + g->xoff;
+ if (base->rbearing < base->xadv + g->rbearing + g->xoff)
+ base->rbearing = base->xadv + g->rbearing + g->xoff;
if (base->ascent < g->ascent - g->yoff)
base->ascent = g->ascent - g->yoff;
if (base->descent < g->descent - g->yoff)
{
base = g;
base_height = g->ascent + g->descent;
+ base_width = g->rbearing - g->lbearing;
}
}
}
for (i = 0; i < ctx->out->used; i++)
{
g = GREF (ctx->out, i);
- if (! GET_COMBINING_CODE (g))
+ if (! GET_COMBINED (g))
{
if (GET_RIGHT_PADDING (g) && g->rbearing > g->xadv)
{
MCharTable *combininig_class_table
= mchar_get_prop_table (Mcombining_class, &type);
- mchartable_set_range (flt->coverage, 0, 0x10FFFF, (void *) 'u');
+ mchartable_set_range (flt->coverage->table, 0, 0x10FFFF, (void *) 'u');
if (combininig_class_table)
mchartable_map (combininig_class_table, (void *) 0,
- setup_combining_coverage, flt->coverage);
+ setup_combining_coverage, flt->coverage->table);
}
#define CHECK_FLT_STAGES(flt) ((flt)->stages || load_flt (flt, NULL) == 0)
+static FontLayoutCategory *
+configure_category (FontLayoutCategory *category, MFLTFont *font)
+{
+ if (! mflt_font_id || ! mflt_iterate_otf_feature)
+ {
+ FontLayoutCategory *new = malloc (sizeof (FontLayoutCategory));
+ new->definition = NULL;
+ new->table = category->table;
+ M17N_OBJECT_REF (new->table);
+ return new;
+ }
+ return load_category_table (category->definition, font);
+}
+
+static MFLT *
+configure_flt (MFLT *flt, MFLTFont *font, MSymbol font_id)
+{
+ MPlist *plist;
+ MFLT *configured;
+
+ if (! mflt_font_id || ! mflt_iterate_otf_feature)
+ return flt;
+ MPLIST_DO (plist, flt_list)
+ {
+ configured = MPLIST_VAL (plist);
+ if (! configured->font_id)
+ break;
+ if (configured->name == flt->name
+ && configured->font_id == font_id)
+ return configured;
+ }
+ if (! MSTRUCT_CALLOC_SAFE (configured))
+ return flt;
+ *configured = *flt;
+ configured->stages = mplist_copy (flt->stages);
+ MPLIST_DO (plist, configured->stages)
+ {
+ FontLayoutStage *stage = MPLIST_VAL (plist);
+ if (stage->category->definition)
+ {
+ MSTRUCT_CALLOC (stage, MERROR_FLT);
+ *stage = *((FontLayoutStage *) MPLIST_VAL (plist));
+ stage->category = configure_category (stage->category, font);
+ MPLIST_VAL (plist) = stage;
+ }
+ else
+ M17N_OBJECT_REF (stage->category->table);
+ }
+ configured->need_config = 0;
+ configured->font_id = font_id;
+ mplist_push (flt_list, flt->name, configured);
+ return configured;
+}
\f
/* Internal API */
Mlayouter = msymbol ("layouter");
Mcombining = msymbol ("combining");
Mfont_facility = msymbol ("font-facility");
+ Mequal = msymbol ("=");
Mgenerator = msymbol ("generator");
Mend = msymbol ("end");
- MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize the flt modules."));
+ mflt_enable_new_feature = 0;
+ mflt_iterate_otf_feature = NULL;
+ mflt_font_id = NULL;
+ mflt_try_otf = NULL;
+
+ MDEBUG_PRINT_TIME ("INIT", (mdebug__output, " to initialize the flt modules."));
MDEBUG_POP_TIME ();
}
MDEBUG_PUSH_TIME ();
free_flt_list ();
- MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize the flt modules."));
+ MDEBUG_PRINT_TIME ("FINI", (mdebug__output, " to finalize the flt modules."));
MDEBUG_POP_TIME ();
m17n_fini_core ();
}
/*=*/
/***en
- @brief Return a FLT object whose name is NAME.
+ @brief Return an FLT object that has a specified name.
- The mflt_get () function returns a FLT object whose name is $NAME.
+ The mflt_get () function returns an FLT object whose name is $NAME.
@return
- If the operation was successfully, mflt_get () returns a pointer
- to a FLT object. Otherwise, it returns @c NULL. */
+ If the operation was successful, mflt_get () returns a pointer
+ to the found FLT object. Otherwise, it returns @c NULL. */
+
+/***ja
+ @brief »ØÄꤵ¤ì¤¿Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹.
+
+ ´Ø¿ô mflt_get () ¤Ï¡¢$NAME ¤È¤¤¤¦Ì¾Á°¤ò»ý¤Ä FLT ¥ª¥Ö¥¸¥§¥¯¥È¤òÊÖ¤¹¡£
+
+ @return
+ ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_get () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
+ ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
MFLT *
mflt_get (MSymbol name)
{
MFLT *flt;
+ MPlist *plist;
if (! flt_list && list_flt () < 0)
return NULL;
- flt = mplist_get (flt_list, name);
+ for (plist = flt_list; plist; plist = plist->next)
+ if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
+ break;
+ flt = mplist_get (plist, name);
if (! flt || ! CHECK_FLT_STAGES (flt))
return NULL;
if (flt->name == Mcombining
- && ! mchartable_lookup (flt->coverage, 0))
+ && ! mchartable_lookup (flt->coverage->table, 0))
setup_combining_flt (flt);
return flt;
/*=*/
/***en
- @brief Find a FLT suitable for a specified character and font.
+ @brief Find an FLT suitable for the specified character and font.
The mflt_find () function returns the most appropriate FLT for
- rendering the character $C by font $FONT.
+ layouting character $C with font $FONT.
+
+ @return
+ If the operation was successful, mflt_find () returns a pointer
+ to the found FLT object. Otherwise, it returns @c NULL. */
+
+/***ja
+ @brief »ØÄꤵ¤ì¤¿Ê¸»ú¤È¥Õ¥©¥ó¥È¤Ë¹ç¤Ã¤¿ FLT ¤òõ¤¹.
+
+ ´Ø¿ô mflt_find () ¤Ï¡¢Ê¸»ú $C ¤ò¥Õ¥©¥ó¥È $FONT
+ ¤Ç¥ì¥¤¥¢¥¦¥È¤¹¤ë¤¿¤á¤ËºÇ¤âŬÀÚ¤Ê FLT ¤òÊÖ¤¹¡£
@return
- If the operation was successfully, mflt_find () returns a pointer
- to a FLT object. Otherwise, it returns @c NULL. */
+ ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢mflt_find () ¤Ï¸«¤Ä¤«¤Ã¤¿ FLT
+ ¥ª¥Ö¥¸¥§¥¯¥È¤Ø¤Î¥Ý¥¤¥ó¥¿¤òÊÖ¤¹¡£¼ºÇÔ¤·¤¿¾ì¹ç¤Ï @c NULL ¤òÊÖ¤¹¡£ */
MFLT *
mflt_find (int c, MFLTFont *font)
{
- MPlist *plist;
+ MPlist *plist, *pl;
MFLT *flt;
static MSymbol unicode_bmp = NULL, unicode_full = NULL;
if (! flt_list && list_flt () < 0)
return NULL;
+ /* Skip configured FLTs. */
+ MPLIST_DO (plist, flt_list)
+ if (((MFLT *) MPLIST_VAL (plist))->font_id == Mnil)
+ break;
if (font)
{
MFLT *best = NULL;
- MPLIST_DO (plist, flt_list)
+ MPLIST_DO (pl, plist)
{
- flt = MPLIST_VAL (plist);
+ flt = MPLIST_VAL (pl);
if (flt->registry != unicode_bmp
&& flt->registry != unicode_full)
continue;
if (flt->family && flt->family != font->family)
continue;
+ if (flt->name == Mcombining
+ && ! mchartable_lookup (flt->coverage->table, 0))
+ setup_combining_flt (flt);
if (c >= 0
- && ! mchartable_lookup (flt->coverage, c))
+ && ! mchartable_lookup (flt->coverage->table, c))
continue;
if (flt->otf.sym)
{
}
else if (! font->check_otf (font, spec))
continue;
- return flt;
+ goto found;
}
best = flt;
}
- return best;
+ if (best == NULL)
+ return NULL;
+ flt = best;
+ goto found;
}
if (c >= 0)
{
- MPLIST_DO (plist, flt_list)
+ MPLIST_DO (pl, plist)
{
- flt = MPLIST_VAL (plist);
- if (mchartable_lookup (flt->coverage, c))
- return flt;
+ flt = MPLIST_VAL (pl);
+ if (mchartable_lookup (flt->coverage->table, c))
+ goto found;
}
}
return NULL;
+
+ found:
+ if (! CHECK_FLT_STAGES (flt))
+ return NULL;
+ if (font && flt->need_config && mflt_font_id)
+ flt = configure_flt (flt, font, mflt_font_id (font));
+ return flt;
}
/*=*/
/***en
- @brief Return a name of a FLT.
+ @brief Return the name of an FLT.
The mflt_name () function returns the name of $FLT. */
+/***ja
+ @brief FLT ¤Î̾Á°¤òÊÖ¤¹.
+
+ ´Ø¿ô mflt_name () ¤Ï $FLT ¤Î̾Á°¤òÊÖ¤¹¡£ */
+
const char *
mflt_name (MFLT *flt)
{
@brief Return a coverage of a FLT.
The mflt_coverage () function returns a char-table that contains
- nonzero value for characters supported by $FLT. */
+ nonzero values for characters supported by $FLT. */
+
+/***ja
+ @brief FLT ¤ÎÈϰϤòÊÖ¤¹.
+
+ ´Ø¿ô mflt_coverage () ¤Ï¡¢$FLT ¤¬¥µ¥Ý¡¼¥È¤¹¤ëʸ»ú¤ËÂФ·¤Æ
+ 0 ¤Ç¤Ê¤¤Ãͤò´Þ¤àʸ»ú¥Æ¡¼¥Ö¥ë¤òÊÖ¤¹¡£ */
MCharTable *
mflt_coverage (MFLT *flt)
{
- return flt->coverage;
+ return flt->coverage->table;
}
/*=*/
/***en
- @brief Layout characters by Font Layout Table.
+ @brief Layout characters with an FLT.
- The mflt_run () function layout characters in $GSTRING between
- $FROM (inclusive) and $TO (exclusive) by $FONT. If $FLT is
+ The mflt_run () function layouts characters in $GSTRING between
+ $FROM (inclusive) and $TO (exclusive) with $FONT. If $FLT is
nonzero, it is used for all the charaters. Otherwise, appropriate
FLTs are automatically chosen.
@retval >=0
- The operation was successful. The value is an index to the
- $GSTRING->glyphs which was previously indexed by $TO.
+ The operation was successful. The value is the index to the
+ glyph, which was previously indexed by $TO, in $GSTRING->glyphs.
@retval -2
- $GSTRING->glyphs is too short to store the result. A caller can
- call this fucntion again with the larger $GSTRING->glyphs.
+ $GSTRING->glyphs is too short to store the result. The caller can
+ call this fucntion again with a longer $GSTRING->glyphs.
@retval -1
Some other error occurred. */
+/***ja
+ @brief FLT ¤ò»È¤Ã¤Æʸ»ú¤ò¥ì¥¤¥¢¥¦¥È¤¹¤ë.
+
+ ´Ø¿ô mflt_run () ¤Ï¡¢$GSTRING Ãæ¤Î $FROM ¤«¤é $TO ľÁ°¤Þ¤Ç¤Îʸ»ú¤ò
+ $FONT ¤òÍѤ¤¤Æ¥ì¥¤¥¢¥¦¥È¤¹¤ë¡£¤â¤· $FLT
+ ¤¬¥¼¥í¤Ç¤Ê¤±¤ì¤Ð¡¢¤½¤ÎÃͤò¤¹¤Ù¤Æ¤Îʸ»ú¤ËÂФ·¤ÆÍѤ¤¤ë¡£
+ ¤½¤¦¤Ç¤Ê¤±¤ì¤ÐŬÀÚ¤Ê FLT ¤ò¼«Æ°Åª¤ËÁªÂò¤¹¤ë¡£
+
+ @retval >=0
+ ¼Â¹ÔÀ®¸ù¤ò¼¨¤¹¡£ÊÖ¤µ¤ì¤ëÃͤϡ¢$GSTRING->glyphs Ãæ¤Ç°ÊÁ° $TO
+ ¤Ë¤è¤Ã¤Æ¼¨¤µ¤ì¤Æ¤¤¤¿¥°¥ê¥Õ¤Ø¤Î¥¤¥ó¥Ç¥¯¥¹¤Ç¤¢¤ë¡£
+
+ @retval -2
+ ·ë²Ì¤ò³ÊǼ¤¹¤ë¤Ë¤Ï $GSTRING->glyphs ¤¬Ã»¤¹¤®¤ë¤³¤È¤ò¼¨¤¹¡£
+ ¸Æ¤Ó½Ð¤·Â¦¤Ï¡¢¤è¤êŤ¤ $GSTRING->glyphs
+ ¤òÍѤ¤¤ÆºÆÅÙ¤³¤Î´Ø¿ô¤ò¸Æ¤Ö¤³¤È¤¬¤Ç¤¤ë¡£
+
+ @retval -1
+ ¤½¤Î¾¤Î¥¨¥é¡¼¤¬µ¯¤¤¿¤³¤È¤ò¼¨¤¹¡£ */
+
int
mflt_run (MFLTGlyphString *gstring, int from, int to,
MFLTFont *font, MFLT *flt)
int auto_flt = ! flt;
int c, i, j, k;
int this_from, this_to;
+ MSymbol font_id = mflt_font_id ? mflt_font_id (font) : Mnil;
out = *gstring;
out.glyphs = NULL;
for (i = from; i < to; i++)
{
g = GREF (gstring, i);
- c = g->c;
- memset (g, 0, sizeof (MFLTGlyph));
- g->code = g->c = c;
+ if (! g->encoded)
+ {
+ c = g->c;
+ memset (g, 0, sizeof (MFLTGlyph));
+ g->code = g->c = c;
+ }
g->from = g->to = i;
}
if (! auto_flt)
{
for (this_to = this_from; this_to < to; this_to++)
- if (mchartable_lookup (flt->coverage, GREF (gstring, this_to)->c))
+ if (mchartable_lookup (flt->coverage->table,
+ GREF (gstring, this_to)->c))
break;
}
else
{
c = GREF (gstring, this_to)->c;
if (font->internal
- && mchartable_lookup (((MFLT *) font->internal)->coverage, c))
+ && mchartable_lookup (((MFLT *) font->internal)->coverage->table, c))
{
flt = font->internal;
break;
MDEBUG_PRINT1 (" [FLT] (%s", MSYMBOL_NAME (flt->name));
+ if (flt->need_config && font_id != Mnil)
+ flt = configure_flt (flt, font, font_id);
+
for (; this_to < to; this_to++)
- if (! mchartable_lookup (flt->coverage, GREF (gstring, this_to)->c))
- break;
+ {
+ char enc;
+ g = GREF (gstring, this_to);
+ enc = (int) mchartable_lookup (flt->coverage->table, g->c);
+ if (! enc)
+ break;
+ SET_CATEGORY_CODE (g, enc);
+ }
if (MDEBUG_FLAG ())
{
{
MDEBUG_PRINT ("\n [FLT] (RESULT");
if (MDEBUG_FLAG () > 1)
- for (i = 0; this_from < this_to; this_from++, i++)
- {
- if (i > 0 && i % 4 == 0)
- MDEBUG_PRINT ("\n [FLT] ");
- g = GREF (gstring, this_from);
- MDEBUG_PRINT4 (" (%04X %d %d %d)",
- g->code, g->xadv, g->xoff, g->yoff);
- }
+ {
+ int idx = -1;
+ for (i = 0; this_from < this_to; i++, this_from++)
+ {
+ g = GREF (gstring, this_from);
+ if (g->from != idx)
+ {
+ if (i > 0)
+ MDEBUG_PRINT2 ("\n [FLT] %02d-%02d",
+ g->from, g->to);
+ else
+ MDEBUG_PRINT2 (" %02d-%02d", g->from, g->to);
+ idx = g->from;
+ }
+ MDEBUG_PRINT4 (" (%04X %d %d %d)",
+ g->code, g->xadv, g->xoff, g->yoff);
+ }
+ }
else
for (; this_from < this_to; this_from++)
MDEBUG_PRINT1 (" %04X", GREF (gstring, this_from)->code);
return to;
}
+int mflt_enable_new_feature;
+
+int (*mflt_iterate_otf_feature) (struct _MFLTFont *font,
+ MFLTOtfSpec *spec,
+ int from, int to,
+ unsigned char *table);
+
+MSymbol (*mflt_font_id) (struct _MFLTFont *font);
+
+int (*mflt_try_otf) (struct _MFLTFont *font, MFLTOtfSpec *spec,
+ MFLTGlyphString *gstring, int from, int to);
+
\f
/* for debugging... */
prefix[indent] = 0;
if (id >= 0)
- fprintf (stderr, "0x%02X", id);
+ fprintf (mdebug__output, "0x%02X", id);
else if (id <= CMD_ID_OFFSET_INDEX)
{
int idx = CMD_ID_TO_INDEX (id);
FontLayoutCmdRule *rule = &cmd->body.rule;
int i;
- fprintf (stderr, "(rule ");
+ fprintf (mdebug__output, "(rule ");
if (rule->src_type == SRC_REGEX)
- fprintf (stderr, "\"%s\"", rule->src.re.pattern);
+ fprintf (mdebug__output, "\"%s\"", rule->src.re.pattern);
else if (rule->src_type == SRC_INDEX)
- fprintf (stderr, "%d", rule->src.match_idx);
+ fprintf (mdebug__output, "%d", rule->src.match_idx);
else if (rule->src_type == SRC_SEQ)
- fprintf (stderr, "(seq)");
+ fprintf (mdebug__output, "(seq)");
else if (rule->src_type == SRC_RANGE)
- fprintf (stderr, "(range)");
+ fprintf (mdebug__output, "(range)");
else
- fprintf (stderr, "(invalid src)");
+ fprintf (mdebug__output, "(invalid src)");
for (i = 0; i < rule->n_cmds; i++)
{
- fprintf (stderr, "\n%s ", prefix);
+ fprintf (mdebug__output, "\n%s ", prefix);
dump_flt_cmd (stage, rule->cmd_ids[i], indent + 2);
}
- fprintf (stderr, ")");
+ fprintf (mdebug__output, ")");
}
else if (cmd->type == FontLayoutCmdTypeCond)
{
FontLayoutCmdCond *cond = &cmd->body.cond;
int i;
- fprintf (stderr, "(cond");
+ fprintf (mdebug__output, "(cond");
for (i = 0; i < cond->n_cmds; i++)
{
- fprintf (stderr, "\n%s ", prefix);
+ fprintf (mdebug__output, "\n%s ", prefix);
dump_flt_cmd (stage, cond->cmd_ids[i], indent + 2);
}
- fprintf (stderr, ")");
+ fprintf (mdebug__output, ")");
}
else if (cmd->type == FontLayoutCmdTypeOTF)
{
- fprintf (stderr, "(otf)");
+ fprintf (mdebug__output, "(otf)");
}
else
- fprintf (stderr, "(error-command)");
+ fprintf (mdebug__output, "(error-command)");
}
else if (id <= CMD_ID_OFFSET_COMBINING)
- fprintf (stderr, "cominging-code");
+ fprintf (mdebug__output, "cominging-code");
else
- fprintf (stderr, "(predefiend %d)", id);
+ fprintf (mdebug__output, "(predefiend %d)", id);
}
-void
+/***en
+ @brief Dump a Font Layout Table.
+
+ The mdebug_dump_flt () function prints the Font Layout Table $FLT
+ 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 $FLT. */
+
+MFLT *
mdebug_dump_flt (MFLT *flt, int indent)
{
char *prefix = (char *) alloca (indent + 1);
memset (prefix, 32, indent);
prefix[indent] = 0;
- fprintf (stderr, "(flt");
+ fprintf (mdebug__output, "(flt");
MPLIST_DO (plist, flt->stages)
{
FontLayoutStage *stage = (FontLayoutStage *) MPLIST_VAL (plist);
int i;
- fprintf (stderr, "\n%s (stage %d", prefix, stage_idx);
+ fprintf (mdebug__output, "\n%s (stage %d", prefix, stage_idx);
for (i = 0; i < stage->used; i++)
{
- fprintf (stderr, "\n%s ", prefix);
+ fprintf (mdebug__output, "\n%s ", prefix);
dump_flt_cmd (stage, INDEX_TO_CMD_ID (i), indent + 4);
}
- fprintf (stderr, ")");
+ fprintf (mdebug__output, ")");
stage_idx++;
}
- fprintf (stderr, ")");
+ fprintf (mdebug__output, ")");
+ return flt;
+}
+
+void
+mflt_dump_gstring (MFLTGlyphString *gstring)
+{
+ int i;
+
+ fprintf (mdebug__output, "(flt-gstring");
+ for (i = 0; i < gstring->used; i++)
+ {
+ MFLTGlyph *g = GREF (gstring, i);
+ fprintf (mdebug__output, "\n (%02d pos:%d-%d c:%04X code:%04X cat:%c)",
+ i, g->from, g->to, g->c, g->code, GET_CATEGORY_CODE (g));
+ }
+ fprintf (mdebug__output, ")\n");
}
/*** @} */