Fixed a lot of bugs in TEXT_TabbedTextOut. With the test cases used to

find them.
This commit is contained in:
Rein Klazes 2005-10-26 10:04:21 +00:00 committed by Alexandre Julliard
parent ca025e2245
commit 16a5c4fbca
2 changed files with 137 additions and 46 deletions

View File

@ -111,7 +111,97 @@ static void test_DrawTextCalcRect(void)
ok( ret, "DestroyWindow error %lu\n", GetLastError()); 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) START_TEST(text)
{ {
test_TabbedText();
test_DrawTextCalcRect(); test_DrawTextCalcRect();
} }

View File

@ -28,6 +28,7 @@
#include "wine/port.h" #include "wine/port.h"
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
@ -1214,17 +1215,13 @@ static LONG TEXT_TabbedTextOut( HDC hdc, INT x, INT y, LPCWSTR lpstr,
{ {
INT defWidth; INT defWidth;
SIZE extent; SIZE extent;
int i; int i, j;
int start = x; int start = x;
BOOL first = TRUE;
extent.cx = 0;
extent.cy = 0;
if (!lpTabPos) if (!lpTabPos)
cTabStops=0; cTabStops=0;
if (cTabStops == 1 && *lpTabPos >= /* sic */ 0) if (cTabStops == 1)
{ {
defWidth = *lpTabPos; defWidth = *lpTabPos;
cTabStops = 0; cTabStops = 0;
@ -1234,66 +1231,70 @@ static LONG TEXT_TabbedTextOut( HDC hdc, INT x, INT y, LPCWSTR lpstr,
TEXTMETRICA tm; TEXTMETRICA tm;
GetTextMetricsA( hdc, &tm ); GetTextMetricsA( hdc, &tm );
defWidth = 8 * tm.tmAveCharWidth; defWidth = 8 * tm.tmAveCharWidth;
if (cTabStops == 1)
cTabStops = 0; /* on negative *lpTabPos */
} }
while (count > 0) 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 <tabs>
* possibly followed by 1 or more normal characters */
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
if (lpstr[i] == '\t') break; if (lpstr[i] != '\t') break;
for (j = i; j < count; j++)
GetTextExtentPointW( hdc, lpstr, i, &extent ); if (lpstr[j] == '\t') break;
/* get the extent of the normal character part */
/* the first time round the loop we should use the value of x GetTextExtentPointW( hdc, lpstr + i, j - i , &extent );
* passed into the function. /* and if there is a <tab>, calculate its position */
* all other times, we calculate it here */ if( i) {
if (!first)
{
/* get x coordinate for the drawing of this string */ /* get x coordinate for the drawing of this string */
for (; cTabStops > 0; lpTabPos++, cTabStops--) for (; cTabStops > i; lpTabPos++, cTabStops--)
{ {
if (*lpTabPos >= 0) if( nTabOrg + abs( *lpTabPos) > x) {
{ if( lpTabPos[ i - 1] >= 0) {
if (nTabOrg + *lpTabPos >= x) /* a left aligned tab */
{ x = nTabOrg + lpTabPos[ i-1] + extent.cx;
x = nTabOrg + *lpTabPos;
break; break;
} }
}
else else
{ {
/* if tab pos is negative then text is right-aligned to tab /* if tab pos is negative then text is right-aligned
* stop meaning that the string extends to the left, so we * to tab stop meaning that the string extends to the
* must subtract the width of the string */ * left, so we must subtract the width of the string */
if (nTabOrg + -*lpTabPos -extent.cx >= x) if (nTabOrg - lpTabPos[ i - 1] - extent.cx > x)
{ {
x = nTabOrg + -*lpTabPos - extent.cx; x = nTabOrg - lpTabPos[ i - 1];
x0 = x - extent.cx;
break; break;
} }
} }
} }
}
/* if we have run out of tab stops and we have a valid default tab /* if we have run out of tab stops and we have a valid default tab
* stop width then round x up to that width */ * stop width then round x up to that width */
if ((cTabStops <= 0) && (defWidth > 0)) if ((cTabStops <= i) && (defWidth > 0)) {
x = nTabOrg + ((x - nTabOrg) / defWidth + 1) * defWidth; 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 first = FALSE; } else
x += extent.cx;
if (fDisplayText) if (fDisplayText)
{ {
RECT r;
r.left = x;
r.top = y; r.top = y;
r.right = x + extent.cx; r.right = x;
r.bottom = y + extent.cy; r.bottom = y + extent.cy;
ExtTextOutW( hdc, x, y, GetBkMode(hdc) == OPAQUE ? ETO_OPAQUE : 0, ExtTextOutW( hdc, x0, y, GetBkMode(hdc) == OPAQUE ? ETO_OPAQUE : 0,
&r, lpstr, i, NULL ); &r, lpstr + i, j - i, NULL );
} }
x += extent.cx; count -= j;
count -= i+1; lpstr += j;
lpstr += i+1;
} }
return MAKELONG(x - start, extent.cy); return MAKELONG(x - start, extent.cy);
} }