From: Nikolay Sivov Subject: [PATCH 1/2] dwrite: Advances and offsets are optional for IDWriteGlyphRunAnalysis Message-Id: <55C074CA.4000707@codeweavers.com> Date: Tue, 04 Aug 2015 11:16:10 +0300 --- From c25ade69962242856bd0fe2d5aeaaeb4c02297ff Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Tue, 4 Aug 2015 10:20:05 +0300 Subject: [PATCH 1/2] dwrite: Advances and offsets are optional for IDWriteGlyphRunAnalysis --- dlls/dwrite/analyzer.c | 5 ---- dlls/dwrite/dwrite_private.h | 7 ++++- dlls/dwrite/font.c | 70 ++++++++++++++++++++++++++++++++++++-------- dlls/dwrite/main.c | 2 +- dlls/dwrite/tests/font.c | 69 ++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 133 insertions(+), 20 deletions(-) diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index eedb41d..448a212 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -1016,11 +1016,6 @@ done: return hr; } -static inline FLOAT get_scaled_advance_width(INT32 advance, FLOAT emSize, const DWRITE_FONT_METRICS *metrics) -{ - return (FLOAT)advance * emSize / (FLOAT)metrics->designUnitsPerEm; -} - 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, diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index b0168ae..75098cf 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -104,6 +104,11 @@ static inline unsigned short get_table_entry(const unsigned short *table, WCHAR return table[table[table[ch >> 8] + ((ch >> 4) & 0x0f)] + (ch & 0xf)]; } +static inline FLOAT get_scaled_advance_width(INT32 advance, FLOAT emSize, const DWRITE_FONT_METRICS *metrics) +{ + return (FLOAT)advance * emSize / (FLOAT)metrics->designUnitsPerEm; +} + extern HRESULT convert_fontface_to_logfont(IDWriteFontFace*, LOGFONTW*) DECLSPEC_HIDDEN; extern HRESULT create_numbersubstitution(DWRITE_NUMBER_SUBSTITUTION_METHOD,const WCHAR *locale,BOOL,IDWriteNumberSubstitution**) DECLSPEC_HIDDEN; extern HRESULT create_textformat(const WCHAR*,IDWriteFontCollection*,DWRITE_FONT_WEIGHT,DWRITE_FONT_STYLE,DWRITE_FONT_STRETCH, @@ -124,7 +129,7 @@ extern HRESULT create_font_file(IDWriteFontFileLoader *loader, const void *refer extern HRESULT create_localfontfileloader(IDWriteLocalFontFileLoader** iface) DECLSPEC_HIDDEN; extern HRESULT create_fontface(DWRITE_FONT_FACE_TYPE,UINT32,IDWriteFontFile* const*,UINT32,DWRITE_FONT_SIMULATIONS,IDWriteFontFace2**) DECLSPEC_HIDDEN; extern HRESULT create_font_collection(IDWriteFactory2*,IDWriteFontFileEnumerator*,BOOL,IDWriteFontCollection**) DECLSPEC_HIDDEN; -extern HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE,DWRITE_GLYPH_RUN const*,FLOAT,FLOAT,FLOAT,IDWriteGlyphRunAnalysis**) DECLSPEC_HIDDEN; +extern HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE,DWRITE_MEASURING_MODE,DWRITE_GLYPH_RUN const*,FLOAT,FLOAT,FLOAT,IDWriteGlyphRunAnalysis**) DECLSPEC_HIDDEN; extern BOOL is_system_collection(IDWriteFontCollection*) DECLSPEC_HIDDEN; extern HRESULT get_local_refkey(const WCHAR*,const FILETIME*,void**,UINT32*) DECLSPEC_HIDDEN; extern HRESULT get_filestream_from_file(IDWriteFontFile*,IDWriteFontFileStream**) DECLSPEC_HIDDEN; diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c index d72f8a6..707ef6d 100644 --- a/dlls/dwrite/font.c +++ b/dlls/dwrite/font.c @@ -2946,16 +2946,19 @@ static void glyphrunanalysis_get_texturebounds(struct dwrite_glyphrunanalysis *a origin_x = 0.0; is_rtl = analysis->run.bidiLevel & 1; for (i = 0; i < analysis->run.glyphCount; i++) { - const DWRITE_GLYPH_OFFSET *offset = &analysis->offsets[i]; + const DWRITE_GLYPH_OFFSET *offset = analysis->offsets ? &analysis->offsets[i] : NULL; FLOAT advance = analysis->advances[i]; RECT bbox; freetype_get_glyph_bbox(fontface2, analysis->run.fontEmSize * analysis->ppdip, analysis->run.glyphIndices[i], nohint, &bbox); if (is_rtl) - OffsetRect(&bbox, origin_x - offset->advanceOffset - advance, -offset->ascenderOffset); + OffsetRect(&bbox, origin_x - advance, 0); else - OffsetRect(&bbox, origin_x + offset->advanceOffset, offset->ascenderOffset); + OffsetRect(&bbox, origin_x, 0); + + if (offset) + OffsetRect(&bbox, is_rtl ? -offset->advanceOffset : offset->advanceOffset, is_rtl ? -offset->ascenderOffset : offset->ascenderOffset); UnionRect(&analysis->bounds, &analysis->bounds, &bbox); origin_x += is_rtl ? -advance : advance; @@ -3026,7 +3029,7 @@ static void glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis, DW origin_x = 0.0; is_rtl = analysis->run.bidiLevel & 1; for (i = 0; i < analysis->run.glyphCount; i++) { - const DWRITE_GLYPH_OFFSET *offset = &analysis->offsets[i]; + const DWRITE_GLYPH_OFFSET *offset = analysis->offsets ? &analysis->offsets[i] : NULL; FLOAT advance = analysis->advances[i]; int pitch, x, y, width, height; BYTE *glyph, *src, *dst; @@ -3047,9 +3050,12 @@ static void glyphrunanalysis_render(struct dwrite_glyphrunanalysis *analysis, DW freetype_get_glyph_bitmap(fontface2, analysis->run.fontEmSize * analysis->ppdip, analysis->run.glyphIndices[i], &bbox, glyph); if (is_rtl) - OffsetRect(&bbox, origin_x - offset->advanceOffset - advance, -offset->ascenderOffset); + OffsetRect(&bbox, origin_x - advance, 0); else - OffsetRect(&bbox, origin_x + offset->advanceOffset, offset->ascenderOffset); + OffsetRect(&bbox, origin_x, 0); + + if (offset) + OffsetRect(&bbox, is_rtl ? -offset->advanceOffset : offset->advanceOffset, is_rtl ? -offset->ascenderOffset : offset->ascenderOffset); OffsetRect(&bbox, analysis->originX, analysis->originY); @@ -3193,8 +3199,8 @@ static const struct IDWriteGlyphRunAnalysisVtbl glyphrunanalysisvtbl = { glyphrunanalysis_GetAlphaBlendParams }; -HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode, DWRITE_GLYPH_RUN const *run, FLOAT ppdip, - FLOAT originX, FLOAT originY, IDWriteGlyphRunAnalysis **ret) +HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode, DWRITE_MEASURING_MODE measuring_mode, DWRITE_GLYPH_RUN const *run, + FLOAT ppdip, FLOAT originX, FLOAT originY, IDWriteGlyphRunAnalysis **ret) { struct dwrite_glyphrunanalysis *analysis; @@ -3221,8 +3227,8 @@ HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode, DWRITE_GLY IDWriteFontFace_AddRef(analysis->run.fontFace); analysis->glyphs = heap_alloc(run->glyphCount*sizeof(*run->glyphIndices)); analysis->advances = heap_alloc(run->glyphCount*sizeof(*run->glyphAdvances)); - analysis->offsets = heap_alloc(run->glyphCount*sizeof(*run->glyphOffsets)); - if (!analysis->glyphs || !analysis->advances || !analysis->offsets) { + analysis->offsets = run->glyphOffsets ? heap_alloc(run->glyphCount*sizeof(*run->glyphOffsets)) : NULL; + if (!analysis->glyphs || !analysis->advances || (!analysis->offsets && run->glyphOffsets)) { heap_free(analysis->glyphs); heap_free(analysis->advances); heap_free(analysis->offsets); @@ -3240,8 +3246,48 @@ HRESULT create_glyphrunanalysis(DWRITE_RENDERING_MODE rendering_mode, DWRITE_GLY analysis->run.glyphOffsets = analysis->offsets; memcpy(analysis->glyphs, run->glyphIndices, run->glyphCount*sizeof(*run->glyphIndices)); - memcpy(analysis->advances, run->glyphAdvances, run->glyphCount*sizeof(*run->glyphAdvances)); - memcpy(analysis->offsets, run->glyphOffsets, run->glyphCount*sizeof(*run->glyphOffsets)); + + if (run->glyphAdvances) + memcpy(analysis->advances, run->glyphAdvances, run->glyphCount*sizeof(*run->glyphAdvances)); + else { + DWRITE_FONT_METRICS metrics; + IDWriteFontFace1 *fontface1; + UINT32 i; + + IDWriteFontFace_GetMetrics(run->fontFace, &metrics); + IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace1, (void**)&fontface1); + + for (i = 0; i < run->glyphCount; i++) { + HRESULT hr; + INT32 a; + + switch (measuring_mode) + { + case DWRITE_MEASURING_MODE_NATURAL: + hr = IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, run->glyphIndices + i, &a, run->isSideways); + if (FAILED(hr)) + a = 0; + analysis->advances[i] = get_scaled_advance_width(a, run->fontEmSize, &metrics); + break; + case DWRITE_MEASURING_MODE_GDI_CLASSIC: + case DWRITE_MEASURING_MODE_GDI_NATURAL: + hr = IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, run->fontEmSize, ppdip, NULL /* FIXME */, + measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, run->isSideways, 1, run->glyphIndices + i, &a); + if (FAILED(hr)) + analysis->advances[i] = 0.0; + else + analysis->advances[i] = floorf(a * run->fontEmSize * ppdip / metrics.designUnitsPerEm + 0.5f) / ppdip; + break; + default: + ; + } + } + + IDWriteFontFace1_Release(fontface1); + } + + if (run->glyphOffsets) + memcpy(analysis->offsets, run->glyphOffsets, run->glyphCount*sizeof(*run->glyphOffsets)); *ret = &analysis->IDWriteGlyphRunAnalysis_iface; return S_OK; diff --git a/dlls/dwrite/main.c b/dlls/dwrite/main.c index 5a8c026..5673bba 100644 --- a/dlls/dwrite/main.c +++ b/dlls/dwrite/main.c @@ -1079,7 +1079,7 @@ static HRESULT WINAPI dwritefactory_CreateGlyphRunAnalysis(IDWriteFactory2 *ifac TRACE("(%p)->(%p %.2f %p %d %d %.2f %.2f %p)\n", This, run, ppdip, transform, rendering_mode, measuring_mode, originX, originY, analysis); - return create_glyphrunanalysis(rendering_mode, run, ppdip, originX, originY, analysis); + return create_glyphrunanalysis(rendering_mode, measuring_mode, run, ppdip, originX, originY, analysis); } static HRESULT WINAPI dwritefactory1_GetEudcFontCollection(IDWriteFactory2 *iface, IDWriteFontCollection **collection, diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c index c132159..0eca7f4 100644 --- a/dlls/dwrite/tests/font.c +++ b/dlls/dwrite/tests/font.c @@ -3431,7 +3431,7 @@ static void test_CreateGlyphRunAnalysis(void) IDWriteFactory *factory; DWRITE_GLYPH_RUN run; IDWriteFontFace *face; - UINT16 glyph; + UINT16 glyph, glyphs[10]; FLOAT advance; HRESULT hr; UINT32 ch; @@ -3578,6 +3578,73 @@ static void test_CreateGlyphRunAnalysis(void) IDWriteGlyphRunAnalysis_Release(analysis); } + /* without offsets */ + run.fontFace = face; + run.fontEmSize = 24.0; + run.glyphCount = 1; + run.glyphIndices = &glyph; + run.glyphAdvances = &advance; + run.glyphOffsets = NULL; + run.isSideways = FALSE; + run.bidiLevel = 0; + + hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL, + DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL, + 0.0, 0.0, &analysis); + ok(hr == S_OK, "got 0x%08x\n", hr); + + SetRectEmpty(&rect); + hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(!IsRectEmpty(&rect), "got empty bounds\n"); + + IDWriteGlyphRunAnalysis_Release(analysis); + + /* without explicit advances */ + run.fontFace = face; + run.fontEmSize = 24.0; + run.glyphCount = 1; + run.glyphIndices = &glyph; + run.glyphAdvances = NULL; + run.glyphOffsets = NULL; + run.isSideways = FALSE; + run.bidiLevel = 0; + + hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL, + DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL, + 0.0, 0.0, &analysis); + ok(hr == S_OK, "got 0x%08x\n", hr); + + SetRectEmpty(&rect); + hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(!IsRectEmpty(&rect), "got empty bounds\n"); + + IDWriteGlyphRunAnalysis_Release(analysis); + + glyphs[0] = glyphs[1] = glyph; + run.fontFace = face; + run.fontEmSize = 24.0; + run.glyphCount = 2; + run.glyphIndices = glyphs; + run.glyphAdvances = NULL; + run.glyphOffsets = NULL; + run.isSideways = FALSE; + run.bidiLevel = 0; + + hr = IDWriteFactory_CreateGlyphRunAnalysis(factory, &run, 1.0, NULL, + DWRITE_RENDERING_MODE_ALIASED, DWRITE_MEASURING_MODE_NATURAL, + 0.0, 0.0, &analysis); + ok(hr == S_OK, "got 0x%08x\n", hr); + + SetRectEmpty(&rect2); + hr = IDWriteGlyphRunAnalysis_GetAlphaTextureBounds(analysis, DWRITE_TEXTURE_ALIASED_1x1, &rect2); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(!IsRectEmpty(&rect2), "got empty bounds\n"); + ok(!EqualRect(&rect, &rect2), "got wrong rect2\n"); + + IDWriteGlyphRunAnalysis_Release(analysis); + IDWriteFontFace_Release(face); IDWriteFactory_Release(factory); } -- 2.1.4