Pedro Araujo Chaves Jr : gdi32: Fix for GetTextExtentExPointW() and ExtTextOutW().

Alexandre Julliard julliard at wine.codeweavers.com
Thu Feb 15 12:52:14 CST 2007


Module: wine
Branch: master
Commit: 2051bcccca872da2a975dfe987622ed3dab9f881
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=2051bcccca872da2a975dfe987622ed3dab9f881

Author: Pedro Araujo Chaves Jr <inckie at gmail.com>
Date:   Thu Feb  8 13:12:08 2007 -0200

gdi32: Fix for GetTextExtentExPointW() and ExtTextOutW().

---

 dlls/gdi32/font.c       |   53 +++++++++++++++++---
 dlls/gdi32/tests/font.c |  124 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 169 insertions(+), 8 deletions(-)

diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c
index 876e49a..f237612 100644
--- a/dlls/gdi32/font.c
+++ b/dlls/gdi32/font.c
@@ -1231,6 +1231,7 @@ BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count,
     LPINT dxs = NULL;
     DC *dc;
     BOOL ret = FALSE;
+    TEXTMETRICW tm;
 
     TRACE("(%p, %s, %d)\n",hdc,debugstr_wn(str,count),maxExt);
 
@@ -1238,6 +1239,8 @@ BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count,
     if (! dc)
         return FALSE;
 
+    GetTextMetricsW(hdc, &tm);
+
     /* If we need to calculate nFit, then we need the partial extents even if
        the user hasn't provided us with an array.  */
     if (lpnFit)
@@ -1263,22 +1266,49 @@ BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count,
     /* Perform device size to world size transformations.  */
     if (ret)
     {
-	INT extra = dc->charExtra, breakRem = dc->breakRem;
+	INT extra      = dc->charExtra,
+        breakExtra = dc->breakExtra,
+        breakRem   = dc->breakRem,
+        i;
 
 	if (dxs)
 	{
-	    INT i;
 	    for (i = 0; i < count; ++i)
 	    {
 		dxs[i] = abs(INTERNAL_XDSTOWS(dc, dxs[i]));
-		dxs[i] += (i+1) * extra + breakRem;
+		dxs[i] += (i+1) * extra;
+                if (count > 1 && (breakExtra || breakRem) && str[i] == tm.tmBreakChar)
+                {
+                    dxs[i] += breakExtra;
+                    if (breakRem > 0)
+                    {
+                        breakRem--;
+                        dxs[i]++;
+                    }
+                }
 		if (dxs[i] <= maxExt)
 		    ++nFit;
 	    }
+            breakRem = dc->breakRem;
 	}
 	size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
 	size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
-	size->cx += count * extra + breakRem;
+
+        if (!dxs && count > 1 && (breakExtra || breakRem))
+        {
+            for (i = 0; i < count; i++)
+            {
+                if (str[i] == tm.tmBreakChar)
+                {
+                    size->cx += breakExtra;
+                    if (breakRem > 0)
+                    {
+                        breakRem--;
+                        (size->cx)++;
+                    }
+                }
+            }
+        }
     }
 
     if (lpnFit)
@@ -1812,12 +1842,15 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
     SIZE sz;
     RECT rc;
     BOOL done_extents = FALSE;
-    INT width, xwidth = 0, ywidth = 0;
+    INT width = 0, xwidth = 0, ywidth = 0;
     DWORD type;
     DC * dc = DC_GetDCUpdate( hdc );
+    INT breakRem;
 
     if (!dc) return FALSE;
 
+    breakRem = dc->breakRem;
+
     if (flags & (ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY))
         FIXME("flags ETO_NUMERICSLOCAL | ETO_NUMERICSLATIN | ETO_PDY unimplemented\n");
 
@@ -1927,8 +1960,7 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
     y = pt.y;
 
     char_extra = GetTextCharacterExtra(hdc);
-    width = 0;
-    if(char_extra || dc->breakExtra || lpDx)
+    if(char_extra || dc->breakExtra || breakRem || lpDx)
     {
         UINT i;
         SIZE tmpsz;
@@ -1949,9 +1981,14 @@ BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags,
                 deltas[i] = tmpsz.cx;
             }
             
-            if (!(flags & ETO_GLYPH_INDEX) && dc->breakExtra && reordered_str[i] == tm.tmBreakChar)
+            if (!(flags & ETO_GLYPH_INDEX) && (dc->breakExtra || breakRem) && reordered_str[i] == tm.tmBreakChar)
             {
                 deltas[i] = deltas[i] + dc->breakExtra;
+                if (breakRem > 0)
+                {
+                    breakRem--;
+                    deltas[i]++;
+                }
             }
             deltas[i] = INTERNAL_XWSTODS(dc, deltas[i]);
             width += deltas[i];
diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c
index 5dddf3a..e8e2527 100644
--- a/dlls/gdi32/tests/font.c
+++ b/dlls/gdi32/tests/font.c
@@ -887,6 +887,129 @@ static BOOL get_glyph_indices(INT charset, UINT code_page, WORD *idx, UINT count
     return TRUE;
 }
 
+static void testJustification(HDC hdc, PSTR str, RECT *clientArea)
+{
+    INT         x, y,
+                breakCount,
+                outputWidth = 0,    /* to test TabbedTextOut() */
+                justifiedWidth = 0, /* to test GetTextExtentExPointW() */
+                areaWidth = clientArea->right - clientArea->left,
+                nErrors = 0, e;
+    BOOL        lastExtent = FALSE;
+    PSTR        pFirstChar, pLastChar;
+    SIZE        size;
+    TEXTMETRICA tm;
+    struct err
+    {
+        char extent[100];
+        int  GetTextExtentExPointWWidth;
+        int  TabbedTextOutWidth;
+    } error[10];
+
+    GetTextMetricsA(hdc, &tm);
+    y = clientArea->top;
+    do {
+        breakCount = 0;
+        while (*str == tm.tmBreakChar) str++; /* skip leading break chars */
+        pFirstChar = str;
+
+        do {
+            pLastChar = str;
+
+            /* if not at the end of the string, ... */
+            if (*str == '\0') break;
+            /* ... add the next word to the current extent */
+            while (*str != '\0' && *str++ != tm.tmBreakChar);
+            breakCount++;
+            SetTextJustification(hdc, 0, 0);
+            GetTextExtentPoint32(hdc, pFirstChar, str - pFirstChar - 1, &size);
+        } while ((int) size.cx < areaWidth);
+
+        /* ignore trailing break chars */
+        breakCount--;
+        while (*(pLastChar - 1) == tm.tmBreakChar)
+        {
+            pLastChar--;
+            breakCount--;
+        }
+
+        if (*str == '\0' || breakCount <= 0) pLastChar = str;
+
+        SetTextJustification(hdc, 0, 0);
+        GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
+
+        /* do not justify the last extent */
+        if (*str != '\0' && breakCount > 0)
+        {
+            SetTextJustification(hdc, areaWidth - size.cx, breakCount);
+            GetTextExtentPoint32(hdc, pFirstChar, pLastChar - pFirstChar, &size);
+            justifiedWidth = size.cx;
+        }
+        else lastExtent = TRUE;
+
+        x = clientArea->left;
+
+        outputWidth = LOWORD(TabbedTextOut(
+                             hdc, x, y, pFirstChar, pLastChar - pFirstChar,
+                             0, NULL, 0));
+        /* catch errors and report them */
+        if (!lastExtent && ((outputWidth != areaWidth) || (justifiedWidth != areaWidth)))
+        {
+            memset(error[nErrors].extent, 0, 100);
+            memcpy(error[nErrors].extent, pFirstChar, pLastChar - pFirstChar);
+            error[nErrors].TabbedTextOutWidth = outputWidth;
+            error[nErrors].GetTextExtentExPointWWidth = justifiedWidth;
+            nErrors++;
+        }
+
+        y += size.cy;
+        str = pLastChar;
+    } while (*str && y < clientArea->bottom);
+
+    for (e = 0; e < nErrors; e++)
+    {
+        ok(error[e].TabbedTextOutWidth == areaWidth,
+            "The output text (\"%s\") width should be %d, not %d.\n",
+            error[e].extent, areaWidth, error[e].TabbedTextOutWidth);
+        /* The width returned by GetTextExtentPoint32() is exactly the same
+           returned by GetTextExtentExPointW() - see dlls/gdi32/font.c */
+        ok(error[e].GetTextExtentExPointWWidth == areaWidth,
+            "GetTextExtentPointW() for \"%s\" should have returned a width of %d, not %d.\n",
+            error[e].extent, areaWidth, error[e].GetTextExtentExPointWWidth);
+    }
+}
+
+static void test_SetTextJustification(void)
+{
+    HDC hdc = GetDC(0);
+    RECT clientArea = {0, 0, 400, 400};
+    LOGFONTA lf;
+    HFONT hfont;
+    static char testText[] =
+            "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
+            "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
+            "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
+            "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
+            "reprehenderit in voluptate velit esse cillum dolore eu fugiat "
+            "nulla pariatur. Excepteur sint occaecat cupidatat non proident, "
+            "sunt in culpa qui officia deserunt mollit anim id est laborum.";
+
+    memset(&lf, 0, sizeof lf);
+    lf.lfCharSet = ANSI_CHARSET;
+    lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+    lf.lfWeight = FW_DONTCARE;
+    lf.lfHeight = 20;
+    lf.lfQuality = DEFAULT_QUALITY;
+    lstrcpyA(lf.lfFaceName, "Times New Roman");
+    hfont = create_font("Times New Roman", &lf);
+    SelectObject(hdc, hfont);
+
+    testJustification(hdc, testText, &clientArea);
+
+    DeleteObject(hfont);
+    ReleaseDC(0, hdc);
+}
+
 static void test_font_charset(void)
 {
     static struct charset_data
@@ -940,5 +1063,6 @@ START_TEST(font)
     test_GetGlyphIndices();
     test_GetKerningPairs();
     test_GetOutlineTextMetrics();
+    test_SetTextJustification();
     test_font_charset();
 }




More information about the wine-cvs mailing list