The "GdiInterop" is a sample application (source code is avaiable in [Github][source_code], relative guide in [MSDN][msdn_guide]) that demostracts how to display DirectWrite text on a GDI surface. After set dpi to 168 in `winecfg`, and run sample application with wine, the font size is normal, but the position of glyph is incorrect.
| Dpi: 96 | Dpi: 168 | |:----------------:|:-----------------:| | ![ss1][sc_96dpi] | ![ss2][sc_168dpi] |
There is the sample application after compile: [Release_x64.tar.gz](/uploads/c70e32824efcaa5d16ab39bbb4b86e30/Release_x64.tar.gz)
After change transform matrix that pass to `IDWriteFactory7_CreateGlyphRunAnalysis`, it can display glyph correctly.
[source_code]: https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/Win7S... [msdn_guide]: https://learn.microsoft.com/en-us/windows/win32/directwrite/render-to-a-gdi-... [sc_96dpi]: /uploads/59cc343cfaa025f4ff4c32a84ab8cfeb/图片.png [sc_168dpi]: /uploads/938be653362bb6ac58471b69ab66099a/图片.png
From: Tingzhong Luo luotingzhong@uniontech.com
Signed-off-by: Tingzhong Luo luotingzhong@uniontech.com --- dlls/dwrite/gdiinterop.c | 10 +++++---- dlls/dwrite/tests/font.c | 44 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 4 deletions(-)
diff --git a/dlls/dwrite/gdiinterop.c b/dlls/dwrite/gdiinterop.c index 5b542d93e32..764ddf1a4df 100644 --- a/dlls/dwrite/gdiinterop.c +++ b/dlls/dwrite/gdiinterop.c @@ -347,7 +347,7 @@ static HRESULT WINAPI rendertarget_DrawGlyphRun(IDWriteBitmapRenderTarget1 *ifac DWRITE_RENDERING_MODE1 rendermode; DWRITE_GRID_FIT_MODE gridfitmode; DWRITE_TEXTURE_TYPE texturetype; - DWRITE_GLYPH_RUN scaled_run; + DWRITE_MATRIX scaled_matrix; IDWriteFontFace3 *fontface; RECT target_rect, bounds; HRESULT hr; @@ -429,9 +429,10 @@ static HRESULT WINAPI rendertarget_DrawGlyphRun(IDWriteBitmapRenderTarget1 *ifac return hr; }
- scaled_run = *run; - scaled_run.fontEmSize *= target->ppdip; - hr = IDWriteFactory7_CreateGlyphRunAnalysis(target->factory, &scaled_run, &target->m, rendermode, measuring_mode, + scaled_matrix = target->m; + scaled_matrix.m11 *= target->ppdip; + scaled_matrix.m22 *= target->ppdip; + hr = IDWriteFactory7_CreateGlyphRunAnalysis(target->factory, run, &scaled_matrix, rendermode, measuring_mode, gridfitmode, target->antialiasmode, originX, originY, &analysis); if (FAILED(hr)) { @@ -451,6 +452,7 @@ static HRESULT WINAPI rendertarget_DrawGlyphRun(IDWriteBitmapRenderTarget1 *ifac } texturetype = DWRITE_TEXTURE_CLEARTYPE_3x1; } + if (bbox_ret) *bbox_ret = bounds;
if (IntersectRect(&target_rect, &target_rect, &bounds)) { diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c index 81008db6f23..535c67558bd 100644 --- a/dlls/dwrite/tests/font.c +++ b/dlls/dwrite/tests/font.c @@ -1225,6 +1225,7 @@ static void test_CreateBitmapRenderTarget(void) SIZE size; ULONG ref; UINT32 ch; + RECT box; HDC hdc; int ret;
@@ -1507,6 +1508,49 @@ static void test_CreateBitmapRenderTarget(void) &run, params, RGB(255, 0, 0), NULL); ok(hr == S_OK, "Failed to draw a run, hr %#lx.\n", hr);
+ hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, 1.0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* Got render bounds if not intersect to render target */ + memset(&box, 0, sizeof(box)); + hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 0.0f, 0.0f, DWRITE_MEASURING_MODE_GDI_NATURAL, + &run, params, RGB(255, 0, 0), &box); + ok(hr == S_OK, "Failed to draw a run, hr %#lx.\n", hr); + ok(box.right - box.left > 0, "got %ld\n", box.right - box.left); + ok(box.bottom - box.top > 0, "got %ld\n", box.bottom - box.top); + + /* Check glyph position */ + run.fontEmSize = 30.0f; + hdc = IDWriteBitmapRenderTarget_GetMemoryDC(target); + ok(hdc != NULL, "got %p\n", hdc); + + hr = IDWriteBitmapRenderTarget_Resize(target, 400, 400); + ok(hr == S_OK, "Failed to resize target, hr %#lx.\n", hr); + + SetDCBrushColor(hdc, 0); + SelectObject(hdc, GetStockObject(DC_BRUSH)); + Rectangle(hdc, 0, 0, 400, 400); + hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 30.0f, 65.0f, DWRITE_MEASURING_MODE_GDI_NATURAL, + &run, params, RGB(255, 0, 0), &box); + ok(hr == S_OK, "Failed to draw a run, hr %#lx.\n", hr); + c = GetPixel(hdc, 30 + 2, 65 - 2); + ok(c == RGB(255, 0, 0), "got 0x%08lx\n", c); + + /* Doubled ppdip */ + hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, 2.0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + SetDCBrushColor(hdc, 0); + SelectObject(hdc, GetStockObject(DC_BRUSH)); + Rectangle(hdc, 0, 0, 400, 400); + hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 30.0f, 65.0f, DWRITE_MEASURING_MODE_GDI_NATURAL, + &run, params, RGB(255, 0, 0), &box); + ok(hr == S_OK, "Failed to draw a run, hr %#lx.\n", hr); + c = GetPixel(hdc, 30 + 2, 65 - 2); + ok(c == RGB(0, 0, 0), "got 0x%08lx\n", c); + c = GetPixel(hdc, 30 * 2 + 2, 65 * 2 - 2); + ok(c == RGB(255, 0, 0), "got 0x%08lx\n", c); + IDWriteRenderingParams_Release(params);
/* Zero sized target returns earlier. */
Nikolay Sivov (@nsivov) commented about dlls/dwrite/tests/font.c:
- ok(c == RGB(255, 0, 0), "got 0x%08lx\n", c);
- /* Doubled ppdip */
- hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, 2.0);
- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
- SetDCBrushColor(hdc, 0);
- SelectObject(hdc, GetStockObject(DC_BRUSH));
- Rectangle(hdc, 0, 0, 400, 400);
- hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 30.0f, 65.0f, DWRITE_MEASURING_MODE_GDI_NATURAL,
&run, params, RGB(255, 0, 0), &box);
- ok(hr == S_OK, "Failed to draw a run, hr %#lx.\n", hr);
- c = GetPixel(hdc, 30 + 2, 65 - 2);
- ok(c == RGB(0, 0, 0), "got 0x%08lx\n", c);
- c = GetPixel(hdc, 30 * 2 + 2, 65 * 2 - 2);
- ok(c == RGB(255, 0, 0), "got 0x%08lx\n", c);
This looks very unreliable. We could add some special font that has full black rectangle for some glyph, and use that.
Nikolay Sivov (@nsivov) commented about dlls/dwrite/gdiinterop.c:
return hr; }
- scaled_run = *run;
- scaled_run.fontEmSize *= target->ppdip;
- hr = IDWriteFactory7_CreateGlyphRunAnalysis(target->factory, &scaled_run, &target->m, rendermode, measuring_mode,
- scaled_matrix = target->m;
- scaled_matrix.m11 *= target->ppdip;
- scaled_matrix.m22 *= target->ppdip;
- hr = IDWriteFactory7_CreateGlyphRunAnalysis(target->factory, run, &scaled_matrix, rendermode, measuring_mode,
As I recall the idea was that bumping fontEmSize is more desirable than scaling outlines up, using smaller size. I think this will need some more testing for CreateGlyphRunAnalysis() itself. I haven't tried, but differences might be easier to spot in aliased mode.
Nikolay Sivov (@nsivov) commented about dlls/dwrite/gdiinterop.c:
} texturetype = DWRITE_TEXTURE_CLEARTYPE_3x1; }
- if (bbox_ret) *bbox_ret = bounds;
This one should be a separate change.