Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 24 +++----- dlls/dwrite/dwrite_private.h | 28 +++++++--- dlls/dwrite/opentype.c | 103 +++++++++++++++++------------------ dlls/dwrite/shape.c | 47 ++++++++++++++++ dlls/dwrite/tests/analyzer.c | 50 +++++------------ 5 files changed, 137 insertions(+), 115 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index a8a3e7c359b..10c59f1bdca 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -1767,29 +1767,23 @@ static HRESULT WINAPI dwritetextanalyzer2_GetTypographicFeatures(IDWriteTextAnal IDWriteFontFace *fontface, DWRITE_SCRIPT_ANALYSIS sa, const WCHAR *locale, UINT32 max_tagcount, UINT32 *actual_tagcount, DWRITE_FONT_FEATURE_TAG *tags) { + struct scriptshaping_context context = { 0 }; const struct dwritescript_properties *props; - const DWORD *scripts; - HRESULT hr = S_OK; - UINT32 language; + struct dwrite_fontface *font_obj;
- TRACE("(%p %u %s %u %p %p)\n", fontface, sa.script, debugstr_w(locale), max_tagcount, actual_tagcount, - tags); + TRACE("%p, %p, %u, %s, %u, %p, %p.\n", iface, fontface, sa.script, debugstr_w(locale), max_tagcount, + actual_tagcount, tags);
if (sa.script > Script_LastId) return E_INVALIDARG;
- language = get_opentype_language(locale); - props = &dwritescripts_properties[sa.script]; - *actual_tagcount = 0; + font_obj = unsafe_impl_from_IDWriteFontFace(fontface);
- scripts = props->scripttags; - while (*scripts && !*actual_tagcount) - { - hr = opentype_get_typographic_features(fontface, *scripts, language, max_tagcount, actual_tagcount, tags); - scripts++; - } + context.cache = fontface_get_shaping_cache(font_obj); + context.language_tag = get_opentype_language(locale); + props = &dwritescripts_properties[sa.script];
- return hr; + return shape_get_typographic_features(&context, props->scripttags, max_tagcount, actual_tagcount, tags); };
static HRESULT WINAPI dwritetextanalyzer2_CheckTypographicFeature(IDWriteTextAnalyzer2 *iface, diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index f8b7e0d139d..246dab69327 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -330,6 +330,21 @@ struct file_stream_desc { extern const void* get_fontface_table(IDWriteFontFace5 *fontface, UINT32 tag, struct dwrite_fonttable *table) DECLSPEC_HIDDEN;
+struct tag_array +{ + unsigned int *tags; + size_t capacity; + size_t count; +}; + +struct ot_gsubgpos_table +{ + struct dwrite_fonttable table; + unsigned int script_list; + unsigned int feature_list; + unsigned int lookup_list; +}; + extern HRESULT opentype_analyze_font(IDWriteFontFileStream*,BOOL*,DWRITE_FONT_FILE_TYPE*,DWRITE_FONT_FACE_TYPE*,UINT32*) DECLSPEC_HIDDEN; extern HRESULT opentype_try_get_font_table(const struct file_stream_desc *stream_desc, UINT32 tag, const void **data, void **context, UINT32 *size, BOOL *exists) DECLSPEC_HIDDEN; @@ -343,7 +358,8 @@ extern HRESULT opentype_get_font_info_strings(const struct file_stream_desc *str DWRITE_INFORMATIONAL_STRING_ID id, IDWriteLocalizedStrings **strings) DECLSPEC_HIDDEN; extern HRESULT opentype_get_font_familyname(struct file_stream_desc*,IDWriteLocalizedStrings**) DECLSPEC_HIDDEN; extern HRESULT opentype_get_font_facename(struct file_stream_desc*,WCHAR*,IDWriteLocalizedStrings**) DECLSPEC_HIDDEN; -extern HRESULT opentype_get_typographic_features(IDWriteFontFace*,UINT32,UINT32,UINT32,UINT32*,DWRITE_FONT_FEATURE_TAG*) DECLSPEC_HIDDEN; +extern void opentype_get_typographic_features(struct ot_gsubgpos_table *table, unsigned int script_index, + unsigned int language_index, struct tag_array *tags) DECLSPEC_HIDDEN; extern BOOL opentype_get_vdmx_size(const struct dwrite_fonttable *table, INT ppem, UINT16 *ascent, UINT16 *descent) DECLSPEC_HIDDEN; extern unsigned int opentype_get_cpal_palettecount(const struct dwrite_fonttable *table) DECLSPEC_HIDDEN; @@ -438,14 +454,6 @@ enum SCRIPT_JUSTIFY SCRIPT_JUSTIFY_ARABIC_SEEN_M };
-struct ot_gsubgpos_table -{ - struct dwrite_fonttable table; - unsigned int script_list; - unsigned int feature_list; - unsigned int lookup_list; -}; - struct scriptshaping_cache { const struct shaping_font_ops *font; @@ -586,3 +594,5 @@ extern void opentype_layout_apply_gpos_features(struct scriptshaping_context *co
extern HRESULT shape_get_glyphs(struct scriptshaping_context *context, const unsigned int *scripts) DECLSPEC_HIDDEN; extern HRESULT shape_get_positions(struct scriptshaping_context *context, const unsigned int *scripts) DECLSPEC_HIDDEN; +extern HRESULT shape_get_typographic_features(struct scriptshaping_context *context, const unsigned int *scripts, + unsigned int max_tagcount, unsigned int *actual_tagcount, unsigned int *tags) DECLSPEC_HIDDEN; diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 2106fe2cf78..a07d12c0f8c 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -2467,74 +2467,69 @@ static inline const struct ot_script *opentype_get_script(const struct ot_script return NULL; }
-static inline const struct ot_langsys *opentype_get_langsys(const struct ot_script *script, UINT32 languagetag) +static const struct ot_langsys *opentype_get_langsys(const struct ot_gsubgpos_table *table, unsigned int script_index, + unsigned int language_index, unsigned int *feature_count) { - UINT16 j; - - for (j = 0; j < GET_BE_WORD(script->langsys_count); j++) { - const char *tag = script->langsys[j].tag; - if (languagetag == DWRITE_MAKE_OPENTYPE_TAG(tag[0], tag[1], tag[2], tag[3])) - return (struct ot_langsys *)((BYTE*)script + GET_BE_WORD(script->langsys[j].langsys)); - } - - return NULL; -} + unsigned int table_offset, langsys_offset; + const struct ot_langsys *langsys = NULL;
-static void opentype_add_font_features(const struct gpos_gsub_header *header, const struct ot_langsys *langsys, - UINT32 max_tagcount, UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags) -{ - const struct ot_feature_list *features = (const struct ot_feature_list *)((const BYTE*)header + GET_BE_WORD(header->feature_list)); - UINT16 j; + *feature_count = 0;
- for (j = 0; j < GET_BE_WORD(langsys->feature_count); j++) { - const struct ot_feature_record *feature = &features->features[langsys->feature_index[j]]; + if (!table->table.data || script_index == ~0u) + return NULL;
- if (*count < max_tagcount) - tags[*count] = GET_BE_DWORD(feature->tag); + /* ScriptTable offset. */ + table_offset = table_read_be_word(&table->table, table->script_list + FIELD_OFFSET(struct ot_script_list, scripts) + + script_index * sizeof(struct ot_script_record) + FIELD_OFFSET(struct ot_script_record, script)); + if (!table_offset) + return NULL;
- (*count)++; - } + if (language_index == ~0u) + langsys_offset = table_read_be_word(&table->table, table->script_list + table_offset); + else + langsys_offset = table_read_be_word(&table->table, table->script_list + table_offset + + FIELD_OFFSET(struct ot_script, langsys) + language_index * sizeof(struct ot_langsys_record) + + FIELD_OFFSET(struct ot_langsys_record, langsys)); + langsys_offset += table->script_list + table_offset; + + *feature_count = table_read_be_word(&table->table, langsys_offset + FIELD_OFFSET(struct ot_langsys, feature_count)); + if (*feature_count) + langsys = table_read_ensure(&table->table, langsys_offset, FIELD_OFFSET(struct ot_langsys, feature_index[*feature_count])); + if (!langsys) + *feature_count = 0; + + return langsys; }
-HRESULT opentype_get_typographic_features(IDWriteFontFace *fontface, UINT32 scripttag, UINT32 languagetag, UINT32 max_tagcount, - UINT32 *count, DWRITE_FONT_FEATURE_TAG *tags) +void opentype_get_typographic_features(struct ot_gsubgpos_table *table, unsigned int script_index, + unsigned int language_index, struct tag_array *t) { - UINT32 tables[2] = { MS_GSUB_TAG, MS_GPOS_TAG }; - HRESULT hr; - UINT8 i; - - *count = 0; - for (i = 0; i < ARRAY_SIZE(tables); i++) { - const struct ot_script_list *scriptlist; - const struct gpos_gsub_header *header; - const struct ot_script *script; - const void *ptr; - void *context; - UINT32 size; - BOOL exists; + unsigned int i, total_feature_count, script_feature_count; + const struct ot_feature_list *feature_list; + const struct ot_langsys *langsys = NULL;
- exists = FALSE; - hr = IDWriteFontFace_TryGetFontTable(fontface, tables[i], &ptr, &size, &context, &exists); - if (FAILED(hr)) - return hr; + langsys = opentype_get_langsys(table, script_index, language_index, &script_feature_count);
- if (!exists) - continue; + total_feature_count = table_read_be_word(&table->table, table->feature_list); + if (!total_feature_count) + return;
- header = (const struct gpos_gsub_header *)ptr; - scriptlist = (const struct ot_script_list *)((const BYTE*)header + GET_BE_WORD(header->script_list)); + feature_list = table_read_ensure(&table->table, table->feature_list, + FIELD_OFFSET(struct ot_feature_list, features[total_feature_count])); + if (!feature_list) + return;
- script = opentype_get_script(scriptlist, scripttag); - if (script) { - const struct ot_langsys *langsys = opentype_get_langsys(script, languagetag); - if (langsys) - opentype_add_font_features(header, langsys, max_tagcount, count, tags); - } + for (i = 0; i < script_feature_count; ++i) + { + unsigned int feature_index = GET_BE_WORD(langsys->feature_index[i]); + if (feature_index >= total_feature_count) + continue;
- IDWriteFontFace_ReleaseFontTable(fontface, context); - } + if (!dwrite_array_reserve((void **)&t->tags, &t->capacity, t->count + 1, sizeof(*t->tags))) + return;
- return *count > max_tagcount ? E_NOT_SUFFICIENT_BUFFER : S_OK; + t->tags[t->count++] = feature_list->features[feature_index].tag; + } }
static unsigned int find_vdmx_group(const struct vdmx_header *hdr) diff --git a/dlls/dwrite/shape.c b/dlls/dwrite/shape.c index 32aabac5f68..4968cd995d4 100644 --- a/dlls/dwrite/shape.c +++ b/dlls/dwrite/shape.c @@ -22,11 +22,18 @@ #define COBJMACROS
#include "dwrite_private.h" +#include "winternl.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dwrite);
+#ifdef WORDS_BIGENDIAN +#define GET_BE_DWORD(x) (x) +#else +#define GET_BE_DWORD(x) RtlUlongByteSwap(x) +#endif + struct scriptshaping_cache *create_scriptshaping_cache(void *context, const struct shaping_font_ops *font_ops) { struct scriptshaping_cache *cache; @@ -303,3 +310,43 @@ HRESULT shape_get_glyphs(struct scriptshaping_context *context, const unsigned i
return (context->glyph_count <= context->u.subst.max_glyph_count) ? S_OK : E_NOT_SUFFICIENT_BUFFER; } + +static int tag_array_sorting_compare(const void *a, const void *b) +{ + unsigned int left = GET_BE_DWORD(*(unsigned int *)a), right = GET_BE_DWORD(*(unsigned int *)b); + return left != right ? (left < right ? -1 : 1) : 0; +}; + +HRESULT shape_get_typographic_features(struct scriptshaping_context *context, const unsigned int *scripts, + unsigned int max_tagcount, unsigned int *actual_tagcount, unsigned int *tags) +{ + unsigned int i, j, script_index, language_index; + struct tag_array t = { 0 }; + + /* Collect from both tables, sort and remove duplicates. */ + + shape_get_script_lang_index(context, scripts, MS_GSUB_TAG, &script_index, &language_index); + opentype_get_typographic_features(&context->cache->gsub, script_index, language_index, &t); + + shape_get_script_lang_index(context, scripts, MS_GPOS_TAG, &script_index, &language_index); + opentype_get_typographic_features(&context->cache->gpos, script_index, language_index, &t); + + /* Sort and remove duplicates. */ + qsort(t.tags, t.count, sizeof(*t.tags), tag_array_sorting_compare); + + for (i = 1, j = 0; i < t.count; ++i) + { + if (t.tags[i] != t.tags[j]) + t.tags[++j] = t.tags[i]; + } + t.count = j + 1; + + if (t.count <= max_tagcount) + memcpy(tags, t.tags, t.count * sizeof(*t.tags)); + + *actual_tagcount = t.count; + + heap_free(t.tags); + + return t.count <= max_tagcount ? S_OK : E_NOT_SUFFICIENT_BUFFER; +} diff --git a/dlls/dwrite/tests/analyzer.c b/dlls/dwrite/tests/analyzer.c index 70becb55ee5..6dd251270c7 100644 --- a/dlls/dwrite/tests/analyzer.c +++ b/dlls/dwrite/tests/analyzer.c @@ -1795,15 +1795,6 @@ if (0) { IDWriteTextAnalyzer_Release(analyzer); }
-static BOOL has_feature(const DWRITE_FONT_FEATURE_TAG *tags, UINT32 count, DWRITE_FONT_FEATURE_TAG feature) -{ - UINT32 i; - - for (i = 0; i < count; i++) - if (tags[i] == feature) return TRUE; - return FALSE; -} - static void test_GetTypographicFeatures(void) { static const WCHAR arabicW[] = {0x064a,0x064f,0x0633,0}; @@ -1814,7 +1805,6 @@ static void test_GetTypographicFeatures(void) DWRITE_SCRIPT_ANALYSIS sa; UINT32 count; HRESULT hr; - BOOL ret;
hr = IDWriteFactory_CreateTextAnalyzer(factory, &analyzer); ok(hr == S_OK, "got 0x%08x\n", hr); @@ -1831,45 +1821,31 @@ static void test_GetTypographicFeatures(void) get_script_analysis(L"abc", &sa); count = 0; hr = IDWriteTextAnalyzer2_GetTypographicFeatures(analyzer2, fontface, sa, NULL, 0, &count, NULL); -todo_wine { - ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr); - ok(count > 0, "got %u\n", count); -} + ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr); + ok(!!count, "Unexpected count %u.\n", count); + /* invalid locale name is ignored */ get_script_analysis(L"abc", &sa); count = 0; hr = IDWriteTextAnalyzer2_GetTypographicFeatures(analyzer2, fontface, sa, L"cadabra", 0, &count, NULL); -todo_wine { - ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr); - ok(count > 0, "got %u\n", count); -} - /* both GSUB and GPOS features are reported */ + ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr); + ok(!!count, "Unexpected count %u.\n", count); + + /* Make some calls for different scripts. */ + get_script_analysis(arabicW, &sa); memset(tags, 0, sizeof(tags)); count = 0; hr = IDWriteTextAnalyzer2_GetTypographicFeatures(analyzer2, fontface, sa, NULL, ARRAY_SIZE(tags), &count, tags); - ok(hr == S_OK, "got 0x%08x\n", hr); -todo_wine { - ok(count > 0, "got %u\n", count); - ret = has_feature(tags, count, DWRITE_FONT_FEATURE_TAG_CONTEXTUAL_ALTERNATES); - ok(ret, "expected 'calt' feature\n"); - ret = has_feature(tags, count, DWRITE_FONT_FEATURE_TAG_MARK_TO_MARK_POSITIONING); - ok(ret, "expected 'mkmk' feature\n"); -} + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!!count, "Unexpected count %u.\n", count); + get_script_analysis(L"abc", &sa); memset(tags, 0, sizeof(tags)); count = 0; hr = IDWriteTextAnalyzer2_GetTypographicFeatures(analyzer2, fontface, sa, NULL, ARRAY_SIZE(tags), &count, tags); - ok(hr == S_OK, "got 0x%08x\n", hr); -todo_wine { - ok(count > 0, "got %u\n", count); - ret = has_feature(tags, count, DWRITE_FONT_FEATURE_TAG_GLYPH_COMPOSITION_DECOMPOSITION); - ok(ret, "expected 'ccmp' feature\n"); - ret = has_feature(tags, count, DWRITE_FONT_FEATURE_TAG_MARK_TO_MARK_POSITIONING); - ok(ret, "expected 'mkmk' feature\n"); -} - ret = has_feature(tags, count, DWRITE_FONT_FEATURE_TAG_CONTEXTUAL_ALTERNATES); - ok(!ret, "unexpected 'calt' feature\n"); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(!!count, "Unexpected count %u.\n", count);
IDWriteFontFace_Release(fontface); IDWriteTextAnalyzer2_Release(analyzer2);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 10c59f1bdca..909d6e91e3e 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -2357,7 +2357,7 @@ static HRESULT WINAPI fontfallbackbuilder_CreateFontFallback(IDWriteFontFallback struct dwrite_fontfallback_builder *fallbackbuilder = impl_from_IDWriteFontFallbackBuilder(iface); struct dwrite_fontfallback *fallback;
- FIXME("%p, %p stub.\n", iface, ret); + TRACE("%p, %p.\n", iface, ret);
*ret = NULL;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 29 +++- dlls/dwrite/dwrite_private.h | 5 + dlls/dwrite/opentype.c | 249 +++++++++++++++++++++++++++++++++++ dlls/dwrite/shape.c | 25 ++++ 4 files changed, 304 insertions(+), 4 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 909d6e91e3e..af4325248a7 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -1787,12 +1787,33 @@ static HRESULT WINAPI dwritetextanalyzer2_GetTypographicFeatures(IDWriteTextAnal };
static HRESULT WINAPI dwritetextanalyzer2_CheckTypographicFeature(IDWriteTextAnalyzer2 *iface, - IDWriteFontFace *face, DWRITE_SCRIPT_ANALYSIS sa, const WCHAR *locale, DWRITE_FONT_FEATURE_TAG feature, + IDWriteFontFace *fontface, DWRITE_SCRIPT_ANALYSIS sa, const WCHAR *locale, DWRITE_FONT_FEATURE_TAG feature, UINT32 glyph_count, const UINT16 *glyphs, UINT8 *feature_applies) { - FIXME("(%p %u %s %s %u %p %p): stub\n", face, sa.script, debugstr_w(locale), debugstr_tag(feature), glyph_count, - glyphs, feature_applies); - return E_NOTIMPL; + struct scriptshaping_context context = { 0 }; + const struct dwritescript_properties *props; + struct dwrite_fontface *font_obj; + HRESULT hr; + + TRACE("%p, %p, %u, %s, %s, %u, %p, %p.\n", iface, fontface, sa.script, debugstr_w(locale), debugstr_tag(feature), + glyph_count, glyphs, feature_applies); + + if (sa.script > Script_LastId) + return E_INVALIDARG; + + font_obj = unsafe_impl_from_IDWriteFontFace(fontface); + + context.cache = fontface_get_shaping_cache(font_obj); + context.language_tag = get_opentype_language(locale); + context.glyph_infos = heap_calloc(glyph_count, sizeof(*context.glyph_infos)); + + props = &dwritescripts_properties[sa.script]; + + hr = shape_check_typographic_feature(&context, props->scripttags, feature, glyph_count, glyphs, feature_applies); + + heap_free(context.glyph_infos); + + return hr; }
static const struct IDWriteTextAnalyzer2Vtbl textanalyzervtbl = { diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 246dab69327..966750c12b4 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -591,8 +591,13 @@ extern void opentype_layout_apply_gsub_features(struct scriptshaping_context *co 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; +extern BOOL opentype_layout_check_feature(struct scriptshaping_context *context, unsigned int script_index, + unsigned int language_index, struct shaping_feature *feature, unsigned int glyph_count, + const UINT16 *glyphs, UINT8 *feature_applies) DECLSPEC_HIDDEN;
extern HRESULT shape_get_glyphs(struct scriptshaping_context *context, const unsigned int *scripts) DECLSPEC_HIDDEN; extern HRESULT shape_get_positions(struct scriptshaping_context *context, const unsigned int *scripts) DECLSPEC_HIDDEN; extern HRESULT shape_get_typographic_features(struct scriptshaping_context *context, const unsigned int *scripts, unsigned int max_tagcount, unsigned int *actual_tagcount, unsigned int *tags) DECLSPEC_HIDDEN; +extern HRESULT shape_check_typographic_feature(struct scriptshaping_context *context, const unsigned int *scripts, + unsigned int tag, unsigned int glyph_count, const UINT16 *glyphs, UINT8 *feature_applies) DECLSPEC_HIDDEN; diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index a07d12c0f8c..cbd43bad495 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -5745,3 +5745,252 @@ void opentype_layout_apply_gsub_features(struct scriptshaping_context *context,
heap_free(lookups.lookups); } + +static BOOL opentype_layout_contextual_lookup_is_glyph_covered(struct scriptshaping_context *context, UINT16 glyph, + unsigned int subtable_offset, unsigned int coverage, unsigned int format) +{ + const struct dwrite_fonttable *table = &context->table->table; + const UINT16 *offsets; + unsigned int count; + + if (format == 1 || format == 2) + { + if (opentype_layout_is_glyph_covered(table, subtable_offset + coverage, glyph) != GLYPH_NOT_COVERED) + return TRUE; + } + else if (format == 3) + { + count = table_read_be_word(table, subtable_offset + 2); + if (!count || !(offsets = table_read_ensure(table, subtable_offset + 6, count * sizeof(*offsets)))) + return FALSE; + + if (opentype_layout_is_glyph_covered(table, subtable_offset + GET_BE_WORD(offsets[0]), glyph) != GLYPH_NOT_COVERED) + return TRUE; + } + + return FALSE; +} + +static BOOL opentype_layout_chain_contextual_lookup_is_glyph_covered(struct scriptshaping_context *context, UINT16 glyph, + unsigned int subtable_offset, unsigned int coverage, unsigned int format) +{ + const struct dwrite_fonttable *table = &context->table->table; + unsigned int count, backtrack_count; + const UINT16 *offsets; + + if (format == 1 || format == 2) + { + if (opentype_layout_is_glyph_covered(table, subtable_offset + coverage, glyph) != GLYPH_NOT_COVERED) + return TRUE; + } + else if (format == 3) + { + backtrack_count = table_read_be_word(table, subtable_offset + 2); + + count = table_read_be_word(table, subtable_offset + 4 + backtrack_count * sizeof(*offsets)); + + if (!count || !(offsets = table_read_ensure(table, subtable_offset + 6 + backtrack_count * sizeof(*offsets), + count * sizeof(*offsets)))) + return FALSE; + + if (opentype_layout_is_glyph_covered(table, subtable_offset + GET_BE_WORD(offsets[0]), glyph) != GLYPH_NOT_COVERED) + return TRUE; + } + + return FALSE; +} + +static BOOL opentype_layout_gsub_lookup_is_glyph_covered(struct scriptshaping_context *context, UINT16 glyph, + const struct lookup *lookup) +{ + const struct dwrite_fonttable *gsub = &context->table->table; + static const unsigned short gsub_formats[] = + { + 0, /* Unused */ + 1, /* SingleSubst */ + 1, /* MultipleSubst */ + 1, /* AlternateSubst */ + 1, /* LigatureSubst */ + 3, /* ContextSubst */ + 3, /* ChainContextSubst */ + 0, /* Extension, unused */ + 1, /* ReverseChainSubst */ + }; + unsigned int i, coverage, lookup_type, format; + + for (i = 0; i < lookup->subtable_count; ++i) + { + unsigned int subtable_offset = opentype_layout_get_gsubgpos_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; + + format = table_read_be_word(gsub, subtable_offset); + + if (!format || format > ARRAY_SIZE(gsub_formats) || format > gsub_formats[lookup_type]) + break; + + coverage = table_read_be_word(gsub, subtable_offset + 2); + + switch (lookup_type) + { + case GSUB_LOOKUP_SINGLE_SUBST: + case GSUB_LOOKUP_MULTIPLE_SUBST: + case GSUB_LOOKUP_ALTERNATE_SUBST: + case GSUB_LOOKUP_LIGATURE_SUBST: + case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST: + + if (opentype_layout_is_glyph_covered(gsub, subtable_offset + coverage, glyph) != GLYPH_NOT_COVERED) + return TRUE; + + break; + + case GSUB_LOOKUP_CONTEXTUAL_SUBST: + + if (opentype_layout_contextual_lookup_is_glyph_covered(context, glyph, subtable_offset, coverage, format)) + return TRUE; + + break; + + case GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST: + + if (opentype_layout_chain_contextual_lookup_is_glyph_covered(context, glyph, subtable_offset, coverage, format)) + return TRUE; + + break; + + default: + WARN("Unknown lookup type %u.\n", lookup_type); + } + } + + return FALSE; +} + +static BOOL opentype_layout_gpos_lookup_is_glyph_covered(struct scriptshaping_context *context, UINT16 glyph, + const struct lookup *lookup) +{ + const struct dwrite_fonttable *gpos = &context->table->table; + static const unsigned short gpos_formats[] = + { + 0, /* Unused */ + 2, /* SinglePos */ + 2, /* PairPos */ + 1, /* CursivePos */ + 1, /* MarkBasePos */ + 1, /* MarkLigPos */ + 1, /* MarkMarkPos */ + 3, /* ContextPos */ + 3, /* ChainContextPos */ + 0, /* Extension, unused */ + }; + unsigned int i, coverage, lookup_type, format; + + for (i = 0; i < lookup->subtable_count; ++i) + { + unsigned int subtable_offset = opentype_layout_get_gsubgpos_subtable(context, lookup->offset, i); + + if (lookup->type == GPOS_LOOKUP_EXTENSION_POSITION) + { + lookup_type = opentype_layout_adjust_extension_subtable(context, &subtable_offset); + if (!lookup_type) + continue; + } + else + lookup_type = lookup->type; + + format = table_read_be_word(gpos, subtable_offset); + + if (!format || format > ARRAY_SIZE(gpos_formats) || format > gpos_formats[lookup_type]) + break; + + coverage = table_read_be_word(gpos, subtable_offset + 2); + + switch (lookup_type) + { + case GPOS_LOOKUP_SINGLE_ADJUSTMENT: + case GPOS_LOOKUP_PAIR_ADJUSTMENT: + case GPOS_LOOKUP_CURSIVE_ATTACHMENT: + case GPOS_LOOKUP_MARK_TO_BASE_ATTACHMENT: + case GPOS_LOOKUP_MARK_TO_LIGATURE_ATTACHMENT: + case GPOS_LOOKUP_MARK_TO_MARK_ATTACHMENT: + + if (opentype_layout_is_glyph_covered(gpos, subtable_offset + coverage, glyph) != GLYPH_NOT_COVERED) + return TRUE; + + break; + + case GPOS_LOOKUP_CONTEXTUAL_POSITION: + + if (opentype_layout_contextual_lookup_is_glyph_covered(context, glyph, subtable_offset, coverage, format)) + return TRUE; + + break; + + case GPOS_LOOKUP_CONTEXTUAL_CHAINING_POSITION: + + if (opentype_layout_chain_contextual_lookup_is_glyph_covered(context, glyph, subtable_offset, coverage, format)) + return TRUE; + + break; + + default: + WARN("Unknown lookup type %u.\n", lookup_type); + } + } + + return FALSE; +} + +typedef BOOL (*p_lookup_is_glyph_covered_func)(struct scriptshaping_context *context, UINT16 glyph, const struct lookup *lookup); + +BOOL opentype_layout_check_feature(struct scriptshaping_context *context, unsigned int script_index, + unsigned int language_index, struct shaping_feature *feature, unsigned int glyph_count, + const UINT16 *glyphs, UINT8 *feature_applies) +{ + p_lookup_is_glyph_covered_func func_is_covered; + struct shaping_features features = { 0 }; + struct lookups lookups = { 0 }; + BOOL ret = FALSE, is_covered; + unsigned int i, j, applies; + + features.features = feature; + features.count = 1; + + for (i = 0; i < context->glyph_count; ++i) + opentype_set_glyph_props(context, i); + + opentype_layout_collect_lookups(context, script_index, language_index, &features, context->table, &lookups); + + func_is_covered = context->table == &context->cache->gsub ? opentype_layout_gsub_lookup_is_glyph_covered : + opentype_layout_gpos_lookup_is_glyph_covered; + + for (i = 0; i < lookups.count; ++i) + { + struct lookup *lookup = &lookups.lookups[i]; + + applies = 0; + for (j = 0; j < context->glyph_count; ++j) + { + if (lookup_is_glyph_match(context, j, lookup->flags)) + { + if ((is_covered = func_is_covered(context, glyphs[i], lookup))) + ++applies; + feature_applies[j] |= is_covered; + } + } + + if ((ret = (applies == context->glyph_count))) + break; + } + + heap_free(lookups.lookups); + + return ret; +} diff --git a/dlls/dwrite/shape.c b/dlls/dwrite/shape.c index 4968cd995d4..82eb5308da6 100644 --- a/dlls/dwrite/shape.c +++ b/dlls/dwrite/shape.c @@ -350,3 +350,28 @@ HRESULT shape_get_typographic_features(struct scriptshaping_context *context, co
return t.count <= max_tagcount ? S_OK : E_NOT_SUFFICIENT_BUFFER; } + +HRESULT shape_check_typographic_feature(struct scriptshaping_context *context, const unsigned int *scripts, + unsigned int tag, unsigned int glyph_count, const UINT16 *glyphs, UINT8 *feature_applies) +{ + static const unsigned int tables[] = { MS_GSUB_TAG, MS_GPOS_TAG }; + struct shaping_feature feature = { .tag = tag }; + unsigned int script_index, language_index; + unsigned int i; + + memset(feature_applies, 0, glyph_count * sizeof(*feature_applies)); + + for (i = 0; i < ARRAY_SIZE(tables); ++i) + { + shape_get_script_lang_index(context, scripts, tables[i], &script_index, &language_index); + context->table = tables[i] == MS_GSUB_TAG ? &context->cache->gsub : &context->cache->gpos; + /* Skip second table if feature applies to all. */ + if (opentype_layout_check_feature(context, script_index, language_index, &feature, glyph_count, + glyphs, feature_applies)) + { + break; + } + } + + return S_OK; +}
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/dwrite_private.h | 7 ++++++ dlls/dwrite/opentype.c | 45 ++++++++++++++++++++++++------------ 2 files changed, 37 insertions(+), 15 deletions(-)
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 966750c12b4..3d7884cb57f 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -489,6 +489,10 @@ struct shaping_glyph_properties UINT16 reserved2 : 4; };
+struct scriptshaping_context; + +typedef void (*p_apply_context_lookup)(struct scriptshaping_context *context, unsigned int lookup_index); + struct scriptshaping_context { struct scriptshaping_cache *cache; @@ -506,12 +510,14 @@ struct scriptshaping_context const UINT16 *glyphs; const DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props; const UINT16 *clustermap; + p_apply_context_lookup apply_context_lookup; } pos; struct { UINT16 *glyphs; DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props; UINT16 *clustermap; + p_apply_context_lookup apply_context_lookup; unsigned int max_glyph_count; unsigned int capacity; const WCHAR *digits; @@ -521,6 +527,7 @@ struct scriptshaping_context UINT16 *glyphs; struct shaping_glyph_properties *glyph_props; UINT16 *clustermap; + p_apply_context_lookup apply_context_lookup; } buffer; } u;
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index cbd43bad495..ace46a7741d 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -4621,6 +4621,14 @@ static void opentype_layout_set_glyph_masks(struct scriptshaping_context *contex } }
+static void opentype_layout_apply_gpos_context_lookup(struct scriptshaping_context *context, unsigned int lookup_index) +{ + struct lookup lookup = { 0 }; + /* Feature mask is intentionally zero, it's not used outside of main loop. */ + if (opentype_layout_init_lookup(context->table, lookup_index, 0, &lookup)) + opentype_layout_apply_gpos_lookup(context, &lookup); +} + void opentype_layout_apply_gpos_features(struct scriptshaping_context *context, unsigned int script_index, unsigned int language_index, const struct shaping_features *features) { @@ -4628,6 +4636,7 @@ void opentype_layout_apply_gpos_features(struct scriptshaping_context *context, unsigned int i; BOOL ret;
+ context->u.buffer.apply_context_lookup = opentype_layout_apply_gpos_context_lookup; opentype_layout_collect_lookups(context, script_index, language_index, features, &context->cache->gpos, &lookups);
for (i = 0; i < context->glyph_count; ++i) @@ -5086,12 +5095,9 @@ static BOOL opentype_layout_context_match_lookahead(const struct match_context * return TRUE; }
-static BOOL opentype_layout_apply_gsub_lookup(struct scriptshaping_context *context, const struct lookup *lookup); - -static BOOL opentype_layout_context_gsub_apply_lookup(struct scriptshaping_context *context, unsigned int count, +static BOOL opentype_layout_context_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;
@@ -5110,8 +5116,8 @@ static BOOL opentype_layout_context_gsub_apply_lookup(struct scriptshaping_conte orig_len = context->glyph_count;
lookup_index = GET_BE_WORD(lookup_records[i+1]); - if (opentype_layout_init_lookup(context->table, lookup_index, 0, &lookup)) - opentype_layout_apply_gsub_lookup(context, &lookup); + + context->u.buffer.apply_context_lookup(context, lookup_index);
delta = context->glyph_count - orig_len; if (!delta) @@ -5154,7 +5160,7 @@ static BOOL opentype_layout_context_gsub_apply_lookup(struct scriptshaping_conte return TRUE; }
-static BOOL opentype_layout_apply_gsub_chain_context_lookup(unsigned int backtrack_count, const UINT16 *backtrack, +static BOOL opentype_layout_apply_chain_context_match(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, const struct match_context *mc) { @@ -5164,7 +5170,7 @@ static BOOL opentype_layout_apply_gsub_chain_context_lookup(unsigned int backtra return opentype_layout_context_match_input(mc, input_count, input, &match_length, match_positions) && opentype_layout_context_match_backtrack(mc, backtrack_count, backtrack, &start_index) && opentype_layout_context_match_lookahead(mc, lookahead_count, lookahead, input_count, &end_index) && - opentype_layout_context_gsub_apply_lookup(mc->context, input_count, match_positions, lookup_count, lookup_records, match_length); + opentype_layout_context_apply_lookup(mc->context, input_count, match_positions, lookup_count, lookup_records, match_length); }
static BOOL opentype_layout_apply_chain_rule_set(const struct match_context *mc, unsigned int offset) @@ -5204,7 +5210,7 @@ static BOOL opentype_layout_apply_chain_rule_set(const struct match_context *mc, lookup_records = table_read_ensure(table, rule_offset, lookup_count * 2 * sizeof(*lookup_records));
/* First applicable rule is used. */ - if (opentype_layout_apply_gsub_chain_context_lookup(backtrack_count, backtrack, input_count, input, lookahead_count, + if (opentype_layout_apply_chain_context_match(backtrack_count, backtrack, input_count, input, lookahead_count, lookahead, lookup_count, lookup_records, mc)) { return TRUE; @@ -5214,14 +5220,14 @@ static BOOL opentype_layout_apply_chain_rule_set(const struct match_context *mc, return FALSE; }
-static BOOL opentype_layout_apply_gsub_context_lookup(unsigned int input_count, const UINT16 *input, unsigned int lookup_count, +static BOOL opentype_layout_apply_context_match(unsigned int input_count, const UINT16 *input, unsigned int lookup_count, const UINT16 *lookup_records, const struct match_context *mc) { unsigned int match_positions[GLYPH_CONTEXT_MAX_LENGTH]; unsigned int match_length = 0;
return opentype_layout_context_match_input(mc, input_count, input, &match_length, match_positions) && - opentype_layout_context_gsub_apply_lookup(mc->context, input_count, match_positions, lookup_count, + opentype_layout_context_apply_lookup(mc->context, input_count, match_positions, lookup_count, lookup_records, match_length); }
@@ -5256,7 +5262,7 @@ static BOOL opentype_layout_apply_rule_set(const struct match_context *mc, unsig continue;
/* First applicable rule is used. */ - if (opentype_layout_apply_gsub_context_lookup(input_count, input, lookup_count, lookup_records, mc)) + if (opentype_layout_apply_context_match(input_count, input, lookup_count, lookup_records, mc)) return TRUE; }
@@ -5357,7 +5363,7 @@ static BOOL opentype_layout_apply_gsub_context_substitution(struct scriptshaping mc.input_offset = subtable_offset; mc.match_func = opentype_match_coverage_func;
- ret = opentype_layout_apply_gsub_context_lookup(input_count, input + 1, lookup_count, lookup_records, &mc); + ret = opentype_layout_apply_context_match(input_count, input + 1, lookup_count, lookup_records, &mc); } else WARN("Unknown contextual substitution format %u.\n", format); @@ -5474,8 +5480,8 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts mc.lookahead_offset = subtable_offset; mc.match_func = opentype_match_coverage_func;
- ret = opentype_layout_apply_gsub_chain_context_lookup(backtrack_count, backtrack, input_count, input + 1, - lookahead_count, lookahead, lookup_count, lookup_records, &mc); + ret = opentype_layout_apply_chain_context_match(backtrack_count, backtrack, input_count, input + 1, lookahead_count, + lookahead, lookup_count, lookup_records, &mc); } else WARN("Unknown chaining contextual substitution format %u.\n", format); @@ -5692,6 +5698,14 @@ static BOOL opentype_is_gsub_lookup_reversed(const struct scriptshaping_context return lookup_type == GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST; }
+static void opentype_layout_apply_gsub_context_lookup(struct scriptshaping_context *context, unsigned int lookup_index) +{ + struct lookup lookup = { 0 }; + /* Feature mask is intentionally zero, it's not used outside of main loop. */ + if (opentype_layout_init_lookup(context->table, lookup_index, 0, &lookup)) + opentype_layout_apply_gsub_lookup(context, &lookup); +} + void opentype_layout_apply_gsub_features(struct scriptshaping_context *context, unsigned int script_index, unsigned int language_index, const struct shaping_features *features) { @@ -5699,6 +5713,7 @@ void opentype_layout_apply_gsub_features(struct scriptshaping_context *context, unsigned int i; BOOL ret;
+ context->u.buffer.apply_context_lookup = opentype_layout_apply_gsub_context_lookup; opentype_layout_collect_lookups(context, script_index, language_index, features, context->table, &lookups);
opentype_get_nominal_glyphs(context, features);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 52 ++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 30 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index ace46a7741d..a423555e0b9 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -610,7 +610,7 @@ struct ot_gsub_lig UINT16 components[1]; };
-struct ot_gsub_context_subst_format1 +struct ot_gsubgpos_context_format1 { UINT16 format; UINT16 coverage; @@ -618,7 +618,7 @@ struct ot_gsub_context_subst_format1 UINT16 rulesets[1]; };
-struct ot_gsub_ruleset +struct ot_gsubgpos_ruleset { UINT16 count; UINT16 offsets[1]; @@ -4210,18 +4210,6 @@ static BOOL opentype_layout_apply_gpos_mark_to_mark_attachment(struct scriptshap return TRUE; }
-static BOOL opentype_layout_apply_gpos_contextual_positioning(const struct scriptshaping_context *context, - const struct lookup *lookup, unsigned int subtable_offset) -{ - return FALSE; -} - -static BOOL opentype_layout_apply_gpos_chaining_contextual_positioning(const struct scriptshaping_context *context, - const struct lookup *lookup, unsigned int subtable_offset) -{ - return FALSE; -} - static unsigned int opentype_layout_adjust_extension_subtable(struct scriptshaping_context *context, unsigned int *subtable_offset) { @@ -4241,6 +4229,11 @@ static unsigned int opentype_layout_adjust_extension_subtable(struct scriptshapi return GET_BE_WORD(format1->lookup_type); }
+static BOOL opentype_layout_apply_context(struct scriptshaping_context *context, const struct lookup *lookup, + unsigned int subtable_offset); +static BOOL opentype_layout_apply_chain_context(struct scriptshaping_context *context, const struct lookup *lookup, + unsigned int subtable_offset); + static BOOL opentype_layout_apply_gpos_lookup(struct scriptshaping_context *context, const struct lookup *lookup) { unsigned int i, lookup_type; @@ -4280,10 +4273,10 @@ static BOOL opentype_layout_apply_gpos_lookup(struct scriptshaping_context *cont ret = opentype_layout_apply_gpos_mark_to_mark_attachment(context, lookup, subtable_offset); break; case GPOS_LOOKUP_CONTEXTUAL_POSITION: - ret = opentype_layout_apply_gpos_contextual_positioning(context, lookup, subtable_offset); + ret = opentype_layout_apply_context(context, lookup, subtable_offset); break; case GPOS_LOOKUP_CONTEXTUAL_CHAINING_POSITION: - ret = opentype_layout_apply_gpos_chaining_contextual_positioning(context, lookup, subtable_offset); + ret = opentype_layout_apply_chain_context(context, lookup, subtable_offset); break; case GPOS_LOOKUP_EXTENSION_POSITION: WARN("Recursive extension lookup.\n"); @@ -5178,7 +5171,7 @@ static BOOL opentype_layout_apply_chain_rule_set(const struct match_context *mc, unsigned int backtrack_count, input_count, lookahead_count, lookup_count; const struct dwrite_fonttable *table = &mc->context->table->table; const UINT16 *backtrack, *lookahead, *input, *lookup_records; - const struct ot_gsub_ruleset *ruleset; + const struct ot_gsubgpos_ruleset *ruleset; unsigned int i, count;
count = table_read_be_word(table, offset); @@ -5236,7 +5229,7 @@ static BOOL opentype_layout_apply_rule_set(const struct match_context *mc, unsig unsigned int input_count, lookup_count; const struct dwrite_fonttable *table = &mc->context->table->table; const UINT16 *input, *lookup_records; - const struct ot_gsub_ruleset *ruleset; + const struct ot_gsubgpos_ruleset *ruleset; unsigned int i, count;
count = table_read_be_word(table, offset); @@ -5269,7 +5262,7 @@ static BOOL opentype_layout_apply_rule_set(const struct match_context *mc, unsig return FALSE; }
-static BOOL opentype_layout_apply_gsub_context_substitution(struct scriptshaping_context *context, const struct lookup *lookup, +static BOOL opentype_layout_apply_context(struct scriptshaping_context *context, const struct lookup *lookup, unsigned int subtable_offset) { struct match_context mc = { .context = context, .lookup = lookup }; @@ -5284,18 +5277,17 @@ static BOOL opentype_layout_apply_gsub_context_substitution(struct scriptshaping
if (format == 1) { - coverage = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_context_subst_format1, coverage)); + coverage = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsubgpos_context_format1, coverage));
coverage_index = opentype_layout_is_glyph_covered(table, subtable_offset + coverage, glyph); if (coverage_index == GLYPH_NOT_COVERED) return FALSE;
- count = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_context_subst_format1, - ruleset_count)); + count = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsubgpos_context_format1, ruleset_count)); if (coverage_index >= count) return FALSE;
- offset = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_context_subst_format1, + offset = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsubgpos_context_format1, rulesets[coverage_index])); offset += subtable_offset;
@@ -5371,8 +5363,8 @@ static BOOL opentype_layout_apply_gsub_context_substitution(struct scriptshaping return ret; }
-static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scriptshaping_context *context, - const struct lookup *lookup, unsigned int subtable_offset) +static BOOL opentype_layout_apply_chain_context(struct scriptshaping_context *context, const struct lookup *lookup, + unsigned int subtable_offset) { struct match_context mc = { .context = context, .lookup = lookup }; const struct dwrite_fonttable *table = &context->table->table; @@ -5386,17 +5378,17 @@ static BOOL opentype_layout_apply_gsub_chain_context_substitution(struct scripts
if (format == 1) { - coverage = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_context_subst_format1, coverage)); + coverage = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsubgpos_context_format1, coverage));
coverage_index = opentype_layout_is_glyph_covered(table, subtable_offset + coverage, glyph); if (coverage_index == GLYPH_NOT_COVERED) return FALSE;
- count = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_context_subst_format1, ruleset_count)); + count = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsubgpos_context_format1, ruleset_count)); if (coverage_index >= count) return FALSE;
- offset = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsub_context_subst_format1, + offset = table_read_be_word(table, subtable_offset + FIELD_OFFSET(struct ot_gsubgpos_context_format1, rulesets[coverage_index])); offset += subtable_offset;
@@ -5584,10 +5576,10 @@ static BOOL opentype_layout_apply_gsub_lookup(struct scriptshaping_context *cont ret = opentype_layout_apply_gsub_lig_substitution(context, lookup, subtable_offset); break; case GSUB_LOOKUP_CONTEXTUAL_SUBST: - ret = opentype_layout_apply_gsub_context_substitution(context, lookup, subtable_offset); + ret = opentype_layout_apply_context(context, lookup, subtable_offset); break; case GSUB_LOOKUP_CHAINING_CONTEXTUAL_SUBST: - ret = opentype_layout_apply_gsub_chain_context_substitution(context, lookup, subtable_offset); + ret = opentype_layout_apply_chain_context(context, lookup, subtable_offset); break; case GSUB_LOOKUP_REVERSE_CHAINING_CONTEXTUAL_SUBST: ret = opentype_layout_apply_gsub_reverse_chain_context_substitution(context, lookup, subtable_offset);