Put in place a proper tab model within DrawText (also includes
simplifying TEXT_NextLineW to remove duplicate code).

diff --git a/dlls/user/text.c b/dlls/user/text.c
index 9c4189d..abdf84c 100644
--- a/dlls/user/text.c
+++ b/dlls/user/text.c
@@ -75,15 +75,9 @@
 #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 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 @@
 		(*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 @@
     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 @@
         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 @@
 	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 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 @@
 	}
 	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;