diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 7ee3675d2ed..13d3d3216a9 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 3595503f1e5..2299a23cf1e 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; }; -extern HRESULT create_scriptshaping_cache(IDWriteFontFace*,struct scriptshaping_cache**) DECLSPEC_HIDDEN; +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 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 d1e4fb97258..f50133d18c3 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 a6039323ea5..69780450e97 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; -}; + struct scriptshaping_cache *cache; -HRESULT create_scriptshaping_cache(IDWriteFontFace *fontface, struct scriptshaping_cache **cache) -{ - struct scriptshaping_cache *ret; + cache = heap_alloc_zero(sizeof(*cache)); + if (!cache) + return NULL; - ret = heap_alloc(sizeof(*ret)); - if (!ret) - return E_OUTOFMEMORY; + cache->font = font_ops; + cache->context = context; - ret->fontface = fontface; - IDWriteFontFace_AddRef(fontface); + cache->upem = cache->font->get_font_upem(cache->context); - *cache = ret; - - 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; +}