With this patch, getting text rect height with DT_CALCRECT doesn't need a second loop with TEXT_NextLineW(). Text rect height is needed for coordinates calculation with DT_BOTTOM set.
Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- dlls/user32/text.c | 102 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 79 insertions(+), 23 deletions(-)
diff --git a/dlls/user32/text.c b/dlls/user32/text.c index 3ba4a129cf..dbde596a1c 100644 --- a/dlls/user32/text.c +++ b/dlls/user32/text.c @@ -856,6 +856,13 @@ static void TEXT_DrawUnderscore (HDC hdc, int x, int y, const WCHAR *str, int of DeleteObject (hpen); }
+struct line_info +{ + int length; + int x; + int prefix_offset; +}; + /*********************************************************************** * DrawTextExW (USER32.@) * @@ -866,7 +873,9 @@ static void TEXT_DrawUnderscore (HDC hdc, int x, int y, const WCHAR *str, int of * 3 more than a null-terminated string). If this is not so then increase * the allowance in DrawTextExA. */ -#define MAX_BUFFER 1024 +#define MIN_BUFFER_SIZE 1024 +#define INIT_BUFFER_SIZE (MIN_BUFFER_SIZE * 2) +#define INIT_LINES_COUNT 4 INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count, LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp ) { @@ -874,11 +883,14 @@ INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count, const WCHAR *strPtr; WCHAR *retstr, *p_retstr; size_t size_retstr; - WCHAR line[MAX_BUFFER]; + WCHAR lines_buffer[INIT_BUFFER_SIZE], *lines_ptr = lines_buffer; + int used_buffer = 0, buffer_size = ARRAY_SIZE(lines_buffer), line_offset = 0; + struct line_info lines_info_buffer[INIT_LINES_COUNT], *lines_info_ptr = lines_info_buffer; + int used_lines = 0, lines_size = ARRAY_SIZE(lines_info_buffer), line_num; int len, lh, count=i_count; TEXTMETRICW tm; int lmargin = 0, rmargin = 0; - int x = rect->left, y = rect->top; + int x = rect->left, y = rect->top, xseg; int width = rect->right - rect->left; int max_width = 0; int last_line; @@ -972,28 +984,77 @@ INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count,
do { - len = ARRAY_SIZE(line); + len = buffer_size - used_buffer; + if (len < MIN_BUFFER_SIZE) + { + buffer_size *= 2; + if (lines_ptr == lines_buffer) + { + lines_ptr = heap_alloc(sizeof(*lines_ptr) * buffer_size); + if (lines_ptr) memcpy(lines_ptr, lines_buffer, sizeof(lines_buffer)); + } + else + lines_ptr = heap_realloc(lines_ptr, sizeof(*lines_ptr) * buffer_size); + if (!lines_ptr) goto done; + len = buffer_size - used_buffer; + } + if (used_lines >= lines_size) + { + lines_size *= 2; + if (lines_info_ptr == lines_info_buffer) + { + lines_info_ptr = heap_alloc(sizeof(*lines_info_ptr) * lines_size); + if (lines_info_ptr) memcpy(lines_info_ptr, lines_info_buffer, sizeof(lines_info_buffer)); + } + else + lines_info_ptr = heap_realloc(lines_info_ptr, sizeof(*lines_info_ptr) * lines_size); + if (!lines_info_ptr) goto done; + } + if (invert_y) 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; - strPtr = TEXT_NextLineW(hdc, strPtr, &count, line, &len, width, flags, &size, last_line, &p_retstr, tabwidth, &prefix_offset, &ellip); + strPtr = TEXT_NextLineW(hdc, strPtr, &count, lines_ptr + used_buffer, &len, width, flags, &size, last_line, &p_retstr, tabwidth, &prefix_offset, &ellip);
if (flags & DT_CENTER) x = (rect->left + rect->right - size.cx) / 2; else if (flags & DT_RIGHT) x = rect->right - size.cx;
- if (flags & DT_SINGLELINE) + lines_info_ptr[used_lines].length = len; + lines_info_ptr[used_lines].x = x; + lines_info_ptr[used_lines].prefix_offset = prefix_offset; + used_buffer += len; + used_lines++; + + if (size.cx > max_width) max_width = size.cx; + + if (invert_y) + y -= lh; + else + y += lh; + if (dtp) + dtp->uiLengthDrawn += len; + } + while (strPtr && !last_line); + + if (!(flags & DT_CALCRECT)) + { + y = rect->top; + if (flags & DT_SINGLELINE) { if (flags & DT_VCENTER) y = rect->top + (rect->bottom - rect->top) / 2 - size.cy / 2; else if (flags & DT_BOTTOM) y = rect->bottom - size.cy; }
- if (!(flags & DT_CALCRECT)) - { - const WCHAR *str = line; - int xseg = x; + for (line_num = 0; line_num < used_lines; line_num++) + { + const WCHAR *str = lines_ptr + line_offset; + line_offset += lines_info_ptr[line_num].length; + len = lines_info_ptr[line_num].length; + xseg = lines_info_ptr[line_num].x; + prefix_offset = lines_info_ptr[line_num].prefix_offset; while (len) { int len_seg; @@ -1041,20 +1102,13 @@ INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count, } } } - } - else if (size.cx > max_width) - max_width = size.cx; - - if (invert_y) - y -= lh; - else - y += lh; - if (dtp) - dtp->uiLengthDrawn += len; + if (invert_y) + y -= lh; + else + y += lh; + } } - while (strPtr && !last_line); - - if (flags & DT_CALCRECT) + else { rect->right = rect->left + max_width; rect->bottom = y; @@ -1067,6 +1121,8 @@ INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count, ret = y - rect->top; done: heap_free(retstr); + if (lines_ptr != lines_buffer) heap_free(lines_ptr); + if (lines_info_ptr != lines_info_buffer) heap_free(lines_info_ptr); return ret; }