[PATCH 2/5] dwrite: Handle extension substitution (GSUB lookup 7).
Nikolay Sivov
nsivov at codeweavers.com
Wed May 27 02:14:22 CDT 2020
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/dwrite/opentype.c | 255 ++++++++++++++++++++++-------------------
1 file changed, 135 insertions(+), 120 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c
index d21397f30a2..81b6aaa229b 100644
--- a/dlls/dwrite/opentype.c
+++ b/dlls/dwrite/opentype.c
@@ -547,7 +547,7 @@ enum OPENTYPE_PLATFORM_ID
OPENTYPE_PLATFORM_CUSTOM
};
-struct ot_gsubgpos_extensionpos_format1
+struct ot_gsubgpos_extension_format1
{
UINT16 format;
UINT16 lookup_type;
@@ -3385,7 +3385,7 @@ static unsigned int opentype_layout_get_gpos_subtable(const struct scriptshaping
FIELD_OFFSET(struct ot_lookup_table, subtable[subtable]));
if (lookup_type == GPOS_LOOKUP_EXTENSION_POSITION)
{
- const struct ot_gsubgpos_extensionpos_format1 *format1 = table_read_ensure(&cache->gpos.table,
+ const struct ot_gsubgpos_extension_format1 *format1 = table_read_ensure(&cache->gpos.table,
lookup_offset + subtable_offset, sizeof(*format1));
subtable_offset += GET_BE_DWORD(format1->extension_offset);
}
@@ -3393,18 +3393,11 @@ static unsigned int opentype_layout_get_gpos_subtable(const struct scriptshaping
return lookup_offset + subtable_offset;
}
-static unsigned int opentype_layout_get_gsub_subtable(const struct scriptshaping_cache *cache,
+static unsigned int opentype_layout_get_gsub_subtable(const struct scriptshaping_context *context,
unsigned int lookup_offset, unsigned int subtable)
{
- UINT16 lookup_type = table_read_be_word(&cache->gsub.table, lookup_offset);
- unsigned int subtable_offset = table_read_be_word(&cache->gsub.table, lookup_offset +
+ unsigned int subtable_offset = table_read_be_word(&context->table->table, lookup_offset +
FIELD_OFFSET(struct ot_lookup_table, subtable[subtable]));
- if (lookup_type == GSUB_LOOKUP_EXTENSION_SUBST)
- {
- const struct ot_gsubgpos_extensionpos_format1 *format1 = table_read_ensure(&cache->gsub.table,
- lookup_offset + subtable_offset, sizeof(*format1));
- subtable_offset += GET_BE_DWORD(format1->extension_offset);
- }
return lookup_offset + subtable_offset;
}
@@ -4086,7 +4079,7 @@ static void opentype_layout_apply_gpos_lookup(struct scriptshaping_context *cont
lookup_type = GET_BE_WORD(lookup_table->lookup_type);
if (lookup_type == GPOS_LOOKUP_EXTENSION_POSITION)
{
- const struct ot_gsubgpos_extensionpos_format1 *extension = table_read_ensure(&cache->gpos.table,
+ const struct ot_gsubgpos_extension_format1 *extension = table_read_ensure(&cache->gpos.table,
lookup.offset + GET_BE_WORD(lookup_table->subtable[0]), sizeof(*extension));
WORD format;
@@ -4462,53 +4455,45 @@ void opentype_layout_apply_gpos_features(struct scriptshaping_context *context,
heap_free(lookups.lookups);
}
-static BOOL opentype_layout_apply_gsub_single_substitution(struct scriptshaping_context *context, const struct lookup *lookup)
+static BOOL opentype_layout_apply_gsub_single_substitution(struct scriptshaping_context *context, const struct lookup *lookup,
+ unsigned int subtable_offset)
{
- struct scriptshaping_cache *cache = context->cache;
const struct dwrite_fonttable *gsub = &context->table->table;
UINT16 format, coverage, orig_glyph, glyph;
- unsigned int i, idx;
+ unsigned int idx, coverage_index;
BOOL ret;
idx = context->cur;
orig_glyph = glyph = context->u.subst.glyphs[idx];
- for (i = 0; i < lookup->subtable_count; ++i)
- {
- unsigned int subtable_offset = opentype_layout_get_gsub_subtable(cache, lookup->offset, i);
- unsigned int coverage_index;
-
- format = table_read_be_word(gsub, subtable_offset);
+ format = table_read_be_word(gsub, subtable_offset);
- coverage = table_read_be_word(gsub, subtable_offset + FIELD_OFFSET(struct ot_gsub_singlesubst_format1, coverage));
+ coverage = table_read_be_word(gsub, subtable_offset + FIELD_OFFSET(struct ot_gsub_singlesubst_format1, coverage));
- if (format == 1)
- {
- const struct ot_gsub_singlesubst_format1 *format1 = table_read_ensure(gsub, subtable_offset, sizeof(*format1));
+ if (format == 1)
+ {
+ const struct ot_gsub_singlesubst_format1 *format1 = table_read_ensure(gsub, subtable_offset, sizeof(*format1));
- coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph);
- if (coverage_index == GLYPH_NOT_COVERED)
- continue;
+ coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph);
+ if (coverage_index == GLYPH_NOT_COVERED)
+ return FALSE;
- glyph = orig_glyph + GET_BE_WORD(format1->delta);
- break;
- }
- else if (format == 2)
- {
- UINT16 count = table_read_be_word(gsub, subtable_offset + FIELD_OFFSET(struct ot_gsub_singlesubst_format2, count));
- const struct ot_gsub_singlesubst_format2 *format2 = table_read_ensure(gsub, subtable_offset,
- FIELD_OFFSET(struct ot_gsub_singlesubst_format2, count) + count * sizeof(UINT16));
+ glyph = orig_glyph + GET_BE_WORD(format1->delta);
+ }
+ else if (format == 2)
+ {
+ UINT16 count = table_read_be_word(gsub, subtable_offset + FIELD_OFFSET(struct ot_gsub_singlesubst_format2, count));
+ const struct ot_gsub_singlesubst_format2 *format2 = table_read_ensure(gsub, subtable_offset,
+ FIELD_OFFSET(struct ot_gsub_singlesubst_format2, count) + count * sizeof(UINT16));
- coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph);
- if (coverage_index == GLYPH_NOT_COVERED || coverage_index >= count)
- continue;
+ coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph);
+ if (coverage_index == GLYPH_NOT_COVERED || coverage_index >= count)
+ return FALSE;
- glyph = GET_BE_WORD(format2->substitutes[coverage_index]);
- break;
- }
- else
- WARN("Unknown single substitution format %u.\n", format);
+ glyph = GET_BE_WORD(format2->substitutes[coverage_index]);
}
+ else
+ WARN("Unknown single substitution format %u.\n", format);
if ((ret = (glyph != orig_glyph)))
{
@@ -4684,111 +4669,141 @@ static BOOL opentype_layout_apply_gsub_chain_context_lookup(struct scriptshaping
}
static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scriptshaping_context *context,
- const struct lookup *lookup)
+ const struct lookup *lookup, unsigned int subtable_offset)
{
- struct scriptshaping_cache *cache = context->cache;
const struct dwrite_fonttable *table = &context->table->table;
- UINT16 format, coverage;
+ unsigned int coverage_index = GLYPH_NOT_COVERED;
+ UINT16 glyph, 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 = context->u.subst.glyphs[context->cur];
- unsigned int coverage_index = GLYPH_NOT_COVERED;
+ glyph = context->u.subst.glyphs[context->cur];
- format = table_read_be_word(&context->table->table, subtable_offset);
+ format = table_read_be_word(table, subtable_offset);
- if (format == 1)
- {
- coverage = table_read_be_word(table, subtable_offset +
- FIELD_OFFSET(struct ot_gsub_chaincontext_subst_format1, coverage));
+ if (format == 1)
+ {
+ coverage = table_read_be_word(table, subtable_offset +
+ FIELD_OFFSET(struct ot_gsub_chaincontext_subst_format1, coverage));
- coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph);
- if (coverage_index == GLYPH_NOT_COVERED)
- continue;
+ coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph);
+ if (coverage_index == GLYPH_NOT_COVERED)
+ return FALSE;
- WARN("Chaining contextual substitution (1) is not supported.\n");
- break;
- }
- else if (format == 2)
- {
- coverage = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_chaincontext_subst_format1, coverage));
+ WARN("Chaining contextual substitution (1) is not supported.\n");
+ }
+ else if (format == 2)
+ {
+ coverage = table_read_be_word(table, subtable_offset +
+ FIELD_OFFSET(struct ot_gsub_chaincontext_subst_format1, coverage));
- coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph);
- if (coverage_index == GLYPH_NOT_COVERED)
- continue;
+ coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + coverage, glyph);
+ if (coverage_index == GLYPH_NOT_COVERED)
+ return FALSE;
- WARN("Chaining contextual substitution (2) is not supported.\n");
- break;
- }
- else if (format == 3)
- {
- unsigned int backtrack_count, input_count, lookahead_count, lookup_count;
- const UINT16 *backtrack, *lookahead, *input, *lookup_records;
+ WARN("Chaining contextual substitution (2) is not supported.\n");
+ }
+ else if (format == 3)
+ {
+ unsigned int backtrack_count, input_count, lookahead_count, lookup_count;
+ const UINT16 *backtrack, *lookahead, *input, *lookup_records;
- unsigned int offset = subtable_offset + 2 /* format */;
+ unsigned int offset = subtable_offset + 2 /* format */;
- backtrack_count = table_read_be_word(table, offset);
- offset += 2;
- backtrack = table_read_ensure(table, offset, backtrack_count * sizeof(*backtrack));
- offset += backtrack_count * sizeof(*backtrack);
+ backtrack_count = table_read_be_word(table, offset);
+ offset += 2;
+ backtrack = table_read_ensure(table, offset, backtrack_count * sizeof(*backtrack));
+ offset += backtrack_count * sizeof(*backtrack);
- input_count = table_read_be_word(table, offset);
- offset += 2;
- input = table_read_ensure(table, offset, input_count * sizeof(*input));
- offset += input_count * sizeof(*input);
+ input_count = table_read_be_word(table, offset);
+ offset += 2;
+ input = table_read_ensure(table, offset, input_count * sizeof(*input));
+ offset += input_count * sizeof(*input);
- lookahead_count = table_read_be_word(table, offset);
- offset += 2;
- lookahead = table_read_ensure(table, offset, lookahead_count * sizeof(*lookahead));
- offset += lookahead_count * sizeof(*lookahead);
+ lookahead_count = table_read_be_word(table, offset);
+ offset += 2;
+ lookahead = table_read_ensure(table, offset, lookahead_count * sizeof(*lookahead));
+ offset += lookahead_count * sizeof(*lookahead);
- lookup_count = table_read_be_word(table, offset);
- offset += 2;
- lookup_records = table_read_ensure(table, offset, lookup_count * 2 * sizeof(*lookup_records));
+ lookup_count = table_read_be_word(table, offset);
+ offset += 2;
+ lookup_records = table_read_ensure(table, offset, lookup_count * 2 * sizeof(*lookup_records));
- if (input)
- coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(input[0]), glyph);
+ if (input)
+ coverage_index = opentype_layout_is_glyph_covered(context, subtable_offset + GET_BE_WORD(input[0]), glyph);
- if (coverage_index == GLYPH_NOT_COVERED)
- continue;
+ if (coverage_index == GLYPH_NOT_COVERED)
+ return FALSE;
- 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;
- }
- }
- else
- WARN("Unknown chaining contextual substitution format %u.\n", format);
+ 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);
}
+ else
+ WARN("Unknown chaining contextual substitution format %u.\n", format);
return ret;
}
+static unsigned int opentype_layout_adjust_extension_subtable(struct scriptshaping_context *context,
+ unsigned int *subtable_offset)
+{
+ const struct ot_gsubgpos_extension_format1 *format1;
+
+ if (!(format1 = table_read_ensure(&context->table->table, *subtable_offset, sizeof(*format1))))
+ return 0;
+
+ if (GET_BE_WORD(format1->format) != 1)
+ {
+ WARN("Unexpected extension table format %#x.\n", format1->format);
+ return 0;
+ }
+
+ *subtable_offset = *subtable_offset + GET_BE_DWORD(format1->extension_offset);
+
+ return GET_BE_WORD(format1->lookup_type);
+}
+
static BOOL opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, const struct lookup *lookup)
{
+ unsigned int i, lookup_type;
BOOL ret = FALSE;
- switch (lookup->type)
+ for (i = 0; i < lookup->subtable_count; ++i)
{
- 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);
+ unsigned int subtable_offset = opentype_layout_get_gsub_subtable(context, lookup->offset, i);
+
+ if (lookup->type == GSUB_LOOKUP_EXTENSION_SUBST)
+ {
+ lookup_type = opentype_layout_adjust_extension_subtable(context, &subtable_offset);
+ if (!lookup_type)
+ continue;
+ }
+ else
+ lookup_type = lookup->type;
+
+ switch (lookup_type)
+ {
+ case GSUB_LOOKUP_SINGLE_SUBST:
+ ret = opentype_layout_apply_gsub_single_substitution(context, lookup, subtable_offset);
+ break;
+ case GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST:
+ ret = opentype_layout_apply_gsub_chain_context_substitution(context, lookup, subtable_offset);
+ 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;
+ case GSUB_LOOKUP_EXTENSION_SUBST:
+ WARN("Invalid lookup type for extension substitution %#x.\n", lookup_type);
+ break;
+ default:
+ WARN("Unknown lookup type %u.\n", lookup_type);
+ }
+
+ if (ret)
break;
- default:
- WARN("Unknown lookup type %u.\n", lookup->type);
}
return ret;
--
2.26.2
More information about the wine-devel
mailing list