[PATCH 3/5] user32: Refactor DrawTextEx() with a dynamic array for lines.

Huw Davies huw at codeweavers.com
Tue May 8 04:17:34 CDT 2018


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 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;

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_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