[PATCH 3/5] dwrite: Implement CheckTypographicFeature().
Nikolay Sivov
nsivov at codeweavers.com
Mon Jun 8 08:29:45 CDT 2020
Signed-off-by: Nikolay Sivov <nsivov at 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;
+}
--
2.26.2
More information about the wine-devel
mailing list