[PATCH 1/5] dwrite: Add a helper to get shaped glyph positions.

Nikolay Sivov nsivov at codeweavers.com
Thu Jan 31 02:35:26 CST 2019


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dwrite/analyzer.c       | 134 ++++++++++++++++-------------------
 dlls/dwrite/dwrite_private.h |  36 ++++++++--
 dlls/dwrite/font.c           |  49 ++++++++++++-
 dlls/dwrite/shape.c          |  48 ++++++++-----
 4 files changed, 172 insertions(+), 95 deletions(-)

diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c
index 7ee3675d2e..13d3d3216a 100644
--- a/dlls/dwrite/analyzer.c
+++ b/dlls/dwrite/analyzer.c
@@ -1157,16 +1157,14 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface,
     UINT16* clustermap, DWRITE_SHAPING_TEXT_PROPERTIES* text_props, UINT16* glyph_indices,
     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_cache *cache = NULL;
+    struct dwrite_fontface *font_obj;
     WCHAR digits[NATIVE_DIGITS_LEN];
     BOOL update_cluster;
     WCHAR *string;
     UINT32 i, g;
     HRESULT hr = S_OK;
-    UINT16 script;
 
     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,
@@ -1175,8 +1173,6 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface,
 
     analyzer_dump_user_features(features, feature_range_lengths, feature_ranges);
 
-    script = analysis->script > Script_LastId ? Script_Unknown : analysis->script;
-
     if (max_glyph_count < length)
         return E_NOT_SUFFICIENT_BUFFER;
 
@@ -1253,33 +1249,19 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphs(IDWriteTextAnalyzer2 *iface,
     }
     *actual_glyph_count = g;
 
-    hr = create_scriptshaping_cache(fontface, &cache);
-    if (FAILED(hr))
-        goto done;
+    font_obj = unsafe_impl_from_IDWriteFontFace(fontface);
 
-    context.cache = cache;
+    context.cache = fontface_get_shaping_cache(font_obj);
     context.text = text;
     context.length = length;
     context.is_rtl = is_rtl;
-    context.max_glyph_count = max_glyph_count;
     context.language_tag = get_opentype_language(locale);
 
-    scriptprops = &dwritescripts_properties[script];
-    if (scriptprops->ops && scriptprops->ops->contextual_shaping) {
-        hr = scriptprops->ops->contextual_shaping(&context, clustermap, glyph_indices, actual_glyph_count);
-        if (FAILED(hr))
-            goto done;
-    }
-
     /* FIXME: apply default features */
 
-    if (scriptprops->ops && scriptprops->ops->set_text_glyphs_props)
-        hr = scriptprops->ops->set_text_glyphs_props(&context, clustermap, glyph_indices, *actual_glyph_count, text_props, glyph_props);
-    else
-        hr = default_shaping_ops.set_text_glyphs_props(&context, clustermap, glyph_indices, *actual_glyph_count, text_props, glyph_props);
+    hr = default_shaping_ops.set_text_glyphs_props(&context, clustermap, glyph_indices, *actual_glyph_count, text_props, glyph_props);
 
 done:
-    release_scriptshaping_cache(cache);
     heap_free(string);
 
     return hr;
@@ -1288,14 +1270,14 @@ done:
 static HRESULT WINAPI dwritetextanalyzer_GetGlyphPlacements(IDWriteTextAnalyzer2 *iface,
     WCHAR const* text, UINT16 const* clustermap, DWRITE_SHAPING_TEXT_PROPERTIES* props,
     UINT32 text_len, UINT16 const* glyphs, DWRITE_SHAPING_GLYPH_PROPERTIES const* glyph_props,
-    UINT32 glyph_count, IDWriteFontFace *fontface, FLOAT emSize, BOOL is_sideways, BOOL is_rtl,
+    UINT32 glyph_count, IDWriteFontFace *fontface, float emSize, BOOL is_sideways, BOOL is_rtl,
     DWRITE_SCRIPT_ANALYSIS const* analysis, WCHAR const* locale, DWRITE_TYPOGRAPHIC_FEATURES const** features,
-    UINT32 const* feature_range_lengths, UINT32 feature_ranges, FLOAT *advances, DWRITE_GLYPH_OFFSET *offsets)
+    UINT32 const* feature_range_lengths, UINT32 feature_ranges, float *advances, DWRITE_GLYPH_OFFSET *offsets)
 {
-    DWRITE_FONT_METRICS metrics;
-    IDWriteFontFace1 *fontface1;
-    HRESULT hr;
-    UINT32 i;
+    const struct dwritescript_properties *scriptprops;
+    struct dwrite_fontface *font_obj;
+    unsigned int i, script;
+    HRESULT hr = S_OK;
 
     TRACE("(%s %p %p %u %p %p %u %p %.2f %d %d %s %s %p %p %u %p %p)\n", debugstr_wn(text, text_len),
         clustermap, props, text_len, glyphs, glyph_props, glyph_count, fontface, emSize, is_sideways,
@@ -1307,46 +1289,51 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphPlacements(IDWriteTextAnalyzer2
     if (glyph_count == 0)
         return S_OK;
 
-    hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
-    if (FAILED(hr)) {
-        WARN("failed to get IDWriteFontFace1.\n");
-        return hr;
-    }
+    font_obj = unsafe_impl_from_IDWriteFontFace(fontface);
 
-    IDWriteFontFace_GetMetrics(fontface, &metrics);
-    for (i = 0; i < glyph_count; i++) {
+    for (i = 0; i < glyph_count; ++i)
+    {
         if (glyph_props[i].isZeroWidthSpace)
             advances[i] = 0.0f;
-        else {
-            INT32 a;
-
-            hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, &glyphs[i], &a, is_sideways);
-            if (FAILED(hr))
-                a = 0;
-            advances[i] = get_scaled_advance_width(a, emSize, &metrics);
-        }
+        else
+            advances[i] = fontface_get_scaled_design_advance(font_obj, DWRITE_MEASURING_MODE_NATURAL, emSize, 1.0f,
+                    NULL, glyphs[i], is_sideways);
         offsets[i].advanceOffset = 0.0f;
         offsets[i].ascenderOffset = 0.0f;
     }
 
-    /* FIXME: actually apply features */
+    script = analysis->script > Script_LastId ? Script_Unknown : analysis->script;
 
-    IDWriteFontFace1_Release(fontface1);
-    return S_OK;
+    scriptprops = &dwritescripts_properties[script];
+    if (scriptprops->ops && scriptprops->ops->gpos_features)
+    {
+        struct scriptshaping_context context;
+
+        context.cache = fontface_get_shaping_cache(font_obj);
+        context.text = text;
+        context.length = text_len;
+        context.is_rtl = is_rtl;
+        context.language_tag = get_opentype_language(locale);
+
+        hr = shape_get_positions(&context, scriptprops->scripttags, scriptprops->ops->gpos_features);
+    }
+
+    return hr;
 }
 
 static HRESULT WINAPI dwritetextanalyzer_GetGdiCompatibleGlyphPlacements(IDWriteTextAnalyzer2 *iface,
     WCHAR const* text, UINT16 const* clustermap, DWRITE_SHAPING_TEXT_PROPERTIES* props,
     UINT32 text_len, UINT16 const* glyphs, DWRITE_SHAPING_GLYPH_PROPERTIES const* glyph_props,
-    UINT32 glyph_count, IDWriteFontFace *fontface, FLOAT emSize, FLOAT ppdip,
+    UINT32 glyph_count, IDWriteFontFace *fontface, float emSize, float ppdip,
     DWRITE_MATRIX const* transform, BOOL use_gdi_natural, BOOL is_sideways, BOOL is_rtl,
     DWRITE_SCRIPT_ANALYSIS const* analysis, WCHAR const* locale, DWRITE_TYPOGRAPHIC_FEATURES const** features,
-    UINT32 const* feature_range_lengths, UINT32 feature_ranges, FLOAT *advances, DWRITE_GLYPH_OFFSET *offsets)
+    UINT32 const* feature_range_lengths, UINT32 feature_ranges, float *advances, DWRITE_GLYPH_OFFSET *offsets)
 {
-    DWRITE_FONT_METRICS metrics;
-    IDWriteFontFace1 *fontface1;
-    HRESULT hr;
-    UINT32 i;
+    const struct dwritescript_properties *scriptprops;
+    DWRITE_MEASURING_MODE measuring_mode;
+    struct dwrite_fontface *font_obj;
+    unsigned int i, script;
+    HRESULT hr = S_OK;
 
     TRACE("(%s %p %p %u %p %p %u %p %.2f %.2f %p %d %d %d %s %s %p %p %u %p %p)\n", debugstr_wn(text, text_len),
         clustermap, props, text_len, glyphs, glyph_props, glyph_count, fontface, emSize, ppdip,
@@ -1358,35 +1345,38 @@ static HRESULT WINAPI dwritetextanalyzer_GetGdiCompatibleGlyphPlacements(IDWrite
     if (glyph_count == 0)
         return S_OK;
 
-    hr = IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void**)&fontface1);
-    if (FAILED(hr)) {
-        WARN("failed to get IDWriteFontFace1.\n");
-        return hr;
-    }
+    font_obj = unsafe_impl_from_IDWriteFontFace(fontface);
 
-    hr = IDWriteFontFace_GetGdiCompatibleMetrics(fontface, emSize, ppdip, transform, &metrics);
-    if (FAILED(hr)) {
-        IDWriteFontFace1_Release(fontface1);
-        WARN("failed to get compat metrics, 0x%08x\n", hr);
-        return hr;
-    }
-    for (i = 0; i < glyph_count; i++) {
-        INT32 a;
+    measuring_mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC;
 
-        hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, emSize, ppdip,
-            transform, use_gdi_natural, is_sideways, 1, &glyphs[i], &a);
-        if (FAILED(hr))
+    for (i = 0; i < glyph_count; ++i)
+    {
+        if (glyph_props[i].isZeroWidthSpace)
             advances[i] = 0.0f;
         else
-            advances[i] = floorf(a * emSize * ppdip / metrics.designUnitsPerEm + 0.5f) / ppdip;
+            advances[i] = fontface_get_scaled_design_advance(font_obj, measuring_mode, emSize, ppdip,
+                    transform, glyphs[i], is_sideways);
         offsets[i].advanceOffset = 0.0f;
         offsets[i].ascenderOffset = 0.0f;
     }
 
-    /* FIXME: actually apply features */
+    script = analysis->script > Script_LastId ? Script_Unknown : analysis->script;
 
-    IDWriteFontFace1_Release(fontface1);
-    return S_OK;
+    scriptprops = &dwritescripts_properties[script];
+    if (scriptprops->ops && scriptprops->ops->gpos_features)
+    {
+        struct scriptshaping_context context;
+
+        context.cache = fontface_get_shaping_cache(font_obj);
+        context.text = text;
+        context.length = text_len;
+        context.is_rtl = is_rtl;
+        context.language_tag = get_opentype_language(locale);
+
+        hr = shape_get_positions(&context, scriptprops->scripttags, scriptprops->ops->gpos_features);
+    }
+
+    return hr;
 }
 
 static inline FLOAT get_cluster_advance(const FLOAT *advances, UINT32 start, UINT32 end)
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h
index 3595503f1e..2299a23cf1 100644
--- a/dlls/dwrite/dwrite_private.h
+++ b/dlls/dwrite/dwrite_private.h
@@ -192,6 +192,12 @@ extern void factory_lock(IDWriteFactory5*) DECLSPEC_HIDDEN;
 extern void factory_unlock(IDWriteFactory5*) DECLSPEC_HIDDEN;
 extern HRESULT create_inmemory_fileloader(IDWriteFontFileLoader**) DECLSPEC_HIDDEN;
 
+struct dwrite_fontface;
+
+extern float fontface_get_scaled_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
+        float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways) DECLSPEC_HIDDEN;
+extern struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface) DECLSPEC_HIDDEN;
+
 /* Opentype font table functions */
 struct dwrite_font_props {
     DWRITE_FONT_STYLE style;
@@ -320,7 +326,12 @@ enum SCRIPT_JUSTIFY
     SCRIPT_JUSTIFY_ARABIC_SEEN_M
 };
 
-struct scriptshaping_cache;
+struct scriptshaping_cache
+{
+    const struct shaping_font_ops *font;
+    void *context;
+    UINT16 upem;
+};
 
 struct scriptshaping_context
 {
@@ -328,21 +339,38 @@ struct scriptshaping_context
     UINT32 language_tag;
 
     const WCHAR *text;
-    UINT32 length;
+    unsigned int length;
     BOOL is_rtl;
+};
 
-    UINT32 max_glyph_count;
+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);
 };
 
-extern HRESULT create_scriptshaping_cache(IDWriteFontFace*,struct scriptshaping_cache**) DECLSPEC_HIDDEN;
+extern struct scriptshaping_cache *create_scriptshaping_cache(void *context,
+        const struct shaping_font_ops *font_ops) DECLSPEC_HIDDEN;
 extern void release_scriptshaping_cache(struct scriptshaping_cache*) DECLSPEC_HIDDEN;
+extern struct scriptshaping_cache *fontface_get_shaping_cache(struct dwrite_fontface *fontface) DECLSPEC_HIDDEN;
+
+struct shaping_features
+{
+    const DWORD *tags;
+    unsigned int count;
+};
 
 struct scriptshaping_ops
 {
     HRESULT (*contextual_shaping)(struct scriptshaping_context *context, UINT16 *clustermap, UINT16 *glyph_indices, UINT32* actual_glyph_count);
     HRESULT (*set_text_glyphs_props)(struct scriptshaping_context *context, UINT16 *clustermap, UINT16 *glyph_indices,
                                      UINT32 glyphcount, DWRITE_SHAPING_TEXT_PROPERTIES *text_props, DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props);
+    const struct shaping_features *gpos_features;
 };
 
 extern const struct scriptshaping_ops default_shaping_ops DECLSPEC_HIDDEN;
 extern const struct scriptshaping_ops latn_shaping_ops DECLSPEC_HIDDEN;
+
+extern HRESULT shape_get_positions(struct scriptshaping_context *context, const DWORD *scripts,
+        const struct shaping_features *features) DECLSPEC_HIDDEN;
diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c
index d1e4fb9725..f50133d18c 100644
--- a/dlls/dwrite/font.c
+++ b/dlls/dwrite/font.c
@@ -240,6 +240,8 @@ struct dwrite_fontface {
     FONTSIGNATURE fontsig;
     UINT32 glyph_image_formats;
 
+    struct scriptshaping_cache *shaping_cache;
+
     LOGFONTW lf;
 };
 
@@ -263,6 +265,47 @@ struct dwrite_fontfacereference {
     IDWriteFactory5 *factory;
 };
 
+static void dwrite_grab_font_table(void *context, UINT32 table, const BYTE **data, UINT32 *size, void **data_context)
+{
+    struct dwrite_fontface *fontface = context;
+    BOOL exists = FALSE;
+
+    if (FAILED(IDWriteFontFace4_TryGetFontTable(&fontface->IDWriteFontFace4_iface, table, (const void **)data,
+            size, data_context, &exists)) || !exists)
+    {
+        *data = NULL;
+        *size = 0;
+        *data_context = NULL;
+    }
+}
+
+static void dwrite_release_font_table(void *context, void *data_context)
+{
+    struct dwrite_fontface *fontface = context;
+    IDWriteFontFace4_ReleaseFontTable(&fontface->IDWriteFontFace4_iface, data_context);
+}
+
+static UINT16 dwrite_get_font_upem(void *context)
+{
+    struct dwrite_fontface *fontface = context;
+    return fontface->metrics.designUnitsPerEm;
+}
+
+static const struct shaping_font_ops dwrite_font_ops =
+{
+    dwrite_grab_font_table,
+    dwrite_release_font_table,
+    dwrite_get_font_upem,
+};
+
+struct scriptshaping_cache *fontface_get_shaping_cache(struct dwrite_fontface *fontface)
+{
+    if (fontface->shaping_cache)
+        return fontface->shaping_cache;
+
+    return fontface->shaping_cache = create_scriptshaping_cache(fontface, &dwrite_font_ops);
+}
+
 static inline struct dwrite_fontface *impl_from_IDWriteFontFace4(IDWriteFontFace4 *iface)
 {
     return CONTAINING_RECORD(iface, struct dwrite_fontface, IDWriteFontFace4_iface);
@@ -493,7 +536,7 @@ static ULONG WINAPI dwritefontface_Release(IDWriteFontFace4 *iface)
             factory_unlock(This->factory);
             heap_free(This->cached);
         }
-
+        release_scriptshaping_cache(This->shaping_cache);
         if (This->cmap.context)
             IDWriteFontFace4_ReleaseFontTable(iface, This->cmap.context);
         if (This->vdmx.context)
@@ -1775,7 +1818,7 @@ static struct dwrite_font *unsafe_impl_from_IDWriteFont(IDWriteFont *iface)
     return CONTAINING_RECORD(iface, struct dwrite_font, IDWriteFont3_iface);
 }
 
-static struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
+struct dwrite_fontface *unsafe_impl_from_IDWriteFontFace(IDWriteFontFace *iface)
 {
     if (!iface)
         return NULL;
@@ -5363,7 +5406,7 @@ static inline void transform_point(D2D_POINT_2F *point, const DWRITE_MATRIX *m)
     *point = ret;
 }
 
-static float fontface_get_scaled_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
+float fontface_get_scaled_design_advance(struct dwrite_fontface *fontface, DWRITE_MEASURING_MODE measuring_mode,
         float emsize, float ppdip, const DWRITE_MATRIX *transform, UINT16 glyph, BOOL is_sideways)
 {
     unsigned int upem = fontface->metrics.designUnitsPerEm;
diff --git a/dlls/dwrite/shape.c b/dlls/dwrite/shape.c
index a6039323ea..69780450e9 100644
--- a/dlls/dwrite/shape.c
+++ b/dlls/dwrite/shape.c
@@ -23,32 +23,26 @@
 
 #include "dwrite_private.h"
 
-struct scriptshaping_cache
+struct scriptshaping_cache *create_scriptshaping_cache(void *context, const struct shaping_font_ops *font_ops)
 {
-    IDWriteFontFace *fontface;
-};
-
-HRESULT create_scriptshaping_cache(IDWriteFontFace *fontface, struct scriptshaping_cache **cache)
-{
-    struct scriptshaping_cache *ret;
+    struct scriptshaping_cache *cache;
 
-    ret = heap_alloc(sizeof(*ret));
-    if (!ret)
-        return E_OUTOFMEMORY;
+    cache = heap_alloc_zero(sizeof(*cache));
+    if (!cache)
+        return NULL;
 
-    ret->fontface = fontface;
-    IDWriteFontFace_AddRef(fontface);
+    cache->font = font_ops;
+    cache->context = context;
 
-    *cache = ret;
+    cache->upem = cache->font->get_font_upem(cache->context);
 
-    return S_OK;
+    return cache;
 }
 
 void release_scriptshaping_cache(struct scriptshaping_cache *cache)
 {
     if (!cache)
         return;
-    IDWriteFontFace_Release(cache->fontface);
     heap_free(cache);
 }
 
@@ -160,10 +154,24 @@ static HRESULT latn_set_text_glyphs_props(struct scriptshaping_context *context,
     return hr;
 }
 
+static const DWORD std_gpos_tags[] =
+{
+    DWRITE_FONT_FEATURE_TAG_KERNING,
+    DWRITE_FONT_FEATURE_TAG_MARK_POSITIONING,
+    DWRITE_FONT_FEATURE_TAG_MARK_TO_MARK_POSITIONING,
+};
+
+static const struct shaping_features std_gpos_features =
+{
+    std_gpos_tags,
+    ARRAY_SIZE(std_gpos_tags),
+};
+
 const struct scriptshaping_ops latn_shaping_ops =
 {
     NULL,
-    latn_set_text_glyphs_props
+    latn_set_text_glyphs_props,
+    &std_gpos_features,
 };
 
 const struct scriptshaping_ops default_shaping_ops =
@@ -171,3 +179,11 @@ const struct scriptshaping_ops default_shaping_ops =
     NULL,
     default_set_text_glyphs_props
 };
+
+HRESULT shape_get_positions(struct scriptshaping_context *context, const DWORD *scripts,
+        const struct shaping_features *features)
+{
+    /* FIXME: stub */
+
+    return S_OK;
+}
-- 
2.20.1




More information about the wine-devel mailing list