From 7423dc04638b177eaa5b150baaef94a5fbfd371d Mon Sep 17 00:00:00 2001 From: Bill Medland Date: Thu, 21 Feb 2002 20:07:26 +0000 Subject: [PATCH] DrawText ellipsification on all lines, not just single-line. --- dlls/user/text.c | 164 +++++++++++++++++++++++++++-------------------- 1 file changed, 94 insertions(+), 70 deletions(-) diff --git a/dlls/user/text.c b/dlls/user/text.c index 5060ba8158e..f5d648acad5 100644 --- a/dlls/user/text.c +++ b/dlls/user/text.c @@ -2,6 +2,7 @@ * USER text functions * * Copyright 1993, 1994 Alexandre Julliard + * Copyright 2002 Bill Medland * * Contains * 1. DrawText functions @@ -24,8 +25,6 @@ DEFAULT_DEBUG_CHANNEL(text); -#define countof(a) (sizeof(a)/sizeof(a[0])) - /********************************************************************* * * DrawText functions @@ -255,29 +254,6 @@ static void TEXT_PathEllipsify (HDC hdc, WCHAR *str, unsigned int max_len, } } -void TEXT_CopySansPrefix (int noprefix, WCHAR *d, int *len_d, const WCHAR *s, int len_s) -{ - if (noprefix) - { - strncpyW (d, s, len_s); - *len_d = len_s; - } - else - { - *len_d = 0; - while (len_s--) - { - if (*s == PREFIX && len_s) - { - len_s--; - s++; - } - *d++ = *s++; - (*len_d)++; - } - } -} - /********************************************************************* * TEXT_WordBreak (static) * @@ -515,6 +491,23 @@ static int TEXT_Reprefix (const WCHAR *str, unsigned int n1, unsigned int n2, return result; } +/********************************************************************* + * Returns true if and only if the remainder of the line is a single + * newline representation or nothing + */ + +static int remainder_is_none_or_newline (int num_chars, const WCHAR *str) +{ + if (!num_chars) return TRUE; + if (*str != LF && *str != CR) return FALSE; + if (!--num_chars) return TRUE; + if (*str == *(str+1)) return FALSE; + str++; + if (*str != CR && *str != LF) return FALSE; + if (--num_chars) return FALSE; + return TRUE; +} + /********************************************************************* * Return next line of text from a string. * @@ -526,13 +519,16 @@ static int TEXT_Reprefix (const WCHAR *str, unsigned int n1, unsigned int n2, * width - maximum width of line in pixels. * format - format type passed to DrawText. * retsize - returned size of the line in pixels. + * last_line - TRUE if is the last line that will be processed + * p_retstr - If DT_MODIFYSTRING this points to a cursor in the buffer in which + * the return string is built. * * Returns pointer to next char in str after end of the line * or NULL if end of str reached. */ static const WCHAR *TEXT_NextLineW( HDC hdc, const WCHAR *str, int *count, - WCHAR *dest, int *len, int width, WORD format, - SIZE *retsize) + WCHAR *dest, int *len, int width, DWORD format, + SIZE *retsize, int last_line, WCHAR **p_retstr) { int i = 0, j = 0; int plen = 0; @@ -544,7 +540,7 @@ static const WCHAR *TEXT_NextLineW( HDC hdc, const WCHAR *str, int *count, int word_broken; int line_fits; int j_in_seg; - + int ellipsified; /* For each text segment in the line */ @@ -600,12 +596,19 @@ static const WCHAR *TEXT_NextLineW( HDC hdc, const WCHAR *str, int *count, } - /* Measure the whole text segment and possibly WordBreak it */ + /* Measure the whole text segment and possibly WordBreak and + * ellipsify it + */ j_in_seg = j - seg_j; max_seg_width = width - plen; GetTextExtentExPointW (hdc, dest + seg_j, j_in_seg, max_seg_width, &num_fit, NULL, &size); + /* The Microsoft handling of various combinations of formats is weird. + * The following may very easily be incorrect if several formats are + * combined, and may differ between versions (to say nothing of the + * several bugs in the Microsoft versions). + */ word_broken = 0; line_fits = (num_fit >= j_in_seg); if (!line_fits && (format & DT_WORDBREAK)) @@ -621,8 +624,69 @@ static const WCHAR *TEXT_NextLineW( HDC hdc, const WCHAR *str, int *count, i = s - str; word_broken = 1; } + len_before_ellipsis = j_in_seg; + len_under_ellipsis = 0; + len_after_ellipsis = 0; + len_ellipsis = 0; + ellipsified = 0; + if (!line_fits && (format & DT_PATH_ELLIPSIS)) + { + TEXT_PathEllipsify (hdc, dest + seg_j, maxl-seg_j, &j_in_seg, + max_seg_width, &size, *p_retstr, &len_before_ellipsis, &len_ellipsis, &len_under_ellipsis, &len_after_ellipsis); + line_fits = (size.cx <= max_seg_width); + ellipsified = 1; + } + /* NB we may end up ellipsifying a word-broken or path_ellipsified + * string */ + if ((!line_fits && (format & DT_WORD_ELLIPSIS)) || + ((format & DT_END_ELLIPSIS) && + ((last_line && *count) || + (remainder_is_none_or_newline (*count, &str[i]) && !line_fits)))) + { + int before; + TEXT_Ellipsify (hdc, dest + seg_j, maxl-seg_j, &j_in_seg, + max_seg_width, &size, *p_retstr, &before, &len_ellipsis); + if (before > len_before_ellipsis) + { + /* We must have done a path ellipsis too */ + len_after_ellipsis = before - len_before_ellipsis - len_ellipsis; + } + else + { + len_before_ellipsis = before; + /* len_after_ellipsis remains as zero as does + * len_under_ellsipsis + */ + } + line_fits = (size.cx <= max_seg_width); + ellipsified = 1; + } + /* As an optimisation if we have ellipsified and we are expanding + * tabs and we haven't reached the end of the line we can skip to it + * now rather than going around the loop again. + */ + if ((format & DT_EXPANDTABS) && ellipsified) + { + if (format & DT_SINGLELINE) + *count = 0; + else + { + while ((*count) && str[i] != CR && str[i] != LF) + { + (*count)--, i++; + } + } + } j = seg_j + j_in_seg; + if (prefix_offset >= seg_j + len_before_ellipsis) + { + prefix_offset = TEXT_Reprefix (str + seg_i, len_before_ellipsis, + len_under_ellipsis, len_ellipsis, + len_after_ellipsis); + if (prefix_offset != -1) + prefix_offset += seg_j; + } plen += size.cx; if (size.cy > retsize->cy) @@ -772,7 +836,7 @@ INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count, prefix_offset = -1; len = MAX_STATIC_BUFFER; 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); + strPtr = TEXT_NextLineW(hdc, strPtr, &count, line, &len, width, flags, &size, last_line, &p_retstr); if (flags & DT_CENTER) x = (rect->left + rect->right - size.cx) / 2; @@ -785,46 +849,6 @@ INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count, else if (flags & DT_BOTTOM) y = rect->bottom - size.cy; } - if ((flags & DT_SINGLELINE) && size.cx > width && - (flags & (DT_PATH_ELLIPSIS | DT_END_ELLIPSIS | DT_WORD_ELLIPSIS))) - { - if ((flags & DT_EXPANDTABS)) - { - /* If there are tabs then we must only ellipsify the last - * segment. That will become trivial when we move the - * ellipsification into the TEXT_NextLineW (coming soon) - */ - const WCHAR *p; - p = line + len; - while (p > line) - if (*(--p) == TAB) - { - FIXME ("Ellipsification of single line tabbed strings will be fixed shortly\n"); - break; - } - } - - if (flags & DT_PATH_ELLIPSIS) - { - /* We may need to remeasure the string because it was clipped */ - if ((flags & DT_WORDBREAK) || !(flags & DT_NOCLIP)) - TEXT_CopySansPrefix ((flags & DT_NOPREFIX), line, &len, str, i_count >= 0 ? i_count : strlenW(str)); - TEXT_PathEllipsify (hdc, line, countof(line), &len, width, &size, retstr, &len_before_ellipsis, &len_ellipsis, &len_under_ellipsis, &len_after_ellipsis); - } - else - { - TEXT_Ellipsify (hdc, line, countof(line), &len, width, &size, retstr, &len_before_ellipsis, &len_ellipsis); - len_after_ellipsis = 0; - len_under_ellipsis = 0; /* It is under the path ellipsis */ - } - - strPtr = NULL; - - if (prefix_offset >= 0 && - prefix_offset >= len_before_ellipsis) - prefix_offset = TEXT_Reprefix (str, len_before_ellipsis, len_under_ellipsis, len_ellipsis, len_after_ellipsis); - - } if (!(flags & DT_CALCRECT)) { const WCHAR *str = line;