Signed-off-by: Sven Baars sbaars@codeweavers.com --- dlls/d3dx9_36/tests/core.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/dlls/d3dx9_36/tests/core.c b/dlls/d3dx9_36/tests/core.c index fa874a5ef5..75146575be 100644 --- a/dlls/d3dx9_36/tests/core.c +++ b/dlls/d3dx9_36/tests/core.c @@ -330,13 +330,13 @@ static void test_ID3DXFont(IDirect3DDevice9 *device)
/* D3DXCreateFont */ ref = get_ref((IUnknown*)device); - hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font); + hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); ok(hr == D3D_OK, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3D_OK); check_ref((IUnknown*)device, ref + 1); check_release((IUnknown*)font, 0); check_ref((IUnknown*)device, ref);
- hr = D3DXCreateFontA(device, 0, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font); + hr = D3DXCreateFontA(device, 0, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); ok(hr == D3D_OK, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3D_OK); ID3DXFont_Release(font);
@@ -348,13 +348,13 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) ok(hr == D3D_OK, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3D_OK); ID3DXFont_Release(font);
- hr = D3DXCreateFontA(NULL, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font); + hr = D3DXCreateFontA(NULL, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); ok(hr == D3DERR_INVALIDCALL, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
- hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", NULL); + hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", NULL); ok(hr == D3DERR_INVALIDCALL, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
- hr = D3DXCreateFontA(NULL, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", NULL); + hr = D3DXCreateFontA(NULL, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", NULL); ok(hr == D3DERR_INVALIDCALL, "D3DXCreateFont returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
@@ -368,7 +368,7 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) desc.OutputPrecision = OUT_DEFAULT_PRECIS; desc.Quality = DEFAULT_QUALITY; desc.PitchAndFamily = DEFAULT_PITCH; - strcpy(desc.FaceName, "Arial"); + strcpy(desc.FaceName, "Tahoma"); hr = D3DXCreateFontIndirectA(device, &desc, &font); ok(hr == D3D_OK, "D3DXCreateFontIndirect returned %#x, expected %#x\n", hr, D3D_OK); ID3DXFont_Release(font); @@ -384,7 +384,7 @@ static void test_ID3DXFont(IDirect3DDevice9 *device)
/* ID3DXFont_GetDevice */ - hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font); + hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); if(SUCCEEDED(hr)) { IDirect3DDevice9 *bufdev;
@@ -401,7 +401,7 @@ static void test_ID3DXFont(IDirect3DDevice9 *device)
/* ID3DXFont_GetDesc */ - hr = D3DXCreateFontA(device, 12, 8, FW_BOLD, 2, TRUE, ANSI_CHARSET, OUT_RASTER_PRECIS, ANTIALIASED_QUALITY, VARIABLE_PITCH, "Arial", &font); + hr = D3DXCreateFontA(device, 12, 8, FW_BOLD, 2, TRUE, ANSI_CHARSET, OUT_RASTER_PRECIS, ANTIALIASED_QUALITY, VARIABLE_PITCH, "Tahoma", &font); if(SUCCEEDED(hr)) { hr = ID3DXFont_GetDescA(font, NULL); ok(hr == D3DERR_INVALIDCALL, "ID3DXFont_GetDevice returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL); @@ -418,14 +418,14 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) ok(desc.OutputPrecision == OUT_RASTER_PRECIS, "ID3DXFont_GetDesc returned an output precision of %d, expected %d\n", desc.OutputPrecision, OUT_RASTER_PRECIS); ok(desc.Quality == ANTIALIASED_QUALITY, "ID3DXFont_GetDesc returned font quality %d, expected %d\n", desc.Quality, ANTIALIASED_QUALITY); ok(desc.PitchAndFamily == VARIABLE_PITCH, "ID3DXFont_GetDesc returned pitch and family %d, expected %d\n", desc.PitchAndFamily, VARIABLE_PITCH); - ok(strcmp(desc.FaceName, "Arial") == 0, "ID3DXFont_GetDesc returned facename "%s", expected "%s"\n", desc.FaceName, "Arial"); + ok(strcmp(desc.FaceName, "Tahoma") == 0, "ID3DXFont_GetDesc returned facename "%s", expected "%s"\n", desc.FaceName, "Tahoma");
ID3DXFont_Release(font); } else skip("Failed to create a ID3DXFont object\n");
/* ID3DXFont_GetDC + ID3DXFont_GetTextMetrics */ - hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font); + hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); if(SUCCEEDED(hr)) { HDC hdc;
@@ -466,7 +466,7 @@ static void test_ID3DXFont(IDirect3DDevice9 *device)
/* ID3DXFont_PreloadText */ - hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font); + hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); if(SUCCEEDED(hr)) { todo_wine { hr = ID3DXFont_PreloadTextA(font, NULL, -1); @@ -493,7 +493,7 @@ static void test_ID3DXFont(IDirect3DDevice9 *device)
/* ID3DXFont_GetGlyphData, ID3DXFont_PreloadGlyphs, ID3DXFont_PreloadCharacters */ - hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font); + hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); if(SUCCEEDED(hr)) { char c; HDC hdc; @@ -565,7 +565,7 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) IDirect3DTexture9 *texture;
hr = D3DXCreateFontA(device, tests[i].font_height, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, - OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Arial", &font); + OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); if(FAILED(hr)) { skip("Failed to create a ID3DXFont object\n"); continue;
From: Alistair Leslie-Hughes leslie_alistair@hotmail.com
Signed-off-by: Sven Baars sbaars@codeweavers.com --- v2: Use Tahoma
dlls/d3dx9_36/tests/core.c | 63 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+)
diff --git a/dlls/d3dx9_36/tests/core.c b/dlls/d3dx9_36/tests/core.c index 75146575be..8c1d41e952 100644 --- a/dlls/d3dx9_36/tests/core.c +++ b/dlls/d3dx9_36/tests/core.c @@ -637,6 +637,69 @@ static void test_ID3DXFont(IDirect3DDevice9 *device)
ID3DXFont_Release(font); } + + /* ID3DXFont_DrawTextA, ID3DXFont_DrawTextW */ + hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); + if (SUCCEEDED(hr)) { + RECT rect; + int height; + + todo_wine { + SetRect(&rect, 10, 10, 200, 200); + + height = ID3DXFont_DrawTextA(font, NULL, "test", -2, &rect, 0, 0xFF00FF); + ok(height == 12, "DrawTextA returned %d, expected 12.\n", height); + + height = ID3DXFont_DrawTextA(font, NULL, "test", -1, &rect, 0, 0xFF00FF); + ok(height == 12, "DrawTextA returned %d, expected 12.\n", height); + + height = ID3DXFont_DrawTextA(font, NULL, "test", 0, &rect, 0, 0xFF00FF); + ok(height == 0, "DrawTextA returned %d, expected 0.\n", height); + + height = ID3DXFont_DrawTextA(font, NULL, "test", 1, &rect, 0, 0xFF00FF); + ok(height == 12, "DrawTextA returned %d, expected 12.\n", height); + + height = ID3DXFont_DrawTextA(font, NULL, "test", 2, &rect, 0, 0xFF00FF); + ok(height == 12, "DrawTextA returned %d, expected 12.\n", height); + + height = ID3DXFont_DrawTextA(font, NULL, "test", -1, NULL, 0, 0xFF00FF); + ok(height == 12, "DrawTextA returned %d, expected 12.\n", height); + + height = ID3DXFont_DrawTextA(font, NULL, "test", -1, NULL, DT_CALCRECT, 0xFF00FF); + ok(height == 12, "DrawTextA returned %d, expected 12.\n", height); + + height = ID3DXFont_DrawTextA(font, NULL, NULL, -1, NULL, 0, 0xFF00FF); + ok(height == 0, "DrawTextA returned %d, expected 0.\n", height); + +if (0) { /* Causes a lockup on windows 7. */ + height = ID3DXFont_DrawTextW(font, NULL, testW, -2, &rect, 0, 0xFF00FF); + ok(height == 12, "DrawTextW returned %d, expected 12.\n", height); +} + + height = ID3DXFont_DrawTextW(font, NULL, testW, -1, &rect, 0, 0xFF00FF); + ok(height == 12, "DrawTextW returned %d, expected 12.\n", height); + + height = ID3DXFont_DrawTextW(font, NULL, testW, 0, &rect, 0, 0xFF00FF); + ok(height == 0, "DrawTextW returned %d, expected 0.\n", height); + + height = ID3DXFont_DrawTextW(font, NULL, testW, 1, &rect, 0, 0xFF00FF); + ok(height == 12, "DrawTextW returned %d, expected 12.\n", height); + + height = ID3DXFont_DrawTextW(font, NULL, testW, 2, &rect, 0, 0xFF00FF); + ok(height == 12, "DrawTextW returned %d, expected 12.\n", height); + + height = ID3DXFont_DrawTextW(font, NULL, testW, -1, NULL, 0, 0xFF00FF); + ok(height == 12, "DrawTextW returned %d, expected 12.\n", height); + + height = ID3DXFont_DrawTextW(font, NULL, testW, -1, NULL, DT_CALCRECT, 0xFF00FF); + ok(height == 12, "DrawTextW returned %d, expected 12.\n", height); + + height = ID3DXFont_DrawTextW(font, NULL, NULL, -1, NULL, 0, 0xFF00FF); + ok(height == 0, "DrawTextW returned %d, expected 0.\n", height); + } + + ID3DXFont_Release(font); + } }
static void test_D3DXCreateRenderToSurface(IDirect3DDevice9 *device)
On Mon, Jan 6, 2020 at 3:34 PM Sven Baars sbaars@codeweavers.com wrote:
From: Alistair Leslie-Hughes leslie_alistair@hotmail.com
Signed-off-by: Sven Baars sbaars@codeweavers.com
Hi Sven,
I finally got around to review this patch series. Comments following...
v2: Use Tahoma
dlls/d3dx9_36/tests/core.c | 63 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+)
diff --git a/dlls/d3dx9_36/tests/core.c b/dlls/d3dx9_36/tests/core.c index 75146575be..8c1d41e952 100644 --- a/dlls/d3dx9_36/tests/core.c +++ b/dlls/d3dx9_36/tests/core.c @@ -637,6 +637,69 @@ static void test_ID3DXFont(IDirect3DDevice9 *device)
ID3DXFont_Release(font); }
- /* ID3DXFont_DrawTextA, ID3DXFont_DrawTextW */
- hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font);
- if (SUCCEEDED(hr)) {
This is never supposed to fail, so I'd get rid of the if entirely (replacing it with a ok()).
RECT rect;
int height;
todo_wine {
SetRect(&rect, 10, 10, 200, 200);
height = ID3DXFont_DrawTextA(font, NULL, "test", -2, &rect, 0, 0xFF00FF);
ok(height == 12, "DrawTextA returned %d, expected 12.\n", height);
It would be nice to know if this test was prompted by debugging some game or just random testing.
Signed-off-by: Sven Baars sbaars@codeweavers.com --- v2: Fix some test failures and remove tests that fail on my machine, but not on the testbot.
dlls/d3dx9_36/tests/core.c | 119 ++++++++++++++++++++++++++++++------- 1 file changed, 99 insertions(+), 20 deletions(-)
diff --git a/dlls/d3dx9_36/tests/core.c b/dlls/d3dx9_36/tests/core.c index 8c1d41e952..b2a44ded70 100644 --- a/dlls/d3dx9_36/tests/core.c +++ b/dlls/d3dx9_36/tests/core.c @@ -306,6 +306,14 @@ static void test_ID3DXSprite(IDirect3DDevice9 *device) static void test_ID3DXFont(IDirect3DDevice9 *device) { static const WCHAR testW[] = {'t','e','s','t',0}; + static const WCHAR emptyW[] = {0}; + static const char longText[] = "Example text to test clipping and other related things"; + static const WCHAR longTextW[] = {'E', 'x', 'a', 'm', 'p', 'l', 'e', ' ', + 't', 'e', 'x', 't', ' ', 't', 'o', ' ', + 't', 'e', 's', 't', ' ', 'c', 'l', 'i', 'p', 'p', 'i', 'n', 'g', ' ', + 'a', 'n', 'd', ' ', 'o', 't', 'h', 'e', 'r', ' ', + 'r', 'e', 'l', 'a', 't', 'e', 'd', ' ', 't', 'h', 'i', 'n', 'g', 's', 0}; + static const struct { int font_height; @@ -314,11 +322,14 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) } tests[] = { - { 6, 128, 4 }, - { 8, 128, 4 }, - { 10, 256, 5 }, - { 12, 256, 5 }, - { 72, 256, 8 }, + { 2, 32, 2 }, + { 6, 128, 4 }, + { 10, 256, 5 }, + { 12, 256, 5 }, + { 72, 256, 8 }, + { 250, 256, 9 }, + { 258, 512, 10 }, + { 512, 512, 10 }, }; const unsigned int size = ARRAY_SIZE(testW); D3DXFONT_DESCA desc; @@ -477,6 +488,10 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) ok(hr == D3DERR_INVALIDCALL, "ID3DXFont_PreloadTextA returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL); hr = ID3DXFont_PreloadTextA(font, "test", -1); ok(hr == D3D_OK, "ID3DXFont_PreloadTextA returned %#x, expected %#x\n", hr, D3D_OK); + hr = ID3DXFont_PreloadTextA(font, "", 0); + ok(hr == D3D_OK, "ID3DXFont_PreloadTextA returned %#x, expected %#x\n", hr, D3D_OK); + hr = ID3DXFont_PreloadTextA(font, "", -1); + ok(hr == D3D_OK, "ID3DXFont_PreloadTextA returned %#x, expected %#x\n", hr, D3D_OK);
hr = ID3DXFont_PreloadTextW(font, NULL, -1); ok(hr == D3DERR_INVALIDCALL, "ID3DXFont_PreloadTextW returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL); @@ -486,6 +501,10 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) ok(hr == D3DERR_INVALIDCALL, "ID3DXFont_PreloadTextW returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL); hr = ID3DXFont_PreloadTextW(font, testW, -1); ok(hr == D3D_OK, "ID3DXFont_PreloadTextW returned %#x, expected %#x\n", hr, D3D_OK); + hr = ID3DXFont_PreloadTextW(font, emptyW, 0); + ok(hr == D3D_OK, "ID3DXFont_PreloadTextW returned %#x, expected %#x\n", hr, D3D_OK); + hr = ID3DXFont_PreloadTextW(font, emptyW, -1); + ok(hr == D3D_OK, "ID3DXFont_PreloadTextW returned %#x, expected %#x\n", hr, D3D_OK); }
check_release((IUnknown*)font, 0); @@ -498,6 +517,7 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) char c; HDC hdc; DWORD ret; + WORD glyph; HRESULT hr; RECT blackbox; POINT cellinc; @@ -524,26 +544,42 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) ok(hr == D3D_OK, "ID3DXFont_PreloadCharacters returned %#x, expected %#x\n", hr, D3D_OK);
for(c = 'b'; c <= 'z'; c++) { - WORD glyph; - ret = GetGlyphIndicesA(hdc, &c, 1, &glyph, 0); ok(ret != GDI_ERROR, "GetGlyphIndicesA failed\n");
hr = ID3DXFont_GetGlyphData(font, glyph, &texture, &blackbox, &cellinc); todo_wine ok(hr == D3D_OK, "ID3DXFont_GetGlyphData returned %#x, expected %#x\n", hr, D3D_OK); if(SUCCEEDED(hr)) { - DWORD levels; + DWORD ret, levels; + TEXTMETRICW tm; D3DSURFACE_DESC desc; + GLYPHMETRICS metrics; + MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
levels = IDirect3DTexture9_GetLevelCount(texture); - ok(levels == 5, "Got levels %u, expected %u\n", levels, 5); + todo_wine ok(levels == 5, "Character %c, got levels %u, expected %u\n", c, levels, 5); hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc); ok(hr == D3D_OK, "IDirect3DTexture9_GetLevelDesc failed\n"); - ok(desc.Format == D3DFMT_A8R8G8B8, "Got format %#x, expected %#x\n", desc.Format, D3DFMT_A8R8G8B8); - ok(desc.Usage == 0, "Got usage %#x, expected %#x\n", desc.Usage, 0); - ok(desc.Width == 256, "Got width %u, expected %u\n", desc.Width, 256); - ok(desc.Height == 256, "Got height %u, expected %u\n", desc.Height, 256); - ok(desc.Pool == D3DPOOL_MANAGED, "Got pool %u, expected %u\n", desc.Pool, D3DPOOL_MANAGED); + ok(desc.Format == D3DFMT_A8R8G8B8, "Character %c, got format %#x, expected %#x\n", c, desc.Format, D3DFMT_A8R8G8B8); + ok(desc.Usage == 0, "Character %c, got usage %#x, expected %#x\n", c, desc.Usage, 0); + ok(desc.Width == 256, "Character %c, got width %u, expected %u\n", c, desc.Width, 256); + ok(desc.Height == 256, "Character %c, got height %u, expected %u\n", c, desc.Height, 256); + ok(desc.Pool == D3DPOOL_MANAGED, "Character %c, got pool %u, expected %u\n", c, desc.Pool, D3DPOOL_MANAGED); + + /* Check blackbox and cellinc, but skip v, w and y, because these + are apparently smaller */ + ret = GetGlyphOutlineW(hdc, glyph, GGO_GLYPH_INDEX | GGO_GRAY8_BITMAP | GGO_METRICS, &metrics, 0, NULL, &mat); + if (ret != GDI_ERROR && c != 'v' && c != 'w' && c != 'y') { + ID3DXFont_GetTextMetricsW(font, &tm); + todo_wine ok(blackbox.right - blackbox.left == metrics.gmBlackBoxX + 2, "Character %c, got %d, expected %d\n", + c, blackbox.right - blackbox.left, metrics.gmBlackBoxX + 2); + todo_wine ok(blackbox.bottom - blackbox.top == metrics.gmBlackBoxY + 2, "Character %c, got %d, expected %d\n", + c, blackbox.bottom - blackbox.top, metrics.gmBlackBoxY + 2); + ok(cellinc.x == metrics.gmptGlyphOrigin.x - 1, "Character %c, got %d, expected %d\n", + c, cellinc.x, metrics.gmptGlyphOrigin.x - 1); + ok(cellinc.y == tm.tmAscent - metrics.gmptGlyphOrigin.y - 1, "Character %c, got %d, expected %d\n", + c, cellinc.y, tm.tmAscent - metrics.gmptGlyphOrigin.y - 1); + } else if (ret == GDI_ERROR) skip("Failed to obtain glyph metrics\n");
check_release((IUnknown*)texture, 1); } @@ -552,6 +588,19 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) hr = ID3DXFont_PreloadCharacters(font, 'a', 'z'); ok(hr == D3D_OK, "ID3DXFont_PreloadCharacters returned %#x, expected %#x\n", hr, D3D_OK);
+ /* Test multiple textures */ + hr = ID3DXFont_PreloadGlyphs(font, 0, 1000); + todo_wine ok(hr == D3D_OK, "ID3DXFont_PreloadGlyphs returned %#x, expected %#x\n", hr, D3D_OK); + + /* Test glyphs that are not rendered */ + for (glyph = 1; glyph < 4; glyph++) + { + texture = (IDirect3DTexture9*)0xdeadbeef; + hr = ID3DXFont_GetGlyphData(font, glyph, &texture, &blackbox, &cellinc); + todo_wine ok(hr == D3D_OK, "ID3DXFont_GetGlyphData returned %#x, expected %#x\n", hr, D3D_OK); + todo_wine ok(!texture, "Got unexpected texture\n"); + } + check_release((IUnknown*)font, 0); } else skip("Failed to create a ID3DXFont object\n");
@@ -611,20 +660,20 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) todo_wine { height = ID3DXFont_DrawTextW(font, sprite, testW, -1, &rect, DT_TOP, 0xffffffff); - ok(height == tests[i].font_height, "Got unexpected height %u.\n", height); + ok(height == tests[i].font_height, "Got height %u, expected %u.\n", height, tests[i].font_height); height = ID3DXFont_DrawTextW(font, sprite, testW, size, &rect, DT_TOP, 0xffffffff); - ok(height == tests[i].font_height, "Got unexpected height %u.\n", height); + ok(height == tests[i].font_height, "Got height %u, expected %u.\n", height, tests[i].font_height); height = ID3DXFont_DrawTextW(font, sprite, testW, size, &rect, DT_RIGHT, 0xffffffff); - ok(height == tests[i].font_height, "Got unexpected height %u.\n", height); + ok(height == tests[i].font_height, "Got height %u, expected %u.\n", height, tests[i].font_height); height = ID3DXFont_DrawTextW(font, sprite, testW, size, &rect, DT_LEFT | DT_NOCLIP, 0xffffffff); - ok(height == tests[i].font_height, "Got unexpected height %u.\n", height); + ok(height == tests[i].font_height, "Got height %u, expected %u.\n", height, tests[i].font_height); }
SetRectEmpty(&rect); height = ID3DXFont_DrawTextW(font, sprite, testW, size, &rect, DT_LEFT | DT_CALCRECT, 0xffffffff); - todo_wine ok(height == tests[i].font_height, "Got unexpected height %u.\n", height); + todo_wine ok(height == tests[i].font_height, "Got height %u, expected %u.\n", height, tests[i].font_height); ok(!rect.left, "Got unexpected rect left %d.\n", rect.left); ok(!rect.top, "Got unexpected rect top %d.\n", rect.top); todo_wine ok(rect.right, "Got unexpected rect right %d.\n", rect.right); @@ -662,6 +711,12 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) height = ID3DXFont_DrawTextA(font, NULL, "test", 2, &rect, 0, 0xFF00FF); ok(height == 12, "DrawTextA returned %d, expected 12.\n", height);
+ height = ID3DXFont_DrawTextA(font, NULL, "", 0, &rect, 0, 0xFF00FF); + ok(height == 0, "DrawTextA returned %d, expected 0.\n", height); + + height = ID3DXFont_DrawTextA(font, NULL, "", -1, &rect, 0, 0xFF00FF); + ok(height == 0, "DrawTextA returned %d, expected 0.\n", height); + height = ID3DXFont_DrawTextA(font, NULL, "test", -1, NULL, 0, 0xFF00FF); ok(height == 12, "DrawTextA returned %d, expected 12.\n", height);
@@ -671,7 +726,17 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) height = ID3DXFont_DrawTextA(font, NULL, NULL, -1, NULL, 0, 0xFF00FF); ok(height == 0, "DrawTextA returned %d, expected 0.\n", height);
-if (0) { /* Causes a lockup on windows 7. */ + SetRect(&rect, 10, 10, 50, 50); + + height = ID3DXFont_DrawTextA(font, NULL, longText, -1, &rect, DT_WORDBREAK, 0xFF00FF); + ok(height == 60, "DrawTextA returned %d, expected 60.\n", height); + + height = ID3DXFont_DrawTextA(font, NULL, longText, -1, &rect, DT_WORDBREAK | DT_NOCLIP, 0xFF00FF); + ok(height == 96, "DrawTextA returned %d, expected 96.\n", height); + + SetRect(&rect, 10, 10, 200, 200); + +if (0) { /* Causes a lockup on Windows 7+ */ height = ID3DXFont_DrawTextW(font, NULL, testW, -2, &rect, 0, 0xFF00FF); ok(height == 12, "DrawTextW returned %d, expected 12.\n", height); } @@ -688,6 +753,12 @@ if (0) { /* Causes a lockup on windows 7. */ height = ID3DXFont_DrawTextW(font, NULL, testW, 2, &rect, 0, 0xFF00FF); ok(height == 12, "DrawTextW returned %d, expected 12.\n", height);
+ height = ID3DXFont_DrawTextW(font, NULL, emptyW, 0, &rect, 0, 0xFF00FF); + ok(height == 0, "DrawTextW returned %d, expected 0.\n", height); + + height = ID3DXFont_DrawTextW(font, NULL, emptyW, -1, &rect, 0, 0xFF00FF); + ok(height == 0, "DrawTextW returned %d, expected 0.\n", height); + height = ID3DXFont_DrawTextW(font, NULL, testW, -1, NULL, 0, 0xFF00FF); ok(height == 12, "DrawTextW returned %d, expected 12.\n", height);
@@ -696,6 +767,14 @@ if (0) { /* Causes a lockup on windows 7. */
height = ID3DXFont_DrawTextW(font, NULL, NULL, -1, NULL, 0, 0xFF00FF); ok(height == 0, "DrawTextW returned %d, expected 0.\n", height); + + SetRect(&rect, 10, 10, 50, 50); + + height = ID3DXFont_DrawTextW(font, NULL, longTextW, -1, &rect, DT_WORDBREAK, 0xFF00FF); + ok(height == 60, "DrawTextW returned %d, expected 60.\n", height); + + height = ID3DXFont_DrawTextW(font, NULL, longTextW, -1, &rect, DT_WORDBREAK | DT_NOCLIP, 0xFF00FF); + ok(height == 96, "DrawTextW returned %d, expected 96.\n", height); }
ID3DXFont_Release(font);
On Mon, Jan 6, 2020 at 3:35 PM Sven Baars sbaars@codeweavers.com wrote:
Signed-off-by: Sven Baars sbaars@codeweavers.com
v2: Fix some test failures and remove tests that fail on my machine, but not on the testbot.
dlls/d3dx9_36/tests/core.c | 119 ++++++++++++++++++++++++++++++------- 1 file changed, 99 insertions(+), 20 deletions(-)
diff --git a/dlls/d3dx9_36/tests/core.c b/dlls/d3dx9_36/tests/core.c index 8c1d41e952..b2a44ded70 100644 --- a/dlls/d3dx9_36/tests/core.c +++ b/dlls/d3dx9_36/tests/core.c @@ -306,6 +306,14 @@ static void test_ID3DXSprite(IDirect3DDevice9 *device) static void test_ID3DXFont(IDirect3DDevice9 *device) { static const WCHAR testW[] = {'t','e','s','t',0};
- static const WCHAR emptyW[] = {0};
- static const char longText[] = "Example text to test clipping and other related things";
- static const WCHAR longTextW[] = {'E', 'x', 'a', 'm', 'p', 'l', 'e', ' ',
't', 'e', 'x', 't', ' ', 't', 'o', ' ',
't', 'e', 's', 't', ' ', 'c', 'l', 'i', 'p', 'p', 'i', 'n', 'g', ' ',
'a', 'n', 'd', ' ', 'o', 't', 'h', 'e', 'r', ' ',
'r', 'e', 'l', 'a', 't', 'e', 'd', ' ', 't', 'h', 'i', 'n', 'g', 's', 0};
You can now use the L"xxx" syntax for WCHAR strings. emptyW in particular could just be dropped and be replaced by a L"" inline.
- static const struct { int font_height;
@@ -314,11 +322,14 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) } tests[] = {
{ 6, 128, 4 },
{ 8, 128, 4 },
{ 10, 256, 5 },
{ 12, 256, 5 },
{ 72, 256, 8 },
{ 2, 32, 2 },
{ 6, 128, 4 },
{ 10, 256, 5 },
{ 12, 256, 5 },
{ 72, 256, 8 },
{ 250, 256, 9 },
{ 258, 512, 10 },
}; const unsigned int size = ARRAY_SIZE(testW); D3DXFONT_DESCA desc;{ 512, 512, 10 },
@@ -477,6 +488,10 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) ok(hr == D3DERR_INVALIDCALL, "ID3DXFont_PreloadTextA returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL); hr = ID3DXFont_PreloadTextA(font, "test", -1); ok(hr == D3D_OK, "ID3DXFont_PreloadTextA returned %#x, expected %#x\n", hr, D3D_OK);
hr = ID3DXFont_PreloadTextA(font, "", 0);
ok(hr == D3D_OK, "ID3DXFont_PreloadTextA returned %#x, expected %#x\n", hr, D3D_OK);
hr = ID3DXFont_PreloadTextA(font, "", -1);
ok(hr == D3D_OK, "ID3DXFont_PreloadTextA returned %#x, expected %#x\n", hr, D3D_OK); hr = ID3DXFont_PreloadTextW(font, NULL, -1); ok(hr == D3DERR_INVALIDCALL, "ID3DXFont_PreloadTextW returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL);
@@ -486,6 +501,10 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) ok(hr == D3DERR_INVALIDCALL, "ID3DXFont_PreloadTextW returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL); hr = ID3DXFont_PreloadTextW(font, testW, -1); ok(hr == D3D_OK, "ID3DXFont_PreloadTextW returned %#x, expected %#x\n", hr, D3D_OK);
hr = ID3DXFont_PreloadTextW(font, emptyW, 0);
ok(hr == D3D_OK, "ID3DXFont_PreloadTextW returned %#x, expected %#x\n", hr, D3D_OK);
hr = ID3DXFont_PreloadTextW(font, emptyW, -1);
ok(hr == D3D_OK, "ID3DXFont_PreloadTextW returned %#x, expected %#x\n", hr, D3D_OK); } check_release((IUnknown*)font, 0);
@@ -498,6 +517,7 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) char c; HDC hdc; DWORD ret;
WORD glyph; HRESULT hr; RECT blackbox; POINT cellinc;
@@ -524,26 +544,42 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) ok(hr == D3D_OK, "ID3DXFont_PreloadCharacters returned %#x, expected %#x\n", hr, D3D_OK);
for(c = 'b'; c <= 'z'; c++) {
WORD glyph;
ret = GetGlyphIndicesA(hdc, &c, 1, &glyph, 0); ok(ret != GDI_ERROR, "GetGlyphIndicesA failed\n"); hr = ID3DXFont_GetGlyphData(font, glyph, &texture, &blackbox, &cellinc); todo_wine ok(hr == D3D_OK, "ID3DXFont_GetGlyphData returned %#x, expected %#x\n", hr, D3D_OK); if(SUCCEEDED(hr)) {
DWORD levels;
DWORD ret, levels;
TEXTMETRICW tm; D3DSURFACE_DESC desc;
GLYPHMETRICS metrics;
MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} }; levels = IDirect3DTexture9_GetLevelCount(texture);
ok(levels == 5, "Got levels %u, expected %u\n", levels, 5);
todo_wine ok(levels == 5, "Character %c, got levels %u, expected %u\n", c, levels, 5);
Why does this require a todo_wine now? My guess is that it actually doesn't, since GetGlyphData() is currently a stub; it would be nicer to add todo_wine in the same patch that implements GetGlyphData().
hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc); ok(hr == D3D_OK, "IDirect3DTexture9_GetLevelDesc failed\n");
ok(desc.Format == D3DFMT_A8R8G8B8, "Got format %#x, expected %#x\n", desc.Format, D3DFMT_A8R8G8B8);
ok(desc.Usage == 0, "Got usage %#x, expected %#x\n", desc.Usage, 0);
ok(desc.Width == 256, "Got width %u, expected %u\n", desc.Width, 256);
ok(desc.Height == 256, "Got height %u, expected %u\n", desc.Height, 256);
ok(desc.Pool == D3DPOOL_MANAGED, "Got pool %u, expected %u\n", desc.Pool, D3DPOOL_MANAGED);
ok(desc.Format == D3DFMT_A8R8G8B8, "Character %c, got format %#x, expected %#x\n", c, desc.Format, D3DFMT_A8R8G8B8);
ok(desc.Usage == 0, "Character %c, got usage %#x, expected %#x\n", c, desc.Usage, 0);
ok(desc.Width == 256, "Character %c, got width %u, expected %u\n", c, desc.Width, 256);
ok(desc.Height == 256, "Character %c, got height %u, expected %u\n", c, desc.Height, 256);
ok(desc.Pool == D3DPOOL_MANAGED, "Character %c, got pool %u, expected %u\n", c, desc.Pool, D3DPOOL_MANAGED);
/* Check blackbox and cellinc, but skip v, w and y, because these
are apparently smaller */
ret = GetGlyphOutlineW(hdc, glyph, GGO_GLYPH_INDEX | GGO_GRAY8_BITMAP | GGO_METRICS, &metrics, 0, NULL, &mat);
if (ret != GDI_ERROR && c != 'v' && c != 'w' && c != 'y') {
Smaller how exactly? Anyway, I don't like this kind of special casing; I'd rather allow some tolerance in the checks below.
ID3DXFont_GetTextMetricsW(font, &tm);
todo_wine ok(blackbox.right - blackbox.left == metrics.gmBlackBoxX + 2, "Character %c, got %d, expected %d\n",
c, blackbox.right - blackbox.left, metrics.gmBlackBoxX + 2);
todo_wine ok(blackbox.bottom - blackbox.top == metrics.gmBlackBoxY + 2, "Character %c, got %d, expected %d\n",
c, blackbox.bottom - blackbox.top, metrics.gmBlackBoxY + 2);
ok(cellinc.x == metrics.gmptGlyphOrigin.x - 1, "Character %c, got %d, expected %d\n",
c, cellinc.x, metrics.gmptGlyphOrigin.x - 1);
ok(cellinc.y == tm.tmAscent - metrics.gmptGlyphOrigin.y - 1, "Character %c, got %d, expected %d\n",
c, cellinc.y, tm.tmAscent - metrics.gmptGlyphOrigin.y - 1);
} else if (ret == GDI_ERROR) skip("Failed to obtain glyph metrics\n"); check_release((IUnknown*)texture, 1); }
@@ -552,6 +588,19 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) hr = ID3DXFont_PreloadCharacters(font, 'a', 'z'); ok(hr == D3D_OK, "ID3DXFont_PreloadCharacters returned %#x, expected %#x\n", hr, D3D_OK);
/* Test multiple textures */
hr = ID3DXFont_PreloadGlyphs(font, 0, 1000);
todo_wine ok(hr == D3D_OK, "ID3DXFont_PreloadGlyphs returned %#x, expected %#x\n", hr, D3D_OK);
/* Test glyphs that are not rendered */
for (glyph = 1; glyph < 4; glyph++)
{
texture = (IDirect3DTexture9*)0xdeadbeef;
hr = ID3DXFont_GetGlyphData(font, glyph, &texture, &blackbox, &cellinc);
todo_wine ok(hr == D3D_OK, "ID3DXFont_GetGlyphData returned %#x, expected %#x\n", hr, D3D_OK);
todo_wine ok(!texture, "Got unexpected texture\n");
}
Nice test.
} else skip("Failed to create a ID3DXFont object\n");check_release((IUnknown*)font, 0);
@@ -611,20 +660,20 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) todo_wine { height = ID3DXFont_DrawTextW(font, sprite, testW, -1, &rect, DT_TOP, 0xffffffff);
ok(height == tests[i].font_height, "Got unexpected height %u.\n", height);
ok(height == tests[i].font_height, "Got height %u, expected %u.\n", height, tests[i].font_height); height = ID3DXFont_DrawTextW(font, sprite, testW, size, &rect, DT_TOP, 0xffffffff);
ok(height == tests[i].font_height, "Got unexpected height %u.\n", height);
ok(height == tests[i].font_height, "Got height %u, expected %u.\n", height, tests[i].font_height); height = ID3DXFont_DrawTextW(font, sprite, testW, size, &rect, DT_RIGHT, 0xffffffff);
ok(height == tests[i].font_height, "Got unexpected height %u.\n", height);
ok(height == tests[i].font_height, "Got height %u, expected %u.\n", height, tests[i].font_height); height = ID3DXFont_DrawTextW(font, sprite, testW, size, &rect, DT_LEFT | DT_NOCLIP, 0xffffffff);
ok(height == tests[i].font_height, "Got unexpected height %u.\n", height);
ok(height == tests[i].font_height, "Got height %u, expected %u.\n", height, tests[i].font_height);
Usually in these cases we prefer printing the test index instead of the expected value, the point being that once you have to look at the code anyway to figure out which test fails it's trivial to recover the expected value.
On 22-01-2020 17:07, Matteo Bruni wrote:
On Mon, Jan 6, 2020 at 3:35 PM Sven Baars sbaars@codeweavers.com wrote:
hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc); ok(hr == D3D_OK, "IDirect3DTexture9_GetLevelDesc failed\n");
ok(desc.Format == D3DFMT_A8R8G8B8, "Got format %#x, expected %#x\n", desc.Format, D3DFMT_A8R8G8B8);
ok(desc.Usage == 0, "Got usage %#x, expected %#x\n", desc.Usage, 0);
ok(desc.Width == 256, "Got width %u, expected %u\n", desc.Width, 256);
ok(desc.Height == 256, "Got height %u, expected %u\n", desc.Height, 256);
ok(desc.Pool == D3DPOOL_MANAGED, "Got pool %u, expected %u\n", desc.Pool, D3DPOOL_MANAGED);
ok(desc.Format == D3DFMT_A8R8G8B8, "Character %c, got format %#x, expected %#x\n", c, desc.Format, D3DFMT_A8R8G8B8);
ok(desc.Usage == 0, "Character %c, got usage %#x, expected %#x\n", c, desc.Usage, 0);
ok(desc.Width == 256, "Character %c, got width %u, expected %u\n", c, desc.Width, 256);
ok(desc.Height == 256, "Character %c, got height %u, expected %u\n", c, desc.Height, 256);
ok(desc.Pool == D3DPOOL_MANAGED, "Character %c, got pool %u, expected %u\n", c, desc.Pool, D3DPOOL_MANAGED);
/* Check blackbox and cellinc, but skip v, w and y, because these
are apparently smaller */
ret = GetGlyphOutlineW(hdc, glyph, GGO_GLYPH_INDEX | GGO_GRAY8_BITMAP | GGO_METRICS, &metrics, 0, NULL, &mat);
if (ret != GDI_ERROR && c != 'v' && c != 'w' && c != 'y') {
Smaller how exactly? Anyway, I don't like this kind of special casing; I'd rather allow some tolerance in the checks below. Hi Matteo,
Thanks for the review.
If I introduce a tolerance here, the Wine tests also start succeeding, which is not what I want, since I want to show that my implementation is not entirely correct. I'm unsure how else the glyphs could be created though, so I'm not sure how this could be tested/implemented differently.
Cheers, Sven
Based on a patch by Tony Wasserka.
Signed-off-by: Sven Baars sbaars@codeweavers.com --- dlls/d3dx9_36/d3dx9_private.h | 2 + dlls/d3dx9_36/font.c | 239 +++++++++++++++++++++++++++++++--- dlls/d3dx9_36/tests/core.c | 4 +- dlls/d3dx9_36/texture.c | 2 +- 4 files changed, 228 insertions(+), 19 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index 61ec320ba5..4f92b914ef 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -225,6 +225,8 @@ static inline BOOL is_param_type_sampler(D3DXPARAMETER_TYPE type) || type == D3DXPT_SAMPLER3D || type == D3DXPT_SAMPLERCUBE; }
+UINT make_pow2(UINT num) DECLSPEC_HIDDEN; + struct d3dx_parameter;
enum pres_reg_tables diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c index cb09af22f5..fe645a51c0 100644 --- a/dlls/d3dx9_36/font.c +++ b/dlls/d3dx9_36/font.c @@ -22,6 +22,14 @@
WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
+typedef struct _GLYPH +{ + UINT id; + RECT blackbox; + POINT cellinc; + IDirect3DTexture9 *texture; +} GLYPH; + struct d3dx_font { ID3DXFont ID3DXFont_iface; @@ -32,6 +40,14 @@ struct d3dx_font
HDC hdc; HFONT hfont; + + GLYPH *glyphs; + UINT allocated_glyphs, glyph_count; + + IDirect3DTexture9 **textures; + UINT texture_count, texture_pos; + + UINT texture_size, glyph_size, glyphs_per_texture; };
static inline struct d3dx_font *impl_from_ID3DXFont(ID3DXFont *iface) @@ -72,11 +88,21 @@ static ULONG WINAPI ID3DXFontImpl_Release(ID3DXFont *iface)
TRACE("%p decreasing refcount to %u\n", iface, ref);
- if(ref==0) { + if (!ref) + { + UINT i; + for(i = 0; i < This->texture_count; i++) + IDirect3DTexture9_Release(This->textures[i]); + + if (This->textures) + heap_free(This->textures); + + heap_free(This->glyphs); + DeleteObject(This->hfont); DeleteDC(This->hdc); IDirect3DDevice9_Release(This->device); - HeapFree(GetProcessHeap(), 0, This); + heap_free(This); } return ref; } @@ -154,10 +180,164 @@ static HRESULT WINAPI ID3DXFontImpl_PreloadCharacters(ID3DXFont *iface, UINT fir return S_OK; }
+/************************************************************ + * ID3DXFont_PreloadGlyphs + * + * Preloads the specified glyph series into the internal texture + * + * PARAMS + * first [I] first glyph to be preloaded + * last [I] last glyph to be preloaded + * + * RETURNS + * Success: D3D_OK + * + * NOTES + * The glyphs are stored in a grid. + * Cell sizes vary between different font sizes. + * The grid is filled in this order: + * 1 2 5 6 17 18 21 22 + * 3 4 7 8 19 20 23 24 + * 9 10 13 14 25 26 29 30 + * 11 12 15 16 27 28 31 32 + * 33 34 ... + * ... + * i.e. we try to fill one small square, then three equal-sized squares so that we get one big square, etc... + * + * The glyphs are positioned around their baseline, which is located at y position glyph_size * i + tmAscent. + * Concerning the x position, the glyphs are centered around glyph_size * (i + 0.5). + * + */ static HRESULT WINAPI ID3DXFontImpl_PreloadGlyphs(ID3DXFont *iface, UINT first, UINT last) { - FIXME("iface %p, first %u, last %u stub!\n", iface, first, last); - return E_NOTIMPL; + struct d3dx_font *This = impl_from_ID3DXFont(iface); + UINT glyph, i, x, y; + TEXTMETRICW tm; + HRESULT hr; + + TRACE("iface %p, first %u, last %u\n", iface, first, last); + + if (last < first) + return D3D_OK; + + ID3DXFont_GetTextMetricsW(iface, &tm); + + for (glyph = first; glyph <= last; glyph++) + { + DWORD ret; + BYTE *buffer; + GLYPHMETRICS metrics; + D3DLOCKED_RECT lockrect; + MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} }; + UINT stride, offx = 0, offy = 0; + GLYPH *current_glyph; + IDirect3DTexture9 *current_texture; + + /* Check whether the glyph is already preloaded */ + for (i = 0; i < This->glyph_count; i++) + if (This->glyphs[i].id == glyph) + break; + if (i < This->glyph_count) + continue; + + /* Calculate glyph position */ + for (i = 0; i < 16; i++) + { + if (This->texture_pos & (1 << (2*i))) + offx += This->glyph_size * (1 << i); + if (i < 15 && This->texture_pos & (1 << (2*i + 1))) + offy += This->glyph_size * (1 << i); + } + + /* Make sure we have enough memory */ + if (This->glyph_count + 1 > This->allocated_glyphs) + { + This->allocated_glyphs <<= 1; + This->glyphs = heap_realloc(This->glyphs, This->allocated_glyphs * sizeof(GLYPH)); + if (!This->glyphs) + return E_OUTOFMEMORY; + } + + current_glyph = This->glyphs + This->glyph_count++; + current_glyph->id = glyph; + current_glyph->texture = NULL; + + /* Spaces are handled separately */ + if (glyph > 0 && glyph < 4) + continue; + + /* Get the glyph data */ + ret = GetGlyphOutlineW(This->hdc, glyph, GGO_GLYPH_INDEX | GGO_GRAY8_BITMAP, &metrics, 0, NULL, &mat); + if (ret == GDI_ERROR) + continue; + + buffer = heap_alloc(ret); + if (!buffer) + return E_OUTOFMEMORY; + + GetGlyphOutlineW(This->hdc, glyph, GGO_GLYPH_INDEX | GGO_GRAY8_BITMAP, &metrics, ret, buffer, &mat); + + /* Create a new texture if necessary */ + if (This->texture_pos % This->glyphs_per_texture == 0) + { + This->textures = heap_realloc(This->textures, (This->texture_count + 1) * sizeof(IDirect3DTexture9 *)); + if (!This->textures) + { + heap_free(buffer); + return E_OUTOFMEMORY; + } + + if (FAILED(hr = IDirect3DDevice9_CreateTexture(This->device, This->texture_size, + This->texture_size, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, + &This->textures[This->texture_count], NULL))) + { + heap_free(buffer); + return hr; + } + + This->texture_count++; + This->texture_pos = 0; + offx = 0; + offy = 0; + } + + current_texture = This->textures[This->texture_count - 1]; + + /* Fill in glyph data */ + current_glyph->blackbox.left = offx - metrics.gmptGlyphOrigin.x + This->glyph_size / 2 - metrics.gmBlackBoxX / 2; + current_glyph->blackbox.top = offy - metrics.gmptGlyphOrigin.y + tm.tmAscent; + current_glyph->blackbox.right = current_glyph->blackbox.left + metrics.gmBlackBoxX; + current_glyph->blackbox.bottom = current_glyph->blackbox.top + metrics.gmBlackBoxY; + current_glyph->cellinc.x = metrics.gmptGlyphOrigin.x - 1; + current_glyph->cellinc.y = tm.tmAscent - metrics.gmptGlyphOrigin.y - 1; + current_glyph->texture = current_texture; + + /* Copy glyph data to the texture */ + if (FAILED(hr = IDirect3DTexture9_LockRect(current_texture, 0, &lockrect, ¤t_glyph->blackbox, 0))) + { + heap_free(buffer); + return hr; + } + + stride = (metrics.gmBlackBoxX + 3) & ~3; + + for (y = 0; y < metrics.gmBlackBoxY; y++) + for (x = 0; x < metrics.gmBlackBoxX; x++) + { + ((BYTE*)lockrect.pBits)[4 * x + y * lockrect.Pitch ] = 255; + ((BYTE*)lockrect.pBits)[4 * x + y * lockrect.Pitch + 1] = 255; + ((BYTE*)lockrect.pBits)[4 * x + y * lockrect.Pitch + 2] = 255; + ((BYTE*)lockrect.pBits)[4 * x + y * lockrect.Pitch + 3] = buffer[x + y * stride] * 255 / 64; + } + + IDirect3DTexture9_UnlockRect(current_texture, 0); + + heap_free(buffer); + + This->texture_pos++; + } + + return D3D_OK; }
static HRESULT WINAPI ID3DXFontImpl_PreloadTextA(ID3DXFont *iface, const char *string, INT count) @@ -294,6 +474,7 @@ HRESULT WINAPI D3DXCreateFontIndirectW(IDirect3DDevice9 *device, const D3DXFONT_ D3DDISPLAYMODE mode; struct d3dx_font *object; IDirect3D9 *d3d; + TEXTMETRICW metrics; HRESULT hr;
TRACE("(%p, %p, %p)\n", device, desc, font); @@ -305,39 +486,65 @@ HRESULT WINAPI D3DXCreateFontIndirectW(IDirect3DDevice9 *device, const D3DXFONT_ IDirect3DDevice9_GetCreationParameters(device, &cpars); IDirect3DDevice9_GetDisplayMode(device, 0, &mode); hr = IDirect3D9_CheckDeviceFormat(d3d, cpars.AdapterOrdinal, cpars.DeviceType, mode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8); - if(FAILED(hr)) { + if (FAILED(hr)) + { IDirect3D9_Release(d3d); return D3DXERR_INVALIDDATA; } IDirect3D9_Release(d3d);
- object = HeapAlloc(GetProcessHeap(), 0, sizeof(struct d3dx_font)); - if(object==NULL) { - *font=NULL; + object = heap_alloc_zero(sizeof(struct d3dx_font)); + if (!object) + { + *font = NULL; return E_OUTOFMEMORY; } object->ID3DXFont_iface.lpVtbl = &D3DXFont_Vtbl; - object->ref=1; - object->device=device; - object->desc=*desc; + object->ref = 1; + object->device = device; + object->desc = *desc;
object->hdc = CreateCompatibleDC(NULL); - if( !object->hdc ) { - HeapFree(GetProcessHeap(), 0, object); + if (!object->hdc) + { + heap_free(object); return D3DXERR_INVALIDDATA; }
object->hfont = CreateFontW(desc->Height, desc->Width, 0, 0, desc->Weight, desc->Italic, FALSE, FALSE, desc->CharSet, desc->OutputPrecision, CLIP_DEFAULT_PRECIS, desc->Quality, desc->PitchAndFamily, desc->FaceName); - if( !object->hfont ) { + if (!object->hfont) + { DeleteDC(object->hdc); - HeapFree(GetProcessHeap(), 0, object); + heap_free(object); return D3DXERR_INVALIDDATA; } SelectObject(object->hdc, object->hfont);
+ /* allocate common memory usage */ + object->allocated_glyphs = 32; + object->glyphs = heap_alloc(object->allocated_glyphs * sizeof(GLYPH)); + if (!object->glyphs) + { + DeleteObject(object->hfont); + DeleteDC(object->hdc); + heap_free(object); + *font = NULL; + return E_OUTOFMEMORY; + } + + GetTextMetricsW(object->hdc, &metrics); + + object->glyph_size = make_pow2(metrics.tmHeight); + + object->texture_size = make_pow2(object->glyph_size); + if (object->glyph_size < 256) + object->texture_size = min(256, object->texture_size << 4); + + object->glyphs_per_texture = object->texture_size * object->texture_size / object->glyph_size / object->glyph_size; + IDirect3DDevice9_AddRef(device); - *font=&object->ID3DXFont_iface; + *font = &object->ID3DXFont_iface;
return D3D_OK; } diff --git a/dlls/d3dx9_36/tests/core.c b/dlls/d3dx9_36/tests/core.c index b2a44ded70..4b731288c7 100644 --- a/dlls/d3dx9_36/tests/core.c +++ b/dlls/d3dx9_36/tests/core.c @@ -538,7 +538,7 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) hr = ID3DXFont_PreloadCharacters(font, 'b', 'a'); ok(hr == D3D_OK, "ID3DXFont_PreloadCharacters returned %#x, expected %#x\n", hr, D3D_OK); hr = ID3DXFont_PreloadGlyphs(font, 1, 0); - todo_wine ok(hr == D3D_OK, "ID3DXFont_PreloadGlyphs returned %#x, expected %#x\n", hr, D3D_OK); + ok(hr == D3D_OK, "ID3DXFont_PreloadGlyphs returned %#x, expected %#x\n", hr, D3D_OK);
hr = ID3DXFont_PreloadCharacters(font, 'a', 'a'); ok(hr == D3D_OK, "ID3DXFont_PreloadCharacters returned %#x, expected %#x\n", hr, D3D_OK); @@ -590,7 +590,7 @@ static void test_ID3DXFont(IDirect3DDevice9 *device)
/* Test multiple textures */ hr = ID3DXFont_PreloadGlyphs(font, 0, 1000); - todo_wine ok(hr == D3D_OK, "ID3DXFont_PreloadGlyphs returned %#x, expected %#x\n", hr, D3D_OK); + ok(hr == D3D_OK, "ID3DXFont_PreloadGlyphs returned %#x, expected %#x\n", hr, D3D_OK);
/* Test glyphs that are not rendered */ for (glyph = 1; glyph < 4; glyph++) diff --git a/dlls/d3dx9_36/texture.c b/dlls/d3dx9_36/texture.c index d96ade9aed..47acf42aa1 100644 --- a/dlls/d3dx9_36/texture.c +++ b/dlls/d3dx9_36/texture.c @@ -31,7 +31,7 @@ static BOOL is_pow2(UINT num) }
/* Returns the smallest power of 2 which is greater than or equal to num */ -static UINT make_pow2(UINT num) +UINT make_pow2(UINT num) { UINT result = 1;
On Mon, Jan 6, 2020 at 3:35 PM Sven Baars sbaars@codeweavers.com wrote:
Based on a patch by Tony Wasserka.
Signed-off-by: Sven Baars sbaars@codeweavers.com
dlls/d3dx9_36/d3dx9_private.h | 2 + dlls/d3dx9_36/font.c | 239 +++++++++++++++++++++++++++++++--- dlls/d3dx9_36/tests/core.c | 4 +- dlls/d3dx9_36/texture.c | 2 +- 4 files changed, 228 insertions(+), 19 deletions(-)
diff --git a/dlls/d3dx9_36/d3dx9_private.h b/dlls/d3dx9_36/d3dx9_private.h index 61ec320ba5..4f92b914ef 100644 --- a/dlls/d3dx9_36/d3dx9_private.h +++ b/dlls/d3dx9_36/d3dx9_private.h @@ -225,6 +225,8 @@ static inline BOOL is_param_type_sampler(D3DXPARAMETER_TYPE type) || type == D3DXPT_SAMPLER3D || type == D3DXPT_SAMPLERCUBE; }
+UINT make_pow2(UINT num) DECLSPEC_HIDDEN;
struct d3dx_parameter;
enum pres_reg_tables diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c index cb09af22f5..fe645a51c0 100644 --- a/dlls/d3dx9_36/font.c +++ b/dlls/d3dx9_36/font.c @@ -22,6 +22,14 @@
WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
+typedef struct _GLYPH +{
- UINT id;
- RECT blackbox;
- POINT cellinc;
- IDirect3DTexture9 *texture;
+} GLYPH;
Please don't add typedefs or type names in caps.
struct d3dx_font { ID3DXFont ID3DXFont_iface; @@ -32,6 +40,14 @@ struct d3dx_font
HDC hdc; HFONT hfont;
- GLYPH *glyphs;
- UINT allocated_glyphs, glyph_count;
- IDirect3DTexture9 **textures;
- UINT texture_count, texture_pos;
- UINT texture_size, glyph_size, glyphs_per_texture;
};
static inline struct d3dx_font *impl_from_ID3DXFont(ID3DXFont *iface) @@ -72,11 +88,21 @@ static ULONG WINAPI ID3DXFontImpl_Release(ID3DXFont *iface)
TRACE("%p decreasing refcount to %u\n", iface, ref);
- if(ref==0) {
- if (!ref)
- {
UINT i;
for(i = 0; i < This->texture_count; i++)
IDirect3DTexture9_Release(This->textures[i]);
if (This->textures)
heap_free(This->textures);
heap_free(This->glyphs);
DeleteObject(This->hfont); DeleteDC(This->hdc); IDirect3DDevice9_Release(This->device);
HeapFree(GetProcessHeap(), 0, This);
} return ref;heap_free(This);
}
Pure nitpick, while at it you could rename This to font or something like that.
@@ -154,10 +180,164 @@ static HRESULT WINAPI ID3DXFontImpl_PreloadCharacters(ID3DXFont *iface, UINT fir return S_OK; }
+/************************************************************
- ID3DXFont_PreloadGlyphs
- Preloads the specified glyph series into the internal texture
- PARAMS
- first [I] first glyph to be preloaded
- last [I] last glyph to be preloaded
- RETURNS
- Success: D3D_OK
- NOTES
- The glyphs are stored in a grid.
- Cell sizes vary between different font sizes.
- The grid is filled in this order:
- 1 2 5 6 17 18 21 22
- 3 4 7 8 19 20 23 24
- 9 10 13 14 25 26 29 30
- 11 12 15 16 27 28 31 32
- 33 34 ...
- ...
- i.e. we try to fill one small square, then three equal-sized squares so that we get one big square, etc...
- The glyphs are positioned around their baseline, which is located at y position glyph_size * i + tmAscent.
- Concerning the x position, the glyphs are centered around glyph_size * (i + 0.5).
- */
I hate the boilerplate documentation of Win32 methods, I think it serves no purpose. I'd keep only the (very useful) notes part.
static HRESULT WINAPI ID3DXFontImpl_PreloadGlyphs(ID3DXFont *iface, UINT first, UINT last) {
- FIXME("iface %p, first %u, last %u stub!\n", iface, first, last);
- return E_NOTIMPL;
- struct d3dx_font *This = impl_from_ID3DXFont(iface);
- UINT glyph, i, x, y;
- TEXTMETRICW tm;
- HRESULT hr;
- TRACE("iface %p, first %u, last %u\n", iface, first, last);
- if (last < first)
return D3D_OK;
- ID3DXFont_GetTextMetricsW(iface, &tm);
- for (glyph = first; glyph <= last; glyph++)
- {
DWORD ret;
BYTE *buffer;
GLYPHMETRICS metrics;
D3DLOCKED_RECT lockrect;
MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
UINT stride, offx = 0, offy = 0;
GLYPH *current_glyph;
IDirect3DTexture9 *current_texture;
/* Check whether the glyph is already preloaded */
for (i = 0; i < This->glyph_count; i++)
if (This->glyphs[i].id == glyph)
break;
if (i < This->glyph_count)
continue;
/* Calculate glyph position */
for (i = 0; i < 16; i++)
{
if (This->texture_pos & (1 << (2*i)))
offx += This->glyph_size * (1 << i);
if (i < 15 && This->texture_pos & (1 << (2*i + 1)))
offy += This->glyph_size * (1 << i);
}
Probably not a big deal but I think that you can compute the x,y offsets more efficiently. See e.g. DecodeMorton2X() and DecodeMorton2Y() at https://fgiesen.wordpress.com/2009/12/13/decoding-morton-codes/ (the usual version would have bitwise or instead of xor at each step but it's probably not going to make any difference either way).
/* Make sure we have enough memory */
if (This->glyph_count + 1 > This->allocated_glyphs)
{
This->allocated_glyphs <<= 1;
This->glyphs = heap_realloc(This->glyphs, This->allocated_glyphs * sizeof(GLYPH));
if (!This->glyphs)
return E_OUTOFMEMORY;
}
This drops the old memory allocation on the floor if the reallocation fails. There are many other places with a similar pattern in Wine (or even in d3dx9, e.g. search for realloc) which you can use as inspiration.
Actually, when looking for those examples I spotted one that does it wrong in d3dx_pool_sync_shared_parameter(), I'm going to write a patch for that one...
current_glyph = This->glyphs + This->glyph_count++;
current_glyph->id = glyph;
current_glyph->texture = NULL;
/* Spaces are handled separately */
if (glyph > 0 && glyph < 4)
continue;
I have no clue if those two values are correct for every font but it smells somewhat fishy...
/* Get the glyph data */
ret = GetGlyphOutlineW(This->hdc, glyph, GGO_GLYPH_INDEX | GGO_GRAY8_BITMAP, &metrics, 0, NULL, &mat);
if (ret == GDI_ERROR)
continue;
We might want to print a WARN when that fails.
buffer = heap_alloc(ret);
if (!buffer)
return E_OUTOFMEMORY;
GetGlyphOutlineW(This->hdc, glyph, GGO_GLYPH_INDEX | GGO_GRAY8_BITMAP, &metrics, ret, buffer, &mat);
/* Create a new texture if necessary */
if (This->texture_pos % This->glyphs_per_texture == 0)
It's probably better to maintain a counter for the "slots" used in the current texture while in this function and avoid a modulo operation for each loop iteration.
{
This->textures = heap_realloc(This->textures, (This->texture_count + 1) * sizeof(IDirect3DTexture9 *));
if (!This->textures)
{
heap_free(buffer);
return E_OUTOFMEMORY;
}
Same issue as above.
if (FAILED(hr = IDirect3DDevice9_CreateTexture(This->device, This->texture_size,
This->texture_size, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED,
&This->textures[This->texture_count], NULL)))
{
heap_free(buffer);
return hr;
}
This->texture_count++;
This->texture_pos = 0;
offx = 0;
offy = 0;
}
current_texture = This->textures[This->texture_count - 1];
/* Fill in glyph data */
current_glyph->blackbox.left = offx - metrics.gmptGlyphOrigin.x + This->glyph_size / 2 - metrics.gmBlackBoxX / 2;
current_glyph->blackbox.top = offy - metrics.gmptGlyphOrigin.y + tm.tmAscent;
current_glyph->blackbox.right = current_glyph->blackbox.left + metrics.gmBlackBoxX;
current_glyph->blackbox.bottom = current_glyph->blackbox.top + metrics.gmBlackBoxY;
current_glyph->cellinc.x = metrics.gmptGlyphOrigin.x - 1;
current_glyph->cellinc.y = tm.tmAscent - metrics.gmptGlyphOrigin.y - 1;
current_glyph->texture = current_texture;
/* Copy glyph data to the texture */
if (FAILED(hr = IDirect3DTexture9_LockRect(current_texture, 0, &lockrect, ¤t_glyph->blackbox, 0)))
{
heap_free(buffer);
return hr;
}
stride = (metrics.gmBlackBoxX + 3) & ~3;
for (y = 0; y < metrics.gmBlackBoxY; y++)
for (x = 0; x < metrics.gmBlackBoxX; x++)
{
((BYTE*)lockrect.pBits)[4 * x + y * lockrect.Pitch ] = 255;
((BYTE*)lockrect.pBits)[4 * x + y * lockrect.Pitch + 1] = 255;
((BYTE*)lockrect.pBits)[4 * x + y * lockrect.Pitch + 2] = 255;
((BYTE*)lockrect.pBits)[4 * x + y * lockrect.Pitch + 3] = buffer[x + y * stride] * 255 / 64;
}
Introducing a DWORD * variable and filling the whole pixel in one go should make this quite a bit nicer. You can assume little-endian. Another stylistic nit: please add brackets to the outer for when the inner for has them.
IDirect3DTexture9_UnlockRect(current_texture, 0);
heap_free(buffer);
This->texture_pos++;
- }
- return D3D_OK;
}
static HRESULT WINAPI ID3DXFontImpl_PreloadTextA(ID3DXFont *iface, const char *string, INT count) @@ -294,6 +474,7 @@ HRESULT WINAPI D3DXCreateFontIndirectW(IDirect3DDevice9 *device, const D3DXFONT_ D3DDISPLAYMODE mode; struct d3dx_font *object; IDirect3D9 *d3d;
TEXTMETRICW metrics; HRESULT hr;
TRACE("(%p, %p, %p)\n", device, desc, font);
@@ -305,39 +486,65 @@ HRESULT WINAPI D3DXCreateFontIndirectW(IDirect3DDevice9 *device, const D3DXFONT_ IDirect3DDevice9_GetCreationParameters(device, &cpars); IDirect3DDevice9_GetDisplayMode(device, 0, &mode); hr = IDirect3D9_CheckDeviceFormat(d3d, cpars.AdapterOrdinal, cpars.DeviceType, mode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8R8G8B8);
- if(FAILED(hr)) {
- if (FAILED(hr))
- { IDirect3D9_Release(d3d); return D3DXERR_INVALIDDATA; } IDirect3D9_Release(d3d);
- object = HeapAlloc(GetProcessHeap(), 0, sizeof(struct d3dx_font));
- if(object==NULL) {
*font=NULL;
- object = heap_alloc_zero(sizeof(struct d3dx_font));
- if (!object)
- {
} object->ID3DXFont_iface.lpVtbl = &D3DXFont_Vtbl;*font = NULL; return E_OUTOFMEMORY;
- object->ref=1;
- object->device=device;
- object->desc=*desc;
object->ref = 1;
object->device = device;
object->desc = *desc;
object->hdc = CreateCompatibleDC(NULL);
- if( !object->hdc ) {
HeapFree(GetProcessHeap(), 0, object);
if (!object->hdc)
{
heap_free(object); return D3DXERR_INVALIDDATA;
}
object->hfont = CreateFontW(desc->Height, desc->Width, 0, 0, desc->Weight, desc->Italic, FALSE, FALSE, desc->CharSet, desc->OutputPrecision, CLIP_DEFAULT_PRECIS, desc->Quality, desc->PitchAndFamily, desc->FaceName);
- if( !object->hfont ) {
- if (!object->hfont)
- { DeleteDC(object->hdc);
HeapFree(GetProcessHeap(), 0, object);
heap_free(object); return D3DXERR_INVALIDDATA;
} SelectObject(object->hdc, object->hfont);
/* allocate common memory usage */
object->allocated_glyphs = 32;
object->glyphs = heap_alloc(object->allocated_glyphs * sizeof(GLYPH));
if (!object->glyphs)
{
DeleteObject(object->hfont);
DeleteDC(object->hdc);
heap_free(object);
*font = NULL;
return E_OUTOFMEMORY;
}
GetTextMetricsW(object->hdc, &metrics);
object->glyph_size = make_pow2(metrics.tmHeight);
object->texture_size = make_pow2(object->glyph_size);
if (object->glyph_size < 256)
object->texture_size = min(256, object->texture_size << 4);
object->glyphs_per_texture = object->texture_size * object->texture_size / object->glyph_size / object->glyph_size;
IDirect3DDevice9_AddRef(device);
- *font=&object->ID3DXFont_iface;
*font = &object->ID3DXFont_iface;
return D3D_OK;
} diff --git a/dlls/d3dx9_36/tests/core.c b/dlls/d3dx9_36/tests/core.c index b2a44ded70..4b731288c7 100644 --- a/dlls/d3dx9_36/tests/core.c +++ b/dlls/d3dx9_36/tests/core.c @@ -538,7 +538,7 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) hr = ID3DXFont_PreloadCharacters(font, 'b', 'a'); ok(hr == D3D_OK, "ID3DXFont_PreloadCharacters returned %#x, expected %#x\n", hr, D3D_OK); hr = ID3DXFont_PreloadGlyphs(font, 1, 0);
todo_wine ok(hr == D3D_OK, "ID3DXFont_PreloadGlyphs returned %#x, expected %#x\n", hr, D3D_OK);
ok(hr == D3D_OK, "ID3DXFont_PreloadGlyphs returned %#x, expected %#x\n", hr, D3D_OK); hr = ID3DXFont_PreloadCharacters(font, 'a', 'a'); ok(hr == D3D_OK, "ID3DXFont_PreloadCharacters returned %#x, expected %#x\n", hr, D3D_OK);
@@ -590,7 +590,7 @@ static void test_ID3DXFont(IDirect3DDevice9 *device)
/* Test multiple textures */ hr = ID3DXFont_PreloadGlyphs(font, 0, 1000);
todo_wine ok(hr == D3D_OK, "ID3DXFont_PreloadGlyphs returned %#x, expected %#x\n", hr, D3D_OK);
ok(hr == D3D_OK, "ID3DXFont_PreloadGlyphs returned %#x, expected %#x\n", hr, D3D_OK); /* Test glyphs that are not rendered */ for (glyph = 1; glyph < 4; glyph++)
diff --git a/dlls/d3dx9_36/texture.c b/dlls/d3dx9_36/texture.c index d96ade9aed..47acf42aa1 100644 --- a/dlls/d3dx9_36/texture.c +++ b/dlls/d3dx9_36/texture.c @@ -31,7 +31,7 @@ static BOOL is_pow2(UINT num) }
/* Returns the smallest power of 2 which is greater than or equal to num */ -static UINT make_pow2(UINT num) +UINT make_pow2(UINT num) { UINT result = 1;
This is okay but I'd prefer to move the helper to d3dx9_private.h and make it static inline instead. BTW, the function can be improved like in https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2. That would be a separate patch though.
Based on a patch by Tony Wasserka.
Signed-off-by: Sven Baars sbaars@codeweavers.com --- dlls/d3dx9_36/font.c | 64 ++++++++++++++++++++++++++++++++++++-- dlls/d3dx9_36/tests/core.c | 11 +++---- 2 files changed, 66 insertions(+), 9 deletions(-)
diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c index fe645a51c0..e204ca3012 100644 --- a/dlls/d3dx9_36/font.c +++ b/dlls/d3dx9_36/font.c @@ -166,12 +166,70 @@ static HDC WINAPI ID3DXFontImpl_GetDC(ID3DXFont *iface) return This->hdc; }
+/************************************************************ + * ID3DXFont_GetGlyphData + * + * Returns the internally stored texture and some info about + * the position of the requested glyph on that texture + * + * PARAMS + * glyph [I] glyph + * texture [O] length of the string + * blackbox [O] smallest rectangle that completely encloses the glyph on the texture + * cellinc [O] offset from the baseline to the bottom of the glyph + * + * RETURNS + * Success: D3D_OK + * Failure: D3DERR_INVALIDCALL + * D3DXERR_INVALIDDATA + * + * NOTES + * Glyphs which are passed to this function get preloaded, too + * + */ static HRESULT WINAPI ID3DXFontImpl_GetGlyphData(ID3DXFont *iface, UINT glyph, IDirect3DTexture9 **texture, RECT *blackbox, POINT *cellinc) { - FIXME("iface %p, glyph %#x, texture %p, blackbox %p, cellinc %p stub!\n", - iface, glyph, texture, blackbox, cellinc); - return E_NOTIMPL; + struct d3dx_font *This = impl_from_ID3DXFont(iface); + HRESULT hr; + int i; + TRACE("iface %p, glyph %#x, texture %p, blackbox %p, cellinc %p\n", + iface, glyph, texture, blackbox, cellinc); + + for (i = 0; i < This->glyph_count; i++) + if (This->glyphs[i].id == glyph) + { + if (cellinc) + *cellinc = This->glyphs[i].cellinc; + if (blackbox) + *blackbox = This->glyphs[i].blackbox; + if (texture) + *texture = This->glyphs[i].texture; + if (texture && *texture) + IDirect3DTexture9_AddRef(This->glyphs[i].texture); + return D3D_OK; + } + + hr = ID3DXFont_PreloadGlyphs(iface, glyph, glyph); + if (FAILED(hr)) + return hr; + + /* Try again */ + for (i = 0; i < This->glyph_count; i++) + if (This->glyphs[i].id == glyph) + { + if (cellinc) + *cellinc = This->glyphs[i].cellinc; + if (blackbox) + *blackbox = This->glyphs[i].blackbox; + if (texture) + *texture = This->glyphs[i].texture; + if (texture && *texture) + IDirect3DTexture9_AddRef(This->glyphs[i].texture); + return D3D_OK; + } + + return D3DXERR_INVALIDDATA; }
static HRESULT WINAPI ID3DXFontImpl_PreloadCharacters(ID3DXFont *iface, UINT first, UINT last) diff --git a/dlls/d3dx9_36/tests/core.c b/dlls/d3dx9_36/tests/core.c index 4b731288c7..4ec591e631 100644 --- a/dlls/d3dx9_36/tests/core.c +++ b/dlls/d3dx9_36/tests/core.c @@ -525,7 +525,6 @@ static void test_ID3DXFont(IDirect3DDevice9 *device)
hdc = ID3DXFont_GetDC(font);
- todo_wine { hr = ID3DXFont_GetGlyphData(font, 0, NULL, &blackbox, &cellinc); ok(hr == D3D_OK, "ID3DXFont_GetGlyphData returned %#x, expected %#x\n", hr, D3D_OK); hr = ID3DXFont_GetGlyphData(font, 0, &texture, NULL, &cellinc); @@ -534,7 +533,6 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) hr = ID3DXFont_GetGlyphData(font, 0, &texture, &blackbox, NULL); if(SUCCEEDED(hr)) check_release((IUnknown*)texture, 1); ok(hr == D3D_OK, "ID3DXFont_GetGlyphData returned %#x, expected %#x\n", hr, D3D_OK); - } hr = ID3DXFont_PreloadCharacters(font, 'b', 'a'); ok(hr == D3D_OK, "ID3DXFont_PreloadCharacters returned %#x, expected %#x\n", hr, D3D_OK); hr = ID3DXFont_PreloadGlyphs(font, 1, 0); @@ -548,7 +546,7 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) ok(ret != GDI_ERROR, "GetGlyphIndicesA failed\n");
hr = ID3DXFont_GetGlyphData(font, glyph, &texture, &blackbox, &cellinc); - todo_wine ok(hr == D3D_OK, "ID3DXFont_GetGlyphData returned %#x, expected %#x\n", hr, D3D_OK); + ok(hr == D3D_OK, "ID3DXFont_GetGlyphData returned %#x, expected %#x\n", hr, D3D_OK); if(SUCCEEDED(hr)) { DWORD ret, levels; TEXTMETRICW tm; @@ -597,8 +595,8 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) { texture = (IDirect3DTexture9*)0xdeadbeef; hr = ID3DXFont_GetGlyphData(font, glyph, &texture, &blackbox, &cellinc); - todo_wine ok(hr == D3D_OK, "ID3DXFont_GetGlyphData returned %#x, expected %#x\n", hr, D3D_OK); - todo_wine ok(!texture, "Got unexpected texture\n"); + ok(hr == D3D_OK, "ID3DXFont_GetGlyphData returned %#x, expected %#x\n", hr, D3D_OK); + ok(!texture, "Got unexpected texture\n"); }
check_release((IUnknown*)font, 0); @@ -626,12 +624,13 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) ok(ret != GDI_ERROR, "GetGlyphIndicesA failed\n");
hr = ID3DXFont_GetGlyphData(font, glyph, &texture, NULL, NULL); - todo_wine ok(hr == D3D_OK, "ID3DXFont_GetGlyphData returned %#x, expected %#x\n", hr, D3D_OK); + ok(hr == D3D_OK, "ID3DXFont_GetGlyphData returned %#x, expected %#x\n", hr, D3D_OK); if(SUCCEEDED(hr)) { DWORD levels; D3DSURFACE_DESC desc;
levels = IDirect3DTexture9_GetLevelCount(texture); + todo_wine_if(tests[i].expected_levels < 9) ok(levels == tests[i].expected_levels, "Got levels %u, expected %u\n", levels, tests[i].expected_levels); hr = IDirect3DTexture9_GetLevelDesc(texture, 0, &desc);
On Mon, Jan 6, 2020 at 3:35 PM Sven Baars sbaars@codeweavers.com wrote:
Based on a patch by Tony Wasserka.
Signed-off-by: Sven Baars sbaars@codeweavers.com
dlls/d3dx9_36/font.c | 64 ++++++++++++++++++++++++++++++++++++-- dlls/d3dx9_36/tests/core.c | 11 +++---- 2 files changed, 66 insertions(+), 9 deletions(-)
diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c index fe645a51c0..e204ca3012 100644 --- a/dlls/d3dx9_36/font.c +++ b/dlls/d3dx9_36/font.c @@ -166,12 +166,70 @@ static HDC WINAPI ID3DXFontImpl_GetDC(ID3DXFont *iface) return This->hdc; }
+/************************************************************
- ID3DXFont_GetGlyphData
- Returns the internally stored texture and some info about
- the position of the requested glyph on that texture
- PARAMS
- glyph [I] glyph
- texture [O] length of the string
- blackbox [O] smallest rectangle that completely encloses the glyph on the texture
- cellinc [O] offset from the baseline to the bottom of the glyph
- RETURNS
- Success: D3D_OK
- Failure: D3DERR_INVALIDCALL
D3DXERR_INVALIDDATA
- NOTES
- Glyphs which are passed to this function get preloaded, too
- */
static HRESULT WINAPI ID3DXFontImpl_GetGlyphData(ID3DXFont *iface, UINT glyph, IDirect3DTexture9 **texture, RECT *blackbox, POINT *cellinc) {
- FIXME("iface %p, glyph %#x, texture %p, blackbox %p, cellinc %p stub!\n",
iface, glyph, texture, blackbox, cellinc);
- return E_NOTIMPL;
- struct d3dx_font *This = impl_from_ID3DXFont(iface);
- HRESULT hr;
- int i;
- TRACE("iface %p, glyph %#x, texture %p, blackbox %p, cellinc %p\n",
iface, glyph, texture, blackbox, cellinc);
Please leave a blank line between variable declarations and the first statement.
- for (i = 0; i < This->glyph_count; i++)
if (This->glyphs[i].id == glyph)
{
if (cellinc)
*cellinc = This->glyphs[i].cellinc;
if (blackbox)
*blackbox = This->glyphs[i].blackbox;
if (texture)
*texture = This->glyphs[i].texture;
if (texture && *texture)
IDirect3DTexture9_AddRef(This->glyphs[i].texture);
return D3D_OK;
}
- hr = ID3DXFont_PreloadGlyphs(iface, glyph, glyph);
- if (FAILED(hr))
return hr;
- /* Try again */
- for (i = 0; i < This->glyph_count; i++)
if (This->glyphs[i].id == glyph)
{
if (cellinc)
*cellinc = This->glyphs[i].cellinc;
if (blackbox)
*blackbox = This->glyphs[i].blackbox;
if (texture)
*texture = This->glyphs[i].texture;
if (texture && *texture)
IDirect3DTexture9_AddRef(This->glyphs[i].texture);
return D3D_OK;
}
A couple of things. Is this "try once, if not found try again" justified by tests? Otherwise it seems easier to call PreloadGlyphs() unconditionally (i.e. get rid of the first loop). The other one is: given that looking up glyphs is going to be a frequent operation, linearly searching an array every time isn't going to be ideal. We probably want to use the RB tree from include/wine/rbtree.h for storing the glyphs.
On 22-01-2020 17:12, Matteo Bruni wrote:
On Mon, Jan 6, 2020 at 3:35 PM Sven Baars sbaars@codeweavers.com wrote:
- for (i = 0; i < This->glyph_count; i++)
if (This->glyphs[i].id == glyph)
{
if (cellinc)
*cellinc = This->glyphs[i].cellinc;
if (blackbox)
*blackbox = This->glyphs[i].blackbox;
if (texture)
*texture = This->glyphs[i].texture;
if (texture && *texture)
IDirect3DTexture9_AddRef(This->glyphs[i].texture);
return D3D_OK;
}
- hr = ID3DXFont_PreloadGlyphs(iface, glyph, glyph);
- if (FAILED(hr))
return hr;
- /* Try again */
- for (i = 0; i < This->glyph_count; i++)
if (This->glyphs[i].id == glyph)
{
if (cellinc)
*cellinc = This->glyphs[i].cellinc;
if (blackbox)
*blackbox = This->glyphs[i].blackbox;
if (texture)
*texture = This->glyphs[i].texture;
if (texture && *texture)
IDirect3DTexture9_AddRef(This->glyphs[i].texture);
return D3D_OK;
}
A couple of things. Is this "try once, if not found try again" justified by tests? Otherwise it seems easier to call PreloadGlyphs() unconditionally (i.e. get rid of the first loop). The other one is: given that looking up glyphs is going to be a frequent operation, linearly searching an array every time isn't going to be ideal. We probably want to use the RB tree from include/wine/rbtree.h for storing the glyphs.
Hi Matteo,
I implemented this with an RB tree, and after that tested it with and without the first lookup. With the first lookup my test program has about 25% more FPS. This is (partially) because it also has to do a lookup in PreloadGlyphs to see if it's already present. So removing the first lookup makes it always preform the lookup twice. I could implement a helper function for the for loop in PreloadGlyphs that returns the glyph if you like that better. Should I do that?
Cheers, Sven
On Mon, Jan 27, 2020 at 4:59 PM Sven Baars sbaars@codeweavers.com wrote:
On 22-01-2020 17:12, Matteo Bruni wrote:
On Mon, Jan 6, 2020 at 3:35 PM Sven Baars sbaars@codeweavers.com wrote:
- for (i = 0; i < This->glyph_count; i++)
if (This->glyphs[i].id == glyph)
{
if (cellinc)
*cellinc = This->glyphs[i].cellinc;
if (blackbox)
*blackbox = This->glyphs[i].blackbox;
if (texture)
*texture = This->glyphs[i].texture;
if (texture && *texture)
IDirect3DTexture9_AddRef(This->glyphs[i].texture);
return D3D_OK;
}
- hr = ID3DXFont_PreloadGlyphs(iface, glyph, glyph);
- if (FAILED(hr))
return hr;
- /* Try again */
- for (i = 0; i < This->glyph_count; i++)
if (This->glyphs[i].id == glyph)
{
if (cellinc)
*cellinc = This->glyphs[i].cellinc;
if (blackbox)
*blackbox = This->glyphs[i].blackbox;
if (texture)
*texture = This->glyphs[i].texture;
if (texture && *texture)
IDirect3DTexture9_AddRef(This->glyphs[i].texture);
return D3D_OK;
}
A couple of things. Is this "try once, if not found try again" justified by tests? Otherwise it seems easier to call PreloadGlyphs() unconditionally (i.e. get rid of the first loop). The other one is: given that looking up glyphs is going to be a frequent operation, linearly searching an array every time isn't going to be ideal. We probably want to use the RB tree from include/wine/rbtree.h for storing the glyphs.
Hi Matteo,
I implemented this with an RB tree, and after that tested it with and without the first lookup. With the first lookup my test program has about 25% more FPS. This is (partially) because it also has to do a lookup in PreloadGlyphs to see if it's already present. So removing the first lookup makes it always preform the lookup twice. I could implement a helper function for the for loop in PreloadGlyphs that returns the glyph if you like that better. Should I do that?
Which for loop you mean, the for-each-glyph one? My guess was that individual glyph lookups become essentially negligible once switching to the RB tree, is that not the case? Otherwise the only other thing that might make a difference is the call to GetTextMetricsW. I think it makes sense to either move it in the code path where it's actually needed (i.e. when inserting new glyphs) or even just cache it in the font object at creation time.
Based on a patch by Tony Wasserka.
Signed-off-by: Sven Baars sbaars@codeweavers.com --- dlls/d3dx9_36/font.c | 52 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-)
diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c index e204ca3012..e7e4f33d2c 100644 --- a/dlls/d3dx9_36/font.c +++ b/dlls/d3dx9_36/font.c @@ -232,10 +232,58 @@ static HRESULT WINAPI ID3DXFontImpl_GetGlyphData(ID3DXFont *iface, UINT glyph, return D3DXERR_INVALIDDATA; }
+/************************************************************ + * ID3DXFont_PreloadCharacters + * + * Preloads the specified character series into the internal texture + * + * PARAMS + * first [I] first character to be preloaded + * last [I] last character to be preloaded + * + * RETURNS + * Success: D3D_OK + * Failure: D3DERR_INVALIDCALL + * + * NOTES + * We just split each character into its glyphs and call PreloadGlyphs here. + * + */ static HRESULT WINAPI ID3DXFontImpl_PreloadCharacters(ID3DXFont *iface, UINT first, UINT last) { - FIXME("iface %p, first %u, last %u stub!\n", iface, first, last); - return S_OK; + struct d3dx_font *This = impl_from_ID3DXFont(iface); + UINT i, count; + WCHAR *chars; + WORD *indices; + + TRACE("iface %p, first %u, last %u\n", iface, first, last); + + if (last < first) return D3D_OK; + + count = last - first + 1; + indices = heap_alloc(count * sizeof(WORD)); + if (!indices) + return E_OUTOFMEMORY; + + chars = heap_alloc(count * sizeof(WCHAR)); + if (!chars) + { + heap_free(indices); + return E_OUTOFMEMORY; + } + + for (i = 0; i < count; i++) + chars[i] = (WCHAR)(first + i); + + GetGlyphIndicesW(This->hdc, chars, count, indices, 0); + + for (i = 0; i < count; i++) + ID3DXFont_PreloadGlyphs(iface, indices[i], indices[i]); + + heap_free(chars); + heap_free(indices); + + return D3D_OK; }
/************************************************************
Based on a patch by Tony Wasserka.
Signed-off-by: Sven Baars sbaars@codeweavers.com --- v2: Fix MultiByteToWideChar usage.
dlls/d3dx9_36/font.c | 63 +++++++++++++++++++++++++++++++++++--- dlls/d3dx9_36/tests/core.c | 2 -- 2 files changed, 59 insertions(+), 6 deletions(-)
diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c index e7e4f33d2c..3742bd7006 100644 --- a/dlls/d3dx9_36/font.c +++ b/dlls/d3dx9_36/font.c @@ -446,16 +446,71 @@ static HRESULT WINAPI ID3DXFontImpl_PreloadGlyphs(ID3DXFont *iface, UINT first, return D3D_OK; }
+/************************************************************ + * ID3DXFont_PreloadText + * + * Preloads a string into the internal texture + * + * PARAMS + * string [I] string to be preloaded + * count [I] length of the string + * + * RETURNS + * Success: D3D_OK, if we successfully preload the text or + * if string and count are NULL + * Failure: D3DERR_INVALIDCALL, if string is NULL and count is not 0 + * + */ static HRESULT WINAPI ID3DXFontImpl_PreloadTextA(ID3DXFont *iface, const char *string, INT count) { - FIXME("iface %p, string %s, count %d stub!\n", iface, debugstr_a(string), count); - return E_NOTIMPL; + + WCHAR *wstr; + HRESULT hr; + INT countW; + TRACE("iface %p, string %s, count %d\n", iface, debugstr_a(string), count); + + if (!string && count == 0) return D3D_OK; + if (!string) return D3DERR_INVALIDCALL; + + countW = MultiByteToWideChar(CP_ACP, 0, string, count < 0 ? -1 : count, NULL, 0); + + wstr = heap_alloc(countW * sizeof(WCHAR)); + if (!wstr) + return E_OUTOFMEMORY; + + MultiByteToWideChar(CP_ACP, 0, string, count < 0 ? -1 : count, wstr, countW); + + hr = ID3DXFont_PreloadTextW(iface, wstr, count); + + heap_free(wstr); + + return hr; }
static HRESULT WINAPI ID3DXFontImpl_PreloadTextW(ID3DXFont *iface, const WCHAR *string, INT count) { - FIXME("iface %p, string %s, count %d stub!\n", iface, debugstr_w(string), count); - return E_NOTIMPL; + struct d3dx_font *This = impl_from_ID3DXFont(iface); + UINT i; + WORD *indices; + + TRACE("iface %p, string %s, count %d\n", iface, debugstr_w(string), count); + + if (!string && count == 0) return D3D_OK; + if (!string) return D3DERR_INVALIDCALL; + if (count < 0) count = lstrlenW(string); + + indices = heap_alloc(count * sizeof(WORD)); + if (!indices) + return E_OUTOFMEMORY; + + GetGlyphIndicesW(This->hdc, string, count, indices, 0); + + for (i = 0; i < count; i++) + ID3DXFont_PreloadGlyphs(iface, indices[i], indices[i]); + + heap_free(indices); + + return D3D_OK; }
static INT WINAPI ID3DXFontImpl_DrawTextA(ID3DXFont *iface, ID3DXSprite *sprite, diff --git a/dlls/d3dx9_36/tests/core.c b/dlls/d3dx9_36/tests/core.c index 4ec591e631..b96df47de5 100644 --- a/dlls/d3dx9_36/tests/core.c +++ b/dlls/d3dx9_36/tests/core.c @@ -479,7 +479,6 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) /* ID3DXFont_PreloadText */ hr = D3DXCreateFontA(device, 12, 0, FW_DONTCARE, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Tahoma", &font); if(SUCCEEDED(hr)) { - todo_wine { hr = ID3DXFont_PreloadTextA(font, NULL, -1); ok(hr == D3DERR_INVALIDCALL, "ID3DXFont_PreloadTextA returned %#x, expected %#x\n", hr, D3DERR_INVALIDCALL); hr = ID3DXFont_PreloadTextA(font, NULL, 0); @@ -505,7 +504,6 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) ok(hr == D3D_OK, "ID3DXFont_PreloadTextW returned %#x, expected %#x\n", hr, D3D_OK); hr = ID3DXFont_PreloadTextW(font, emptyW, -1); ok(hr == D3D_OK, "ID3DXFont_PreloadTextW returned %#x, expected %#x\n", hr, D3D_OK); - }
check_release((IUnknown*)font, 0); } else skip("Failed to create a ID3DXFont object\n");
Based on a patch by Tony Wasserka.
Signed-off-by: Sven Baars sbaars@codeweavers.com --- v2: Fix MultiByteToWideChar usage.
dlls/d3dx9_24/Makefile.in | 2 +- dlls/d3dx9_25/Makefile.in | 2 +- dlls/d3dx9_26/Makefile.in | 2 +- dlls/d3dx9_27/Makefile.in | 2 +- dlls/d3dx9_28/Makefile.in | 2 +- dlls/d3dx9_29/Makefile.in | 2 +- dlls/d3dx9_30/Makefile.in | 2 +- dlls/d3dx9_31/Makefile.in | 2 +- dlls/d3dx9_32/Makefile.in | 2 +- dlls/d3dx9_33/Makefile.in | 2 +- dlls/d3dx9_34/Makefile.in | 2 +- dlls/d3dx9_35/Makefile.in | 2 +- dlls/d3dx9_36/Makefile.in | 2 +- dlls/d3dx9_36/font.c | 391 ++++++++++++++++++++++++++++++++++++- dlls/d3dx9_36/tests/core.c | 15 +- dlls/d3dx9_37/Makefile.in | 2 +- dlls/d3dx9_38/Makefile.in | 2 +- dlls/d3dx9_39/Makefile.in | 2 +- dlls/d3dx9_40/Makefile.in | 2 +- dlls/d3dx9_41/Makefile.in | 2 +- dlls/d3dx9_42/Makefile.in | 2 +- dlls/d3dx9_43/Makefile.in | 2 +- 22 files changed, 410 insertions(+), 36 deletions(-)
diff --git a/dlls/d3dx9_24/Makefile.in b/dlls/d3dx9_24/Makefile.in index faad4c49ac..f80541a9aa 100644 --- a/dlls/d3dx9_24/Makefile.in +++ b/dlls/d3dx9_24/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=24 MODULE = d3dx9_24.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase PARENTSRC = ../d3dx9_36 -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/d3dx9_25/Makefile.in b/dlls/d3dx9_25/Makefile.in index 292b33db2b..e3144f0d45 100644 --- a/dlls/d3dx9_25/Makefile.in +++ b/dlls/d3dx9_25/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=25 MODULE = d3dx9_25.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase PARENTSRC = ../d3dx9_36 -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/d3dx9_26/Makefile.in b/dlls/d3dx9_26/Makefile.in index 22bb54a498..1b432afb21 100644 --- a/dlls/d3dx9_26/Makefile.in +++ b/dlls/d3dx9_26/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=26 MODULE = d3dx9_26.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase PARENTSRC = ../d3dx9_36 -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/d3dx9_27/Makefile.in b/dlls/d3dx9_27/Makefile.in index 4ed104a170..65d8cad9d6 100644 --- a/dlls/d3dx9_27/Makefile.in +++ b/dlls/d3dx9_27/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=27 MODULE = d3dx9_27.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase PARENTSRC = ../d3dx9_36 -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/d3dx9_28/Makefile.in b/dlls/d3dx9_28/Makefile.in index 94e059ae9d..ff7ba564c1 100644 --- a/dlls/d3dx9_28/Makefile.in +++ b/dlls/d3dx9_28/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=28 MODULE = d3dx9_28.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase PARENTSRC = ../d3dx9_36 -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/d3dx9_29/Makefile.in b/dlls/d3dx9_29/Makefile.in index 94b39aee37..7e53415c43 100644 --- a/dlls/d3dx9_29/Makefile.in +++ b/dlls/d3dx9_29/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=29 MODULE = d3dx9_29.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase PARENTSRC = ../d3dx9_36 -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/d3dx9_30/Makefile.in b/dlls/d3dx9_30/Makefile.in index 6beadbc47e..9bc955753f 100644 --- a/dlls/d3dx9_30/Makefile.in +++ b/dlls/d3dx9_30/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=30 MODULE = d3dx9_30.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase PARENTSRC = ../d3dx9_36 -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/d3dx9_31/Makefile.in b/dlls/d3dx9_31/Makefile.in index b73f32872c..58b72c527c 100644 --- a/dlls/d3dx9_31/Makefile.in +++ b/dlls/d3dx9_31/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=31 MODULE = d3dx9_31.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase PARENTSRC = ../d3dx9_36 -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/d3dx9_32/Makefile.in b/dlls/d3dx9_32/Makefile.in index 50bc9d0e26..88cc083bbe 100644 --- a/dlls/d3dx9_32/Makefile.in +++ b/dlls/d3dx9_32/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=32 MODULE = d3dx9_32.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase PARENTSRC = ../d3dx9_36 -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/d3dx9_33/Makefile.in b/dlls/d3dx9_33/Makefile.in index 7be34e1d4b..f6de942ed8 100644 --- a/dlls/d3dx9_33/Makefile.in +++ b/dlls/d3dx9_33/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=33 MODULE = d3dx9_33.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase PARENTSRC = ../d3dx9_36 -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/d3dx9_34/Makefile.in b/dlls/d3dx9_34/Makefile.in index 248735a531..5d0bc9b3a4 100644 --- a/dlls/d3dx9_34/Makefile.in +++ b/dlls/d3dx9_34/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=34 MODULE = d3dx9_34.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase PARENTSRC = ../d3dx9_36 -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/d3dx9_35/Makefile.in b/dlls/d3dx9_35/Makefile.in index 01c809dab2..5eb00327c1 100644 --- a/dlls/d3dx9_35/Makefile.in +++ b/dlls/d3dx9_35/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=35 MODULE = d3dx9_35.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase PARENTSRC = ../d3dx9_36 -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/d3dx9_36/Makefile.in b/dlls/d3dx9_36/Makefile.in index 825e5ddfbc..6a08c41159 100644 --- a/dlls/d3dx9_36/Makefile.in +++ b/dlls/d3dx9_36/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=36 MODULE = d3dx9_36.dll IMPORTLIB = d3dx9 IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c index 3742bd7006..b1c940c316 100644 --- a/dlls/d3dx9_36/font.c +++ b/dlls/d3dx9_36/font.c @@ -20,6 +20,10 @@
#include "d3dx9_private.h"
+#include <assert.h> + +#include "usp10.h" + WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
typedef struct _GLYPH @@ -513,20 +517,395 @@ static HRESULT WINAPI ID3DXFontImpl_PreloadTextW(ID3DXFont *iface, const WCHAR * return D3D_OK; }
+/************************************************************ + * ID3DXFont_DrawText + * + * Renders the specified string to the screen + * + * PARAMS + * sprite [I] sprite object used to draw the text + * string [I] string to be drawn + * count [I] length of the string + * rect [I,O] rect which tells us where to draw the string, + * which can be computed by passing DT_CALCRECT + * format [I] format of the string + * color [I] text color + * + * RETURNS + * The height of the drawn text + * + */ static INT WINAPI ID3DXFontImpl_DrawTextA(ID3DXFont *iface, ID3DXSprite *sprite, const char *string, INT count, RECT *rect, DWORD format, D3DCOLOR color) { - FIXME("iface %p, sprite %p, string %s, count %d, rect %s, format %#x, color 0x%08x stub!\n", - iface, sprite, debugstr_a(string), count, wine_dbgstr_rect(rect), format, color); - return 1; + WCHAR *wstr; + INT ret, countW; + + TRACE("iface %p, sprite %p, string %s, count %d, rect %s, format %#x, color 0x%08x\n", + iface, sprite, debugstr_a(string), count, wine_dbgstr_rect(rect), format, color); + + if (!string || count == 0) + return 0; + + countW = MultiByteToWideChar(CP_ACP, 0, string, count < 0 ? -1 : count, NULL, 0); + + if (countW == 0) + return 0; + + wstr = heap_alloc_zero(countW * sizeof(WCHAR)); + if (!wstr) + return 0; + + MultiByteToWideChar(CP_ACP, 0, string, count < 0 ? -1 : count, wstr, countW); + + ret = ID3DXFont_DrawTextW(iface, sprite, wstr, count, rect, format, color); + + heap_free(wstr); + + return ret; +} + +/* DrawText helpers copied from user32 */ +#define TAB 9 +#define LF 10 +#define CR 13 +#define SPACE 32 +static void TEXT_WordBreak(HDC hdc, WCHAR *str, unsigned int max_str, + unsigned int *len_str, + int width, int format, unsigned int chars_fit, + unsigned int *chars_used, SIZE *size) +{ + WCHAR *p; + BOOL word_fits; + SCRIPT_LOGATTR *sla; + SCRIPT_ANALYSIS sa; + int i; + + assert(format & DT_WORDBREAK); + assert(chars_fit < *len_str); + + sla = heap_alloc(sizeof(SCRIPT_LOGATTR) * *len_str); + + memset(&sa, 0, sizeof(SCRIPT_ANALYSIS)); + sa.eScript = SCRIPT_UNDEFINED; + + ScriptBreak(str, *len_str, &sa, sla); + + /* Work back from the last character that did fit to either a space or the + * last character of a word, whichever is met first. + */ + p = str + chars_fit; /* The character that doesn't fit */ + i = chars_fit; + word_fits = TRUE; + if (!chars_fit) + word_fits = FALSE; + else if (sla[i].fSoftBreak) /* chars_fit < *len_str so this is valid */ + { + /* the word just fitted */ + p--; + } + else + { + while (i > 0 && !sla[(--i)+1].fSoftBreak) p--; + p--; + word_fits = (i != 0 || sla[i+1].fSoftBreak); + } + + /* If there was one. */ + if (word_fits) + { + BOOL next_is_space; + /* break the line before/after that character */ + if (!(format & (DT_RIGHT | DT_CENTER)) || *p != SPACE) + p++; + next_is_space = (p - str) < *len_str && *p == SPACE; + *len_str = p - str; + /* and if the next character is a space then discard it. */ + *chars_used = *len_str; + if (next_is_space) + (*chars_used)++; + } + /* Suppose there was none. */ + else + { + /* discard any trailing space. */ + const WCHAR *e = str + *len_str; + p = str + chars_fit; + while (p < e && *p != SPACE) + p++; + *chars_used = p - str; + if (p < e) /* i.e. loop failed because *p == SPACE */ + (*chars_used)++; + *len_str = p - str; + } + /* Remeasure the string */ + GetTextExtentExPointW(hdc, str, *len_str, 0, NULL, NULL, size); + heap_free(sla); +} + +static const WCHAR *TEXT_NextLineW(HDC hdc, const WCHAR *str, int *count, + WCHAR *dest, int *len, int width, DWORD format, + SIZE *retsize, int last_line, int tabwidth) +{ + int i = 0, j = 0; + int plen = 0; + SIZE size; + int maxl = *len; + int seg_i, seg_count, seg_j; + int max_seg_width; + int num_fit; + BOOL word_broken, line_fits; + unsigned int j_in_seg; + + /* For each text segment in the line */ + + retsize->cy = 0; + while (*count) + { + + /* Skip any leading tabs */ + + if (str[i] == TAB && (format & DT_EXPANDTABS)) + { + plen = ((plen/tabwidth)+1)*tabwidth; + (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++; + while (*count && str[i] == TAB) + { + plen += tabwidth; + (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++; + } + } + + + /* Now copy as far as the next tab or cr/lf or eos */ + + seg_i = i; + seg_count = *count; + seg_j = j; + + while (*count && (str[i] != TAB || !(format & DT_EXPANDTABS)) && ((str[i] != CR && str[i] != LF) || (format & DT_SINGLELINE))) + { + (*count)--; + if (j < maxl) dest[j++] = str[i]; + i++; + } + + /* Measure the whole text segment and possibly WordBreak */ + + j_in_seg = j - seg_j; + max_seg_width = width - plen; + GetTextExtentExPointW(hdc, dest + seg_j, j_in_seg, max_seg_width, &num_fit, NULL, &size); + + /* The Microsoft handling of various combinations of formats is weird. + * The following may very easily be incorrect if several formats are + * combined, and may differ between versions (to say nothing of the + * several bugs in the Microsoft versions). + */ + word_broken = FALSE; + line_fits = (num_fit >= j_in_seg); + if (!line_fits && (format & DT_WORDBREAK)) + { + const WCHAR *s; + unsigned int chars_used; + TEXT_WordBreak(hdc, dest+seg_j, maxl-seg_j, &j_in_seg, + max_seg_width, format, num_fit, &chars_used, &size); + line_fits = (size.cx <= max_seg_width); + /* and correct the counts */ + *count = seg_count - chars_used; + s = str + seg_i + chars_used; + i = s - str; + word_broken = TRUE; + } + + j = seg_j + j_in_seg; + + plen += size.cx; + if (size.cy > retsize->cy) + retsize->cy = size.cy; + + if (word_broken) + break; + else if (!*count) + break; + else if (str[i] == CR || str[i] == LF) + { + (*count)--, i++; + if (*count && (str[i] == CR || str[i] == LF) && str[i] != str[i-1]) + { + (*count)--, i++; + } + break; + } + /* else it was a Tab and we go around again */ + } + + retsize->cx = plen; + *len = j; + if (*count) + return (&str[i]); + else + return NULL; }
+#define MAX_BUFFER 1024 static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, const WCHAR *string, INT count, RECT *rect, DWORD format, D3DCOLOR color) { - FIXME("iface %p, sprite %p, string %s, count %d, rect %s, format %#x, color 0x%08x stub!\n", - iface, sprite, debugstr_w(string), count, wine_dbgstr_rect(rect), format, color); - return 1; + struct d3dx_font *This = impl_from_ID3DXFont(iface); + ID3DXSprite *target = sprite; + + const WCHAR *strPtr; + WCHAR line[MAX_BUFFER]; + int lh; + TEXTMETRICW tm; + int x, y; + int width; + int max_width = 0; + int last_line; + int tabwidth = 0; + RECT textrect = {0}; + + TRACE("iface %p, sprite %p, string %s, count %d, rect %s, format %#x, color 0x%08x\n", + iface, sprite, debugstr_w(string), count, wine_dbgstr_rect(rect), format, color); + + if (!string) + return 0; + + if (count < 0) + count = lstrlenW(string); + + if (count == 0) + return 0; + + if (format & DT_SINGLELINE) + format &= ~DT_WORDBREAK; + if (format & DT_CALCRECT) + format |= DT_NOCLIP; + + if (!rect) + { + y = ID3DXFont_DrawTextW(iface, NULL, string, count, &textrect, format | DT_CALCRECT, 0); + + if (format & DT_CALCRECT) + return y; + } + else + textrect = *rect; + + x = textrect.left; + y = textrect.top; + width = textrect.right - textrect.left; + strPtr = string; + + ID3DXFont_GetTextMetricsW(iface, &tm); + lh = tm.tmHeight; + + if (format & DT_EXPANDTABS) + tabwidth = tm.tmAveCharWidth * 8; + + if (!(format & DT_CALCRECT) && !sprite) + { + D3DXCreateSprite(This->device, &target); + ID3DXSprite_Begin(target, 0); + } + + do { + SIZE size; + int len = ARRAY_SIZE(line); + + last_line = !(format & DT_NOCLIP) && (y + lh > textrect.bottom); + strPtr = TEXT_NextLineW(This->hdc, strPtr, &count, line, &len, width, format, &size, last_line, tabwidth); + + if (format & DT_CENTER) + x = (textrect.left + textrect.right - size.cx) / 2; + else if (format & DT_RIGHT) + x = textrect.right - size.cx; + + if (format & DT_SINGLELINE) + { + if (format & DT_VCENTER) + y = textrect.top + (textrect.bottom - textrect.top) / 2 - size.cy / 2; + else if (format & DT_BOTTOM) + y = textrect.bottom - size.cy; + } + + if (!(format & DT_CALCRECT)) + { + int xseg = x; + const WCHAR *str = line; + + while (len) + { + int len_seg; + GCP_RESULTSW results; + D3DXVECTOR3 pos; + UINT i; + + if ((format & DT_EXPANDTABS)) + { + const WCHAR *p; + p = str; while (p < str+len && *p != TAB) p++; + len_seg = p - str; + if (len_seg != len && !GetTextExtentPointW(This->hdc, str, len_seg, &size)) + return 0; + } + else + len_seg = len; + + ZeroMemory(&results, sizeof(GCP_RESULTSW)); + results.lpCaretPos = heap_alloc(len_seg * sizeof(INT)); + results.lpGlyphs = heap_alloc(len_seg * sizeof(WORD)); + results.nGlyphs = len_seg; + + GetCharacterPlacementW(This->hdc, str, len_seg, 0, &results, 0); + + for (i = 0; i < results.nGlyphs; i++) + { + LPDIRECT3DTEXTURE9 tex; + RECT bbox; + POINT cinc; + + ID3DXFont_GetGlyphData(iface, results.lpGlyphs[i], &tex, &bbox, &cinc); + + if (!tex) + continue; + + pos.x = results.lpCaretPos[i] + cinc.x + xseg; + pos.y = cinc.y + y; + + ID3DXSprite_Draw(target, tex, &bbox, NULL, &pos, color); + IDirect3DTexture9_Release(tex); + } + + len -= len_seg; + str += len_seg; + if (len) + { + assert((format & DT_EXPANDTABS) && *str == TAB); + len--; str++; + xseg += ((size.cx/tabwidth)+1)*tabwidth; + } + } + } + else if (size.cx > max_width) + max_width = size.cx; + + y += lh; + } while (strPtr && !last_line); + + textrect.right = textrect.left + max_width; + textrect.bottom = y; + + if ((format & DT_CALCRECT) && rect) + *rect = textrect; + + if (target != sprite) + { + ID3DXSprite_End(target); + ID3DXSprite_Release(target); + } + + return y - textrect.top; }
static HRESULT WINAPI ID3DXFontImpl_OnLostDevice(ID3DXFont *iface) diff --git a/dlls/d3dx9_36/tests/core.c b/dlls/d3dx9_36/tests/core.c index b96df47de5..c3527d655d 100644 --- a/dlls/d3dx9_36/tests/core.c +++ b/dlls/d3dx9_36/tests/core.c @@ -654,8 +654,6 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) hr = ID3DXSprite_Begin(sprite, D3DXSPRITE_ALPHABLEND); ok (hr == D3D_OK, "Got unexpected hr %#x.\n", hr);
- todo_wine - { height = ID3DXFont_DrawTextW(font, sprite, testW, -1, &rect, DT_TOP, 0xffffffff); ok(height == tests[i].font_height, "Got height %u, expected %u.\n", height, tests[i].font_height); height = ID3DXFont_DrawTextW(font, sprite, testW, size, &rect, DT_TOP, 0xffffffff); @@ -665,16 +663,15 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) height = ID3DXFont_DrawTextW(font, sprite, testW, size, &rect, DT_LEFT | DT_NOCLIP, 0xffffffff); ok(height == tests[i].font_height, "Got height %u, expected %u.\n", height, tests[i].font_height); - }
SetRectEmpty(&rect); height = ID3DXFont_DrawTextW(font, sprite, testW, size, &rect, DT_LEFT | DT_CALCRECT, 0xffffffff); - todo_wine ok(height == tests[i].font_height, "Got height %u, expected %u.\n", height, tests[i].font_height); + ok(height == tests[i].font_height, "Got height %u, expected %u.\n", height, tests[i].font_height); ok(!rect.left, "Got unexpected rect left %d.\n", rect.left); ok(!rect.top, "Got unexpected rect top %d.\n", rect.top); - todo_wine ok(rect.right, "Got unexpected rect right %d.\n", rect.right); - todo_wine ok(rect.bottom == tests[i].font_height, "Got unexpected rect bottom %d.\n", rect.bottom); + ok(rect.right, "Got unexpected rect right %d.\n", rect.right); + ok(rect.bottom == tests[i].font_height, "Got unexpected rect bottom %d.\n", rect.bottom);
hr = ID3DXSprite_End(sprite); ok (hr == D3D_OK, "Got unexpected hr %#x.\n", hr); @@ -690,7 +687,6 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) RECT rect; int height;
- todo_wine { SetRect(&rect, 10, 10, 200, 200);
height = ID3DXFont_DrawTextA(font, NULL, "test", -2, &rect, 0, 0xFF00FF); @@ -726,7 +722,7 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) SetRect(&rect, 10, 10, 50, 50);
height = ID3DXFont_DrawTextA(font, NULL, longText, -1, &rect, DT_WORDBREAK, 0xFF00FF); - ok(height == 60, "DrawTextA returned %d, expected 60.\n", height); + todo_wine ok(height == 60, "DrawTextA returned %d, expected 60.\n", height);
height = ID3DXFont_DrawTextA(font, NULL, longText, -1, &rect, DT_WORDBREAK | DT_NOCLIP, 0xFF00FF); ok(height == 96, "DrawTextA returned %d, expected 96.\n", height); @@ -768,11 +764,10 @@ if (0) { /* Causes a lockup on Windows 7+ */ SetRect(&rect, 10, 10, 50, 50);
height = ID3DXFont_DrawTextW(font, NULL, longTextW, -1, &rect, DT_WORDBREAK, 0xFF00FF); - ok(height == 60, "DrawTextW returned %d, expected 60.\n", height); + todo_wine ok(height == 60, "DrawTextW returned %d, expected 60.\n", height);
height = ID3DXFont_DrawTextW(font, NULL, longTextW, -1, &rect, DT_WORDBREAK | DT_NOCLIP, 0xFF00FF); ok(height == 96, "DrawTextW returned %d, expected 96.\n", height); - }
ID3DXFont_Release(font); } diff --git a/dlls/d3dx9_37/Makefile.in b/dlls/d3dx9_37/Makefile.in index a0896df82e..b9dda315f2 100644 --- a/dlls/d3dx9_37/Makefile.in +++ b/dlls/d3dx9_37/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=37 MODULE = d3dx9_37.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase PARENTSRC = ../d3dx9_36 -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/d3dx9_38/Makefile.in b/dlls/d3dx9_38/Makefile.in index 24bbc3f0cf..adeb4f245a 100644 --- a/dlls/d3dx9_38/Makefile.in +++ b/dlls/d3dx9_38/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=38 MODULE = d3dx9_38.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase PARENTSRC = ../d3dx9_36 -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/d3dx9_39/Makefile.in b/dlls/d3dx9_39/Makefile.in index a3f7626f33..0e210488f6 100644 --- a/dlls/d3dx9_39/Makefile.in +++ b/dlls/d3dx9_39/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=39 MODULE = d3dx9_39.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase PARENTSRC = ../d3dx9_36 -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/d3dx9_40/Makefile.in b/dlls/d3dx9_40/Makefile.in index fbbcb0c04e..05349e4b40 100644 --- a/dlls/d3dx9_40/Makefile.in +++ b/dlls/d3dx9_40/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=40 MODULE = d3dx9_40.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase PARENTSRC = ../d3dx9_36 -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/d3dx9_41/Makefile.in b/dlls/d3dx9_41/Makefile.in index 9b44213117..587e94b7d1 100644 --- a/dlls/d3dx9_41/Makefile.in +++ b/dlls/d3dx9_41/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=41 MODULE = d3dx9_41.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase PARENTSRC = ../d3dx9_36 -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/d3dx9_42/Makefile.in b/dlls/d3dx9_42/Makefile.in index f725e87471..bb837c4e39 100644 --- a/dlls/d3dx9_42/Makefile.in +++ b/dlls/d3dx9_42/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=42 MODULE = d3dx9_42.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase PARENTSRC = ../d3dx9_36 -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
diff --git a/dlls/d3dx9_43/Makefile.in b/dlls/d3dx9_43/Makefile.in index dbebc51ad0..0701cde7b7 100644 --- a/dlls/d3dx9_43/Makefile.in +++ b/dlls/d3dx9_43/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -DD3DX_SDK_VERSION=43 MODULE = d3dx9_43.dll IMPORTS = d3d9 d3dcompiler dxguid d3dxof ole32 gdi32 user32 ucrtbase PARENTSRC = ../d3dx9_36 -DELAYIMPORTS = windowscodecs +DELAYIMPORTS = windowscodecs usp10
EXTRADLLFLAGS = -mno-cygwin
On Mon, Jan 6, 2020 at 3:36 PM Sven Baars sbaars@codeweavers.com wrote:
+/* DrawText helpers copied from user32 */ +#define TAB 9 +#define LF 10 +#define CR 13 +#define SPACE 32 +static void TEXT_WordBreak(HDC hdc, WCHAR *str, unsigned int max_str,
unsigned int *len_str,
int width, int format, unsigned int chars_fit,
unsigned int *chars_used, SIZE *size)
As I already mentioned in a private email a while back, I don't think copying whole chunks of user32 is going to be a good idea.
ID3DXFont's DrawText is supposed to be quite a bit simpler than the user32 counterpart. I imagine that it should be possible to reimplement the required features without carrying this much stuff over. Maybe Uniscribe can help more, I don't know the API (Nikolay?)
Either way, I'd initially introduce a simpler DrawText implementation (no line breaks, no word breaks, as bare-bones as possible) and then proceed to add features incrementally over a number of patches. That will also make the initial DrawText patch easier to review.
On 1/22/20 7:14 PM, Matteo Bruni wrote:
On Mon, Jan 6, 2020 at 3:36 PM Sven Baars sbaars@codeweavers.com wrote:
+/* DrawText helpers copied from user32 */ +#define TAB 9 +#define LF 10 +#define CR 13 +#define SPACE 32 +static void TEXT_WordBreak(HDC hdc, WCHAR *str, unsigned int max_str,
unsigned int *len_str,
int width, int format, unsigned int chars_fit,
unsigned int *chars_used, SIZE *size)
As I already mentioned in a private email a while back, I don't think copying whole chunks of user32 is going to be a good idea.
ID3DXFont's DrawText is supposed to be quite a bit simpler than the user32 counterpart. I imagine that it should be possible to reimplement the required features without carrying this much stuff over. Maybe Uniscribe can help more, I don't know the API (Nikolay?)
The reason it's exploded like that is because you need access to glyph sequence + positions at the end, to render from glyph-indexed cache. As far as I can tell it should at least support multiple lines.
Uniscribe is lower level, it won't do such layout for you, and that's why existing DrawText has line breaking logic, while using Uniscribe.
There is a way with minimal or potentially no duplication of formatting code - you can use regular DrawTextExW() enhanced metafile context. This will create a number of EXTTEXTOUT records that could be iterated over and rendered. Each record should contain glyph ids, and positions. This way you don't have to deal with formatting at all.
Either way, I'd initially introduce a simpler DrawText implementation (no line breaks, no word breaks, as bare-bones as possible) and then proceed to add features incrementally over a number of patches. That will also make the initial DrawText patch easier to review.