From: Nikolay Sivov Subject: dwrite: Initial implementation of GetGlyphPlacements() Message-Id: <54C0E371.5060508@codeweavers.com> Date: Thu, 22 Jan 2015 14:48:01 +0300 --- From be4bc58820337c23ebac52f073df69ec060a9692 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Thu, 22 Jan 2015 14:43:24 +0300 Subject: [PATCH] dwrite: Initial implementation of GetGlyphPlacements() --- dlls/dwrite/analyzer.c | 48 ++++++++++++--- dlls/dwrite/tests/analyzer.c | 142 +++++++++++++++++++++++++++++++++++++++++++ dlls/dwrite/tests/layout.c | 4 +- 3 files changed, 185 insertions(+), 9 deletions(-) diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 17e0351..d162076 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -962,17 +962,51 @@ 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* glyph_indices, DWRITE_SHAPING_GLYPH_PROPERTIES const* glyph_props, - UINT32 glyph_count, IDWriteFontFace * font_face, FLOAT fontEmSize, BOOL is_sideways, BOOL is_rtl, + 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, DWRITE_SCRIPT_ANALYSIS const* analysis, WCHAR const* locale, DWRITE_TYPOGRAPHIC_FEATURES const** features, - UINT32 const* feature_range_len, UINT32 feature_ranges, FLOAT* glyph_advances, DWRITE_GLYPH_OFFSET* glyph_offsets) + UINT32 const* feature_range_len, UINT32 feature_ranges, FLOAT *advances, DWRITE_GLYPH_OFFSET *offsets) { - FIXME("(%s %p %p %u %p %p %u %p %f %d %d %p %s %p %p %u %p %p): stub\n", debugstr_w(text), - clustermap, props, text_len, glyph_indices, glyph_props, glyph_count, font_face, fontEmSize, is_sideways, - is_rtl, analysis, debugstr_w(locale), features, feature_range_len, feature_ranges, glyph_advances, glyph_offsets); - return E_NOTIMPL; + DWRITE_FONT_METRICS metrics; + IDWriteFontFace1 *fontface1; + HRESULT hr; + UINT32 i; + + TRACE("(%s %p %p %u %p %p %u %p %.2f %d %d %p %s %p %p %u %p %p)\n", debugstr_w(text), + clustermap, props, text_len, glyphs, glyph_props, glyph_count, fontface, emSize, is_sideways, + is_rtl, analysis, debugstr_w(locale), features, feature_range_len, feature_ranges, advances, offsets); + + 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; + } + + IDWriteFontFace_GetMetrics(fontface, &metrics); + for (i = 0; i < glyph_count; i++) { + 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); + offsets[i].advanceOffset = 0.0; + offsets[i].ascenderOffset = 0.0; + } + + /* FIXME: actually apply features */ + return S_OK; } static HRESULT WINAPI dwritetextanalyzer_GetGdiCompatibleGlyphPlacements(IDWriteTextAnalyzer2 *iface, diff --git a/dlls/dwrite/tests/analyzer.c b/dlls/dwrite/tests/analyzer.c index acb5b18..4b8cbcd 100644 --- a/dlls/dwrite/tests/analyzer.c +++ b/dlls/dwrite/tests/analyzer.c @@ -30,6 +30,7 @@ #include "wine/test.h" static IDWriteFactory *factory; +static const WCHAR test_fontfile[] = {'w','i','n','e','_','t','e','s','t','_','f','o','n','t','.','t','t','f',0}; enum analysis_kind { ScriptAnalysis, @@ -442,6 +443,40 @@ static IDWriteFontFace *create_fontface(void) return fontface; } +static void create_testfontfile(const WCHAR *filename) +{ + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + + file = CreateFileW(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "file creation failed\n"); + + res = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA); + ok(res != 0, "couldn't find resource\n"); + ptr = LockResource(LoadResource(GetModuleHandleA(NULL), res)); + WriteFile(file, ptr, SizeofResource(GetModuleHandleA(NULL), res), &written, NULL); + ok(written == SizeofResource(GetModuleHandleA(NULL), res), "couldn't write resource\n"); + CloseHandle(file); +} + +static IDWriteFontFace *create_testfontface(const WCHAR *filename) +{ + IDWriteFontFace *face; + IDWriteFontFile *file; + HRESULT hr; + + hr = IDWriteFactory_CreateFontFileReference(factory, filename, NULL, &file); + ok(hr == S_OK, "got 0x%08x\n",hr); + + hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, + DWRITE_FONT_SIMULATIONS_NONE, &face); + ok(hr == S_OK, "got 0x%08x\n", hr); + + return face; +} + struct sa_test { const WCHAR string[50]; int item_count; @@ -1291,6 +1326,112 @@ todo_wine { IDWriteTextAnalyzer2_Release(analyzer2); } +static void test_GetGlyphPlacements(void) +{ + DWRITE_SHAPING_GLYPH_PROPERTIES glyphprops[2]; + DWRITE_SHAPING_TEXT_PROPERTIES textprops[2]; + static const WCHAR aW[] = {'A','D',0}; + UINT16 clustermap[2], glyphs[2]; + DWRITE_GLYPH_OFFSET offsets[2]; + IDWriteTextAnalyzer *analyzer; + IDWriteFontFace *fontface; + DWRITE_SCRIPT_ANALYSIS sa; + FLOAT advances[2]; + UINT32 count, len; + HRESULT hr; + + hr = IDWriteFactory_CreateTextAnalyzer(factory, &analyzer); + ok(hr == S_OK, "got 0x%08x\n", hr); + + create_testfontfile(test_fontfile); + fontface = create_testfontface(test_fontfile); + + get_script_analysis(aW, &sa); + count = 0; + len = lstrlenW(aW); + hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, aW, len, fontface, FALSE, FALSE, &sa, NULL, + NULL, NULL, NULL, 0, len, clustermap, textprops, glyphs, glyphprops, &count); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(count == 2, "got %u\n", count); + + /* just return on zero glyphs */ + advances[0] = advances[1] = 1.0; + offsets[0].advanceOffset = offsets[0].ascenderOffset = 2.0; + hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, aW, clustermap, textprops, + len, glyphs, glyphprops, 0, fontface, 0.0, FALSE, FALSE, &sa, NULL, NULL, + NULL, 0, advances, offsets); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(advances[0] == 1.0, "got %.2f\n", advances[0]); + ok(offsets[0].advanceOffset == 2.0 && offsets[0].ascenderOffset == 2.0, "got %.2f,%.2f\n", + offsets[0].advanceOffset, offsets[0].ascenderOffset); + + /* advances/offsets are scaled with provided font emSize and designed eM box size */ + advances[0] = advances[1] = 1.0; + memset(offsets, 0xcc, sizeof(offsets)); + hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, aW, clustermap, textprops, + len, glyphs, glyphprops, len, fontface, 0.0, FALSE, FALSE, &sa, NULL, NULL, + NULL, 0, advances, offsets); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(advances[0] == 0.0, "got %.2f\n", advances[0]); + ok(offsets[0].advanceOffset == 0.0 && offsets[0].ascenderOffset == 0.0, "got %.2f,%.2f\n", + offsets[0].advanceOffset, offsets[0].ascenderOffset); + + advances[0] = advances[1] = 1.0; + memset(offsets, 0xcc, sizeof(offsets)); + hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, aW, clustermap, textprops, + len, glyphs, glyphprops, len, fontface, 2048.0, FALSE, FALSE, &sa, NULL, NULL, + NULL, 0, advances, offsets); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(advances[0] == 1000.0, "got %.2f\n", advances[0]); + ok(offsets[0].advanceOffset == 0.0 && offsets[0].ascenderOffset == 0.0, "got %.2f,%.2f\n", + offsets[0].advanceOffset, offsets[0].ascenderOffset); + + advances[0] = advances[1] = 1.0; + memset(offsets, 0xcc, sizeof(offsets)); + hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, aW, clustermap, textprops, + len, glyphs, glyphprops, len, fontface, 1024.0, FALSE, FALSE, &sa, NULL, NULL, + NULL, 0, advances, offsets); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(advances[0] == 500.0, "got %.2f\n", advances[0]); + ok(advances[1] == 500.0, "got %.2f\n", advances[1]); + ok(offsets[0].advanceOffset == 0.0 && offsets[0].ascenderOffset == 0.0, "got %.2f,%.2f\n", + offsets[0].advanceOffset, offsets[0].ascenderOffset); + + advances[0] = advances[1] = 1.0; + memset(offsets, 0xcc, sizeof(offsets)); + hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, aW, clustermap, textprops, + len, glyphs, glyphprops, len, fontface, 20.48, FALSE, FALSE, &sa, NULL, NULL, + NULL, 0, advances, offsets); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(advances[0] == 10.0, "got %.2f\n", advances[0]); + ok(advances[1] == 10.0, "got %.2f\n", advances[1]); + ok(offsets[0].advanceOffset == 0.0 && offsets[0].ascenderOffset == 0.0, "got %.2f,%.2f\n", + offsets[0].advanceOffset, offsets[0].ascenderOffset); + + /* without clustermap */ + advances[0] = advances[1] = 1.0; + hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, aW, NULL, textprops, + len, glyphs, glyphprops, len, fontface, 1024.0, FALSE, FALSE, &sa, NULL, NULL, + NULL, 0, advances, offsets); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(advances[0] == 500.0, "got %.2f\n", advances[0]); + ok(advances[1] == 500.0, "got %.2f\n", advances[1]); + + /* it's happy to use negative size too */ + advances[0] = advances[1] = 1.0; + memset(offsets, 0xcc, sizeof(offsets)); + hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, aW, clustermap, textprops, + len, glyphs, glyphprops, len, fontface, -10.24, FALSE, FALSE, &sa, NULL, NULL, + NULL, 0, advances, offsets); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(advances[0] == -5.0, "got %.2f\n", advances[0]); + ok(offsets[0].advanceOffset == 0.0 && offsets[0].ascenderOffset == 0.0, "got %.2f,%.2f\n", + offsets[0].advanceOffset, offsets[0].ascenderOffset); + + IDWriteTextAnalyzer_Release(analyzer); + DeleteFileW(test_fontfile); +} + START_TEST(analyzer) { HRESULT hr; @@ -1313,6 +1454,7 @@ START_TEST(analyzer) test_GetGlyphs(); test_numbersubstitution(); test_GetTypographicFeatures(); + test_GetGlyphPlacements(); IDWriteFactory_Release(factory); } diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c index 760c34f..98358a4 100644 --- a/dlls/dwrite/tests/layout.c +++ b/dlls/dwrite/tests/layout.c @@ -921,10 +921,10 @@ static void test_GetClusterMetrics(void) count = 0; hr = IDWriteTextLayout_GetClusterMetrics(layout, NULL, 0, &count); -todo_wine { +todo_wine ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr); ok(count == 4, "got %u\n", count); -} + hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &trimm); ok(hr == S_OK, "got 0x%08x\n", hr); -- 2.1.4