From cabe8ca58054757aa71d46afc6a8b0c373e90c52 Mon Sep 17 00:00:00 2001 From: Bill Medland Date: Tue, 12 Feb 2002 18:40:36 +0000 Subject: [PATCH] Put in place a proper tab model within DrawText (also includes simplifying TEXT_NextLineW to remove duplicate code). --- dlls/user/text.c | 202 ++++++++++++++++++++++++++++++----------------- 1 file changed, 128 insertions(+), 74 deletions(-) diff --git a/dlls/user/text.c b/dlls/user/text.c index 9c4189de962..abdf84c4624 100644 --- a/dlls/user/text.c +++ b/dlls/user/text.c @@ -75,15 +75,9 @@ DEFAULT_DEBUG_CHANNEL(text); #define FORWARD_SLASH '/' #define BACK_SLASH '\\' -static const WCHAR SPACEW[] = {' ', 0}; -static const WCHAR oW[] = {'o', 0}; static const WCHAR ELLIPSISW[] = {'.','.','.', 0}; -static const WCHAR FORWARD_SLASHW[] = {'/', 0}; -static const WCHAR BACK_SLASHW[] = {'\\', 0}; -static int tabstop; static int tabwidth; -static int spacewidth; static int prefix_offset; /********************************************************************* @@ -349,23 +343,24 @@ static int TEXT_Reprefix (const WCHAR *str, unsigned int n1, unsigned int n2, static const WCHAR *TEXT_NextLineW( HDC hdc, const WCHAR *str, int *count, WCHAR *dest, int *len, int width, WORD format) { - int i = 0, j = 0, k; + int i = 0, j = 0; int plen = 0; - int numspaces; SIZE size; - int lasttab = 0; int wb_i = 0, wb_j = 0, wb_count = 0; int maxl = *len; + int normal_char; while (*count && j < maxl) { + normal_char = 1; switch (str[i]) { case CR: case LF: if (!(format & DT_SINGLELINE)) { - if ((*count > 1) && (str[i] == CR) && (str[i+1] == LF)) + if ((*count > 1) && (((str[i] == CR) && (str[i+1] == LF)) || + ((str[i] == LF) && (str[i+1] == CR)))) { (*count)--; i++; @@ -375,89 +370,61 @@ static const WCHAR *TEXT_NextLineW( HDC hdc, const WCHAR *str, int *count, (*count)--; return (&str[i]); } - dest[j++] = str[i++]; - if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) || - (format & DT_WORDBREAK)) - { - if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size)) - return NULL; - plen += size.cx; - } + /* else it's just another character */ break; case PREFIX: if (!(format & DT_NOPREFIX) && *count > 1) { if (str[++i] == PREFIX) - (*count)--; + (*count)--; /* and treat it as just another character */ else { prefix_offset = j; + normal_char = 0; /* we are skipping the PREFIX itself */ break; } } - dest[j++] = str[i++]; - if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) || - (format & DT_WORDBREAK)) - { - if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size)) - return NULL; - plen += size.cx; - } break; case TAB: if (format & DT_EXPANDTABS) { - wb_i = ++i; - wb_j = j; - wb_count = *count; + if ((format & DT_WORDBREAK)) + { + wb_i = i+1; + wb_j = j; + wb_count = *count; + } - if (!GetTextExtentPointW(hdc, &dest[lasttab], j - lasttab, &size)) - return NULL; - - numspaces = (tabwidth - size.cx) / spacewidth; - for (k = 0; k < numspaces; k++) - dest[j++] = SPACE; - plen += tabwidth - size.cx; - lasttab = wb_j + numspaces; - } - else - { - dest[j++] = str[i++]; - if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) || - (format & DT_WORDBREAK)) - { - if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size)) - return NULL; - plen += size.cx; - } + normal_char = 0; + dest[j++] = str[i++]; + if (!(format & DT_NOCLIP) || (format & DT_WORDBREAK)) + plen = ((plen/tabwidth)+1)*tabwidth; } break; case SPACE: - dest[j++] = str[i++]; - if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) || - (format & DT_WORDBREAK)) + if ((format & DT_WORDBREAK)) { - wb_i = i; - wb_j = j - 1; + wb_i = i+1; + wb_j = j; wb_count = *count; - if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size)) - return NULL; - plen += size.cx; - } + } break; default: + + } + if (normal_char) + { dest[j++] = str[i++]; - if (!(format & DT_NOCLIP) || !(format & DT_NOPREFIX) || - (format & DT_WORDBREAK)) + if (!(format & DT_NOCLIP) || (format & DT_WORDBREAK)) { if (!GetTextExtentPointW(hdc, &dest[j-1], 1, &size)) return NULL; plen += size.cx; } - } + } (*count)--; if (!(format & DT_NOCLIP) || (format & DT_WORDBREAK)) @@ -523,6 +490,39 @@ static void TEXT_DrawUnderscore (HDC hdc, int x, int y, const WCHAR *str, int of DeleteObject (hpen); } +/* We are only going to need this until we correct the measuring in + * TEXT_NextLineW (coming soon) + */ +static int TEXT_TextExtent (HDC hdc, UINT flags, const WCHAR *line, int len, SIZE *size) +{ + if ((flags & DT_EXPANDTABS)) + { + SIZE tsize; + const WCHAR *p; + size->cx = 0; + size->cy = 0; + while (len) + { + p = line; while (p < line+len && *p != TAB) p++; + if (!GetTextExtentPointW (hdc, line, p-line, &tsize)) return 0; + size->cx += tsize.cx; + if (tsize.cy > size->cy) size->cy = tsize.cy; + len -= (p-line); + line=p; + if (len) + { + assert (*line == TAB); + len--; + line++; + size->cx = ((size->cx/tabwidth)+1)*tabwidth; + } + } + return 1; + } + else + return GetTextExtentPointW(hdc, line, len, size); +} + /*********************************************************************** * DrawTextExW (USER32.@) * @@ -573,14 +573,10 @@ INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count, dtp->uiLengthDrawn = 0; /* This param RECEIVES number of chars processed */ } - tabstop = ((flags & DT_TABSTOP) && dtp) ? dtp->iTabLength : 8; - if (flags & DT_EXPANDTABS) { - GetTextExtentPointW(hdc, SPACEW, 1, &size); - spacewidth = size.cx; - GetTextExtentPointW(hdc, oW, 1, &size); - tabwidth = size.cx * tabstop; + int tabstop = ((flags & DT_TABSTOP) && dtp) ? dtp->iTabLength : 8; + tabwidth = tm.tmAveCharWidth * tabstop; } if (flags & DT_CALCRECT) flags |= DT_NOCLIP; @@ -591,7 +587,7 @@ INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count, len = MAX_STATIC_BUFFER; strPtr = TEXT_NextLineW(hdc, strPtr, &count, line, &len, width, flags); - if (!GetTextExtentPointW(hdc, line, len, &size)) return 0; + if (!TEXT_TextExtent(hdc, flags, line, len, &size)) return 0; if (flags & DT_CENTER) x = (rect->left + rect->right - size.cx) / 2; else if (flags & DT_RIGHT) x = rect->right - size.cx; @@ -611,6 +607,22 @@ INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count, int len_ellipsis; int len_after_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 */ @@ -637,12 +649,54 @@ INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count, } if (!(flags & DT_CALCRECT)) { - if (!ExtTextOutW( hdc, x, y, - ((flags & DT_NOCLIP) ? 0 : ETO_CLIPPED) | - ((flags & DT_RTLREADING) ? ETO_RTLREADING : 0), - rect, line, len, NULL )) return 0; - if (prefix_offset != -1) - TEXT_DrawUnderscore (hdc, x, y + tm.tmAscent + 1, line, prefix_offset); + const WCHAR *str = line; + int xseg = x; + while (len) + { + int len_seg; + SIZE size; + if ((flags & DT_EXPANDTABS)) + { + const WCHAR *p; + p = str; while (p < str+len && *p != TAB) p++; + len_seg = p - str; + if (len_seg != len && !GetTextExtentPointW(hdc, str, len_seg, &size)) + return 0; + } + else + len_seg = len; + + if (!ExtTextOutW( hdc, xseg, y, + ((flags & DT_NOCLIP) ? 0 : ETO_CLIPPED) | + ((flags & DT_RTLREADING) ? ETO_RTLREADING : 0), + rect, str, len_seg, NULL )) return 0; + if (prefix_offset != -1 && prefix_offset < len_seg) + { + TEXT_DrawUnderscore (hdc, xseg, y + tm.tmAscent + 1, str, prefix_offset); + } + len -= len_seg; + str += len_seg; + if (len) + { + assert ((flags & DT_EXPANDTABS) && *str == TAB); + len--; str++; + xseg += ((size.cx/tabwidth)+1)*tabwidth; + if (prefix_offset != -1) + { + if (prefix_offset < len_seg) + { + /* We have just drawn an underscore; we ought to + * figure out where the next one is. I am going + * to leave it for now until I have a better model + * for the line, which will make reprefixing easier + */ + prefix_offset = -1; + } + else + prefix_offset -= len_seg; + } + } + } } else if (size.cx > max_width) max_width = size.cx;