From da55f010dfe1b8e51582f11259637f9cf0c45499 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Fri, 22 May 2020 13:58:09 +0300 Subject: [PATCH] dwrite: Use mirrored character only if font supports it. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/dwrite/analyzer.c | 106 +++++------------------------------ dlls/dwrite/bidi.c | 7 --- dlls/dwrite/dwrite_private.h | 7 ++- dlls/dwrite/font.c | 40 +++++++++---- dlls/dwrite/opentype.c | 67 +++++++++++++++++++++- dlls/dwrite/shape.c | 12 +--- 6 files changed, 119 insertions(+), 120 deletions(-) diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 62258ec4416..786d68ac278 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -280,16 +280,6 @@ static inline struct dwrite_fontfallback_builder *impl_from_IDWriteFontFallbackB return CONTAINING_RECORD(iface, struct dwrite_fontfallback_builder, IDWriteFontFallbackBuilder_iface); } -static inline UINT32 decode_surrogate_pair(const WCHAR *str, UINT32 index, UINT32 end) -{ - if (index < end-1 && IS_SURROGATE_PAIR(str[index], str[index+1])) { - UINT32 ch = 0x10000 + ((str[index] - 0xd800) << 10) + (str[index+1] - 0xdc00); - TRACE("surrogate pair (%x %x) => %x\n", str[index], str[index+1], ch); - return ch; - } - return 0; -} - static inline UINT16 get_char_script(WCHAR c) { UINT16 script = get_table_entry(wine_scripts_table, c); @@ -1059,15 +1049,17 @@ static UINT32 get_opentype_language(const WCHAR *locale) return language; } -static DWRITE_NUMBER_SUBSTITUTION_METHOD get_number_substitutes(IDWriteNumberSubstitution *substitution, WCHAR *digits) +static void get_number_substitutes(IDWriteNumberSubstitution *substitution, BOOL is_rtl, WCHAR *digits) { struct dwrite_numbersubstitution *numbersubst = unsafe_impl_from_IDWriteNumberSubstitution(substitution); DWRITE_NUMBER_SUBSTITUTION_METHOD method; WCHAR isolang[9]; DWORD lctype; + digits[0] = 0; + if (!numbersubst) - return DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE; + return; lctype = numbersubst->ignore_user_override ? LOCALE_NOUSEROVERRIDE : 0; @@ -1096,7 +1088,6 @@ static DWRITE_NUMBER_SUBSTITUTION_METHOD get_number_substitutes(IDWriteNumberSub else method = numbersubst->method; - digits[0] = 0; switch (method) { case DWRITE_NUMBER_SUBSTITUTION_METHOD_NATIONAL: @@ -1125,7 +1116,8 @@ static DWRITE_NUMBER_SUBSTITUTION_METHOD get_number_substitutes(IDWriteNumberSub method = DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE; } - return method; + if ((method == DWRITE_NUMBER_SUBSTITUTION_METHOD_CONTEXTUAL && !is_rtl) || method == DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE) + digits[0] = 0; } static void analyzer_dump_user_features(DWRITE_TYPOGRAPHIC_FEATURES const **features, @@ -1153,14 +1145,11 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface, DWRITE_SHAPING_GLYPH_PROPERTIES* glyph_props, UINT32* actual_glyph_count) { const struct dwritescript_properties *scriptprops; - DWRITE_NUMBER_SUBSTITUTION_METHOD method; - struct scriptshaping_context context; + struct scriptshaping_context context = { 0 }; struct dwrite_fontface *font_obj; WCHAR digits[NATIVE_DIGITS_LEN]; - unsigned int i, g, script; - BOOL update_cluster; - WCHAR *string; - HRESULT hr = S_OK; + unsigned int script; + HRESULT hr; TRACE("(%s:%u %p %d %d %s %s %p %p %p %u %u %p %p %p %p %p)\n", debugstr_wn(text, length), length, fontface, is_sideways, is_rtl, debugstr_sa_script(analysis->script), debugstr_w(locale), substitution, @@ -1172,78 +1161,11 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface, if (max_glyph_count < length) return E_NOT_SUFFICIENT_BUFFER; - string = heap_calloc(length, sizeof(*string)); - if (!string) - return E_OUTOFMEMORY; - - method = get_number_substitutes(substitution, digits); + get_number_substitutes(substitution, is_rtl, digits); /* FIXME: have the shaping engine set this */ memset(text_props, 0, length * sizeof(*text_props)); - for (i = 0; i < length; i++) { - /* FIXME: set to better values */ - glyph_props[i].justification = text[i] == ' ' ? SCRIPT_JUSTIFY_BLANK : SCRIPT_JUSTIFY_CHARACTER; - glyph_props[i].isClusterStart = 1; - glyph_props[i].isDiacritic = 0; - glyph_props[i].isZeroWidthSpace = 0; - glyph_props[i].reserved = 0; - - clustermap[i] = i; - - string[i] = text[i]; - switch (method) - { - case DWRITE_NUMBER_SUBSTITUTION_METHOD_CONTEXTUAL: - if (!is_rtl) - break; - /* fallthrough */ - default: - if (string[i] >= '0' && string[i] <= '9') - string[i] = digits[string[i] - '0']; - break; - case DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE: - ; - } - } - - for (; i < max_glyph_count; i++) { - glyph_props[i].justification = SCRIPT_JUSTIFY_NONE; - glyph_props[i].isClusterStart = 0; - glyph_props[i].isDiacritic = 0; - glyph_props[i].isZeroWidthSpace = 0; - glyph_props[i].reserved = 0; - } - - for (i = 0, g = 0, update_cluster = FALSE; i < length; i++) { - UINT32 codepoint; - - if (!update_cluster) { - codepoint = decode_surrogate_pair(string, i, length); - if (!codepoint) - codepoint = is_rtl ? bidi_get_mirrored_char(string[i]) : string[i]; - else - update_cluster = TRUE; - - hr = IDWriteFontFace_GetGlyphIndices(fontface, &codepoint, 1, &glyphs[g]); - if (FAILED(hr)) - goto done; - - g++; - } - else { - INT32 k; - - update_cluster = FALSE; - /* mark surrogate halves with same cluster */ - clustermap[i] = clustermap[i-1]; - /* update following clusters */ - for (k = i + 1; k >= 0 && k < length; k++) - clustermap[k]--; - } - } - *actual_glyph_count = g; - font_obj = unsafe_impl_from_IDWriteFontFace(fontface); context.cache = fontface_get_shaping_cache(font_obj); @@ -1253,8 +1175,9 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface, context.is_sideways = is_sideways; context.u.subst.glyphs = glyphs; context.u.subst.glyph_props = glyph_props; + context.u.subst.clustermap = clustermap; context.u.subst.max_glyph_count = max_glyph_count; - context.glyph_count = g; + context.u.subst.digits = digits; context.language_tag = get_opentype_language(locale); context.user_features.features = features; context.user_features.range_lengths = feature_range_lengths; @@ -1265,12 +1188,13 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface, scriptprops = &dwritescripts_properties[script]; hr = shape_get_glyphs(&context, scriptprops->scripttags); if (SUCCEEDED(hr)) + { + *actual_glyph_count = context.glyph_count; hr = default_shaping_ops.set_text_glyphs_props(&context, clustermap, glyphs, *actual_glyph_count, text_props, glyph_props); + } -done: heap_free(context.glyph_infos); - heap_free(string); return hr; } diff --git a/dlls/dwrite/bidi.c b/dlls/dwrite/bidi.c index 0323afb88cd..e2f3385519d 100644 --- a/dlls/dwrite/bidi.c +++ b/dlls/dwrite/bidi.c @@ -158,13 +158,6 @@ static void bidi_classify(const WCHAR *string, UINT8 *chartype, UINT32 count) chartype[i] = get_table_entry( bidi_direction_table, string[i] ); } -WCHAR bidi_get_mirrored_char(WCHAR ch) -{ - extern const WCHAR wine_mirror_map[] DECLSPEC_HIDDEN; - WCHAR mirror = get_table_entry( wine_mirror_map, ch ); - return mirror ? mirror : ch; -} - /* RESOLVE EXPLICIT */ static inline UINT8 get_greater_even_level(UINT8 level) diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index afa4bce91df..4cf1523f470 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -300,6 +300,8 @@ extern void factory_unlock(IDWriteFactory7 *factory) DECLSPEC_HIDDEN; extern HRESULT create_inmemory_fileloader(IDWriteFontFileLoader**) DECLSPEC_HIDDEN; extern HRESULT create_font_resource(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 face_index, IDWriteFontResource **resource) DECLSPEC_HIDDEN; +extern HRESULT fontface_get_glyphs(struct dwrite_fontface *fontface, UINT32 const *codepoints, + UINT32 count, UINT16 *glyphs); struct dwrite_fontface; @@ -378,7 +380,6 @@ extern unsigned int opentype_get_gasp_flags(const struct dwrite_fonttable *gasp, /* BiDi helpers */ extern HRESULT bidi_computelevels(const WCHAR*,UINT32,UINT8,UINT8*,UINT8*) DECLSPEC_HIDDEN; -extern WCHAR bidi_get_mirrored_char(WCHAR) DECLSPEC_HIDDEN; /* FreeType integration */ struct dwrite_glyphbitmap @@ -487,7 +488,9 @@ struct scriptshaping_context { UINT16 *glyphs; DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props; + UINT16 *clustermap; unsigned int max_glyph_count; + const WCHAR *digits; } subst; } u; @@ -512,6 +515,8 @@ struct shaping_font_ops void (*grab_font_table)(void *context, UINT32 table, const BYTE **data, UINT32 *size, void **data_context); void (*release_font_table)(void *context, void *data_context); UINT16 (*get_font_upem)(void *context); + BOOL (*has_glyph)(void *context, unsigned int codepoint); + UINT16 (*get_glyph)(void *context, unsigned int codepoint); }; extern struct scriptshaping_cache *create_scriptshaping_cache(void *context, diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c index ee52c3e321c..75d2593e07e 100644 --- a/dlls/dwrite/font.c +++ b/dlls/dwrite/font.c @@ -272,11 +272,29 @@ static UINT16 dwrite_get_font_upem(void *context) return fontface->metrics.designUnitsPerEm; } +static BOOL dwrite_has_glyph(void *context, unsigned int codepoint) +{ + struct dwrite_fontface *fontface = context; + UINT16 index = 0; + fontface_get_glyphs(fontface, &codepoint, 1, &index); + return !!index; +} + +static UINT16 dwrite_get_glyph(void *context, unsigned int codepoint) +{ + struct dwrite_fontface *fontface = context; + UINT16 index = 0; + fontface_get_glyphs(fontface, &codepoint, 1, &index); + return index; +} + static const struct shaping_font_ops dwrite_font_ops = { dwrite_grab_font_table, dwrite_release_font_table, dwrite_get_font_upem, + dwrite_has_glyph, + dwrite_get_glyph, }; struct scriptshaping_cache *fontface_get_shaping_cache(struct dwrite_fontface *fontface) @@ -714,17 +732,9 @@ static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace5 *ifa return S_OK; } -static HRESULT fontface_get_glyphs(struct dwrite_fontface *fontface, UINT32 const *codepoints, +HRESULT fontface_get_glyphs(struct dwrite_fontface *fontface, UINT32 const *codepoints, UINT32 count, UINT16 *glyphs) { - if (!glyphs) - return E_INVALIDARG; - - if (!codepoints) { - memset(glyphs, 0, count * sizeof(*glyphs)); - return E_INVALIDARG; - } - freetype_get_glyphs(&fontface->IDWriteFontFace5_iface, fontface->charmap, codepoints, count, glyphs); return S_OK; } @@ -736,6 +746,15 @@ static HRESULT WINAPI dwritefontface_GetGlyphIndices(IDWriteFontFace5 *iface, UI TRACE("%p, %p, %u, %p.\n", iface, codepoints, count, glyphs); + if (!glyphs) + return E_INVALIDARG; + + if (!codepoints) + { + memset(glyphs, 0, count * sizeof(*glyphs)); + return E_INVALIDARG; + } + return fontface_get_glyphs(fontface, codepoints, count, glyphs); } @@ -1390,8 +1409,7 @@ static BOOL WINAPI dwritefontface3_HasCharacter(IDWriteFontFace5 *iface, UINT32 TRACE("%p, %#x.\n", iface, ch); index = 0; - if (FAILED(fontface_get_glyphs(fontface, &ch, 1, &index))) - return FALSE; + fontface_get_glyphs(fontface, &ch, 1, &index); return index != 0; } diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 35b02d55730..77ae1e84473 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -4187,6 +4187,9 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex unsigned int global_bit_mask = 1; UINT16 feature_index; + if (!table->table.data) + return; + /* 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)); @@ -4329,7 +4332,7 @@ static unsigned int shaping_features_get_mask(const struct shaping_features *fea if (!feature || feature->index == 0xffff) return 0; - *shift = feature->shift; + if (shift) *shift = feature->shift; return feature->mask; } @@ -4671,6 +4674,67 @@ static void opentype_layout_apply_gsub_lookup(struct scriptshaping_context *cont } } +static unsigned int unicode_get_mirrored_char(unsigned int codepoint) +{ + extern const WCHAR wine_mirror_map[] DECLSPEC_HIDDEN; + WCHAR mirror; + /* TODO: check if mirroring for higher planes makes sense at all */ + if (codepoint > 0xffff) return codepoint; + mirror = get_table_entry(wine_mirror_map, codepoint); + return mirror ? mirror : codepoint; +} + +static void opentype_get_nominal_glyphs(struct scriptshaping_context *context, const struct shaping_features *features) +{ + unsigned int rtlm_mask = shaping_features_get_mask(features, DWRITE_MAKE_OPENTYPE_TAG('r','t','l','m'), NULL); + const struct shaping_font_ops *font = context->cache->font; + UINT16 *clustermap = context->u.subst.clustermap; + const WCHAR *text = context->text; + unsigned int i, g, c, codepoint; + BOOL bmp; + + memset(context->u.subst.glyph_props, 0, context->u.subst.max_glyph_count * sizeof(*context->u.subst.glyph_props)); + + for (i = 0; i < context->length; ++i) + { + g = context->glyph_count; + + if ((bmp = !(IS_HIGH_SURROGATE(text[i]) && (i < context->length - 1) && IS_LOW_SURROGATE(text[i + 1])))) + { + codepoint = text[i]; + } + else + { + codepoint = 0x10000 + ((text[i] - 0xd800) << 10) + (text[i + 1] - 0xdc00); + } + + if (context->is_rtl) + { + c = unicode_get_mirrored_char(codepoint); + if (c != codepoint && font->has_glyph(context->cache->context, c)) + codepoint = c; + else + context->glyph_infos[i].mask |= rtlm_mask; + } + + /* TODO: should this check for glyph availability? */ + if (*context->u.subst.digits && codepoint >= '0' && codepoint <= '9') + codepoint = context->u.subst.digits[codepoint - '0']; + + 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; + context->glyph_count++; + + clustermap[i] = i; + if (!bmp) + { + clustermap[i + 1] = i; + ++i; + } + } +} + HRESULT opentype_layout_apply_gsub_features(struct scriptshaping_context *context, unsigned int script_index, unsigned int language_index, const struct shaping_features *features) { @@ -4679,6 +4743,7 @@ HRESULT opentype_layout_apply_gsub_features(struct scriptshaping_context *contex opentype_layout_collect_lookups(context, script_index, language_index, features, &context->cache->gsub, &lookups); + opentype_get_nominal_glyphs(context, features); opentype_layout_set_glyph_masks(context, features); for (i = 0; i < lookups.count; ++i) diff --git a/dlls/dwrite/shape.c b/dlls/dwrite/shape.c index 18afb2212bd..3d25898cf7a 100644 --- a/dlls/dwrite/shape.c +++ b/dlls/dwrite/shape.c @@ -362,8 +362,7 @@ HRESULT shape_get_glyphs(struct scriptshaping_context *context, const unsigned i DWRITE_MAKE_OPENTYPE_TAG('l','i','g','a'), DWRITE_MAKE_OPENTYPE_TAG('r','c','l','t'), }; - struct scriptshaping_cache *cache = context->cache; - unsigned int script_index, language_index, script; + unsigned int script_index, language_index; struct shaping_features features = { 0 }; unsigned int i; @@ -396,13 +395,8 @@ HRESULT shape_get_glyphs(struct scriptshaping_context *context, const unsigned i shape_merge_features(context, &features); /* Resolve script tag to actually supported script. */ - if (cache->gsub.table.data) - { - if ((script = shape_get_script_lang_index(context, scripts, MS_GSUB_TAG, &script_index, &language_index))) - { - opentype_layout_apply_gsub_features(context, script_index, language_index, &features); - } - } + shape_get_script_lang_index(context, scripts, MS_GSUB_TAG, &script_index, &language_index); + opentype_layout_apply_gsub_features(context, script_index, language_index, &features); heap_free(features.features);