/* 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
;; 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:
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)
FontLayoutCmdTypeRule,
FontLayoutCmdTypeCond,
FontLayoutCmdTypeOTF,
+ FontLayoutCmdTypeOTFCategory,
FontLayoutCmdTypeMAX
};
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;
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 ) *
*/
{
FontLayoutCategory *category;
MCharTable *table;
+ MPlist *feature_table_head = NULL;
+ int feature_table_size = 0;
MPlist *p;
int need_otf = 0;
MPlist *elt;
int from, to, category_code;
- if (! MPLIST_PLIST (p))
- MERROR_GOTO (MERROR_FONT, end);
+ 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_GOTO (MERROR_FONT, end);
+ MERROR_GOTO (MERROR_FLT, end);
from = MPLIST_INTEGER (elt);
elt = MPLIST_NEXT (elt);
if (! MPLIST_INTEGER_P (elt))
- MERROR_GOTO (MERROR_FONT, end);
+ MERROR_GOTO (MERROR_FLT, end);
to = MPLIST_INTEGER (elt);
elt = MPLIST_NEXT (elt);
if (MPLIST_TAIL_P (elt))
}
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_FONT, end);
+ MERROR_GOTO (MERROR_FLT, end);
elt = MPLIST_NEXT (elt);
if (! MPLIST_INTEGER_P (elt))
- MERROR_GOTO (MERROR_FONT, end);
+ MERROR_GOTO (MERROR_FLT, end);
category_code = MPLIST_INTEGER (elt);
if (! isalnum (category_code))
- MERROR_GOTO (MERROR_FONT, end);
+ MERROR_GOTO (MERROR_FLT, end);
apply_otf_feature (font, &spec, from, to, table, category_code);
}
else
else
{
if (! MPLIST_INTEGER_P (elt))
- MERROR_GOTO (MERROR_FONT, end);
+ MERROR_GOTO (MERROR_FLT, end);
category_code = MPLIST_INTEGER (elt);
}
if (! isalnum (category_code))
- MERROR_GOTO (MERROR_FONT, end);
+ MERROR_GOTO (MERROR_FLT, end);
if (from == to)
mchartable_set (table, from, (void *) category_code);
}
end:
- category = malloc (sizeof (FontLayoutCategory));
+ category = calloc (1, sizeof (FontLayoutCategory));
category->table = table;
if (need_otf)
{
}
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;
}
{
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;
}
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;
+ }
+ script = gen_otf_tag (str, 8);
str += 4;
if (*str == '/')
{
- langsys = gen_otf_tag (str);
+ langsys = gen_otf_tag (str, 8);
str += 4;
}
else
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);
&& ((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]);
continue;
}
category = load_category_table (pl, NULL);
+ if (! category)
+ goto err;
if (! flt->coverage)
{
flt->coverage = category;
}
if (category)
unref_category_table (category);
-
+ err:
if (! MPLIST_TAIL_P (plist))
{
M17N_OBJECT_UNREF (top);
/* 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;
} 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
if (len > (to - from))
return 0;
for (i = 0; i < len; i++)
- if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->code)
+ if (rule->src.seq.codes[i] != GREF (ctx->in, from + i)->c)
break;
if (i < len)
return 0;
if (from >= to)
return 0;
- head = GREF (ctx->in, from)->code;
+ 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;
{
if (MPLIST_INTEGER_P (p))
{
- GREF (&gstring, i)->code = MPLIST_INTEGER (p);
+ GREF (&gstring, i)->c = MPLIST_INTEGER (p);
GREF (&gstring, i)->encoded = 0;
}
else
{
- GREF (&gstring, i)->code = GREF (ctx->in, idx)->code;
+ GREF (&gstring, i)->c = GREF (ctx->in, idx)->code;
GREF (&gstring, i)->encoded = GREF (ctx->in, idx)->encoded;
idx++;
}
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;
+ }
+ if (tag & 0xFFFFF80)
+ {
+ int i;
+
+ /* Clear the feature tag code. */
+ g->internal &= ~0xFFFFFFF;
+ for (i = 0, enc = '\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;
+ }
+ }
+ else
+ enc = '\0';
+ if (! enc)
+ enc = g->c > 0 ? (int) mchartable_lookup (category->table, g->c) : 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->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;
g->descent -= aa->yoff;
}
}
- SET_COMBINING_CODE (g, ctx, 0);
g->adjusted = 1;
}
}
return to;
}
+static int
+try_otf (int depth, MFLTOtfSpec *otf_spec, int from, int to,
+ FontLayoutContext *ctx)
+{
+ MFLTFont *font = ctx->font;
+ int from_idx = ctx->out->used;
+
+ 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)
+ {
+ int out_len;
+ int i;
+
+ 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. */
GDUP (ctx, i);
g = GREF (ctx->out, ctx->out->used - 1);
g->c = g->code = ctx->code_offset + id;
- SET_ENCODED (g, 0);
- SET_MEASURED (g, 0);
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++)
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;
}
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);
g->xadv = g->yadv = 0;
SET_ENCODED (g, 0);
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;
ctx->stage = (FontLayoutStage *) MPLIST_VAL (stages);
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;
+ 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)
{
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)
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;
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;
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)
{
Mgenerator = msymbol ("generator");
Mend = msymbol ("end");
+ mflt_enable_new_feature = 0;
mflt_iterate_otf_feature = NULL;
mflt_font_id = NULL;
+ mflt_try_otf = NULL;
MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize the flt modules."));
MDEBUG_POP_TIME ();
}
best = flt;
}
+ if (best == NULL)
+ return NULL;
flt = best;
goto found;
}
flt = configure_flt (flt, font, font_id);
for (; this_to < to; this_to++)
- if (! mchartable_lookup (flt->coverage->table,
- 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 ())
{
return to;
}
+int mflt_enable_new_feature;
+
int (*mflt_iterate_otf_feature) (struct _MFLTFont *font,
MFLTOtfSpec *spec,
int from, int to,
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... */
return flt;
}
+void
+mflt_dump_gstring (MFLTGlyphString *gstring)
+{
+ int i;
+
+ fprintf (stderr, "(flt-gstring");
+ for (i = 0; i < gstring->used; i++)
+ {
+ MFLTGlyph *g = GREF (gstring, i);
+ fprintf (stderr, "\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 (stderr, ")\n");
+}
+
/*** @} */
/*