[PATCH 3/5] user32: Refactor DrawTextEx() with a dynamic array for lines.
Zhiyi Zhang
zzhang at codeweavers.com
Thu May 3 22:12:37 CDT 2018
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 at 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;
}
--
2.17.0
More information about the wine-devel
mailing list