From 16a5c4fbca187768e5aea19eb74790122c8bec4e Mon Sep 17 00:00:00 2001 From: Rein Klazes Date: Wed, 26 Oct 2005 10:04:21 +0000 Subject: [PATCH] Fixed a lot of bugs in TEXT_TabbedTextOut. With the test cases used to find them. --- dlls/user/tests/text.c | 90 ++++++++++++++++++++++++++++++++++++++++ dlls/user/text.c | 93 +++++++++++++++++++++--------------------- 2 files changed, 137 insertions(+), 46 deletions(-) diff --git a/dlls/user/tests/text.c b/dlls/user/tests/text.c index b2ba93ca3aa..15188f53664 100644 --- a/dlls/user/tests/text.c +++ b/dlls/user/tests/text.c @@ -111,7 +111,97 @@ static void test_DrawTextCalcRect(void) ok( ret, "DestroyWindow error %lu\n", GetLastError()); } +/* replace tabs by \t */ +static void strfmt( char *str, char *strout) +{ + unsigned int i,j ; + for(i=0,j=0;i<=strlen(str);i++,j++) + if((strout[j]=str[i])=='\t') { + strout[j++]='\\'; + strout[j]='t'; + } +} + + +#define TABTEST( tabval, tabcount, string, _exp) \ +{ int i,x_act, x_exp; char strdisp[64];\ + for(i=0;i<8;i++) tabs[i]=(i+1)*(tabval); \ + extent = GetTabbedTextExtentA( hdc, string, strlen( string), (tabcount), tabs); \ + strfmt( string, strdisp); \ + /* trace( "Extent is %08lx\n", extent); */\ + x_act = LOWORD( extent); \ + x_exp = (_exp); \ + ok( x_act == x_exp, "Test case \"%s\". Text extent is %d, expected %d tab %d tabcount %d\n", \ + strdisp, x_act, x_exp, tabval, tabcount); \ +} \ + + +static void test_TabbedText() +{ + HWND hwnd; + HDC hdc; + BOOL ret; + TEXTMETRICA tm; + DWORD extent; + INT tabs[8], cx, cy, tab, tabcount,t,align; + + /* Initialization */ + hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP, + 0, 0, 200, 200, 0, 0, 0, NULL); + ok(hwnd != 0, "CreateWindowExA error %lu\n", GetLastError()); + hdc = GetDC(hwnd); + ok(hdc != 0, "GetDC error %lu\n", GetLastError()); + + ret = GetTextMetricsA( hdc, &tm); + ok( ret, "GetTextMetrics error %lu\n", GetLastError()); + + extent = GetTabbedTextExtentA( hdc, "x", 1, 1, tabs); + cx = LOWORD( extent); + cy = HIWORD( extent); + trace( "cx is %d cy is %d\n", cx, cy); + + align=1; + for( t=-1; t<=1; t++) { /* slightly adjust the 4 char tabstop, to + catch the one off errors */ + tab = (cx *4 + t); + /* test the special case tabcount =1 and the general array (80 of tabs */ + for( tabcount = 1; tabcount <= 8; tabcount +=7) { + TABTEST( align * tab, tabcount, "\t", tab) + TABTEST( align * tab, tabcount, "xxx\t", tab) + TABTEST( align * tab, tabcount, "\tx", tab+cx) + TABTEST( align * tab, tabcount, "\t\t", tab*2) + TABTEST( align * tab, tabcount, "\tx\t", tab*2) + TABTEST( align * tab, tabcount, "x\tx", tab+cx) + TABTEST( align * tab, tabcount, "xx\tx", tab+cx) + TABTEST( align * tab, tabcount, "xxx\tx", tab+cx) + TABTEST( align * tab, tabcount, "xxxx\tx", t>0 ? tab + cx : 2*tab+cx) + TABTEST( align * tab, tabcount, "xxxxx\tx", 2*tab+cx) + } + } + align=-1; + for( t=-1; t<=1; t++) { /* slightly adjust the 4 char tabstop, to + catch the one off errors */ + tab = (cx *4 + t); + /* test the special case tabcount =1 and the general array (8) of tabs */ + for( tabcount = 1; tabcount <= 8; tabcount +=7) { + TABTEST( align * tab, tabcount, "\t", tab) + TABTEST( align * tab, tabcount, "xxx\t", tab) + TABTEST( align * tab, tabcount, "\tx", tab) + TABTEST( align * tab, tabcount, "\t\t", tab*2) + TABTEST( align * tab, tabcount, "\tx\t", tab*2) + TABTEST( align * tab, tabcount, "x\tx", tab) + TABTEST( align * tab, tabcount, "xx\tx", tab) + TABTEST( align * tab, tabcount, "xxx\tx", 4 * cx >= tab ? 2*tab :tab) + TABTEST( align * tab, tabcount, "xxxx\tx", 2*tab) + TABTEST( align * tab, tabcount, "xxxxx\tx", 2*tab) + } + } + + +} + START_TEST(text) { + test_TabbedText(); test_DrawTextCalcRect(); } diff --git a/dlls/user/text.c b/dlls/user/text.c index c05d008358d..2c3f265e7ff 100644 --- a/dlls/user/text.c +++ b/dlls/user/text.c @@ -28,6 +28,7 @@ #include "wine/port.h" #include +#include #include #include @@ -1214,17 +1215,13 @@ static LONG TEXT_TabbedTextOut( HDC hdc, INT x, INT y, LPCWSTR lpstr, { INT defWidth; SIZE extent; - int i; + int i, j; int start = x; - BOOL first = TRUE; - - extent.cx = 0; - extent.cy = 0; if (!lpTabPos) cTabStops=0; - if (cTabStops == 1 && *lpTabPos >= /* sic */ 0) + if (cTabStops == 1) { defWidth = *lpTabPos; cTabStops = 0; @@ -1234,66 +1231,70 @@ static LONG TEXT_TabbedTextOut( HDC hdc, INT x, INT y, LPCWSTR lpstr, TEXTMETRICA tm; GetTextMetricsA( hdc, &tm ); defWidth = 8 * tm.tmAveCharWidth; - if (cTabStops == 1) - cTabStops = 0; /* on negative *lpTabPos */ } while (count > 0) { - /* tokenize string by tabs */ + RECT r; + INT x0; + x0 = x; + r.left = x0; + /* chop the string into substrings of 0 or more + * possibly followed by 1 or more normal characters */ for (i = 0; i < count; i++) - if (lpstr[i] == '\t') break; - - GetTextExtentPointW( hdc, lpstr, i, &extent ); - - /* the first time round the loop we should use the value of x - * passed into the function. - * all other times, we calculate it here */ - if (!first) - { + if (lpstr[i] != '\t') break; + for (j = i; j < count; j++) + if (lpstr[j] == '\t') break; + /* get the extent of the normal character part */ + GetTextExtentPointW( hdc, lpstr + i, j - i , &extent ); + /* and if there is a , calculate its position */ + if( i) { /* get x coordinate for the drawing of this string */ - for (; cTabStops > 0; lpTabPos++, cTabStops--) + for (; cTabStops > i; lpTabPos++, cTabStops--) { - if (*lpTabPos >= 0) - { - if (nTabOrg + *lpTabPos >= x) - { - x = nTabOrg + *lpTabPos; + if( nTabOrg + abs( *lpTabPos) > x) { + if( lpTabPos[ i - 1] >= 0) { + /* a left aligned tab */ + x = nTabOrg + lpTabPos[ i-1] + extent.cx; break; } - } - else - { - /* if tab pos is negative then text is right-aligned to tab - * stop meaning that the string extends to the left, so we - * must subtract the width of the string */ - if (nTabOrg + -*lpTabPos -extent.cx >= x) + else { - x = nTabOrg + -*lpTabPos - extent.cx; - break; + /* if tab pos is negative then text is right-aligned + * to tab stop meaning that the string extends to the + * left, so we must subtract the width of the string */ + if (nTabOrg - lpTabPos[ i - 1] - extent.cx > x) + { + x = nTabOrg - lpTabPos[ i - 1]; + x0 = x - extent.cx; + break; + } } } } /* if we have run out of tab stops and we have a valid default tab * stop width then round x up to that width */ - if ((cTabStops <= 0) && (defWidth > 0)) - x = nTabOrg + ((x - nTabOrg) / defWidth + 1) * defWidth; - } - else first = FALSE; - + if ((cTabStops <= i) && (defWidth > 0)) { + x0 = nTabOrg + ((x - nTabOrg) / defWidth + i) * defWidth; + x = x0 + extent.cx; + } else if ((cTabStops <= i) && (defWidth < 0)) { + x = nTabOrg + ((x - nTabOrg + extent.cx) / -defWidth + i) + * -defWidth; + x0 = x - extent.cx; + } + } else + x += extent.cx; + if (fDisplayText) { - RECT r; - r.left = x; r.top = y; - r.right = x + extent.cx; + r.right = x; r.bottom = y + extent.cy; - ExtTextOutW( hdc, x, y, GetBkMode(hdc) == OPAQUE ? ETO_OPAQUE : 0, - &r, lpstr, i, NULL ); + ExtTextOutW( hdc, x0, y, GetBkMode(hdc) == OPAQUE ? ETO_OPAQUE : 0, + &r, lpstr + i, j - i, NULL ); } - x += extent.cx; - count -= i+1; - lpstr += i+1; + count -= j; + lpstr += j; } return MAKELONG(x - start, extent.cy); }