[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