Drawtext tidying up ready for the next big change:
- Fix brainfade in previous delta
- Move ellipsification results to static memory; they are going to
  have to be referenced inside NextLineW and the arg list is too big
  already.
- Add the missing ellipsification result (len_under) to simplify coding.
- Slight correction to prefix tracking for when there are several
  underlined characters on a single line (DT_EXPANDTABS only).
- Allocate and free the temporary copy required for DT_MODIFYSTRING
  rather than using a fixed size stack array.
- Introduce lastline into the main loop; it simplifies the code and we
  are going to need it.

diff --git a/dlls/user/text.c b/dlls/user/text.c
index 0848961..5060ba8 100644
--- a/dlls/user/text.c
+++ b/dlls/user/text.c
@@ -76,8 +76,13 @@
 
 static const WCHAR ELLIPSISW[] = {'.','.','.', 0};
 
+/* These will have to go into a structure to be passed around rather than
+ * sitting in static memory
+ */
 static int tabwidth;
 static int prefix_offset;
+static int len_before_ellipsis, len_ellipsis, len_under_ellipsis,
+           len_after_ellipsis;
 
 /*********************************************************************
  *                      TEXT_Ellipsify (static)
@@ -165,6 +170,7 @@
  *                    the modified string is not required.
  *   len_before [out] The number of characters before the ellipsis.
  *   len_ellip  [out] The number of characters in the ellipsis.
+ *   len_under  [out] The number of characters replaced by the ellipsis.
  *   len_after  [out] The number of characters after the ellipsis.
  *
  * For now we will simply use three dots rather than worrying about whether
@@ -190,7 +196,8 @@
 static void TEXT_PathEllipsify (HDC hdc, WCHAR *str, unsigned int max_len,
                                 unsigned int *len_str, int width, SIZE *size,
                                 WCHAR *modstr,
-                                int *len_before, int *len_ellip, int *len_after)
+                                int *len_before, int *len_ellip, int *len_under,
+                                int *len_after)
 {
     int len_ellipsis;
     int len_trailing;
@@ -220,6 +227,7 @@
      * of the last slash and len_trailing includes the ellipsis
      */
 
+    *len_under = 0;
     for ( ; ; )
     {
         if (!GetTextExtentExPointW (hdc, str, *len_str + len_ellipsis, width,
@@ -230,6 +238,7 @@
         /* overlap-safe movement to the left */
         memmove (lastSlash-1, lastSlash, len_trailing * sizeof(WCHAR));
         lastSlash--;
+        (*len_under)++;
         
         assert (*len_str);
         (*len_str)--;
@@ -533,6 +542,8 @@
     int max_seg_width;
     int num_fit;
     int word_broken;
+    int line_fits;
+    int j_in_seg;
 
 
     /* For each text segment in the line */
@@ -573,10 +584,14 @@
                     /* Swallow it before we see it again */
 		    (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++;
                 }
-		else
+		else if (prefix_offset == -1 || prefix_offset >= seg_j)
                 {
                     prefix_offset = j;
                 }
+                /* else the previous prefix was in an earlier segment of the
+                 * line; we will leave it to the drawing code to catch this
+                 * one.
+                 */
 	    }
             else
             {
@@ -587,25 +602,28 @@
 
         /* Measure the whole text segment and possibly WordBreak it */
 
+        j_in_seg = j - seg_j;
         max_seg_width = width - plen;
-        GetTextExtentExPointW (hdc, dest + seg_j, j - seg_j, max_seg_width, &num_fit, NULL, &size);
+        GetTextExtentExPointW (hdc, dest + seg_j, j_in_seg, max_seg_width, &num_fit, NULL, &size);
 
         word_broken = 0;
-        if (num_fit < j-seg_j && (format & DT_WORDBREAK))
+        line_fits = (num_fit >= j_in_seg);
+        if (!line_fits && (format & DT_WORDBREAK))
         {
             const WCHAR *s;
             int chars_used;
-            int j_in_seg = j-seg_j;
             TEXT_WordBreak (hdc, dest+seg_j, maxl-seg_j, &j_in_seg,
                             max_seg_width, format, num_fit, &chars_used, &size);
+            line_fits = (size.cx <= max_seg_width);
             /* and correct the counts */
-            j = seg_j + j_in_seg;
             TEXT_SkipChars (count, &s, seg_count, str+seg_i, i-seg_i,
                             chars_used, !(format & DT_NOPREFIX));
             i = s - str;
             word_broken = 1;
         }
 
+        j = seg_j + j_in_seg;
+
         plen += size.cx;
         if (size.cy > retsize->cy)
             retsize->cy = size.cy;
@@ -616,10 +634,10 @@
             break;
         else if (str[i] == CR || str[i] == LF)
         {
-            count--, i++;
-            if (count && (str[i] == CR || str[i] == LF) && str[i] != str[i-1])
+            (*count)--, i++;
+            if (*count && (str[i] == CR || str[i] == LF) && str[i] != str[i-1])
             {
-                count--, i++;
+                (*count)--, i++;
             }
             break;
         }
@@ -687,6 +705,8 @@
 {
     SIZE size;
     const WCHAR *strPtr;
+    WCHAR *retstr, *p_retstr;
+    size_t size_retstr;
     static WCHAR line[MAX_STATIC_BUFFER];
     int len, lh, count=i_count;
     TEXTMETRICW tm;
@@ -694,6 +714,7 @@
     int x = rect->left, y = rect->top;
     int width = rect->right - rect->left;
     int max_width = 0;
+    int last_line;
 
     TRACE("%s, %d , [(%d,%d),(%d,%d)]\n", debugstr_wn (str, count), count,
 	  rect->left, rect->top, rect->right, rect->bottom);
@@ -732,10 +753,25 @@
 
     if (flags & DT_CALCRECT) flags |= DT_NOCLIP;
 
+    if (flags & DT_MODIFYSTRING)
+    {
+        size_retstr = (count + 4) * sizeof (WCHAR);
+        retstr = HeapAlloc(GetProcessHeap(), 0, size_retstr);
+        if (!retstr) return 0;
+        memcpy (retstr, str, size_retstr);
+    }
+    else
+    {
+        size_retstr = 0;
+        retstr = NULL;
+    }
+    p_retstr = retstr;
+
     do
     {
 	prefix_offset = -1;
 	len = MAX_STATIC_BUFFER;
+        last_line = !(flags & DT_NOCLIP) && y + ((flags & DT_EDITCONTROL) ? 2*lh-1 : lh) > rect->bottom;
 	strPtr = TEXT_NextLineW(hdc, strPtr, &count, line, &len, width, flags, &size);
 
 	if (flags & DT_CENTER) x = (rect->left + rect->right -
@@ -752,11 +788,6 @@
         if ((flags & DT_SINGLELINE) && size.cx > width &&
 	    (flags & (DT_PATH_ELLIPSIS | DT_END_ELLIPSIS | DT_WORD_ELLIPSIS)))
         {
-            WCHAR tmpstr[countof(line)];
-            int len_before_ellipsis;
-            int len_ellipsis;
-            int len_after_ellipsis;
-
             if ((flags & DT_EXPANDTABS))
             {
                 /* If there are tabs then we must only ellipsify the last
@@ -778,23 +809,20 @@
                 /* We may need to remeasure the string because it was clipped */
                 if ((flags & DT_WORDBREAK) || !(flags & DT_NOCLIP))
                     TEXT_CopySansPrefix ((flags & DT_NOPREFIX), line, &len, str, i_count >= 0 ? i_count : strlenW(str));
-                TEXT_PathEllipsify (hdc, line, countof(line), &len, width, &size, tmpstr, &len_before_ellipsis, &len_ellipsis, &len_after_ellipsis);
+                TEXT_PathEllipsify (hdc, line, countof(line), &len, width, &size, retstr, &len_before_ellipsis, &len_ellipsis, &len_under_ellipsis, &len_after_ellipsis);
             }
             else
             {
-                TEXT_Ellipsify (hdc, line, countof(line), &len, width, &size, tmpstr, &len_before_ellipsis, &len_ellipsis);
+                TEXT_Ellipsify (hdc, line, countof(line), &len, width, &size, retstr, &len_before_ellipsis, &len_ellipsis);
                 len_after_ellipsis = 0;
+                len_under_ellipsis = 0; /* It is under the path ellipsis */
             }
 
             strPtr = NULL; 
 
             if (prefix_offset >= 0 &&
                 prefix_offset >= len_before_ellipsis)
-                prefix_offset = TEXT_Reprefix (str, len_before_ellipsis, strlenW(str)-len_ellipsis-len_before_ellipsis-len_after_ellipsis, len_ellipsis, len_after_ellipsis);
-
-            if (flags & DT_MODIFYSTRING)
-                strcpyW(str, tmpstr);
-
+                prefix_offset = TEXT_Reprefix (str, len_before_ellipsis, len_under_ellipsis, len_ellipsis, len_after_ellipsis);
 
 	}
 	if (!(flags & DT_CALCRECT))
@@ -852,18 +880,10 @@
 	    max_width = size.cx;
 
 	y += lh;
-	if (strPtr)
-	{
-	    if (!(flags & DT_NOCLIP))
-	    {
-		if (y > rect->bottom - lh)
-		    break;
-	    }
-	}
         if (dtp)
             dtp->uiLengthDrawn += len;
     }
-    while (strPtr);
+    while (strPtr && !last_line);
 
     if (flags & DT_CALCRECT)
     {
@@ -872,6 +892,11 @@
         if (dtp)
             rect->right += lmargin + rmargin;
     }
+    if (retstr)
+    {
+        memcpy (str, retstr, size_retstr);
+        HeapFree (GetProcessHeap(), 0, retstr);
+    }
     return y - rect->top;
 }