From e877cfbcfa4759b57048f029c14e12acbb6acafb Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Mon, 27 Jul 2015 11:10:32 +0300 Subject: [PATCH] dwrite: Implement GetRecommendedRenderingMode(). --- dlls/dwrite/dwrite_private.h | 9 +++ dlls/dwrite/font.c | 134 +++++++++++++++++++++++++++++++++++++++---- dlls/dwrite/opentype.c | 30 +++++++++- dlls/dwrite/tests/font.c | 28 +++++---- 4 files changed, 174 insertions(+), 27 deletions(-) diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 0111e46af2c..65cf4b047c7 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -148,6 +148,15 @@ extern HRESULT opentype_get_font_strings_from_id(const void*,DWRITE_INFORMATIONA extern HRESULT opentype_get_typographic_features(IDWriteFontFace*,UINT32,UINT32,UINT32,UINT32*,DWRITE_FONT_FEATURE_TAG*) DECLSPEC_HIDDEN; extern BOOL opentype_get_vdmx_size(const void*,INT,UINT16*,UINT16*) DECLSPEC_HIDDEN; +enum gasp_flags { + GASP_GRIDFIT = 0x0001, + GASP_DOGRAY = 0x0002, + GASP_SYMMETRIC_GRIDFIT = 0x0004, + GASP_SYMMETRIC_SMOOTHING = 0x0008, +}; + +extern WORD opentype_get_gasp_flags(const WORD*,UINT32,INT) DECLSPEC_HIDDEN; + /* BiDi helpers */ extern HRESULT bidi_computelevels(const WCHAR*,UINT32,UINT8,UINT8*,UINT8*) DECLSPEC_HIDDEN; extern WCHAR bidi_get_mirrored_char(WCHAR) DECLSPEC_HIDDEN; diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c index 2d01574c153..4fdea6c8963 100644 --- a/dlls/dwrite/font.c +++ b/dlls/dwrite/font.c @@ -32,9 +32,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(dwrite); #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p') #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e') #define MS_VDMX_TAG DWRITE_MAKE_OPENTYPE_TAG('V','D','M','X') +#define MS_GASP_TAG DWRITE_MAKE_OPENTYPE_TAG('g','a','s','p') static const IID IID_issystemcollection = {0x14d88047,0x331f,0x4cd3,{0xbc,0xa8,0x3e,0x67,0x99,0xaf,0x34,0x75}}; +static const FLOAT RECOMMENDED_OUTLINE_AA_THRESHOLD = 100.0f; +static const FLOAT RECOMMENDED_OUTLINE_A_THRESHOLD = 350.0f; +static const FLOAT RECOMMENDED_NATURAL_PPEM = 20.0f; + struct dwrite_font_data { LONG ref; @@ -129,6 +134,7 @@ struct dwrite_fontface { struct dwrite_fonttable cmap; struct dwrite_fonttable vdmx; + struct dwrite_fonttable gasp; DWRITE_GLYPH_METRICS *glyphs[GLYPH_MAX/GLYPH_BLOCK_SIZE]; }; @@ -230,6 +236,13 @@ static inline void* get_fontface_vdmx(struct dwrite_fontface *fontface) return get_fontface_table(fontface, MS_VDMX_TAG, &fontface->vdmx); } +static inline void* get_fontface_gasp(struct dwrite_fontface *fontface, UINT32 *size) +{ + void *ptr = get_fontface_table(fontface, MS_GASP_TAG, &fontface->gasp); + *size = fontface->gasp.size; + return ptr; +} + static void release_font_data(struct dwrite_font_data *data) { int i; @@ -304,6 +317,8 @@ static ULONG WINAPI dwritefontface_Release(IDWriteFontFace2 *iface) IDWriteFontFace2_ReleaseFontTable(iface, This->cmap.context); if (This->vdmx.context) IDWriteFontFace2_ReleaseFontTable(iface, This->vdmx.context); + if (This->gasp.context) + IDWriteFontFace2_ReleaseFontTable(iface, This->gasp.context); for (i = 0; i < This->file_count; i++) { if (This->streams[i]) IDWriteFontFileStream_Release(This->streams[i]); @@ -585,12 +600,64 @@ static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace2 *iface, return S_OK; } +static DWRITE_RENDERING_MODE fontface_renderingmode_from_measuringmode(DWRITE_MEASURING_MODE measuring, + FLOAT ppem, WORD gasp) +{ + DWRITE_RENDERING_MODE mode = DWRITE_RENDERING_MODE_DEFAULT; + + switch (measuring) + { + case DWRITE_MEASURING_MODE_NATURAL: + { + if (!(gasp & GASP_SYMMETRIC_SMOOTHING) && (ppem <= RECOMMENDED_NATURAL_PPEM)) + mode = DWRITE_RENDERING_MODE_NATURAL; + else + mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC; + break; + } + case DWRITE_MEASURING_MODE_GDI_CLASSIC: + mode = DWRITE_RENDERING_MODE_GDI_CLASSIC; + break; + case DWRITE_MEASURING_MODE_GDI_NATURAL: + mode = DWRITE_RENDERING_MODE_GDI_NATURAL; + break; + default: + ; + } + + return mode; +} + static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace2 *iface, FLOAT emSize, - FLOAT pixels_per_dip, DWRITE_MEASURING_MODE mode, IDWriteRenderingParams* params, DWRITE_RENDERING_MODE* rendering_mode) + FLOAT ppdip, DWRITE_MEASURING_MODE measuring, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *mode) { struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface); - FIXME("(%p)->(%f %f %d %p %p): stub\n", This, emSize, pixels_per_dip, mode, params, rendering_mode); - return E_NOTIMPL; + WORD gasp, *ptr; + UINT32 size; + FLOAT ppem; + + TRACE("(%p)->(%.2f %.2f %d %p %p)\n", This, emSize, ppdip, measuring, params, mode); + + if (!params) { + *mode = DWRITE_RENDERING_MODE_DEFAULT; + return E_INVALIDARG; + } + + *mode = IDWriteRenderingParams_GetRenderingMode(params); + if (*mode != DWRITE_RENDERING_MODE_DEFAULT) + return S_OK; + + ppem = emSize * ppdip; + + if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) { + *mode = DWRITE_RENDERING_MODE_OUTLINE; + return S_OK; + } + + ptr = get_fontface_gasp(This, &size); + gasp = opentype_get_gasp_flags(ptr, size, ppem); + *mode = fontface_renderingmode_from_measuringmode(measuring, ppem, gasp); + return S_OK; } static HRESULT WINAPI dwritefontface_GetGdiCompatibleMetrics(IDWriteFontFace2 *iface, FLOAT emSize, FLOAT pixels_per_dip, @@ -832,10 +899,7 @@ static HRESULT WINAPI dwritefontface1_GetRecommendedRenderingMode(IDWriteFontFac FLOAT font_emsize, FLOAT dpiX, FLOAT dpiY, const DWRITE_MATRIX *transform, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuring_mode, DWRITE_RENDERING_MODE *rendering_mode) { - struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface); DWRITE_GRID_FIT_MODE gridfitmode; - TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p)\n", This, font_emsize, dpiX, dpiY, transform, is_sideways, - threshold, measuring_mode, rendering_mode); return IDWriteFontFace2_GetRecommendedRenderingMode(iface, font_emsize, dpiX, dpiY, transform, is_sideways, threshold, measuring_mode, NULL, rendering_mode, &gridfitmode); } @@ -884,15 +948,63 @@ static HRESULT WINAPI dwritefontface2_GetPaletteEntries(IDWriteFontFace2 *iface, return E_NOTIMPL; } -static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace2 *iface, FLOAT fontEmSize, - FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *transform, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, +static HRESULT WINAPI dwritefontface2_GetRecommendedRenderingMode(IDWriteFontFace2 *iface, FLOAT emSize, + FLOAT dpiX, FLOAT dpiY, DWRITE_MATRIX const *m, BOOL is_sideways, DWRITE_OUTLINE_THRESHOLD threshold, DWRITE_MEASURING_MODE measuringmode, IDWriteRenderingParams *params, DWRITE_RENDERING_MODE *renderingmode, DWRITE_GRID_FIT_MODE *gridfitmode) { struct dwrite_fontface *This = impl_from_IDWriteFontFace2(iface); - FIXME("(%p)->(%f %f %f %p %d %d %d %p %p %p): stub\n", This, fontEmSize, dpiX, dpiY, transform, is_sideways, threshold, + FLOAT emthreshold; + WORD gasp, *ptr; + UINT32 size; + + TRACE("(%p)->(%.2f %.2f %.2f %p %d %d %d %p %p %p)\n", This, emSize, dpiX, dpiY, m, is_sideways, threshold, measuringmode, params, renderingmode, gridfitmode); - return E_NOTIMPL; + + if (m) + FIXME("transform not supported %s\n", debugstr_matrix(m)); + + if (is_sideways) + FIXME("sideways mode not supported\n"); + + *renderingmode = DWRITE_RENDERING_MODE_DEFAULT; + *gridfitmode = DWRITE_GRID_FIT_MODE_DEFAULT; + if (params) { + IDWriteRenderingParams2 *params2; + HRESULT hr; + + hr = IDWriteRenderingParams_QueryInterface(params, &IID_IDWriteRenderingParams2, (void**)¶ms2); + if (hr == S_OK) { + *renderingmode = IDWriteRenderingParams2_GetRenderingMode(params2); + *gridfitmode = IDWriteRenderingParams2_GetGridFitMode(params2); + IDWriteRenderingParams2_Release(params2); + } + else + *renderingmode = IDWriteRenderingParams_GetRenderingMode(params); + } + + emthreshold = threshold == DWRITE_OUTLINE_THRESHOLD_ANTIALIASED ? RECOMMENDED_OUTLINE_AA_THRESHOLD : RECOMMENDED_OUTLINE_A_THRESHOLD; + + ptr = get_fontface_gasp(This, &size); + gasp = opentype_get_gasp_flags(ptr, size, emSize); + + if (*renderingmode == DWRITE_RENDERING_MODE_DEFAULT) { + if (emSize >= emthreshold) + *renderingmode = DWRITE_RENDERING_MODE_OUTLINE; + else + *renderingmode = fontface_renderingmode_from_measuringmode(measuringmode, emSize, gasp); + } + + if (*gridfitmode == DWRITE_GRID_FIT_MODE_DEFAULT) { + if (emSize >= emthreshold) + *gridfitmode = DWRITE_GRID_FIT_MODE_DISABLED; + else if (measuringmode == DWRITE_MEASURING_MODE_GDI_CLASSIC || measuringmode == DWRITE_MEASURING_MODE_GDI_NATURAL) + *gridfitmode = DWRITE_GRID_FIT_MODE_ENABLED; + else + *gridfitmode = (gasp & (GASP_GRIDFIT|GASP_SYMMETRIC_GRIDFIT)) ? DWRITE_GRID_FIT_MODE_ENABLED : DWRITE_GRID_FIT_MODE_DISABLED; + } + + return S_OK; } static const IDWriteFontFace2Vtbl dwritefontfacevtbl = { @@ -2344,8 +2456,10 @@ HRESULT create_fontface(DWRITE_FONT_FACE_TYPE facetype, UINT32 files_number, IDW fontface->file_count = files_number; memset(&fontface->cmap, 0, sizeof(fontface->cmap)); memset(&fontface->vdmx, 0, sizeof(fontface->vdmx)); + memset(&fontface->gasp, 0, sizeof(fontface->gasp)); fontface->cmap.exists = TRUE; fontface->vdmx.exists = TRUE; + fontface->gasp.exists = TRUE; fontface->index = index; fontface->simulations = simulations; memset(fontface->glyphs, 0, sizeof(fontface->glyphs)); diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 8d90c04752c..3cb8afba8ea 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -21,6 +21,7 @@ #define COBJMACROS #include "dwrite_private.h" +#include "winternl.h" WINE_DEFAULT_DEBUG_CHANNEL(dwrite); @@ -37,8 +38,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(dwrite); #define GET_BE_WORD(x) (x) #define GET_BE_DWORD(x) (x) #else -#define GET_BE_WORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x)) -#define GET_BE_DWORD(x) MAKELONG(GET_BE_WORD(HIWORD(x)), GET_BE_WORD(LOWORD(x))) +#define GET_BE_WORD(x) RtlUshortByteSwap(x) +#define GET_BE_DWORD(x) RtlUlongByteSwap(x) #endif typedef struct { @@ -1377,3 +1378,28 @@ BOOL opentype_get_vdmx_size(const void *data, INT emsize, UINT16 *ascent, UINT16 } return FALSE; } + +WORD opentype_get_gasp_flags(const WORD *ptr, UINT32 size, INT emsize) +{ + WORD num_recs, version; + WORD flags = 0; + + if (!ptr) + return 0; + + version = GET_BE_WORD( *ptr++ ); + num_recs = GET_BE_WORD( *ptr++ ); + if (version > 1 || size < (num_recs * 2 + 2) * sizeof(WORD)) { + ERR("unsupported gasp table: ver %d size %d recs %d\n", version, size, num_recs); + goto done; + } + + while (num_recs--) { + flags = GET_BE_WORD( *(ptr + 1) ); + if (emsize <= GET_BE_WORD( *ptr )) break; + ptr += 2; + } + +done: + return flags; +} diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c index 485b9787487..bd001e72e80 100644 --- a/dlls/dwrite/tests/font.c +++ b/dlls/dwrite/tests/font.c @@ -4238,10 +4238,9 @@ if (0) /* crashes on native */ mode = 10; hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 3.0, 1.0, DWRITE_MEASURING_MODE_GDI_CLASSIC, NULL, &mode); -todo_wine { ok(hr == E_INVALIDARG, "got 0x%08x\n", hr); ok(mode == DWRITE_RENDERING_MODE_DEFAULT, "got %d\n", mode); -} + hr = IDWriteFactory_CreateRenderingParams(factory, ¶ms); ok(hr == S_OK, "got 0x%08x\n", hr); @@ -4251,24 +4250,16 @@ todo_wine { for (emsize = 1.0; emsize < 500.0; emsize += 1.0) { WORD gasp = get_gasp_flags(fontface, emsize); DWRITE_RENDERING_MODE expected; - int i, skiptest = 0; + int i; for (i = 0; i < sizeof(recmode_tests)/sizeof(recmode_tests[0]); i++) { mode = 10; expected = get_expected_rendering_mode(emsize, gasp, recmode_tests[i].measuring, recmode_tests[i].threshold); hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, emsize, 1.0, recmode_tests[i].measuring, params, &mode); - todo_wine ok(hr == S_OK, "got 0x%08x\n", hr); - if (hr != S_OK) { - skiptest = 1; - break; - } ok(mode == expected, "%.2f/%d: got %d, flags 0x%04x, expected %d\n", emsize, i, mode, gasp, expected); } - if (skiptest) - break; - /* IDWriteFontFace1 offers another variant of this method */ if (fontface1) { for (i = 0; i < sizeof(recmode_tests1)/sizeof(recmode_tests1[0]); i++) { @@ -4308,10 +4299,9 @@ todo_wine { mode = 10; hr = IDWriteFontFace_GetRecommendedRenderingMode(fontface, 500.0, 1.0, DWRITE_MEASURING_MODE_NATURAL, params, &mode); -todo_wine { ok(hr == S_OK, "got 0x%08x\n", hr); ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode); -} + IDWriteRenderingParams_Release(params); if (fontface2) { @@ -4330,12 +4320,20 @@ todo_wine { gridfit = 10; hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0, 96.0, 96.0, NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC, + NULL, &mode, &gridfit); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(mode == DWRITE_RENDERING_MODE_GDI_CLASSIC, "got %d\n", mode); + ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit); + + mode = 10; + gridfit = 10; + hr = IDWriteFontFace2_GetRecommendedRenderingMode(fontface2, 5.0, 96.0, 96.0, + NULL, FALSE, DWRITE_OUTLINE_THRESHOLD_ANTIALIASED, DWRITE_MEASURING_MODE_GDI_CLASSIC, (IDWriteRenderingParams*)params2, &mode, &gridfit); -todo_wine { ok(hr == S_OK, "got 0x%08x\n", hr); ok(mode == DWRITE_RENDERING_MODE_OUTLINE, "got %d\n", mode); ok(gridfit == DWRITE_GRID_FIT_MODE_ENABLED, "got %d\n", gridfit); -} + IDWriteRenderingParams2_Release(params2); IDWriteFactory2_Release(factory2); } -- 2.11.4.GIT