Signed-off-by: Sven Baars sbaars@codeweavers.com --- dlls/d3dx9_36/font.c | 29 ++++++++++++++++++++--------- dlls/d3dx9_36/tests/core.c | 2 +- 2 files changed, 21 insertions(+), 10 deletions(-)
diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c index 5d4c0a5786..e27858a2ce 100644 --- a/dlls/d3dx9_36/font.c +++ b/dlls/d3dx9_36/font.c @@ -512,7 +512,7 @@ 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, SIZE *size) + unsigned int chars_fit, unsigned int *chars_used, DWORD format, SIZE *size) { SCRIPT_LOGATTR *sla; SCRIPT_ANALYSIS sa; @@ -535,7 +535,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) + if (!sla[i].fSoftBreak || (format & DT_SINGLELINE)) i = chars_fit;
*chars_used = i; @@ -561,10 +561,10 @@ static const WCHAR *read_line(HDC hdc, const WCHAR *str, int *count, SIZE size;
*dest_len = 0; - while (*count && str[i] != '\n') + while (*count && (str[i] != '\n' || (format & DT_SINGLELINE))) { --(*count); - if (str[i] != '\r') + if (str[i] != '\r' && str[i] != '\n') dest[(*dest_len)++] = str[i]; ++i; } @@ -572,13 +572,21 @@ static const WCHAR *read_line(HDC hdc, const WCHAR *str, int *count, num_fit = 0; GetTextExtentExPointW(hdc, dest, *dest_len, width, &num_fit, NULL, &size);
- if (num_fit < *dest_len && (format & DT_WORDBREAK)) + if (num_fit < *dest_len) { - unsigned int chars_used; + if (format & DT_WORDBREAK) + { + unsigned int chars_used;
- word_break(hdc, dest, dest_len, num_fit, &chars_used, &size); - *count = orig_count - chars_used; - i = chars_used; + word_break(hdc, dest, dest_len, num_fit, &chars_used, format, &size); + *count = orig_count - chars_used; + i = chars_used; + } + else if (format & DT_SINGLELINE) + { + *dest_len = num_fit; + *count = 0; + } }
if (*count && str[i] == '\n') @@ -617,6 +625,9 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, if (format & DT_CALCRECT) format |= DT_NOCLIP;
+ if (format & DT_SINGLELINE) + format &= ~DT_WORDBREAK; + if (!rect) { y = ID3DXFont_DrawTextW(iface, NULL, string, count, &textrect, format | DT_CALCRECT, 0); diff --git a/dlls/d3dx9_36/tests/core.c b/dlls/d3dx9_36/tests/core.c index 45cde62b3a..2b5a868033 100644 --- a/dlls/d3dx9_36/tests/core.c +++ b/dlls/d3dx9_36/tests/core.c @@ -771,7 +771,7 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) ok(height == 12, "Got unexpected height %d.\n", height);
height = ID3DXFont_DrawTextW(font, NULL, L"a\na", -1, &rect, DT_SINGLELINE, 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"a\naaaaa aaaa", -1, &rect, 0, 0xff00ff); ok(height == 24, "Got unexpected height %d.\n", height);
Signed-off-by: Sven Baars sbaars@codeweavers.com --- dlls/d3dx9_36/font.c | 24 +++++++++++++++++++----- dlls/d3dx9_36/tests/core.c | 18 ++++++++++++++++-- 2 files changed, 35 insertions(+), 7 deletions(-)
diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c index e27858a2ce..3645903367 100644 --- a/dlls/d3dx9_36/font.c +++ b/dlls/d3dx9_36/font.c @@ -553,12 +553,11 @@ 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) + WCHAR *dest, unsigned int *dest_len, int width, DWORD format, SIZE *size) { unsigned int i = 0; int orig_count = *count; int num_fit; - SIZE size;
*dest_len = 0; while (*count && (str[i] != '\n' || (format & DT_SINGLELINE))) @@ -570,7 +569,7 @@ static const WCHAR *read_line(HDC hdc, const WCHAR *str, int *count, }
num_fit = 0; - GetTextExtentExPointW(hdc, dest, *dest_len, width, &num_fit, NULL, &size); + GetTextExtentExPointW(hdc, dest, *dest_len, width, &num_fit, NULL, size);
if (num_fit < *dest_len) { @@ -578,7 +577,7 @@ static const WCHAR *read_line(HDC hdc, const WCHAR *str, int *count, { unsigned int chars_used;
- word_break(hdc, dest, dest_len, num_fit, &chars_used, format, &size); + word_break(hdc, dest, dest_len, num_fit, &chars_used, format, size); *count = orig_count - chars_used; i = chars_used; } @@ -608,7 +607,9 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, 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", iface, sprite, debugstr_wn(string, count), count, wine_dbgstr_rect(rect), format, color); @@ -660,7 +661,7 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, { unsigned int line_len;
- string = read_line(font->hdc, string, &count, line, &line_len, width, format); + string = read_line(font->hdc, string, &count, line, &line_len, width, format, &size);
if (!(format & DT_CALCRECT)) { @@ -705,11 +706,24 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, heap_free(results.lpCaretPos); heap_free(results.lpGlyphs); } + else if (size.cx > max_width) + { + max_width = size.cx; + } + y += lh; if (!(DT_NOCLIP & format) && (y > textrect.bottom)) break; }
+ if (format & DT_CALCRECT) + { + *rect = textrect; + + rect->bottom = y; + rect->right = rect->left + max_width; + } + ret = y - textrect.top;
cleanup: diff --git a/dlls/d3dx9_36/tests/core.c b/dlls/d3dx9_36/tests/core.c index 2b5a868033..6fae8bf8d5 100644 --- a/dlls/d3dx9_36/tests/core.c +++ b/dlls/d3dx9_36/tests/core.c @@ -64,6 +64,15 @@ static inline void check_mat(D3DXMATRIX got, D3DXMATRIX exp) U(exp).m[3][0],U(exp).m[3][1],U(exp).m[3][2],U(exp).m[3][3]); }
+#define check_rect(rect, left, top, right, bottom) _check_rect(__LINE__, rect, left, top, right, bottom) +static inline void _check_rect(unsigned int line, const RECT *rect, int left, int top, int right, int bottom) +{ + ok_(__FILE__, line)(rect->left == left, "Unexpected rect.left %d\n", rect->left); + ok_(__FILE__, line)(rect->top == top, "Unexpected rect.top %d\n", rect->top); + ok_(__FILE__, line)(rect->right == right, "Unexpected rect.right %d\n", rect->right); + ok_(__FILE__, line)(rect->bottom == bottom, "Unexpected rect.bottom %d\n", rect->bottom); +} + static void test_ID3DXBuffer(void) { ID3DXBuffer *buffer; @@ -667,8 +676,8 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) ok(height == tests[i].font_height, "Test %d: got unexpected height %u.\n", i, height); ok(!rect.left, "Test %d: got unexpected rect left %d.\n", i, rect.left); ok(!rect.top, "Test %d: got unexpected rect top %d.\n", i, rect.top); - todo_wine ok(rect.right, "Test %d: got unexpected rect right %d.\n", i, rect.right); - todo_wine ok(rect.bottom == tests[i].font_height, "Test %d: got unexpected rect bottom %d.\n", i, rect.bottom); + ok(rect.right, "Test %d: got unexpected rect right %d.\n", i, rect.right); + ok(rect.bottom == tests[i].font_height, "Test %d: got unexpected rect bottom %d.\n", i, rect.bottom);
hr = ID3DXSprite_End(sprite); ok (hr == D3D_OK, "Test %d: got unexpected hr %#x.\n", i, hr); @@ -839,6 +848,11 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) height = ID3DXFont_DrawTextW(font, NULL, L"aaaa\naaaa", -1, &rect, DT_CENTER, 0xff00ff); ok(height == 24, "Got unexpected height %d.\n", height);
+ SetRect(&rect, 10, 10, 50, 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); + ID3DXFont_Release(font); }
Signed-off-by: Matteo Bruni mbruni@codeweavers.com
On Tue, Mar 10, 2020 at 11:38 AM Sven Baars sbaars@codeweavers.com wrote:
@@ -705,11 +706,24 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, heap_free(results.lpCaretPos); heap_free(results.lpGlyphs); }
else if (size.cx > max_width)
{
max_width = size.cx;
}
I don't know if this is going to change afterwards but, currently, it seems to me that the "else if" condition is always true.
On 13-03-2020 17:21, Matteo Bruni wrote:
On Tue, Mar 10, 2020 at 11:38 AM Sven Baars sbaars@codeweavers.com wrote:
@@ -705,11 +706,24 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, heap_free(results.lpCaretPos); heap_free(results.lpGlyphs); }
else if (size.cx > max_width)
{
max_width = size.cx;
}
I don't know if this is going to change afterwards but, currently, it seems to me that the "else if" condition is always true.
I don't think so. There is a while loop over all lines. If the first line has width 20 and the second line has width 10, the first one counts.
On Mon, Mar 16, 2020 at 11:09 AM Sven Baars sbaars@codeweavers.com wrote:
On 13-03-2020 17:21, Matteo Bruni wrote:
On Tue, Mar 10, 2020 at 11:38 AM Sven Baars sbaars@codeweavers.com wrote:
@@ -705,11 +706,24 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, heap_free(results.lpCaretPos); heap_free(results.lpGlyphs); }
else if (size.cx > max_width)
{
max_width = size.cx;
}
I don't know if this is going to change afterwards but, currently, it seems to me that the "else if" condition is always true.
I don't think so. There is a while loop over all lines. If the first line has width 20 and the second line has width 10, the first one counts.
Indeed, not sure what I saw earlier...
Signed-off-by: Sven Baars sbaars@codeweavers.com --- dlls/d3dx9_36/font.c | 30 ++++++++++++++++++++++++------ dlls/d3dx9_36/tests/core.c | 14 ++++++++++++-- 2 files changed, 36 insertions(+), 8 deletions(-)
diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c index 3645903367..bd81a7044b 100644 --- a/dlls/d3dx9_36/font.c +++ b/dlls/d3dx9_36/font.c @@ -603,12 +603,12 @@ 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); + RECT calcrect, textrect = {0}; ID3DXSprite *target = sprite; - WCHAR *line; - RECT textrect = {0}; int lh, x, y, width; int max_width = 0; int ret = 0; + WCHAR *line; SIZE size;
TRACE("iface %p, sprite %p, string %s, count %d, rect %s, format %#x, color 0x%08x.\n", @@ -641,9 +641,27 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, textrect = *rect; }
- x = textrect.left; - y = textrect.top; - width = textrect.right - textrect.left; + calcrect = textrect; + + if (format & (DT_VCENTER | DT_BOTTOM)) + { + y = ID3DXFont_DrawTextW(iface, NULL, string, count, &calcrect, + format & ~DT_BOTTOM & ~DT_VCENTER, 0); + + if (format & DT_VCENTER) + { + calcrect.top = textrect.top + (textrect.bottom - textrect.top - y) / 2; + calcrect.bottom = calcrect.top + y; + } + else if (format & DT_BOTTOM) + { + calcrect.top = textrect.bottom - y; + } + } + + x = calcrect.left; + y = calcrect.top; + width = calcrect.right - calcrect.left;
lh = font->metrics.tmHeight;
@@ -718,7 +736,7 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite,
if (format & DT_CALCRECT) { - *rect = textrect; + *rect = calcrect;
rect->bottom = y; rect->right = rect->left + max_width; diff --git a/dlls/d3dx9_36/tests/core.c b/dlls/d3dx9_36/tests/core.c index 6fae8bf8d5..7800e6036c 100644 --- a/dlls/d3dx9_36/tests/core.c +++ b/dlls/d3dx9_36/tests/core.c @@ -837,10 +837,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); @@ -853,6 +853,16 @@ 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, 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, 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); + ID3DXFont_Release(font); }
On Tue, Mar 10, 2020 at 11:38 AM Sven Baars sbaars@codeweavers.com wrote:
Signed-off-by: Sven Baars sbaars@codeweavers.com
dlls/d3dx9_36/font.c | 30 ++++++++++++++++++++++++------ dlls/d3dx9_36/tests/core.c | 14 ++++++++++++-- 2 files changed, 36 insertions(+), 8 deletions(-)
diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c index 3645903367..bd81a7044b 100644 --- a/dlls/d3dx9_36/font.c +++ b/dlls/d3dx9_36/font.c @@ -603,12 +603,12 @@ 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);
- RECT calcrect, textrect = {0}; ID3DXSprite *target = sprite;
- WCHAR *line;
- RECT textrect = {0}; int lh, x, y, width; int max_width = 0; int ret = 0;
WCHAR *line; SIZE size;
TRACE("iface %p, sprite %p, string %s, count %d, rect %s, format %#x, color 0x%08x.\n",
@@ -641,9 +641,27 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, textrect = *rect; }
- x = textrect.left;
- y = textrect.top;
- width = textrect.right - textrect.left;
- calcrect = textrect;
- if (format & (DT_VCENTER | DT_BOTTOM))
- {
y = ID3DXFont_DrawTextW(iface, NULL, string, count, &calcrect,
format & ~DT_BOTTOM & ~DT_VCENTER, 0);
Was the idea here to add DT_CALCRECT to the format flags, by any chance? As it is now I think you end up drawing the text twice, once top-aligned and once with the "correct" vertical alignment flags. FWIW it doesn't look to me like it's necessary to do a recursive call to handle those flags.
Nitpick: indentation.
On 13-03-2020 17:22, Matteo Bruni wrote:
On Tue, Mar 10, 2020 at 11:38 AM Sven Baars sbaars@codeweavers.com wrote:
Signed-off-by: Sven Baars sbaars@codeweavers.com
dlls/d3dx9_36/font.c | 30 ++++++++++++++++++++++++------ dlls/d3dx9_36/tests/core.c | 14 ++++++++++++-- 2 files changed, 36 insertions(+), 8 deletions(-)
diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c index 3645903367..bd81a7044b 100644 --- a/dlls/d3dx9_36/font.c +++ b/dlls/d3dx9_36/font.c @@ -603,12 +603,12 @@ 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);
- RECT calcrect, textrect = {0}; ID3DXSprite *target = sprite;
- WCHAR *line;
- RECT textrect = {0}; int lh, x, y, width; int max_width = 0; int ret = 0;
WCHAR *line; SIZE size;
TRACE("iface %p, sprite %p, string %s, count %d, rect %s, format %#x, color 0x%08x.\n",
@@ -641,9 +641,27 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, textrect = *rect; }
- x = textrect.left;
- y = textrect.top;
- width = textrect.right - textrect.left;
- calcrect = textrect;
- if (format & (DT_VCENTER | DT_BOTTOM))
- {
y = ID3DXFont_DrawTextW(iface, NULL, string, count, &calcrect,
format & ~DT_BOTTOM & ~DT_VCENTER, 0);
Was the idea here to add DT_CALCRECT to the format flags, by any chance? As it is now I think you end up drawing the text twice, once top-aligned and once with the "correct" vertical alignment flags. FWIW it doesn't look to me like it's necessary to do a recursive call to handle those flags.
Nitpick: indentation.
In an earlier version there was a reason why I didn't need DT_CALCRECT there for sure, but I don't see anymore why that would work right now. What's weird is that I don't see the top-aligned draw of the text in my test application. Anyhow, I added the DT_CALCRECT flag since it makes sense to have it, and I also added some extra tests to show that the recursive call is useful (MSDN says only single line drawing is supported, but that is not true).
Signed-off-by: Sven Baars sbaars@codeweavers.com --- dlls/d3dx9_36/font.c | 22 +++++++++++++++++++++- dlls/d3dx9_36/tests/core.c | 15 +++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c index bd81a7044b..550ff2c0fe 100644 --- a/dlls/d3dx9_36/font.c +++ b/dlls/d3dx9_36/font.c @@ -687,6 +687,13 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, D3DXVECTOR3 pos; unsigned int i;
+ if (format & DT_CENTER) + x = (calcrect.left + calcrect.right - size.cx) / 2; + else if (format & DT_RIGHT) + x = calcrect.right - size.cx; + else + x = calcrect.left; + memset(&results, 0, sizeof(results)); results.nGlyphs = line_len;
@@ -739,7 +746,20 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, *rect = calcrect;
rect->bottom = y; - 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; + } }
ret = y - textrect.top; diff --git a/dlls/d3dx9_36/tests/core.c b/dlls/d3dx9_36/tests/core.c index 7800e6036c..c2244b1a97 100644 --- a/dlls/d3dx9_36/tests/core.c +++ b/dlls/d3dx9_36/tests/core.c @@ -863,6 +863,21 @@ static void test_ID3DXFont(IDirect3DDevice9 *device) ok(height == 32, "Got unexpected height %d.\n", height); check_rect(&rect, 10, 18, 30, 42);
+ 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, 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, 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); + ID3DXFont_Release(font); }
Signed-off-by: Sven Baars sbaars@codeweavers.com --- dlls/d3dx9_36/font.c | 212 +++++++++++++++++++++++++------------ dlls/d3dx9_36/tests/core.c | 8 +- 2 files changed, 151 insertions(+), 69 deletions(-)
diff --git a/dlls/d3dx9_36/font.c b/dlls/d3dx9_36/font.c index 550ff2c0fe..dc0a72c197 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,47 +554,95 @@ 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) + max_seg_width = width - current_width; + if (max_seg_width < 0 && (format & DT_WORDBREAK)) + break; + + if (str[i] == '\t') { - unsigned int chars_used; + if (tab_width) + current_width = ((current_width / tab_width) + 1) * tab_width;
- word_break(hdc, dest, dest_len, num_fit, &chars_used, format, size); - *count = orig_count - chars_used; - i = chars_used; + --(*count); + if (format & DT_EXPANDTABS) + dest[(*dest_len)++] = str[i]; + ++i; + 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; + 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; @@ -605,6 +654,7 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, struct d3dx_font *font = impl_from_ID3DXFont(iface); RECT calcrect, textrect = {0}; ID3DXSprite *target = sprite; + unsigned int tab_width = 0; int lh, x, y, width; int max_width = 0; int ret = 0; @@ -669,6 +719,9 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, if (!line) return 0;
+ if (format & DT_EXPANDTABS) + tab_width = font->metrics.tmAveCharWidth * 8; + if (!(format & DT_CALCRECT) && !sprite) { D3DXCreateSprite(font->device, &target); @@ -679,13 +732,12 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, { 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_CALCRECT)) { - GCP_RESULTSW results; - D3DXVECTOR3 pos; - unsigned int i; + const WCHAR *line_seg = line;
if (format & DT_CENTER) x = (calcrect.left + calcrect.right - size.cx) / 2; @@ -694,42 +746,72 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, else x = calcrect.left;
- 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) + while (line_len) { - heap_free(results.lpCaretPos); - goto cleanup; - } - - GetCharacterPlacementW(font->hdc, line, line_len, 0, &results, 0); - - for (i = 0; i < results.nGlyphs; ++i) - { - IDirect3DTexture9 *texture; - POINT cell_inc; - RECT black_box; - - ID3DXFont_GetGlyphData(iface, results.lpGlyphs[i], &texture, &black_box, &cell_inc); + unsigned int i, seg_len = line_len; + GCP_RESULTSW results; + D3DXVECTOR3 pos; + + 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; + } + + memset(&results, 0, sizeof(results)); + results.nGlyphs = seg_len; + + results.lpCaretPos = heap_alloc(seg_len * sizeof(*results.lpCaretPos)); + if (!results.lpCaretPos) + goto cleanup; + + 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); + + for (i = 0; i < results.nGlyphs; ++i) + { + IDirect3DTexture9 *texture; + POINT cell_inc; + RECT black_box; + + ID3DXFont_GetGlyphData(iface, results.lpGlyphs[i], &texture, + &black_box, &cell_inc); + + if (!texture) + continue; + + 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; + }
- if (!texture) - continue; - - 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); + heap_free(results.lpCaretPos); + heap_free(results.lpGlyphs); } - - heap_free(results.lpCaretPos); - heap_free(results.lpGlyphs); } else if (size.cx > max_width) { diff --git a/dlls/d3dx9_36/tests/core.c b/dlls/d3dx9_36/tests/core.c index c2244b1a97..65d4c66708 100644 --- a/dlls/d3dx9_36/tests/core.c +++ b/dlls/d3dx9_36/tests/core.c @@ -798,10 +798,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); @@ -810,7 +810,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); @@ -819,7 +819,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);
On Tue, Mar 10, 2020 at 11:22 AM Sven Baars sbaars@codeweavers.com wrote:
@@ -617,6 +625,9 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, if (format & DT_CALCRECT) format |= DT_NOCLIP;
- if (format & DT_SINGLELINE)
format &= ~DT_WORDBREAK;
I don't think we have a test for this specific case at the moment, it would be nice to have one.
On 13-03-2020 17:20, Matteo Bruni wrote:
On Tue, Mar 10, 2020 at 11:22 AM Sven Baars sbaars@codeweavers.com wrote:
@@ -617,6 +625,9 @@ static INT WINAPI ID3DXFontImpl_DrawTextW(ID3DXFont *iface, ID3DXSprite *sprite, if (format & DT_CALCRECT) format |= DT_NOCLIP;
- if (format & DT_SINGLELINE)
format &= ~DT_WORDBREAK;
I don't think we have a test for this specific case at the moment, it would be nice to have one.
Hi Matteo,
I added some more tests for this in my updated patch series.
Sven