[PATCH 5/5] dwrite: Use global cursor to glyph array for substitutions.
Nikolay Sivov
nsivov at codeweavers.com
Tue May 26 03:16:12 CDT 2020
Signed-off-by: Nikolay Sivov <nsivov at 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);
}
--
2.26.2
More information about the wine-devel
mailing list