Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index abf9cba105d..5d90bad79c7 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -3137,7 +3137,7 @@ static unsigned int opentype_set_glyph_props(struct scriptshaping_context *conte
if (cache->gdef.classdef) { - glyph_class = opentype_layout_get_glyph_class(&cache->gdef.table, cache->gdef.classdef, context->u.subst.glyphs[g]); + glyph_class = opentype_layout_get_glyph_class(&cache->gdef.table, cache->gdef.classdef, glyph); }
switch (glyph_class) @@ -3160,6 +3160,13 @@ static unsigned int opentype_set_glyph_props(struct scriptshaping_context *conte return props; }
+static void opentype_set_subst_glyph_props(struct scriptshaping_context *context, unsigned int g, UINT16 glyph) +{ + unsigned int glyph_props = opentype_set_glyph_props(context, g, glyph); + context->u.subst.glyph_props[g].isDiacritic = !!(glyph_props == GLYPH_PROP_MARK); + context->u.subst.glyph_props[g].isZeroWidthSpace = !!(glyph_props == GLYPH_PROP_MARK); +} + struct coverage_compare_format1_context { UINT16 glyph; @@ -4419,15 +4426,14 @@ void opentype_layout_apply_gpos_features(struct scriptshaping_context *context,
static BOOL opentype_layout_apply_gsub_single_substitution(struct glyph_iterator *iter, const struct ot_lookup *lookup) { + UINT16 format, coverage, orig_glyph = iter->context->u.subst.glyphs[iter->pos], glyph = orig_glyph; struct scriptshaping_cache *cache = iter->context->cache; const struct dwrite_fonttable *gsub = &cache->gsub.table; - UINT16 format, coverage; unsigned int i;
for (i = 0; i < lookup->subtable_count; ++i) { unsigned int subtable_offset = opentype_layout_get_gsub_subtable(cache, lookup->offset, i); - UINT16 glyph = iter->context->u.subst.glyphs[iter->pos]; unsigned int coverage_index;
format = table_read_be_word(&cache->gsub.table, subtable_offset); @@ -4443,7 +4449,7 @@ static BOOL opentype_layout_apply_gsub_single_substitution(struct glyph_iterator if (coverage_index == GLYPH_NOT_COVERED) continue;
- iter->context->u.subst.glyphs[iter->pos] = glyph + GET_BE_WORD(format1->delta); + glyph = orig_glyph + GET_BE_WORD(format1->delta); break; } else if (format == 2) @@ -4456,13 +4462,19 @@ static BOOL opentype_layout_apply_gsub_single_substitution(struct glyph_iterator if (coverage_index == GLYPH_NOT_COVERED || coverage_index >= count) continue;
- iter->context->u.subst.glyphs[iter->pos] = GET_BE_WORD(format2->substitutes[coverage_index]); + glyph = GET_BE_WORD(format2->substitutes[coverage_index]); break; } else WARN("Unknown single substitution format %u.\n", format); }
+ if (glyph != orig_glyph) + { + iter->context->u.subst.glyphs[iter->pos] = glyph; + opentype_set_subst_glyph_props(iter->context, iter->pos, glyph); + } + return FALSE; }
@@ -4762,11 +4774,7 @@ static void opentype_get_nominal_glyphs(struct scriptshaping_context *context, c context->u.subst.glyphs[g] = font->get_glyph(context->cache->context, codepoint); context->u.subst.glyph_props[g].justification = SCRIPT_JUSTIFY_CHARACTER; context->u.subst.glyph_props[g].isClusterStart = 1; - if (opentype_set_glyph_props(context, g, context->u.subst.glyphs[g]) == GLYPH_PROP_MARK) - { - context->u.subst.glyph_props[g].isDiacritic = 1; - context->u.subst.glyph_props[g].isZeroWidthSpace = 1; - } + opentype_set_subst_glyph_props(context, g, context->u.subst.glyphs[g]); context->glyph_count++;
clustermap[i] = i;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 5d90bad79c7..54d066e0173 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -4550,7 +4550,7 @@ static BOOL opentype_layout_context_match_lookahead(struct glyph_iterator *iter, }
static void opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, unsigned int first_glyph, - unsigned int glyph_count, int lookup_index); + unsigned int glyph_count, int lookup_index, BOOL only_single);
static BOOL opentype_layout_context_gsub_apply_lookup(struct glyph_iterator *iter, unsigned int count, unsigned int lookup_count, const UINT16 *lookup_records) @@ -4559,7 +4559,7 @@ static BOOL opentype_layout_context_gsub_apply_lookup(struct glyph_iterator *ite FIXME("Only first lookup used.\n");
opentype_layout_apply_gsub_lookup(iter->context, iter->pos + GET_BE_WORD(lookup_records[0]), count, - GET_BE_WORD(lookup_records[1])); + GET_BE_WORD(lookup_records[1]), TRUE);
return TRUE; } @@ -4661,7 +4661,7 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct glyph_i }
static void opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, unsigned int first_glyph, - unsigned int glyph_count, int lookup_index) + unsigned int glyph_count, int lookup_index, BOOL only_single) { struct ot_gsubgpos_table *table = &context->cache->gsub; const struct ot_lookup_table *lookup_table; @@ -4685,6 +4685,9 @@ static void opentype_layout_apply_gsub_lookup(struct scriptshaping_context *cont lookup_type = GET_BE_WORD(lookup_table->lookup_type); lookup.flags = GET_BE_WORD(lookup_table->flags);
+ if (lookup_type != GSUB_LOOKUP_SINGLE_SUBST && only_single) + return; + glyph_iterator_init(context, lookup.flags, first_glyph, glyph_count, &iter);
while (iter.pos < first_glyph + iter.len) @@ -4798,7 +4801,7 @@ HRESULT opentype_layout_apply_gsub_features(struct scriptshaping_context *contex opentype_layout_set_glyph_masks(context, features);
for (i = 0; i < lookups.count; ++i) - opentype_layout_apply_gsub_lookup(context, 0, context->glyph_count, lookups.lookups[i].index); + opentype_layout_apply_gsub_lookup(context, 0, context->glyph_count, lookups.lookups[i].index, FALSE);
heap_free(lookups.lookups);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 9 +++++++-- dlls/dwrite/dwrite_private.h | 1 + dlls/dwrite/shape.c | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 786d68ac278..3754fe39a19 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -1173,10 +1173,11 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface, context.length = length; context.is_rtl = is_rtl; context.is_sideways = is_sideways; - context.u.subst.glyphs = glyphs; - context.u.subst.glyph_props = glyph_props; + context.u.subst.glyphs = heap_calloc(max_glyph_count, sizeof(*glyphs)); + context.u.subst.glyph_props = heap_calloc(max_glyph_count, sizeof(*glyph_props)); context.u.subst.clustermap = clustermap; context.u.subst.max_glyph_count = max_glyph_count; + context.u.subst.capacity = max_glyph_count; context.u.subst.digits = digits; context.language_tag = get_opentype_language(locale); context.user_features.features = features; @@ -1190,10 +1191,14 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface, if (SUCCEEDED(hr)) { *actual_glyph_count = context.glyph_count; + memcpy(glyphs, context.u.subst.glyphs, context.glyph_count * sizeof(*glyphs)); + memcpy(glyph_props, context.u.subst.glyph_props, context.glyph_count * sizeof(*glyph_props)); hr = default_shaping_ops.set_text_glyphs_props(&context, clustermap, glyphs, *actual_glyph_count, text_props, glyph_props); }
+ heap_free(context.u.subst.glyph_props); + heap_free(context.u.subst.glyphs); heap_free(context.glyph_infos);
return hr; diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index dd25c619c11..ce278e54992 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -491,6 +491,7 @@ struct scriptshaping_context DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props; UINT16 *clustermap; unsigned int max_glyph_count; + unsigned int capacity; const WCHAR *digits; } subst; } u; diff --git a/dlls/dwrite/shape.c b/dlls/dwrite/shape.c index 77c5ba1f8a2..b7b40d1211d 100644 --- a/dlls/dwrite/shape.c +++ b/dlls/dwrite/shape.c @@ -400,5 +400,5 @@ HRESULT shape_get_glyphs(struct scriptshaping_context *context, const unsigned i
heap_free(features.features);
- return S_OK; + return (context->glyph_count <= context->u.subst.max_glyph_count) ? S_OK : E_NOT_SUFFICIENT_BUFFER; }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 98 +++++++++++++++++++++++++----------------- 1 file changed, 59 insertions(+), 39 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 54d066e0173..7e35feb7f51 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -4159,7 +4159,12 @@ static void opentype_layout_apply_gpos_lookup(struct scriptshaping_context *cont struct lookup { unsigned short index; + unsigned short type; + unsigned short flags; + unsigned short subtable_count; + unsigned int mask; + unsigned int offset; };
struct lookups @@ -4176,11 +4181,45 @@ static int lookups_sorting_compare(const void *a, const void *b) return left->index < right->index ? -1 : left->index > right->index ? 1 : 0; };
+static BOOL opentype_layout_init_lookup(struct ot_gsubgpos_table *table, unsigned short lookup_index, unsigned int mask, + struct lookup *lookup) +{ + unsigned short subtable_count, lookup_type, flags; + const struct ot_lookup_table *lookup_table; + unsigned int offset; + + if (!(offset = table_read_be_word(&table->table, table->lookup_list + + FIELD_OFFSET(struct ot_lookup_list, lookup[lookup_index])))) + { + return FALSE; + } + + offset += table->lookup_list; + + if (!(lookup_table = table_read_ensure(&table->table, offset, sizeof(*lookup_table)))) + return FALSE; + + if (!(subtable_count = GET_BE_WORD(lookup_table->subtable_count))) + return FALSE; + + lookup_type = GET_BE_WORD(lookup_table->lookup_type); + flags = GET_BE_WORD(lookup_table->flags); + + lookup->index = lookup_index; + lookup->type = lookup_type; + lookup->flags = flags; + lookup->subtable_count = subtable_count; + lookup->mask = mask; + lookup->offset = offset; + + return TRUE; +} + static void opentype_layout_add_lookups(const struct ot_feature_list *feature_list, UINT16 total_lookup_count, struct ot_gsubgpos_table *table, struct shaping_feature *feature, struct lookups *lookups) { UINT16 feature_offset, lookup_count; - unsigned int i, j; + unsigned int i;
/* Feature wasn't found */ if (feature->index == 0xffff) @@ -4211,10 +4250,8 @@ static void opentype_layout_add_lookups(const struct ot_feature_list *feature_li if (lookup_index >= total_lookup_count) continue;
- j = lookups->count; - lookups->lookups[j].index = lookup_index; - lookups->lookups[j].mask = feature->mask; - lookups->count++; + if (opentype_layout_init_lookup(table, lookup_index, feature->mask, &lookups->lookups[lookups->count])) + lookups->count++; } }
@@ -4424,7 +4461,7 @@ void opentype_layout_apply_gpos_features(struct scriptshaping_context *context, heap_free(lookups.lookups); }
-static BOOL opentype_layout_apply_gsub_single_substitution(struct glyph_iterator *iter, const struct ot_lookup *lookup) +static BOOL opentype_layout_apply_gsub_single_substitution(struct glyph_iterator *iter, const struct lookup *lookup) { UINT16 format, coverage, orig_glyph = iter->context->u.subst.glyphs[iter->pos], glyph = orig_glyph; struct scriptshaping_cache *cache = iter->context->cache; @@ -4550,16 +4587,19 @@ static BOOL opentype_layout_context_match_lookahead(struct glyph_iterator *iter, }
static void opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, unsigned int first_glyph, - unsigned int glyph_count, int lookup_index, BOOL only_single); + unsigned int glyph_count, struct lookup *lookup, BOOL only_single);
static BOOL opentype_layout_context_gsub_apply_lookup(struct glyph_iterator *iter, unsigned int count, unsigned int lookup_count, const UINT16 *lookup_records) { + struct lookup lookup = { 0 }; + if (lookup_count > 1) FIXME("Only first lookup used.\n");
- opentype_layout_apply_gsub_lookup(iter->context, iter->pos + GET_BE_WORD(lookup_records[0]), count, - GET_BE_WORD(lookup_records[1]), TRUE); + if (opentype_layout_init_lookup(&iter->context->cache->gsub, GET_BE_WORD(lookup_records[1]), 0, &lookup)) + opentype_layout_apply_gsub_lookup(iter->context, iter->pos + GET_BE_WORD(lookup_records[0]), count, + &lookup, TRUE);
return TRUE; } @@ -4574,7 +4614,7 @@ static BOOL opentype_layout_apply_gsub_chain_context_lookup(struct glyph_iterato opentype_layout_context_gsub_apply_lookup(iter, input_count, lookup_count, lookup_records); }
-static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct glyph_iterator *iter, const struct ot_lookup *lookup) +static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct glyph_iterator *iter, const struct lookup *lookup) { struct scriptshaping_cache *cache = iter->context->cache; UINT16 format, coverage; @@ -4661,34 +4701,14 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct glyph_i }
static void opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, unsigned int first_glyph, - unsigned int glyph_count, int lookup_index, BOOL only_single) + unsigned int glyph_count, struct lookup *lookup, BOOL only_single) { - struct ot_gsubgpos_table *table = &context->cache->gsub; - const struct ot_lookup_table *lookup_table; struct glyph_iterator iter; - struct ot_lookup lookup; - WORD lookup_type;
- lookup.offset = table_read_be_word(&table->table, table->lookup_list + FIELD_OFFSET(struct ot_lookup_list, lookup[lookup_index])); - if (!lookup.offset) + if (lookup->type != GSUB_LOOKUP_SINGLE_SUBST && only_single) return;
- lookup.offset += table->lookup_list; - - if (!(lookup_table = table_read_ensure(&table->table, lookup.offset, sizeof(*lookup_table)))) - return; - - lookup.subtable_count = GET_BE_WORD(lookup_table->subtable_count); - if (!lookup.subtable_count) - return; - - lookup_type = GET_BE_WORD(lookup_table->lookup_type); - lookup.flags = GET_BE_WORD(lookup_table->flags); - - if (lookup_type != GSUB_LOOKUP_SINGLE_SUBST && only_single) - return; - - glyph_iterator_init(context, lookup.flags, first_glyph, glyph_count, &iter); + glyph_iterator_init(context, lookup->flags, first_glyph, glyph_count, &iter);
while (iter.pos < first_glyph + iter.len) { @@ -4700,13 +4720,13 @@ static void opentype_layout_apply_gsub_lookup(struct scriptshaping_context *cont continue; }
- switch (lookup_type) + switch (lookup->type) { case GSUB_LOOKUP_SINGLE_SUBST: - ret = opentype_layout_apply_gsub_single_substitution(&iter, &lookup); + ret = opentype_layout_apply_gsub_single_substitution(&iter, lookup); break; case GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST: - ret = opentype_layout_apply_gsub_chain_context_substitution(&iter, &lookup); + ret = opentype_layout_apply_gsub_chain_context_substitution(&iter, lookup); break; case GSUB_LOOKUP_MULTIPLE_SUBST: case GSUB_LOOKUP_ALTERNATE_SUBST: @@ -4714,10 +4734,10 @@ static void opentype_layout_apply_gsub_lookup(struct scriptshaping_context *cont case GSUB_LOOKUP_CONTEXTUAL_SUBST: case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST: ret = FALSE; - WARN("Unimplemented lookup %d.\n", lookup_type); + WARN("Unimplemented lookup %d.\n", lookup->type); break; default: - WARN("Unknown lookup type %u.\n", lookup_type); + WARN("Unknown lookup type %u.\n", lookup->type); return; }
@@ -4801,7 +4821,7 @@ HRESULT opentype_layout_apply_gsub_features(struct scriptshaping_context *contex opentype_layout_set_glyph_masks(context, features);
for (i = 0; i < lookups.count; ++i) - opentype_layout_apply_gsub_lookup(context, 0, context->glyph_count, lookups.lookups[i].index, FALSE); + opentype_layout_apply_gsub_lookup(context, 0, context->glyph_count, &lookups.lookups[i], FALSE);
heap_free(lookups.lookups);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/dwrite_private.h | 3 +- dlls/dwrite/opentype.c | 273 ++++++++++++++++++++++------------- 2 files changed, 177 insertions(+), 99 deletions(-)
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index ce278e54992..b1391cb911a 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -505,6 +505,7 @@ struct scriptshaping_context unsigned int global_mask; struct shaping_glyph_info *glyph_infos;
+ unsigned int cur; unsigned int glyph_count; float emsize; DWRITE_MEASURING_MODE measuring_mode; @@ -557,7 +558,7 @@ extern DWORD opentype_layout_find_script(const struct scriptshaping_cache *cache unsigned int *script_index) DECLSPEC_HIDDEN; extern DWORD opentype_layout_find_language(const struct scriptshaping_cache *cache, DWORD kind, DWORD tag, unsigned int script_index, unsigned int *language_index) DECLSPEC_HIDDEN; -extern HRESULT opentype_layout_apply_gsub_features(struct scriptshaping_context *context, unsigned int script_index, +extern void opentype_layout_apply_gsub_features(struct scriptshaping_context *context, unsigned int script_index, unsigned int language_index, const struct shaping_features *features) DECLSPEC_HIDDEN; extern void opentype_layout_apply_gpos_features(struct scriptshaping_context *context, unsigned int script_index, unsigned int language_index, const struct shaping_features *features) DECLSPEC_HIDDEN; diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 7e35feb7f51..16abb4c93aa 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -4461,12 +4461,16 @@ void opentype_layout_apply_gpos_features(struct scriptshaping_context *context, heap_free(lookups.lookups); }
-static BOOL opentype_layout_apply_gsub_single_substitution(struct glyph_iterator *iter, const struct lookup *lookup) +static BOOL opentype_layout_apply_gsub_single_substitution(struct scriptshaping_context *context, const struct lookup *lookup) { - UINT16 format, coverage, orig_glyph = iter->context->u.subst.glyphs[iter->pos], glyph = orig_glyph; - struct scriptshaping_cache *cache = iter->context->cache; + struct scriptshaping_cache *cache = context->cache; const struct dwrite_fonttable *gsub = &cache->gsub.table; - unsigned int i; + UINT16 format, coverage, orig_glyph, glyph; + unsigned int i, idx; + BOOL ret; + + idx = context->cur; + orig_glyph = glyph = context->u.subst.glyphs[idx];
for (i = 0; i < lookup->subtable_count; ++i) { @@ -4506,76 +4510,97 @@ static BOOL opentype_layout_apply_gsub_single_substitution(struct glyph_iterator WARN("Unknown single substitution format %u.\n", format); }
- if (glyph != orig_glyph) + if ((ret = (glyph != orig_glyph))) { - iter->context->u.subst.glyphs[iter->pos] = glyph; - opentype_set_subst_glyph_props(iter->context, iter->pos, glyph); + context->u.subst.glyphs[idx] = glyph; + opentype_set_subst_glyph_props(context, idx, glyph); + context->cur++; }
- return FALSE; + return ret; }
-static BOOL opentype_layout_context_match_input(struct glyph_iterator *iter, unsigned int subtable_offset, - unsigned int count, const UINT16 *input) +#define CHAIN_CONTEXT_MAX_LENGTH 64 + +static BOOL opentype_layout_context_match_input(struct scriptshaping_context *context, unsigned int subtable_offset, + unsigned int count, const UINT16 *input, unsigned int *end_offset, unsigned int *match_positions) { - struct scriptshaping_cache *cache = iter->context->cache; - unsigned int i, pos; + struct scriptshaping_cache *cache = context->cache; + struct glyph_iterator iter; + unsigned int i; + UINT16 glyph;
- if (iter->pos + count > iter->len) + if (count > CHAIN_CONTEXT_MAX_LENGTH) return FALSE;
- pos = iter->pos; + match_positions[0] = context->cur;
- for (i = 0; i < count; ++i, ++pos) + glyph_iterator_init(context, 0, context->cur, count - 1, &iter); + + for (i = 1; i < count; ++i) { - UINT16 glyph = iter->context->u.subst.glyphs[pos]; + if (!glyph_iterator_next(&iter)) + return FALSE; + + /* TODO: this only covers Format3 substitution */ + glyph = context->u.subst.glyphs[iter.pos]; if (opentype_layout_is_glyph_covered(&cache->gsub.table, subtable_offset + GET_BE_WORD(input[i]), glyph) == GLYPH_NOT_COVERED) { return FALSE; } + + match_positions[i] = iter.pos; }
+ *end_offset = iter.pos - context->cur + 1; + return TRUE; }
-static BOOL opentype_layout_context_match_backtrack(struct glyph_iterator *iter, unsigned int subtable_offset, - unsigned int count, const UINT16 *backtrack) +static BOOL opentype_layout_context_match_backtrack(struct scriptshaping_context *context, unsigned int subtable_offset, + unsigned int count, const UINT16 *backtrack, unsigned int *match_start) { - struct scriptshaping_cache *cache = iter->context->cache; + struct glyph_iterator iter; unsigned int i; + UINT16 glyph;
- if (iter->pos < count) - return FALSE; + glyph_iterator_init(context, 0, context->cur, count, &iter);
for (i = 0; i < count; ++i) { - UINT16 glyph = iter->context->u.subst.glyphs[iter->pos - i - 1]; + if (!glyph_iterator_prev(&iter)) + return FALSE;
- if (opentype_layout_is_glyph_covered(&cache->gsub.table, subtable_offset + GET_BE_WORD(backtrack[i]), + glyph = context->u.subst.glyphs[iter.pos]; + if (opentype_layout_is_glyph_covered(&context->cache->gsub.table, subtable_offset + GET_BE_WORD(backtrack[i]), glyph) == GLYPH_NOT_COVERED) { return FALSE; } }
+ *match_start = iter.pos; + return TRUE; }
-static BOOL opentype_layout_context_match_lookahead(struct glyph_iterator *iter, unsigned int subtable_offset, - unsigned int count, const UINT16 *lookahead, unsigned int offset) +static BOOL opentype_layout_context_match_lookahead(struct scriptshaping_context *context, unsigned int subtable_offset, + unsigned int count, const UINT16 *lookahead, unsigned int offset, unsigned int *end_index) { - struct scriptshaping_cache *cache = iter->context->cache; - unsigned int i, pos; - - if (iter->pos + offset + count > iter->len) - return FALSE; + struct scriptshaping_cache *cache = context->cache; + struct glyph_iterator iter; + unsigned int i; + UINT16 glyph;
- pos = iter->pos + offset; + glyph_iterator_init(context, 0, context->cur + offset - 1, count, &iter);
- for (i = 0; i < count; ++i, ++pos) + for (i = 0; i < count; ++i) { - UINT16 glyph = iter->context->u.subst.glyphs[pos]; + if (!glyph_iterator_next(&iter)) + return FALSE; + + glyph = context->u.subst.glyphs[iter.pos]; if (opentype_layout_is_glyph_covered(&cache->gsub.table, subtable_offset + GET_BE_WORD(lookahead[i]), glyph) == GLYPH_NOT_COVERED) { @@ -4583,47 +4608,104 @@ static BOOL opentype_layout_context_match_lookahead(struct glyph_iterator *iter, } }
+ *end_index = iter.pos; + return TRUE; }
-static void opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, unsigned int first_glyph, - unsigned int glyph_count, struct lookup *lookup, BOOL only_single); +static BOOL opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, const struct lookup *lookup);
-static BOOL opentype_layout_context_gsub_apply_lookup(struct glyph_iterator *iter, unsigned int count, - unsigned int lookup_count, const UINT16 *lookup_records) +static BOOL opentype_layout_context_gsub_apply_lookup(struct scriptshaping_context *context, unsigned int count, + unsigned int *match_positions, unsigned int lookup_count, const UINT16 *lookup_records, unsigned int match_length) { struct lookup lookup = { 0 }; + unsigned int i, j; + int end, delta; + + end = context->cur + match_length; + + for (i = 0; i < lookup_count; ++i) + { + unsigned int idx = GET_BE_WORD(lookup_records[i]); + unsigned int orig_len, lookup_index, next; + + if (idx >= count) + continue; + + context->cur = match_positions[idx]; + + orig_len = context->glyph_count; + + lookup_index = GET_BE_WORD(lookup_records[i+1]); + if (opentype_layout_init_lookup(&context->cache->gsub, lookup_index, 0, &lookup)) + opentype_layout_apply_gsub_lookup(context, &lookup); + + delta = context->glyph_count - orig_len; + if (!delta) + continue; + + end += delta; + if (end <= (int)match_positions[idx]) + { + end = match_positions[idx]; + break; + } + + next = idx + 1; + + if (delta > 0) + { + if (delta + count > CHAIN_CONTEXT_MAX_LENGTH) + break; + } + else + { + delta = max(delta, (int)next - (int)count); + next -= delta; + }
- if (lookup_count > 1) - FIXME("Only first lookup used.\n"); + memmove(match_positions + next + delta, match_positions + next, + (count - next) * sizeof (*match_positions)); + next += delta; + count += delta;
- if (opentype_layout_init_lookup(&iter->context->cache->gsub, GET_BE_WORD(lookup_records[1]), 0, &lookup)) - opentype_layout_apply_gsub_lookup(iter->context, iter->pos + GET_BE_WORD(lookup_records[0]), count, - &lookup, TRUE); + for (j = idx + 1; j < next; j++) + match_positions[j] = match_positions[j - 1] + 1; + + for (; next < count; next++) + match_positions[next] += delta; + } + + context->cur = end;
return TRUE; }
-static BOOL opentype_layout_apply_gsub_chain_context_lookup(struct glyph_iterator *iter, unsigned int subtable_offset, +static BOOL opentype_layout_apply_gsub_chain_context_lookup(struct scriptshaping_context *context, unsigned int subtable_offset, unsigned int backtrack_count, const UINT16 *backtrack, unsigned int input_count, const UINT16 *input, unsigned int lookahead_count, const UINT16 *lookahead, unsigned int lookup_count, const UINT16 *lookup_records) { - return opentype_layout_context_match_input(iter, subtable_offset, input_count, input) && - opentype_layout_context_match_backtrack(iter, subtable_offset, backtrack_count, backtrack) && - opentype_layout_context_match_lookahead(iter, subtable_offset, lookahead_count, lookahead, input_count) && - opentype_layout_context_gsub_apply_lookup(iter, input_count, lookup_count, lookup_records); + unsigned int start_index = 0, match_length = 0, end_index = 0; + unsigned int match_positions[CHAIN_CONTEXT_MAX_LENGTH]; + + return opentype_layout_context_match_input(context, subtable_offset, input_count, input, &match_length, match_positions) && + opentype_layout_context_match_backtrack(context, subtable_offset, backtrack_count, backtrack, &start_index) && + opentype_layout_context_match_lookahead(context, subtable_offset, lookahead_count, lookahead, input_count, &end_index) && + opentype_layout_context_gsub_apply_lookup(context, input_count, match_positions, lookup_count, lookup_records, match_length); }
-static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct glyph_iterator *iter, const struct lookup *lookup) +static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scriptshaping_context *context, + const struct lookup *lookup) { - struct scriptshaping_cache *cache = iter->context->cache; + struct scriptshaping_cache *cache = context->cache; UINT16 format, coverage; + BOOL ret = FALSE; unsigned int i;
for (i = 0; i < lookup->subtable_count; ++i) { unsigned int subtable_offset = opentype_layout_get_gsub_subtable(cache, lookup->offset, i); - UINT16 glyph = iter->context->u.subst.glyphs[iter->pos]; + UINT16 glyph = context->u.subst.glyphs[context->cur]; unsigned int coverage_index = GLYPH_NOT_COVERED;
format = table_read_be_word(&cache->gsub.table, subtable_offset); @@ -4687,8 +4769,8 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct glyph_i if (coverage_index == GLYPH_NOT_COVERED) continue;
- if (opentype_layout_apply_gsub_chain_context_lookup(iter, subtable_offset, backtrack_count, backtrack, - input_count, input, lookahead_count, lookahead, lookup_count, lookup_records)) + if ((ret = opentype_layout_apply_gsub_chain_context_lookup(context, subtable_offset, backtrack_count, backtrack, + input_count, input + 1, lookahead_count, lookahead, lookup_count, lookup_records))) { break; } @@ -4697,54 +4779,33 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct glyph_i WARN("Unknown chaining contextual substitution format %u.\n", format); }
- return FALSE; + return ret; }
-static void opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, unsigned int first_glyph, - unsigned int glyph_count, struct lookup *lookup, BOOL only_single) +static BOOL opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, const struct lookup *lookup) { - struct glyph_iterator iter; - - if (lookup->type != GSUB_LOOKUP_SINGLE_SUBST && only_single) - return; - - glyph_iterator_init(context, lookup->flags, first_glyph, glyph_count, &iter); + BOOL ret = FALSE;
- while (iter.pos < first_glyph + iter.len) + switch (lookup->type) { - BOOL ret; - - if (!glyph_iterator_match(&iter)) - { - ++iter.pos; - continue; - } - - switch (lookup->type) - { - case GSUB_LOOKUP_SINGLE_SUBST: - ret = opentype_layout_apply_gsub_single_substitution(&iter, lookup); - break; - case GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST: - ret = opentype_layout_apply_gsub_chain_context_substitution(&iter, lookup); - break; - case GSUB_LOOKUP_MULTIPLE_SUBST: - case GSUB_LOOKUP_ALTERNATE_SUBST: - case GSUB_LOOKUP_LIGATURE_SUBST: - case GSUB_LOOKUP_CONTEXTUAL_SUBST: - case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST: - ret = FALSE; - WARN("Unimplemented lookup %d.\n", lookup->type); - break; - default: - WARN("Unknown lookup type %u.\n", lookup->type); - return; - } - - /* Some lookups update position after making changes. */ - if (!ret) - ++iter.pos; + case GSUB_LOOKUP_SINGLE_SUBST: + ret = opentype_layout_apply_gsub_single_substitution(context, lookup); + break; + case GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST: + ret = opentype_layout_apply_gsub_chain_context_substitution(context, lookup); + break; + case GSUB_LOOKUP_MULTIPLE_SUBST: + case GSUB_LOOKUP_ALTERNATE_SUBST: + case GSUB_LOOKUP_LIGATURE_SUBST: + case GSUB_LOOKUP_CONTEXTUAL_SUBST: + case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST: + WARN("Unimplemented lookup %d.\n", lookup->type); + break; + default: + WARN("Unknown lookup type %u.\n", lookup->type); } + + return ret; }
static unsigned int unicode_get_mirrored_char(unsigned int codepoint) @@ -4809,11 +4870,12 @@ static void opentype_get_nominal_glyphs(struct scriptshaping_context *context, c } }
-HRESULT opentype_layout_apply_gsub_features(struct scriptshaping_context *context, unsigned int script_index, +void opentype_layout_apply_gsub_features(struct scriptshaping_context *context, unsigned int script_index, unsigned int language_index, const struct shaping_features *features) { struct lookups lookups = { 0 }; unsigned int i; + BOOL ret;
opentype_layout_collect_lookups(context, script_index, language_index, features, &context->cache->gsub, &lookups);
@@ -4821,9 +4883,24 @@ HRESULT opentype_layout_apply_gsub_features(struct scriptshaping_context *contex opentype_layout_set_glyph_masks(context, features);
for (i = 0; i < lookups.count; ++i) - opentype_layout_apply_gsub_lookup(context, 0, context->glyph_count, &lookups.lookups[i], FALSE); + { + const struct lookup *lookup = &lookups.lookups[i];
- heap_free(lookups.lookups); + context->cur = 0; + while (context->cur < context->glyph_count) + { + ret = FALSE;
- return S_OK; + if ((context->glyph_infos[context->cur].mask & lookup->mask) && + lookup_is_glyph_match(context->glyph_infos[context->cur].props, lookup->flags)) + { + ret = opentype_layout_apply_gsub_lookup(context, lookup); + } + + if (!ret) + context->cur++; + } + } + + heap_free(lookups.lookups); }