Fixed a lot of bugs in TEXT_TabbedTextOut. With the test cases used to find them.
diff --git a/dlls/user/text.c b/dlls/user/text.c index c05d008..2c3f265 100644 --- a/dlls/user/text.c +++ b/dlls/user/text.c
@@ -28,6 +28,7 @@ #include "wine/port.h" #include <stdarg.h> +#include <stdlib.h> #include <string.h> #include <assert.h> @@ -1214,17 +1215,13 @@ { 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 @@ 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 <tabs> + * 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 <tab>, 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); }