X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=src%2Fm17n-flt.c;h=76f0f99579aa0287c4730ce4290718a3a5cf459e;hb=321cff23a5f50b3e3c703a2c6e830604362f5b7e;hp=aa7f48d4ef71207bb7d130f126caa323a15b4ae2;hpb=607e889125351447b8bdfbd00c450ea12313a358;p=m17n%2Fm17n-lib.git diff --git a/src/m17n-flt.c b/src/m17n-flt.c index aa7f48d..76f0f99 100644 --- a/src/m17n-flt.c +++ b/src/m17n-flt.c @@ -1,5 +1,5 @@ /* 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 @@ -25,7 +25,16 @@ @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 ¤Ëµ­½Ò¤µ¤ì¤Æ¤¤¤ë¡£ */ /*=*/ @@ -113,9 +122,9 @@ PREDEFIND-COMMAND ::= ;; 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: @@ -235,7 +244,7 @@ MACRO-NAME ::= SYMBOL */ -static int mdebug_flag = MDEBUG_FONT_FLT; +static int mdebug_flag = MDEBUG_FLT; MSymbol Mfont, Mlayouter, Mcombining; @@ -246,18 +255,26 @@ static int flt_min_coverage, flt_max_coverage; 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) @@ -358,7 +375,7 @@ GREPLACE (MFLTGlyphString *src, int src_from, int src_to, #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) @@ -367,13 +384,10 @@ static MSymbol Mcond, Mrange, Mfont_facility; #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 @@ -402,8 +416,11 @@ typedef struct struct { int from, to; } range; - int supported_glyph; - MFLTOtfSpec otf_spec; + struct { + int len; + MPlist *codes; + MFLTOtfSpec otf_spec; + } facility; } src; int n_cmds; @@ -426,6 +443,7 @@ enum FontLayoutCmdType FontLayoutCmdTypeRule, FontLayoutCmdTypeCond, FontLayoutCmdTypeOTF, + FontLayoutCmdTypeOTFCategory, FontLayoutCmdTypeMAX }; @@ -439,9 +457,25 @@ typedef struct } 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; @@ -453,39 +487,83 @@ struct _MFLT 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)) @@ -493,14 +571,38 @@ load_category_table (MPlist *plist) 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); @@ -508,19 +610,75 @@ load_category_table (MPlist *plist) 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; } @@ -576,86 +734,101 @@ otf_store_features (char *p, char *end, unsigned *buf) { 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; } @@ -685,7 +858,8 @@ load_otf_command (FontLayoutCmd *cmd, MSymbol sym) result = parse_otf_command (sym, &cmd->body.otf); if (result == -2) return result; - cmd->type = FontLayoutCmdTypeOTF; + cmd->type = (name[4] == '?' ? FontLayoutCmdTypeOTFCategory + : FontLayoutCmdTypeOTF); return 0; } @@ -811,6 +985,7 @@ load_command (FontLayoutStage *stage, MPlist *plist, /* PLIST ::= ( cond ... ) | ( STRING ... ) | ( INTEGER ... ) | ( ( INTEGER INTEGER ) ... ) | ( ( range INTEGER INTEGER ) ... ) + | ( ( SYMBOL STRING ) ... ) | ( ( font-facilty [ INTEGER ] ) ... ) | ( ( font-facilty OTF-SPEC ) ... ) */ MPlist *elt = MPLIST_PLIST (plist); @@ -916,7 +1091,7 @@ load_command (FontLayoutStage *stage, MPlist *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)) @@ -935,47 +1110,58 @@ load_command (FontLayoutStage *stage, MPlist *plist, = (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 @@ -1011,7 +1197,7 @@ load_command (FontLayoutStage *stage, MPlist *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) @@ -1091,7 +1277,8 @@ free_flt_command (FontLayoutCmd *cmd) } 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]); @@ -1149,7 +1336,7 @@ static int load_flt (MFLT *flt, MPlist *key_list) { MPlist *top, *plist, *pl, *p; - MCharTable *category = NULL; + FontLayoutCategory *category = NULL; MSymbol sym; if (key_list) @@ -1226,18 +1413,23 @@ load_flt (MFLT *flt, MPlist *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) { @@ -1249,15 +1441,15 @@ load_flt (MFLT *flt, MPlist *key_list) 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); - printf ("FLT:%s\n", MSYMBOL_NAME (flt->name)); + unref_category_table (category); + err: if (! MPLIST_TAIL_P (plist)) { M17N_OBJECT_UNREF (top); @@ -1270,14 +1462,17 @@ load_flt (MFLT *flt, MPlist *key_list) 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); } @@ -1293,13 +1488,15 @@ free_flt_list () 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); } @@ -1337,17 +1534,17 @@ list_flt () { 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; } @@ -1375,6 +1572,9 @@ typedef struct /* 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; @@ -1385,6 +1585,7 @@ typedef struct 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; @@ -1396,6 +1597,8 @@ typedef struct } 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 @@ -1408,40 +1611,9 @@ run_rule (int depth, 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; @@ -1449,18 +1621,19 @@ run_rule (int depth, 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) @@ -1476,9 +1649,44 @@ run_rule (int depth, } 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) { @@ -1489,56 +1697,128 @@ run_rule (int depth, 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; @@ -1591,6 +1871,46 @@ run_cond (int depth, 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) @@ -1626,6 +1946,8 @@ run_otf (int depth, 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]) { @@ -1652,7 +1974,7 @@ run_otf (int depth, 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); @@ -1660,14 +1982,26 @@ run_otf (int depth, 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; @@ -1685,6 +2019,54 @@ run_otf (int depth, 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 * @@ -1727,6 +2109,8 @@ run_command (int depth, int id, int from, int to, FontLayoutContext *ctx) 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. */ @@ -1736,11 +2120,20 @@ run_command (int depth, int id, int from, int to, FontLayoutContext *ctx) 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++) @@ -1752,7 +2145,8 @@ run_command (int depth, int id, int from, int to, FontLayoutContext *ctx) 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 (")"); @@ -1773,6 +2167,8 @@ run_command (int depth, int id, int from, int to, FontLayoutContext *ctx) 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; } @@ -1797,13 +2193,14 @@ run_command (int depth, int id, int from, int to, FontLayoutContext *ctx) 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); @@ -1842,13 +2239,16 @@ run_command (int depth, int id, int from, int to, FontLayoutContext *ctx) { 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; } @@ -1883,6 +2283,7 @@ run_stages (MFLTGlyphString *gstring, int from, int to, 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; @@ -1901,25 +2302,40 @@ run_stages (MFLTGlyphString *gstring, int from, int 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++) @@ -1928,7 +2344,7 @@ run_stages (MFLTGlyphString *gstring, int from, int to, 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++) { @@ -1946,12 +2362,12 @@ run_stages (MFLTGlyphString *gstring, int from, int to, 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) @@ -1998,8 +2414,8 @@ run_stages (MFLTGlyphString *gstring, int from, int to, 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) @@ -2036,18 +2452,21 @@ run_stages (MFLTGlyphString *gstring, int from, int to, 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) @@ -2062,8 +2481,9 @@ run_stages (MFLTGlyphString *gstring, int from, int to, 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 @@ -2073,8 +2493,8 @@ run_stages (MFLTGlyphString *gstring, int from, int to, 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) @@ -2088,6 +2508,7 @@ run_stages (MFLTGlyphString *gstring, int from, int to, { base = g; base_height = g->ascent + g->descent; + base_width = g->rbearing - g->lbearing; } } } @@ -2097,7 +2518,7 @@ run_stages (MFLTGlyphString *gstring, int from, int to, 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) { @@ -2155,14 +2576,67 @@ setup_combining_flt (MFLT *flt) 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; +} /* Internal API */ @@ -2197,10 +2671,16 @@ m17n_init_flt (void) 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 (); } @@ -2215,7 +2695,7 @@ m17n_fini_flt (void) 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 (); } @@ -2229,26 +2709,39 @@ m17n_fini_flt (void) /*=*/ /***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; @@ -2256,19 +2749,29 @@ mflt_get (MSymbol name) /*=*/ /***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 successfully, mflt_find () returns a pointer - to a FLT object. Otherwise, it returns @c NULL. */ + 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 + ¤â¤·À®¸ù¤¹¤ì¤Ð¡¢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; @@ -2280,20 +2783,27 @@ mflt_find (int c, MFLTFont *font) 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) { @@ -2307,30 +2817,45 @@ mflt_find (int c, MFLTFont *font) } 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) { @@ -2342,34 +2867,60 @@ 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) @@ -2381,6 +2932,7 @@ mflt_run (MFLTGlyphString *gstring, int from, int to, 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; @@ -2392,9 +2944,12 @@ mflt_run (MFLTGlyphString *gstring, int from, int to, 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; } @@ -2403,7 +2958,8 @@ mflt_run (MFLTGlyphString *gstring, int from, int to, 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 @@ -2425,7 +2981,7 @@ mflt_run (MFLTGlyphString *gstring, int from, int to, { 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; @@ -2453,9 +3009,18 @@ mflt_run (MFLTGlyphString *gstring, int from, int to, 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 ()) { @@ -2496,14 +3061,24 @@ mflt_run (MFLTGlyphString *gstring, int from, int to, { 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); @@ -2532,6 +3107,25 @@ mflt_run (MFLTGlyphString *gstring, int from, int to, return to; } +/***en + @brief Flag to control several new OTF handling commands. + + If the variable mflt_enable_new_feature is nonzero, the function + #mflt_run () can drive a Font Layout Table that contains the new + OTF-related commands ":otf?" and/or OTF feature specification in a + category table. */ +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); + /* for debugging... */ @@ -2544,7 +3138,7 @@ dump_flt_cmd (FontLayoutStage *stage, int id, int indent) 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); @@ -2555,52 +3149,63 @@ dump_flt_cmd (FontLayoutStage *stage, int id, int indent) 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); @@ -2609,22 +3214,45 @@ mdebug_dump_flt (MFLT *flt, int indent) 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; +} + +/***en + @brief Dump an MFLTGlyphString. + + The mflt_dump_gstring () function prints the glyph sequence + $GSTRING in a human readable way to the stderr or to what + specified by the environment variable MDEBUG_OUTPUT_FILE. */ + +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"); } /*** @} */