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; }
On Fri, May 04, 2018 at 11:12:37AM +0800, Zhiyi Zhang wrote:
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;
This patch is still pretty confusing I'm afraid. Part of the problem is the bad choice of the above variable names, so since that's easy to fix let's start with that.
The lines_buffer, lines_ptr etc set doesn't really have anything to do with a 'line' (the buffer it replaced did, since it held the current line). 'text' might be a better name. Also lose the _ptr suffix, it doesn't help. So we'd have text_buffer, text. Then the ints would be text_used and text_size and text_offset. (Note how 'text' is always first). TEXT_INIT_SIZE would be the #define
For the line_info stuff I'd go with lines_buffer, lines, lines_used, lines_size and line_num (lines_num seems odd). LINES_INIT_SIZE for the #define.
Btw, please make sure you've tested the allocation stuff by setting the initial buffer sizes to something small.
Huw.
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_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_SINGLELINE)
- 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