dwrite: Add a helper to get shaped glyph positions.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2019-01-31 11:35:26 +03:00 committed by Alexandre Julliard
parent e020d6c99d
commit d1c7348997
4 changed files with 173 additions and 96 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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;
}