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
-- v5: dwrite: Fix incorrect position of glyph when rendering with BitmapRenderTarget in HiDPI dwrite: Return render bounds if text not intersect to BitmapRenderTarget
From: Tingzhong Luo luotingzhong@uniontech.com
Signed-off-by: Tingzhong Luo luotingzhong@uniontech.com --- dlls/dwrite/gdiinterop.c | 1 + dlls/dwrite/tests/font.c | 8 ++++++++ 2 files changed, 9 insertions(+)
diff --git a/dlls/dwrite/gdiinterop.c b/dlls/dwrite/gdiinterop.c index 5b542d93e32..2eafe4064d2 100644 --- a/dlls/dwrite/gdiinterop.c +++ b/dlls/dwrite/gdiinterop.c @@ -451,6 +451,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..5052de00329 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,13 @@ 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);
+ /* Got render bounds if not intersect to render target */ + SetRectEmpty(&box); + hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, -100.0f, -100.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(!IsRectEmpty(&box), "got empty rect\n"); + IDWriteRenderingParams_Release(params);
/* Zero sized target returns earlier. */
From: Tingzhong Luo luotingzhong@uniontech.com
Signed-off-by: Tingzhong Luo luotingzhong@uniontech.com --- dlls/dwrite/gdiinterop.c | 21 ++++- dlls/dwrite/tests/font.c | 134 +++++++++++++++++++++++++++++++- dlls/dwrite/tests/wine_test.sfd | 31 ++++++-- dlls/dwrite/tests/wine_test.ttf | Bin 1812 -> 1836 bytes 4 files changed, 173 insertions(+), 13 deletions(-)
diff --git a/dlls/dwrite/gdiinterop.c b/dlls/dwrite/gdiinterop.c index 2eafe4064d2..c87401f4c2a 100644 --- a/dlls/dwrite/gdiinterop.c +++ b/dlls/dwrite/gdiinterop.c @@ -337,6 +337,18 @@ static inline DWORD colorref_to_pixel_888(COLORREF color) return (((color >> 16) & 0xff) | (color & 0xff00) | ((color << 16) & 0xff0000)); }
+static inline void dwrite_matrix_multiply(DWRITE_MATRIX *a, const DWRITE_MATRIX *b) +{ + DWRITE_MATRIX tmp = *a; + + a->m11 = tmp.m11 * b->m11 + tmp.m12 * b->m21; + a->m12 = tmp.m11 * b->m12 + tmp.m12 * b->m22; + a->m21 = tmp.m21 * b->m11 + tmp.m22 * b->m21; + a->m22 = tmp.m21 * b->m12 + tmp.m22 * b->m22; + a->dx = tmp.dx * b->m11 + tmp.dy * b->m21 + b->dx; + a->dy = tmp.dy * b->m12 + tmp.dy * b->m22 + b->dx; +} + static HRESULT WINAPI rendertarget_DrawGlyphRun(IDWriteBitmapRenderTarget1 *iface, FLOAT originX, FLOAT originY, DWRITE_MEASURING_MODE measuring_mode, DWRITE_GLYPH_RUN const *run, IDWriteRenderingParams *params, COLORREF color, @@ -347,7 +359,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 m, scale = { 0 }; IDWriteFontFace3 *fontface; RECT target_rect, bounds; HRESULT hr; @@ -429,9 +441,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, + m = target->m; + scale.m11 = scale.m22 = target->ppdip; + dwrite_matrix_multiply(&m, &scale); + hr = IDWriteFactory7_CreateGlyphRunAnalysis(target->factory, run, &m, rendermode, measuring_mode, gridfitmode, target->antialiasmode, originX, originY, &analysis); if (FAILED(hr)) { diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c index 5052de00329..342c32bd965 100644 --- a/dlls/dwrite/tests/font.c +++ b/dlls/dwrite/tests/font.c @@ -1205,18 +1205,61 @@ static void test_CreateFontFromLOGFONT(void) ok(ref == 0, "factory is not released, %lu\n", ref); }
+static IDWriteFontFace *create_winetest_fontface(IDWriteFactory *factory) +{ + static IDWriteFontFileLoader rloader = { &resourcefontfileloadervtbl }; + IDWriteFontFace *face; + IDWriteFontFile *file; + HRSRC fontsrc; + HRESULT hr; + + hr = IDWriteFactory_RegisterFontFileLoader(factory, &rloader); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + fontsrc = FindResourceA(GetModuleHandleA(NULL), (LPCSTR)MAKEINTRESOURCE(1), (LPCSTR)RT_RCDATA); + ok(fontsrc != NULL, "Failed to find font resource\n"); + + hr = IDWriteFactory_CreateCustomFontFileReference(factory, &fontsrc, sizeof(HRSRC), &rloader, &file); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(file != NULL, "Failed to create font file reference\n"); + + hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0, DWRITE_FONT_SIMULATIONS_NONE, &face); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(face != NULL, "Failed to create font face\n"); + + hr = IDWriteFactory_UnregisterFontFileLoader(factory, &rloader); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IDWriteFontFile_Release(file); + return face; +} + +static inline void dwrite_matrix_multiply(DWRITE_MATRIX *a, const DWRITE_MATRIX *b) +{ + DWRITE_MATRIX tmp = *a; + + a->m11 = tmp.m11 * b->m11 + tmp.m12 * b->m21; + a->m12 = tmp.m11 * b->m12 + tmp.m12 * b->m22; + a->m21 = tmp.m21 * b->m11 + tmp.m22 * b->m21; + a->m22 = tmp.m21 * b->m12 + tmp.m22 * b->m22; + a->dx = tmp.dx * b->m11 + tmp.dy * b->m21 + b->dx; + a->dy = tmp.dy * b->m12 + tmp.dy * b->m22 + b->dx; +} + static void test_CreateBitmapRenderTarget(void) { IDWriteBitmapRenderTarget *target, *target2; IDWriteBitmapRenderTarget1 *target1; IDWriteRenderingParams *params; + DWRITE_GLYPH_OFFSET offsets[2]; IDWriteGdiInterop *interop; IDWriteFontFace *fontface; + DWRITE_MATRIX m, m2, ms; IDWriteFactory *factory; DWRITE_GLYPH_RUN run; HBITMAP hbm, hbm2; UINT16 glyphs[2]; - DWRITE_MATRIX m; + RECT box, box2; DIBSECTION ds; XFORM xform; COLORREF c; @@ -1225,7 +1268,6 @@ static void test_CreateBitmapRenderTarget(void) SIZE size; ULONG ref; UINT32 ch; - RECT box; HDC hdc; int ret;
@@ -1515,6 +1557,92 @@ static void test_CreateBitmapRenderTarget(void) ok(hr == S_OK, "Failed to draw a run, hr %#lx.\n", hr); ok(!IsRectEmpty(&box), "got empty rect\n");
+ IDWriteFontFace_Release(fontface); + fontface = create_winetest_fontface(factory); + + /* 0xa9 map to a black rectangle */ + ch = 0xa9; + glyphs[0] = 0; + hr = IDWriteFontFace_GetGlyphIndices(fontface, &ch, 1, glyphs); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(glyphs[0] > 0, "got 0\n"); + glyphs[1] = glyphs[0]; + + offsets[0].advanceOffset = 0; + offsets[0].ascenderOffset = 0; + offsets[1].advanceOffset = 3; + offsets[1].ascenderOffset = 0; + + memset(&run, 0, sizeof(run)); + run.glyphCount = 2; + run.fontEmSize = 5.0f; + run.fontFace = fontface; + run.glyphIndices = glyphs; + run.glyphOffsets = offsets; + + hr = IDWriteBitmapRenderTarget1_Resize(target1, 40, 30); + ok(hr == S_OK, "Failed to set target size, hr %#lx.\n", hr); + + /* Check bounding box in different transform */ + memset(&ms, 0, sizeof(ms)); + ms.m11 = ms.m22 = 2.0f; + for (int i = 0; i < 3; i++) + { + m2 = m; + memset(&m, 0, sizeof(m)); + switch (i) + { + case 0: + /* dont apply transform first */ + m.m11 = m.m22 = 1; + break; + case 1: + /* then rotate 45 degree */ + m.m11 = m.m22 = cos(3.1415 / 4); + m.m12 = sin(3.1415 / 4); + m.m21 = -m.m12; + dwrite_matrix_multiply(&m, &m2); + break; + case 2: + /* then shift on x with 10px */ + m.m11 = m.m22 = 1; + m.dx = 10; + dwrite_matrix_multiply(&m, &m2); + break; + default: + m = m2; + break; + } + + /* Draw in double ddpi */ + hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, 2.0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, &m); + ok(hr == S_OK, "Failed to set current transform, hr %#lx.\n", hr); + + SetRectEmpty(&box); + hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 5.0f, 2.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); + + /* Draw in one ddpi, scale in double first, then apply transform matrix */ + hr = IDWriteBitmapRenderTarget_SetPixelsPerDip(target, 1.0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + m2 = m; + dwrite_matrix_multiply(&m2, &ms); + hr = IDWriteBitmapRenderTarget_SetCurrentTransform(target, &m2); + ok(hr == S_OK, "Failed to set current transform, hr %#lx.\n", hr); + + SetRectEmpty(&box2); + hr = IDWriteBitmapRenderTarget_DrawGlyphRun(target, 5.0f, 2.0f, DWRITE_MEASURING_MODE_GDI_NATURAL, + &run, params, RGB(255, 0, 0), &box2); + ok(hr == S_OK, "Failed to draw a run, hr %#lx.\n", hr); + + ok(box.left == box2.left && box.right == box2.right && box.top== box2.top && box.bottom == box2.bottom, + "%d: Bounding box dismatch %s != %s\n", i, wine_dbgstr_rect(&box), wine_dbgstr_rect(&box2)); + } + IDWriteRenderingParams_Release(params);
/* Zero sized target returns earlier. */ @@ -5533,7 +5661,7 @@ static void test_GetGlyphCount(void) IDWriteFontFile_Release(file);
count = IDWriteFontFace_GetGlyphCount(fontface); - ok(count == 8, "got %u\n", count); + ok(count == 9, "got %u\n", count);
IDWriteFontFace_Release(fontface); ref = IDWriteFactory_Release(factory); diff --git a/dlls/dwrite/tests/wine_test.sfd b/dlls/dwrite/tests/wine_test.sfd index e533323db75..cbc20ca7450 100644 --- a/dlls/dwrite/tests/wine_test.sfd +++ b/dlls/dwrite/tests/wine_test.sfd @@ -1,4 +1,4 @@ -SplineFontDB: 3.0 +SplineFontDB: 3.2 FontName: wine_test FullName: wine_test FamilyName: wine_test @@ -10,6 +10,7 @@ UnderlinePosition: -205 UnderlineWidth: 102 Ascent: 1638 Descent: 410 +InvalidEm: 0 sfntRevision: 0x00010000 LayerCount: 2 Layer: 0 1 "Back" 1 @@ -19,6 +20,8 @@ FSType: 0 OS2Version: 2 OS2_WeightWidthSlopeOnly: 0 OS2_UseTypoMetrics: 1 +CreationTime: 1690872262 +ModificationTime: 1696993054 PfmFamily: 17 TTFWeight: 500 TTFWidth: 5 @@ -83,14 +86,14 @@ NameList: Adobe Glyph List DisplaySize: -24 AntiAlias: 1 FitToEm: 1 -WinInfo: 47 47 13 +WinInfo: 0 47 13 BeginPrivate: 0 EndPrivate -BeginChars: 65539 8 +BeginChars: 65539 9
StartChar: .notdef Encoding: 65536 -1 0 -AltUni2: 00fffe.ffffffff.0 00fffd.ffffffff.0 00fffc.ffffffff.0 00fffb.ffffffff.0 +AltUni2: 00fffb.ffffffff.0 00fffc.ffffffff.0 00fffd.ffffffff.0 00fffe.ffffffff.0 Width: 748 Flags: W TtInstrs: @@ -189,7 +192,7 @@ SplineSet 620.215 824.429 m 1,0,1 760.84 777.554 760.84 777.554 713.965 636.929 c 1,2,-1 620.215 824.429 l 1,0,1 -154.883 324.971 m 0,3,-1 +154.883 324.971 m 1024,3,-1 254.492 773.213 m 1,4,5 310.707 834.805 310.707 834.805 374.609 767.354 c 1,6,7 410.471 728.672 410.471 728.672 374.609 691.182 c 0,8,9 @@ -249,7 +252,23 @@ Flags: W LayerCount: 2 Fore SplineSet -500 500 m 24,0,-1 +500 500 m 1048,0,-1 +EndSplineSet +EndChar + +StartChar: copyright +Encoding: 169 169 8 +Width: 1000 +VWidth: 0 +Flags: W +LayerCount: 2 +Fore +SplineSet +-3 -415 m 1,0,-1 + 997 -409 l 1,1,-1 + 997 84 l 1,2,-1 + -3 84 l 1,3,-1 + -3 -415 l 1,0,-1 EndSplineSet EndChar EndChars diff --git a/dlls/dwrite/tests/wine_test.ttf b/dlls/dwrite/tests/wine_test.ttf index 72dadf5d5438ffbcfff5b2442eb62028245aa9a3..937065fb87955c2d1ebc41946f8f80b09b69186d 100644 GIT binary patch delta 633 zcmYjPO=}ZT6g_v|OeV3C#8OisQWKgeqO@Za!4HJuBnqWwVJ*c?I>y8ik|wlW)Roz| z5)1meP*6eKSco9D;0K}$H~t1!Q7B|lMHenaC(k>RE*zNm=A8R^?w!?WJ8FXfMA3r4 zT%j;M_4H6`3NYi$?mcJc3pjvrAk<~Nzj$#xcjw;17C<iJxpLiU>RW@)@7kj`J4}SH z)oxUC>c=V|YV2gW73XTUSZ=e8gK*qsVqo2P$F>aPj9Xt?PLMId_!Hw)tx<O9Fs*R> zEaRcNv)n`xdA6VT?ek8(lDzfy5uiT=w0N_zxP*gr25>`ukz;`xR`l}4mG`CC>0j6v zW*X>xzg+O|FOwf0E6>{yo8~aXFf^a#hhxlPZv(HxP#%}x3^Mg?{nHGXh`c~aq3dsC zjZPUYq_HO3bW&5E?9%9o9YIQsX&Y;*rxeGgF@b05k5cL@pi2E>><8@RSBJr8NZQ&f zojFrJ(Prc&k)ZpsCO(Sa;;hW+#Uv@O=WtikyeEk4uCx%{zk7O4h`z~|J{gNqUpuEl zgl6SuJs%sPA@(Lc!rUO)>tn`Iiesj-uz0;OpR%kYW0qyf2S#dOdkU(GD%am#iUdt+ u+*}4({sUHU+h<sg7EHl!Jb{q_5lbQV<b4ED!7TY}`|kV<xjy)R1OEUVlZANz
delta 589 zcmX|8O-NKx7(MsBJ8xz}W=ba&jC!J0i>TKGh86U~o0*W(MJAyOec0Fw-g5?Zp%66d zs3@+xXwgo>MWj%RR!UIQrfsXDRf}ks1Yx)H?pPP@{W$0QzVrRuwcJY1hX9a612(41 z<*}<oWSn2L2P%H4jML~R{z!au^xBEygGcjU7!nds&%{C9$?jWz?DyS$M<R18TAuyX z^C1T8h(U$08r+<?|2*-1=N$}5?0J%ULmx%aAI6JIok;n_NzB2hHWP?r*k=9>;`TUL zs$&Et`Y#i^b3t5v`T5>qKsErYqh4EB)SFlbLT7~mMKcZiFI;*1eky<NCk|yu19t{q zH2zzEXTxfyyNENe5|)QK>8_m(yl%x?O{3KEwcfO0GHOKh*p~dEB5^i#0lipNYvK%L z)Hl&L)Mg|l=}Yjjs{d%s>|R_n=(pDTtKQO^da6}&S6?#Qw_ed8t)5xq>bl)2pdx$A zZrVetC`Z*(Ih@}s26wx1kQI|^TbA;!DDdZm%)&vtsH_jCPKgc|7_ZJR+^)^Jo_F%N z=XtI=@3?LMre#mFth2w83@gY={_y~g;Gt<quxZOw$`N;ias~?|J4m`rw#JQ_%a>Z+ Fe*qFdaiahL
On Mon Oct 9 17:04:55 2023 +0000, Nikolay Sivov wrote:
The reason we currently modify font size is to produce better quality output. If you keep original size, then scale 10 times, it won't necessarily be looking good. Regarding matrix modification, how does that work for other components, for e.g. rotation? Maybe we should multiply by diagonal matrix instead?
Yep, We need to multiply by matrix instread of just changing elements. New tests has been add to test `rendertarget_DrawGlyphRun()` in different transformation matrices.
This merge request was closed by Nikolay Sivov.
This is merged with !6903.