uiLengthDrawn should represent the number of characters that have been processed. However, the original implementation uses len (the count of displayed characters in the current line), which is not accurate.
When text requires line breaks or special processing (such as adding an ellipsis), the actual number of processed characters may differ from the number of displayed characters.
When the DT_CALCRECT flag is absent, len gets decremented to 0 during the drawing loop.
Consequently, uiLengthDrawn becomes inaccurate since it relies on len's value for statistics.
-- v8: user32: Fix uiLengthDrawn calculation in DrawTextExW(). user32/tests: Add some tests for uiLengthDrawn calculation in DrawTextExW().
From: chenjiangyi chenjiangyi@uniontech.com
--- dlls/user32/tests/text.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+)
diff --git a/dlls/user32/tests/text.c b/dlls/user32/tests/text.c index d3228eae1e0..963af800b12 100644 --- a/dlls/user32/tests/text.c +++ b/dlls/user32/tests/text.c @@ -47,6 +47,8 @@ static void test_DrawTextCalcRect(void) static WCHAR wordbreak_textW[] = {'l','i','n','e','1',' ','l','i','n','e','2',0}; static WCHAR wordbreak_text_colonW[] = {'l','i','n','e','1',' ','l','i','n','e','2',' ',':',0}; static WCHAR wordbreak_text_csbW[] = {'l','i','n','e','1',' ','l','i','n','e','2',' ',']',0}; + static WCHAR complex_format_textW[] = {'H','e','l','l','o',' ','&','W','o','r','l','d','!', + '\t','T','h','i','s',' ','i','s',' ','a',' ','t','e','s','t','.','\r','\n','L','i','n','e',' ','2',0}; static char tabstring[] = "one\ttwo"; INT textlen, textheight, heightcheck; RECT rect = { 0, 0, 100, 0 }, rect2; @@ -657,6 +659,39 @@ static void test_DrawTextCalcRect(void) ok(rect.bottom == rect2.bottom , "unexpected value %ld, got %ld\n", rect.bottom, rect2.bottom);
+ /* Test uiLengthDrawn calculation */ + SetRect(&rect, 0, 0, 100, 25); + memset(&dtp, 0, sizeof(dtp)); + dtp.cbSize = sizeof(dtp); + textheight = DrawTextExW(hdc, textW, lstrlenW(textW), &rect, DT_EDITCONTROL | DT_NOPREFIX | DT_WORDBREAK, &dtp); + todo_wine ok(dtp.uiLengthDrawn == 16, "Unexpected uiLengthDrawn %d\n", dtp.uiLengthDrawn ); + + memset(&dtp, 0, sizeof(dtp)); + dtp.cbSize = sizeof(dtp); + textheight = DrawTextExW(hdc, textW, lstrlenW(textW), &rect, DT_EDITCONTROL | DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT, &dtp); + ok(dtp.uiLengthDrawn == 16, "Unexpected uiLengthDrawn %d\n", dtp.uiLengthDrawn ); + + memset(&dtp, 0, sizeof(dtp)); + dtp.cbSize = sizeof(dtp); + textheight = DrawTextExW(hdc, textW, -1, &rect, DT_EXPANDTABS, &dtp); + todo_wine ok(dtp.uiLengthDrawn == 16, "Unexpected uiLengthDrawn %d\n", dtp.uiLengthDrawn ); + + memset(&dtp, 0, sizeof(dtp)); + dtp.cbSize = sizeof(dtp); + textheight = DrawTextExW(hdc, complex_format_textW, lstrlenW(complex_format_textW), &rect, DT_EDITCONTROL | DT_NOPREFIX | DT_WORDBREAK, &dtp); + todo_wine ok(dtp.uiLengthDrawn == 14, "Unexpected uiLengthDrawn %d\n", dtp.uiLengthDrawn ); + + memset(&dtp, 0, sizeof(dtp)); + dtp.cbSize = sizeof(dtp); + textheight = DrawTextExW(hdc, complex_format_textW, lstrlenW(complex_format_textW), &rect, DT_EDITCONTROL | DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT, &dtp); + todo_wine ok(dtp.uiLengthDrawn == 37, "Unexpected uiLengthDrawn %d\n", dtp.uiLengthDrawn ); + + memset(&dtp, 0, sizeof(dtp)); + dtp.cbSize = sizeof(dtp); + textheight = DrawTextExW(hdc, complex_format_textW, -1, &rect, DT_EXPANDTABS, &dtp); + todo_wine ok(dtp.uiLengthDrawn == 37, "Unexpected uiLengthDrawn %d\n", dtp.uiLengthDrawn ); + + SelectObject(hdc, hOldFont); ret = DeleteObject(hFont); ok( ret, "DeleteObject error %lu\n", GetLastError());
From: chenjiangyi chenjiangyi@uniontech.com
uiLengthDrawn should represent the number of characters that have been processed. However, the original implementation uses len (the count of displayed characters in the current line), which is not accurate.
When text requires line breaks or special processing (such as adding an ellipsis), the actual number of processed characters may differ from the number of displayed characters.
When the DT_CALCRECT flag is absent, len gets decremented to 0 during the drawing loop.
Consequently, uiLengthDrawn becomes inaccurate since it relies on len's value for statistics. --- dlls/user32/tests/text.c | 10 +++++----- dlls/user32/text.c | 8 +++++--- 2 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/dlls/user32/tests/text.c b/dlls/user32/tests/text.c index 963af800b12..80fcdc1da9a 100644 --- a/dlls/user32/tests/text.c +++ b/dlls/user32/tests/text.c @@ -664,7 +664,7 @@ static void test_DrawTextCalcRect(void) memset(&dtp, 0, sizeof(dtp)); dtp.cbSize = sizeof(dtp); textheight = DrawTextExW(hdc, textW, lstrlenW(textW), &rect, DT_EDITCONTROL | DT_NOPREFIX | DT_WORDBREAK, &dtp); - todo_wine ok(dtp.uiLengthDrawn == 16, "Unexpected uiLengthDrawn %d\n", dtp.uiLengthDrawn ); + ok(dtp.uiLengthDrawn == 16, "Unexpected uiLengthDrawn %d\n", dtp.uiLengthDrawn );
memset(&dtp, 0, sizeof(dtp)); dtp.cbSize = sizeof(dtp); @@ -674,22 +674,22 @@ static void test_DrawTextCalcRect(void) memset(&dtp, 0, sizeof(dtp)); dtp.cbSize = sizeof(dtp); textheight = DrawTextExW(hdc, textW, -1, &rect, DT_EXPANDTABS, &dtp); - todo_wine ok(dtp.uiLengthDrawn == 16, "Unexpected uiLengthDrawn %d\n", dtp.uiLengthDrawn ); + ok(dtp.uiLengthDrawn == 16, "Unexpected uiLengthDrawn %d\n", dtp.uiLengthDrawn );
memset(&dtp, 0, sizeof(dtp)); dtp.cbSize = sizeof(dtp); textheight = DrawTextExW(hdc, complex_format_textW, lstrlenW(complex_format_textW), &rect, DT_EDITCONTROL | DT_NOPREFIX | DT_WORDBREAK, &dtp); - todo_wine ok(dtp.uiLengthDrawn == 14, "Unexpected uiLengthDrawn %d\n", dtp.uiLengthDrawn ); + ok(dtp.uiLengthDrawn == 14, "Unexpected uiLengthDrawn %d\n", dtp.uiLengthDrawn );
memset(&dtp, 0, sizeof(dtp)); dtp.cbSize = sizeof(dtp); textheight = DrawTextExW(hdc, complex_format_textW, lstrlenW(complex_format_textW), &rect, DT_EDITCONTROL | DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT, &dtp); - todo_wine ok(dtp.uiLengthDrawn == 37, "Unexpected uiLengthDrawn %d\n", dtp.uiLengthDrawn ); + ok(dtp.uiLengthDrawn == 37, "Unexpected uiLengthDrawn %d\n", dtp.uiLengthDrawn );
memset(&dtp, 0, sizeof(dtp)); dtp.cbSize = sizeof(dtp); textheight = DrawTextExW(hdc, complex_format_textW, -1, &rect, DT_EXPANDTABS, &dtp); - todo_wine ok(dtp.uiLengthDrawn == 37, "Unexpected uiLengthDrawn %d\n", dtp.uiLengthDrawn ); + ok(dtp.uiLengthDrawn == 37, "Unexpected uiLengthDrawn %d\n", dtp.uiLengthDrawn );
SelectObject(hdc, hOldFont); diff --git a/dlls/user32/text.c b/dlls/user32/text.c index 1896627c893..20c73aef80e 100644 --- a/dlls/user32/text.c +++ b/dlls/user32/text.c @@ -871,7 +871,7 @@ INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count, WCHAR *retstr; size_t size_retstr; WCHAR line[MAX_BUFFER]; - int len, lh, count=i_count; + int len, lh, old_count, count=i_count; TEXTMETRICW tm; int lmargin = 0, rmargin = 0; int x, y, width; @@ -978,7 +978,11 @@ INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count, last_line = !(flags & DT_NOCLIP) && y - ((flags & DT_EDITCONTROL) ? 2*lh-1 : lh) < rect->bottom; else last_line = !(flags & DT_NOCLIP) && y + ((flags & DT_EDITCONTROL) ? 2*lh-1 : lh) > rect->bottom; + + old_count = count; strPtr = TEXT_NextLineW(hdc, strPtr, &count, line, &len, width, flags, &size, last_line, retstr, tabwidth, &prefix_offset, &ellip); + if (dtp) + { dtp->uiLengthDrawn += old_count - count; }
if (flags & DT_CENTER) x = (rect->left + lmargin + rect->right - rmargin - size.cx) / 2; @@ -1051,8 +1055,6 @@ INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count, y -= lh; else y += lh; - if (dtp) - dtp->uiLengthDrawn += len; } while (strPtr && !last_line);