[PATCH 5/5] dwrite: Use mirrored character only if font supports it.

Nikolay Sivov nsivov at codeweavers.com
Fri May 22 05:58:09 CDT 2020


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dwrite/analyzer.c       | 96 ++++++------------------------------
 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(+), 110 deletions(-)

diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c
index 62258ec4416..85fd10b0b28 100644
--- a/dlls/dwrite/analyzer.c
+++ b/dlls/dwrite/analyzer.c
@@ -1059,15 +1059,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 +1098,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 +1126,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 +1155,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 +1171,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 +1185,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 +1198,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);
 
-- 
2.26.2




More information about the wine-devel mailing list