diff --git a/dlls/dwrite/main.c b/dlls/dwrite/main.c index 9b5de8aeea9..067bc8a3ce0 100644 --- a/dlls/dwrite/main.c +++ b/dlls/dwrite/main.c @@ -21,6 +21,7 @@ #define COBJMACROS #include +#include #include "windef.h" #include "winbase.h" @@ -1438,14 +1439,86 @@ static HRESULT WINAPI dwritefactory4_TranslateColorGlyphRun(IDWriteFactory4 *ifa return E_NOTIMPL; } +static HRESULT compute_glyph_origins(DWRITE_GLYPH_RUN const *run, DWRITE_MEASURING_MODE measuring_mode, + D2D1_POINT_2F baseline_origin, DWRITE_MATRIX const *transform, D2D1_POINT_2F *origins) +{ + IDWriteFontFace1 *fontface1 = NULL; + DWRITE_FONT_METRICS metrics; + FLOAT rtl_factor; + UINT32 i; + + rtl_factor = run->bidiLevel & 1 ? -1.0f : 1.0f; + + if (run->fontFace) { + IDWriteFontFace_GetMetrics(run->fontFace, &metrics); + IDWriteFontFace_QueryInterface(run->fontFace, &IID_IDWriteFontFace1, (void **)&fontface1); + } + + for (i = 0; i < run->glyphCount; i++) { + FLOAT advance; + + /* Use nominal advances if not provided by caller. */ + if (run->glyphAdvances) + advance = rtl_factor * run->glyphAdvances[i]; + else { + INT32 a; + + advance = 0.0f; + switch (measuring_mode) + { + case DWRITE_MEASURING_MODE_NATURAL: + if (SUCCEEDED(IDWriteFontFace1_GetDesignGlyphAdvances(fontface1, 1, run->glyphIndices + i, &a, + run->isSideways))) + advance = rtl_factor * get_scaled_advance_width(a, run->fontEmSize, &metrics); + break; + case DWRITE_MEASURING_MODE_GDI_CLASSIC: + case DWRITE_MEASURING_MODE_GDI_NATURAL: + if (SUCCEEDED(IDWriteFontFace1_GetGdiCompatibleGlyphAdvances(fontface1, run->fontEmSize, + 1.0f, transform, measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL, + run->isSideways, 1, run->glyphIndices + i, &a))) + advance = rtl_factor * floorf(a * run->fontEmSize / metrics.designUnitsPerEm + 0.5f); + break; + default: + ; + } + } + + origins[i] = baseline_origin; + + /* Apply offsets. */ + if (run->glyphOffsets) { + FLOAT advanceoffset = rtl_factor * run->glyphOffsets[i].advanceOffset; + FLOAT ascenderoffset = -run->glyphOffsets[i].ascenderOffset; + + if (run->isSideways) { + origins[i].x += ascenderoffset; + origins[i].y += advanceoffset; + } + else { + origins[i].x += advanceoffset; + origins[i].y += ascenderoffset; + } + } + + if (run->isSideways) + baseline_origin.y += advance; + else + baseline_origin.x += advance; + } + + if (fontface1) + IDWriteFontFace1_Release(fontface1); + return S_OK; +} + static HRESULT WINAPI dwritefactory4_ComputeGlyphOrigins_(IDWriteFactory4 *iface, DWRITE_GLYPH_RUN const *run, D2D1_POINT_2F baseline_origin, D2D1_POINT_2F *origins) { struct dwritefactory *This = impl_from_IDWriteFactory4(iface); - FIXME("(%p)->(%p %p): stub\n", This, run, origins); + TRACE("(%p)->(%p (%f,%f) %p)\n", This, run, baseline_origin.x, baseline_origin.y, origins); - return E_NOTIMPL; + return compute_glyph_origins(run, DWRITE_MEASURING_MODE_NATURAL, baseline_origin, NULL, origins); } static HRESULT WINAPI dwritefactory4_ComputeGlyphOrigins(IDWriteFactory4 *iface, DWRITE_GLYPH_RUN const *run, @@ -1454,9 +1527,10 @@ static HRESULT WINAPI dwritefactory4_ComputeGlyphOrigins(IDWriteFactory4 *iface, { struct dwritefactory *This = impl_from_IDWriteFactory4(iface); - FIXME("(%p)->(%p %d %p %p): stub\n", This, run, measuring_mode, transform, origins); + TRACE("(%p)->(%p %d (%f,%f) %p %p)\n", This, run, measuring_mode, baseline_origin.x, baseline_origin.y, + transform, origins); - return E_NOTIMPL; + return compute_glyph_origins(run, measuring_mode, baseline_origin, transform, origins); } static const struct IDWriteFactory4Vtbl dwritefactoryvtbl = { diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c index 2bdc024a041..79aebe3ebe8 100644 --- a/dlls/dwrite/tests/font.c +++ b/dlls/dwrite/tests/font.c @@ -6858,6 +6858,70 @@ static void test_HasKerningPairs(void) IDWriteFactory_Release(factory); } +static void test_ComputeGlyphOrigins(void) +{ + IDWriteFactory4 *factory4; + IDWriteFactory *factory; + DWRITE_GLYPH_RUN run; + HRESULT hr; + D2D1_POINT_2F origins[2]; + D2D1_POINT_2F baseline_origin; + UINT16 glyphs[2]; + FLOAT advances[2]; + DWRITE_MATRIX m; + + factory = create_factory(); + hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory4, (void **)&factory4); + IDWriteFactory_Release(factory); + if (FAILED(hr)) { + win_skip("ComputeGlyphOrigins() is not supported.\n"); + return; + } + + advances[0] = 10.0f; + advances[1] = 20.0f; + + run.fontFace = NULL; + run.fontEmSize = 16.0f; + run.glyphCount = 2; + run.glyphIndices = glyphs; + run.glyphAdvances = advances; + run.glyphOffsets = NULL; + run.isSideways = FALSE; + run.bidiLevel = 0; + + baseline_origin.x = 123.0f; + baseline_origin.y = 321.0f; + + memset(origins, 0, sizeof(origins)); + hr = IDWriteFactory4_ComputeGlyphOrigins_(factory4, &run, baseline_origin, origins); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(origins[0].x == 123.0f && origins[0].y == 321.0f, "origins[0] %f,%f\n", origins[0].x, origins[0].y); + ok(origins[1].x == 133.0f && origins[1].y == 321.0f, "origins[1] %f,%f\n", origins[1].x, origins[1].y); + + memset(origins, 0, sizeof(origins)); + hr = IDWriteFactory4_ComputeGlyphOrigins(factory4, &run, DWRITE_MEASURING_MODE_NATURAL, baseline_origin, + NULL, origins); + ok(origins[0].x == 123.0f && origins[0].y == 321.0f, "origins[0] %f,%f\n", origins[0].x, origins[0].y); + ok(origins[1].x == 133.0f && origins[1].y == 321.0f, "origins[1] %f,%f\n", origins[1].x, origins[1].y); + + /* transform is not applied to returned origins */ + m.m11 = 2.0f; + m.m12 = 0.0f; + m.m21 = 0.0f; + m.m22 = 1.0f; + m.dx = 0.0f; + m.dy = 0.0f; + + memset(origins, 0, sizeof(origins)); + hr = IDWriteFactory4_ComputeGlyphOrigins(factory4, &run, DWRITE_MEASURING_MODE_NATURAL, baseline_origin, + &m, origins); + ok(origins[0].x == 123.0f && origins[0].y == 321.0f, "origins[0] %f,%f\n", origins[0].x, origins[0].y); + ok(origins[1].x == 133.0f && origins[1].y == 321.0f, "origins[1] %f,%f\n", origins[1].x, origins[1].y); + + IDWriteFactory4_Release(factory4); +} + START_TEST(font) { IDWriteFactory *factory; @@ -6917,6 +6981,7 @@ START_TEST(font) test_font_properties(); test_HasVerticalGlyphVariants(); test_HasKerningPairs(); + test_ComputeGlyphOrigins(); IDWriteFactory_Release(factory); }