Signed-off-by: Sven Baars sbaars@codeweavers.com --- dlls/d3dx9_36/font.c | 170 +++++++++++++++++++++++-------------- dlls/d3dx9_36/tests/core.c | 152 ++++++++++++++++++++++++++++++++- 2 files changed, 257 insertions(+), 65 deletions(-)
diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c index 54b1574bb1..20757ae839 100644 --- a/dlls/d3dx9_36/font.c +++ b/dlls/d3dx9_36/font.c @@ -599,16 +599,56 @@ static const WCHAR *read_line(HDC hdc, const WCHAR *str, int *count, return NULL; }
+static int compute_rect(struct d3dx_font *font, const WCHAR *string, INT count, WCHAR *line, RECT *rect, DWORD format) +{ + int y, lh, width, top = rect->top; + int max_width = 0; + SIZE size; + + y = rect->top; + lh = font->metrics.tmHeight; + width = rect->right - rect->left; + + while (string) + { + unsigned int line_len; + + string = read_line(font->hdc, string, &count, line, &line_len, width, format, &size); + + if (size.cx > max_width) + max_width = size.cx; + + y += lh; + if (!(format & DT_NOCLIP) && (y > rect->bottom)) + break; + } + + rect->right = rect->left + max_width; + if (format & DT_VCENTER) + { + rect->top += (rect->bottom - y) / 2; + rect->bottom = rect->top + y - top; + } + else if (format & DT_BOTTOM) + { + rect->top += rect->bottom - y; + } + else + { + rect->bottom = y; + } + + return rect->bottom - top; +} + static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, const WCHAR *string, INT count, RECT *rect, DWORD format, D3DCOLOR color) { struct d3dx_font *font = impl_from_ID3DXFont(iface); + int lh, x, y, width, top, ret = 0; ID3DXSprite *target = sprite; + RECT r = {0}; WCHAR *line; - RECT textrect = {0}; - int lh, x, y, width; - int max_width = 0; - int ret = 0; SIZE size;
TRACE("iface %p, sprite %p, string %s, count %d, rect %s, format %#x, color 0x%08x.\n", @@ -629,20 +669,41 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, if (format & DT_SINGLELINE) format &= ~DT_WORDBREAK;
- if (rect) - textrect = *rect; - - x = textrect.left; - y = textrect.top; - width = textrect.right - textrect.left; - - lh = font->metrics.tmHeight; - line = heap_alloc(count * sizeof(*line)); if (!line) return 0;
- if (!(format & DT_CALCRECT) && !sprite) + if (!rect || format & (DT_CALCRECT | DT_VCENTER | DT_BOTTOM)) + { + if (!rect) + { + rect = &r; + format |= DT_NOCLIP; + } + else if (!(format & DT_CALCRECT)) + { + r = *rect; + rect = &r; + } + + top = rect->top; + + ret = compute_rect(font, string, count, line, rect, format); + + if (format & DT_CALCRECT) + goto cleanup; + } + else + { + top = rect->top; + } + + x = rect->left; + y = rect->top; + lh = font->metrics.tmHeight; + width = rect->right - rect->left; + + if (!sprite) { D3DXCreateSprite(font->device, &target); ID3DXSprite_Begin(target, 0); @@ -650,72 +711,55 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite,
while (string) { - unsigned int line_len; + unsigned int line_len, i; + GCP_RESULTSW results; + D3DXVECTOR3 pos;
string = read_line(font->hdc, string, &count, line, &line_len, width, format, &size);
- if (!(format & DT_CALCRECT)) - { - GCP_RESULTSW results; - D3DXVECTOR3 pos; - unsigned int i; - - memset(&results, 0, sizeof(results)); - results.nGlyphs = line_len; + memset(&results, 0, sizeof(results)); + results.nGlyphs = line_len;
- results.lpCaretPos = heap_alloc(line_len * sizeof(*results.lpCaretPos)); - if (!results.lpCaretPos) - goto cleanup; - - results.lpGlyphs = heap_alloc(line_len * sizeof(*results.lpGlyphs)); - if (!results.lpGlyphs) - { - heap_free(results.lpCaretPos); - goto cleanup; - } + results.lpCaretPos = heap_alloc(line_len * sizeof(*results.lpCaretPos)); + if (!results.lpCaretPos) + goto cleanup;
- GetCharacterPlacementW(font->hdc, line, line_len, 0, &results, 0); + results.lpGlyphs = heap_alloc(line_len * sizeof(*results.lpGlyphs)); + if (!results.lpGlyphs) + { + heap_free(results.lpCaretPos); + goto cleanup; + }
- for (i = 0; i < results.nGlyphs; ++i) - { - IDirect3DTexture9 *texture; - POINT cell_inc; - RECT black_box; + GetCharacterPlacementW(font->hdc, line, line_len, 0, &results, 0);
- ID3DXFont_GetGlyphData(iface, results.lpGlyphs[i], &texture, &black_box, &cell_inc); + for (i = 0; i < results.nGlyphs; ++i) + { + IDirect3DTexture9 *texture; + POINT cell_inc; + RECT black_box;
- if (!texture) - continue; + ID3DXFont_GetGlyphData(iface, results.lpGlyphs[i], &texture, &black_box, &cell_inc);
- pos.x = cell_inc.x + x + results.lpCaretPos[i]; - pos.y = cell_inc.y + y; + if (!texture) + continue;
- ID3DXSprite_Draw(target, texture, &black_box, NULL, &pos, color); - IDirect3DTexture9_Release(texture); - } + pos.x = cell_inc.x + x + results.lpCaretPos[i]; + pos.y = cell_inc.y + y;
- heap_free(results.lpCaretPos); - heap_free(results.lpGlyphs); - } - else if (size.cx > max_width) - { - max_width = size.cx; + ID3DXSprite_Draw(target, texture, &black_box, NULL, &pos, color); + IDirect3DTexture9_Release(texture); }
+ heap_free(results.lpCaretPos); + heap_free(results.lpGlyphs); + y += lh; - if (!(DT_NOCLIP & format) && (y > textrect.bottom)) + if (!(DT_NOCLIP & format) && (y > rect->bottom)) break; }
- if (format & DT_CALCRECT && rect) - { - *rect = textrect; - - rect->bottom = y; - rect->right = rect->left + max_width; - } - - ret = y - textrect.top; + ret = y - top;
cleanup: if (target != sprite) diff --git a/dlls/d3dx9_36/tests/core.c b/dlls/d3dx9_36/tests/core.c index fb55a547a0..9de91b2b08 100644 --- a/dlls/d3dx9_36/tests/core.c +++ b/dlls/d3dx9_36/tests/core.c @@ -770,6 +770,9 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) height = ID3DXFont_DrawTextW(font, NULL, long_textW, -1, &rect, DT_WORDBREAK | DT_NOCLIP, 0xff00ff); ok(height == 96, "Got unexpected height %d.\n", height);
+ height = ID3DXFont_DrawTextW(font, NULL, L"a\na", -1, NULL, 0, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + height = ID3DXFont_DrawTextW(font, NULL, L"a\na", -1, &rect, 0, 0xff00ff); ok(height == 24, "Got unexpected height %d.\n", height);
@@ -843,10 +846,10 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) ok(height == 36, "Got unexpected height %d.\n", height);
height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM, 0xff00ff); - todo_wine ok(height == 40, "Got unexpected height %d.\n", height); + ok(height == 40, "Got unexpected height %d.\n", height);
height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER, 0xff00ff); - todo_wine ok(height == 32, "Got unexpected height %d.\n", height); + ok(height == 32, "Got unexpected height %d.\n", height);
height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_RIGHT, 0xff00ff); ok(height == 24, "Got unexpected height %d.\n", height); @@ -859,6 +862,151 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) ok(height == 24, "Got unexpected height %d.\n", height); check_rect(&rect, 10, 10, 30, 34);
+ SetRect(&rect, -10, 10, 30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, -10, 10, 10, 34); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, -10, 30, 14); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, 10, 30, 34); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, 10, 30, 34); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, 10, 30, 34); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, -10, 10, 10, 34); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, -10, 30, 14); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 12, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, 10, 53, 22); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, 10, 30, 34); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, 0xff00ff); + ok(height == 40, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, 26, 30, 50); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, 0xff00ff); + ok(height == 40, "Got unexpected height %d.\n", height); + check_rect(&rect, -10, 26, 10, 50); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, 0xff00ff); + ok(height == 40, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, 6, 30, 30); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, 0xff00ff); + ok(height == 40, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, 26, 30, 50); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM | DT_CALCRECT, 0xff00ff); + ok(height == -40, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, -54, 30, -30); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 40, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, 26, 30, 50); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 40, "Got unexpected height %d.\n", height); + check_rect(&rect, -10, 26, 10, 50); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 40, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, 6, 30, 30); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 40, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, 38, 53, 50); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_BOTTOM | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == -40, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, -54, 30, -30); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, 0xff00ff); + ok(height == 32, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, 18, 30, 42); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, 0xff00ff); + ok(height == 32, "Got unexpected height %d.\n", height); + check_rect(&rect, -10, 18, 10, 42); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, 0xff00ff); + ok(height == 32, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, -2, 30, 22); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, 0xff00ff); + ok(height == 32, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, 18, 30, 42); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_VCENTER | DT_CALCRECT, 0xff00ff); + ok(height == -8, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, -22, 30, 2); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 32, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, 18, 30, 42); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 32, "Got unexpected height %d.\n", height); + check_rect(&rect, -10, 18, 10, 42); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 32, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, -2, 30, 22); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 26, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, 24, 53, 36); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == -8, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, -22, 30, 2); + ID3DXFont_Release(font); }
Signed-off-by: Sven Baars sbaars@codeweavers.com --- dlls/d3dx9_36/font.c | 23 +++++- dlls/d3dx9_36/tests/core.c | 162 ++++++++++++++++++++++++++++++++++++- 2 files changed, 182 insertions(+), 3 deletions(-)
diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c index 20757ae839..54aef71913 100644 --- a/dlls/d3dx9_36/font.c +++ b/dlls/d3dx9_36/font.c @@ -623,7 +623,20 @@ static int compute_rect(struct d3dx_font *font, const WCHAR *string, INT count, break; }
- rect->right = rect->left + max_width; + if (format & DT_CENTER) + { + rect->left += (rect->right - rect->left - max_width) / 2; + rect->right = rect->left + max_width; + } + else if (format & DT_RIGHT) + { + rect->left = rect->right - max_width; + } + else + { + rect->right = rect->left + max_width; + } + if (format & DT_VCENTER) { rect->top += (rect->bottom - y) / 2; @@ -698,7 +711,6 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, top = rect->top; }
- x = rect->left; y = rect->top; lh = font->metrics.tmHeight; width = rect->right - rect->left; @@ -717,6 +729,13 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite,
string = read_line(font->hdc, string, &count, line, &line_len, width, format, &size);
+ if (format & DT_CENTER) + x = (rect->left + rect->right - size.cx) / 2; + else if (format & DT_RIGHT) + x = rect->right - size.cx; + else + x = rect->left; + memset(&results, 0, sizeof(results)); results.nGlyphs = line_len;
diff --git a/dlls/d3dx9_36/tests/core.c b/dlls/d3dx9_36/tests/core.c index 9de91b2b08..020f18e622 100644 --- a/dlls/d3dx9_36/tests/core.c +++ b/dlls/d3dx9_36/tests/core.c @@ -842,7 +842,7 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_RIGHT, 0xff00ff); ok(height == 36, "Got unexpected height %d.\n", height);
- height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_RIGHT, 0xff00ff); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_WORDBREAK | DT_CENTER, 0xff00ff); ok(height == 36, "Got unexpected height %d.\n", height);
height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_BOTTOM, 0xff00ff); @@ -1007,6 +1007,166 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) ok(height == -8, "Got unexpected height %d.\n", height); check_rect(&rect, 10, -22, 30, 2);
+ SetRect(&rect, 10, 10, 50, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_RIGHT | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 30, 10, 50, 34); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_RIGHT | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, 10, 30, 34); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_RIGHT | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 30, -10, 50, 14); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_RIGHT | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, -50, 10, -30, 34); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_RIGHT | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 30, 10, 50, 34); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_RIGHT | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 30, 10, 50, 34); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_RIGHT | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 10, 10, 30, 34); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_RIGHT | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 30, -10, 50, 14); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_RIGHT | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 12, "Got unexpected height %d.\n", height); + check_rect(&rect, -73, 10, -30, 22); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_RIGHT | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 30, 10, 50, 34); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 20, 10, 40, 34); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 0, 10, 20, 34); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 20, -10, 40, 14); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, -20, 10, 0, 34); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 20, 10, 40, 34); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 20, 10, 40, 34); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 0, 10, 20, 34); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 20, -10, 40, 14); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 12, "Got unexpected height %d.\n", height); + check_rect(&rect, -31, 10, 12, 22); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 24, "Got unexpected height %d.\n", height); + check_rect(&rect, 20, 10, 40, 34); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_CALCRECT, 0xff00ff); + ok(height == 32, "Got unexpected height %d.\n", height); + check_rect(&rect, 20, 18, 40, 42); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_CALCRECT, 0xff00ff); + ok(height == 32, "Got unexpected height %d.\n", height); + check_rect(&rect, 20, 18, 40, 42); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_CALCRECT, 0xff00ff); + ok(height == 32, "Got unexpected height %d.\n", height); + check_rect(&rect, 0, 18, 20, 42); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_CALCRECT, 0xff00ff); + ok(height == 32, "Got unexpected height %d.\n", height); + check_rect(&rect, 20, -2, 40, 22); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_CALCRECT, 0xff00ff); + ok(height == 32, "Got unexpected height %d.\n", height); + check_rect(&rect, -20, 18, 0, 42); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_CALCRECT, 0xff00ff); + ok(height == -8, "Got unexpected height %d.\n", height); + check_rect(&rect, 20, -22, 40, 2); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 32, "Got unexpected height %d.\n", height); + check_rect(&rect, 20, 18, 40, 42); + + SetRect(&rect, 10, 10, 50, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 32, "Got unexpected height %d.\n", height); + check_rect(&rect, 20, 18, 40, 42); + + SetRect(&rect, -10, 10, 30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 32, "Got unexpected height %d.\n", height); + check_rect(&rect, 0, 18, 20, 42); + + SetRect(&rect, 10, -10, 50, 30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 32, "Got unexpected height %d.\n", height); + check_rect(&rect, 20, -2, 40, 22); + + SetRect(&rect, 10, 10, -30, 50); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == 26, "Got unexpected height %d.\n", height); + check_rect(&rect, -31, 24, 12, 36); + + SetRect(&rect, 10, 10, 50, -30); + height = ID3DXFont_DrawTextW(font, NULL, L"aaaa aaaa", -1, &rect, DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT, 0xff00ff); + ok(height == -8, "Got unexpected height %d.\n", height); + check_rect(&rect, 20, -22, 40, 2); + ID3DXFont_Release(font); }
Signed-off-by: Sven Baars sbaars@codeweavers.com --- dlls/d3dx9_36/font.c | 213 ++++++++++++++++++++++++++----------- dlls/d3dx9_36/tests/core.c | 8 +- 2 files changed, 155 insertions(+), 66 deletions(-)
diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c index 54aef71913..4835732931 100644 --- a/dlls/d3dx9_36/font.c +++ b/dlls/d3dx9_36/font.c @@ -512,7 +512,8 @@ static INT WINAPI ID3DXFontImpl_DrawTextA(ID3DXFont *iface, ID3DXSprite *sprite, }
static void word_break(HDC hdc, const WCHAR *str, unsigned int *str_len, - unsigned int chars_fit, unsigned int *chars_used, DWORD format, SIZE *size) + unsigned int chars_fit, unsigned int *chars_used, BOOL line_start, + DWORD format, SIZE *size) { SCRIPT_LOGATTR *sla; SCRIPT_ANALYSIS sa; @@ -535,7 +536,7 @@ static void word_break(HDC hdc, const WCHAR *str, unsigned int *str_len, --i;
/* If the there is no word that fits put in all characters that do fit */ - if (!sla[i].fSoftBreak || (format & DT_SINGLELINE)) + if ((!sla[i].fSoftBreak && line_start) || (format & DT_SINGLELINE)) i = chars_fit;
*chars_used = i; @@ -553,53 +554,104 @@ static void word_break(HDC hdc, const WCHAR *str, unsigned int *str_len, }
static const WCHAR *read_line(HDC hdc, const WCHAR *str, int *count, - WCHAR *dest, unsigned int *dest_len, int width, DWORD format, SIZE *size) + WCHAR *dest, unsigned int *dest_len, int width, unsigned int tab_width, + DWORD format, SIZE *size) { + int num_fit, current_width = 0; unsigned int i = 0; - int orig_count = *count; - int num_fit;
+ size->cy = 0; *dest_len = 0; - while (*count && (str[i] != '\n' || (format & DT_SINGLELINE))) + while (*count) { - --(*count); - if (str[i] != '\r' && str[i] != '\n') - dest[(*dest_len)++] = str[i]; - ++i; - } + unsigned int seg_i, seg_len, prev_dest_len; + int seg_count, max_seg_width; + BOOL word_broken = FALSE; + SIZE seg_size = {0};
- num_fit = 0; - GetTextExtentExPointW(hdc, dest, *dest_len, width, &num_fit, NULL, size); + /* Create line segments until the next tab. If we don't have to expand */ + /* tabs, just skip the tab character. */
- if (num_fit < *dest_len) - { - if (format & DT_WORDBREAK) + if (str[i] == '\t') { - unsigned int chars_used; + if (tab_width) + current_width = ((current_width / tab_width) + 1) * tab_width; + + --(*count); + if (format & DT_EXPANDTABS) + dest[(*dest_len)++] = str[i]; + ++i;
- word_break(hdc, dest, dest_len, num_fit, &chars_used, format, size); - *count = orig_count - chars_used; - i = chars_used; + max_seg_width = width - current_width; + if (max_seg_width < 0 && (format & DT_WORDBREAK)) + break; + + continue; } - else if (format & DT_SINGLELINE) + + seg_i = i; + seg_count = *count; + prev_dest_len = *dest_len; + + while (*count && (str[i] != '\n' || (format & DT_SINGLELINE)) && str[i] != '\t') { - *dest_len = num_fit; - *count = 0; + --(*count); + if (str[i] != '\r' && str[i] != '\n') + dest[(*dest_len)++] = str[i]; + ++i; } - }
- if (*count && str[i] == '\n') - { - --(*count); - ++i; + num_fit = 0; + seg_len = *(dest_len) - prev_dest_len; + max_seg_width = width - current_width; + GetTextExtentExPointW(hdc, dest + prev_dest_len, seg_len, max_seg_width, + &num_fit, NULL, &seg_size); + + if (num_fit < seg_len) + { + if (format & DT_WORDBREAK) + { + unsigned int chars_used; + + word_break(hdc, dest + prev_dest_len, &seg_len, num_fit, &chars_used, + !current_width, format, &seg_size); + *count = seg_count - chars_used; + i = seg_i + chars_used; + word_broken = TRUE; + } + else if (format & DT_SINGLELINE) + { + seg_len = num_fit; + *count = 0; + word_broken = TRUE; + } + *dest_len = prev_dest_len + seg_len; + } + + current_width += seg_size.cx; + if (seg_size.cy > size->cy) + size->cy = seg_size.cy; + + if (word_broken) + { + break; + } + else if (*count && str[i] == '\n') + { + --(*count); + ++i; + break; + } }
+ size->cx = current_width; if (*count) return str + i; return NULL; }
-static int compute_rect(struct d3dx_font *font, const WCHAR *string, INT count, WCHAR *line, RECT *rect, DWORD format) +static int compute_rect(struct d3dx_font *font, const WCHAR *string, INT count, + WCHAR *line, RECT *rect, DWORD format, unsigned int tab_width) { int y, lh, width, top = rect->top; int max_width = 0; @@ -613,7 +665,8 @@ static int compute_rect(struct d3dx_font *font, const WCHAR *string, INT count, { unsigned int line_len;
- string = read_line(font->hdc, string, &count, line, &line_len, width, format, &size); + string = read_line(font->hdc, string, &count, line, &line_len, + width, tab_width, format, &size);
if (size.cx > max_width) max_width = size.cx; @@ -660,6 +713,7 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, struct d3dx_font *font = impl_from_ID3DXFont(iface); int lh, x, y, width, top, ret = 0; ID3DXSprite *target = sprite; + unsigned int tab_width = 0; RECT r = {0}; WCHAR *line; SIZE size; @@ -682,6 +736,9 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, if (format & DT_SINGLELINE) format &= ~DT_WORDBREAK;
+ if (format & DT_EXPANDTABS) + tab_width = font->metrics.tmAveCharWidth * 8; + line = heap_alloc(count * sizeof(*line)); if (!line) return 0; @@ -701,7 +758,7 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite,
top = rect->top;
- ret = compute_rect(font, string, count, line, rect, format); + ret = compute_rect(font, string, count, line, rect, format, tab_width);
if (format & DT_CALCRECT) goto cleanup; @@ -721,13 +778,14 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, ID3DXSprite_Begin(target, 0); }
+ /* Iterate over all lines */ while (string) { - unsigned int line_len, i; - GCP_RESULTSW results; - D3DXVECTOR3 pos; + const WCHAR *line_seg = line; + unsigned int line_len;
- string = read_line(font->hdc, string, &count, line, &line_len, width, format, &size); + string = read_line(font->hdc, string, &count, line, &line_len, + width, tab_width, format, &size);
if (format & DT_CENTER) x = (rect->left + rect->right - size.cx) / 2; @@ -736,42 +794,73 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, else x = rect->left;
- memset(&results, 0, sizeof(results)); - results.nGlyphs = line_len; + /* Iterate over all line segments separated by tabs */ + while (line_len) + { + unsigned int i, seg_len = line_len; + GCP_RESULTSW results; + D3DXVECTOR3 pos;
- results.lpCaretPos = heap_alloc(line_len * sizeof(*results.lpCaretPos)); - if (!results.lpCaretPos) - goto cleanup; + if (format & DT_EXPANDTABS) + { + /* Iterate until the next tab to create a line segment */ + i = 0; + while (i < line_len && line_seg[i] != '\t') + ++i; + seg_len = i; + if (seg_len != line_len && !GetTextExtentPointW( + font->hdc, line_seg, seg_len, &size)) + goto cleanup; + }
- results.lpGlyphs = heap_alloc(line_len * sizeof(*results.lpGlyphs)); - if (!results.lpGlyphs) - { - heap_free(results.lpCaretPos); - goto cleanup; - } + memset(&results, 0, sizeof(results)); + results.nGlyphs = seg_len;
- GetCharacterPlacementW(font->hdc, line, line_len, 0, &results, 0); + results.lpCaretPos = heap_alloc(seg_len * sizeof(*results.lpCaretPos)); + if (!results.lpCaretPos) + goto cleanup;
- for (i = 0; i < results.nGlyphs; ++i) - { - IDirect3DTexture9 *texture; - POINT cell_inc; - RECT black_box; + results.lpGlyphs = heap_alloc(seg_len * sizeof(*results.lpGlyphs)); + if (!results.lpGlyphs) + { + heap_free(results.lpCaretPos); + goto cleanup; + } + + GetCharacterPlacementW(font->hdc, line_seg, seg_len, 0, &results, 0);
- ID3DXFont_GetGlyphData(iface, results.lpGlyphs[i], &texture, &black_box, &cell_inc); + for (i = 0; i < results.nGlyphs; ++i) + { + IDirect3DTexture9 *texture; + POINT cell_inc; + RECT black_box;
- if (!texture) - continue; + ID3DXFont_GetGlyphData(iface, results.lpGlyphs[i], &texture, + &black_box, &cell_inc);
- pos.x = cell_inc.x + x + results.lpCaretPos[i]; - pos.y = cell_inc.y + y; + if (!texture) + continue;
- ID3DXSprite_Draw(target, texture, &black_box, NULL, &pos, color); - IDirect3DTexture9_Release(texture); - } + pos.x = cell_inc.x + x + results.lpCaretPos[i]; + pos.y = cell_inc.y + y; + + ID3DXSprite_Draw(target, texture, &black_box, NULL, &pos, color); + IDirect3DTexture9_Release(texture); + } + + line_len -= seg_len; + line_seg += seg_len; + if (line_len) + { + /* If there is anything left, this character is a tab */ + --line_len; + ++line_seg; + x += ((size.cx / tab_width) + 1) * tab_width; + }
- heap_free(results.lpCaretPos); - heap_free(results.lpGlyphs); + heap_free(results.lpCaretPos); + heap_free(results.lpGlyphs); + }
y += lh; if (!(DT_NOCLIP & format) && (y > rect->bottom)) diff --git a/dlls/d3dx9_36/tests/core.c b/dlls/d3dx9_36/tests/core.c index 020f18e622..9b942e1535 100644 --- a/dlls/d3dx9_36/tests/core.c +++ b/dlls/d3dx9_36/tests/core.c @@ -807,10 +807,10 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) todo_wine ok(height == 0, "Got unexpected height %d.\n", height);
height = ID3DXFont_DrawTextW(font, NULL, L"\t\t\t\t\t\t\t\t\t\ta", -1, &rect, DT_WORDBREAK, 0xff00ff); - todo_wine ok(height == 12, "Got unexpected height %d.\n", height); + ok(height == 12, "Got unexpected height %d.\n", height);
height = ID3DXFont_DrawTextW(font, NULL, L"\taaaaaaaaaa", -1, &rect, DT_WORDBREAK, 0xff00ff); - todo_wine ok(height == 24, "Got unexpected height %d.\n", height); + ok(height == 24, "Got unexpected height %d.\n", height);
height = ID3DXFont_DrawTextW(font, NULL, L"\taaaaaaaaaa", -1, &rect, DT_EXPANDTABS | DT_WORDBREAK, 0xff00ff); ok(height == 36, "Got unexpected height %d.\n", height); @@ -819,7 +819,7 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) ok(height == 24, "Got unexpected height %d.\n", height);
height = ID3DXFont_DrawTextW(font, NULL, L"\taaa\taaa\taaa", -1, &rect, DT_EXPANDTABS | DT_WORDBREAK, 0xff00ff); - todo_wine ok(height == 48, "Got unexpected height %d.\n", height); + ok(height == 48, "Got unexpected height %d.\n", height);
height = ID3DXFont_DrawTextW(font, NULL, L"\t\t\t\t\t\t\t\t\t\t", -1, &rect, DT_EXPANDTABS | DT_WORDBREAK, 0xff00ff); todo_wine ok(height == 60, "Got unexpected height %d.\n", height); @@ -828,7 +828,7 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) ok(height == 12, "Got unexpected height %d.\n", height);
height = ID3DXFont_DrawTextW(font, NULL, L"a\ta\ta", -1, &rect, DT_EXPANDTABS | DT_WORDBREAK, 0xff00ff); - todo_wine ok(height == 24, "Got unexpected height %d.\n", height); + ok(height == 24, "Got unexpected height %d.\n", height);
height = ID3DXFont_DrawTextW(font, NULL, L"aaaaaaaaaaaaaaaaaaaa", -1, &rect, DT_WORDBREAK, 0xff00ff); ok(height == 36, "Got unexpected height %d.\n", height);
Signed-off-by: Sven Baars sbaars@codeweavers.com --- dlls/d3dx9_36/font.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c index 4835732931..5adb2f3a89 100644 --- a/dlls/d3dx9_36/font.c +++ b/dlls/d3dx9_36/font.c @@ -621,7 +621,6 @@ static const WCHAR *read_line(HDC hdc, const WCHAR *str, int *count, } else if (format & DT_SINGLELINE) { - seg_len = num_fit; *count = 0; word_broken = TRUE; } @@ -844,6 +843,21 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, pos.x = cell_inc.x + x + results.lpCaretPos[i]; pos.y = cell_inc.y + y;
+ if (!(format & DT_NOCLIP)) + { + if (pos.x > rect->right) + { + IDirect3DTexture9_Release(texture); + continue; + } + + if (pos.x + black_box.right - black_box.left > rect->right) + black_box.right = black_box.left + rect->right - pos.x; + + if (pos.y + black_box.bottom - black_box.top > rect->bottom) + black_box.bottom = black_box.top + rect->bottom - pos.y; + } + ID3DXSprite_Draw(target, texture, &black_box, NULL, &pos, color); IDirect3DTexture9_Release(texture); }