Slow EULA display patch 2

Dan Hipschman dsh at linux.ucla.edu
Wed Jul 5 17:05:04 CDT 2006


On Mon, Jul 03, 2006 at 12:17:23PM +0200, Alexandre Julliard wrote:
> Looks good, but you should remove the non-Ex entry points in
> freetype.c and the DC table, there's no reason to have both.

OK, I did that.  I also fixed some broken logic in my last patch.  Now the
partial extents are consistent with the FIT and SIZE parameters.  Lastly,
I wrote a test to verify this.  The test passes on Windows and Wine.

ChangeLog:
* Eliminate order n-squared algorithm in GetTextExtentExPointW by replacing
  Freetype/DC function (WineEng|p)GetTextExtentPointW with Ex versions.
---
 dlls/gdi/driver.c        |    2 -
 dlls/gdi/enhmfdrv/init.c |    2 -
 dlls/gdi/font.c          |   95 ++++++++++++++++++++++++----------------------
 dlls/gdi/freetype.c      |   35 +++++++++++------
 dlls/gdi/gdi_private.h   |    4 +-
 dlls/gdi/mfdrv/init.c    |    2 -
 dlls/gdi/tests/font.c    |   26 ++++++++++++-
 7 files changed, 103 insertions(+), 63 deletions(-)

diff --git a/dlls/gdi/driver.c b/dlls/gdi/driver.c
index 8d50e8c..76657a7 100644
--- a/dlls/gdi/driver.c
+++ b/dlls/gdi/driver.c
@@ -121,7 +121,7 @@ #define GET_FUNC(name) driver->funcs.p##
         GET_FUNC(GetPixel);
         GET_FUNC(GetPixelFormat);
         GET_FUNC(GetSystemPaletteEntries);
-        GET_FUNC(GetTextExtentPoint);
+        GET_FUNC(GetTextExtentExPoint);
         GET_FUNC(GetTextMetrics);
         GET_FUNC(IntersectClipRect);
         GET_FUNC(InvertRgn);
diff --git a/dlls/gdi/enhmfdrv/init.c b/dlls/gdi/enhmfdrv/init.c
index 82f0222..c3677b0 100644
--- a/dlls/gdi/enhmfdrv/init.c
+++ b/dlls/gdi/enhmfdrv/init.c
@@ -80,7 +80,7 @@ static const DC_FUNCTIONS EMFDRV_Funcs =
     NULL,                            /* pGetPixel */
     NULL,                            /* pGetPixelFormat */
     NULL,                            /* pGetSystemPaletteEntries */
-    NULL,                            /* pGetTextExtentPoint */
+    NULL,                            /* pGetTextExtentExPoint */
     NULL,                            /* pGetTextMetrics */
     EMFDRV_IntersectClipRect,        /* pIntersectClipRect */
     EMFDRV_InvertRgn,                /* pInvertRgn */
diff --git a/dlls/gdi/font.c b/dlls/gdi/font.c
index 33a03f6..7d5bcc0 100644
--- a/dlls/gdi/font.c
+++ b/dlls/gdi/font.c
@@ -1053,27 +1053,7 @@ BOOL WINAPI GetTextExtentPoint32W(
     INT count,   /* [in]  Number of characters in string */
     LPSIZE size) /* [out] Address of structure for string size */
 {
-    BOOL ret = FALSE;
-    DC * dc = DC_GetDCPtr( hdc );
-    if (!dc) return FALSE;
-
-    if(dc->gdiFont)
-        ret = WineEngGetTextExtentPoint(dc->gdiFont, str, count, size);
-    else if(dc->funcs->pGetTextExtentPoint)
-        ret = dc->funcs->pGetTextExtentPoint( dc->physDev, str, count, size );
-
-    if (ret)
-    {
-	size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
-	size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
-        size->cx += count * dc->charExtra + dc->breakRem;
-    }
-
-    GDI_ReleaseObj( hdc );
-
-    TRACE("(%p %s %d %p): returning %ld x %ld\n",
-          hdc, debugstr_wn (str, count), count, size, size->cx, size->cy );
-    return ret;
+    return GetTextExtentExPointW(hdc, str, count, 0, NULL, NULL, size);
 }
 
 /***********************************************************************
@@ -1101,9 +1081,10 @@ BOOL WINAPI GetTextExtentPointI(
 	size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
         size->cx += count * dc->charExtra;
     }
-    else if(dc->funcs->pGetTextExtentPoint) {
-        FIXME("calling GetTextExtentPoint\n");
-        ret = dc->funcs->pGetTextExtentPoint( dc->physDev, (LPCWSTR)indices, count, size );
+    else if(dc->funcs->pGetTextExtentExPoint) {
+        FIXME("calling GetTextExtentExPoint\n");
+        ret = dc->funcs->pGetTextExtentExPoint( dc->physDev, (LPCWSTR)indices,
+                                                count, 0, NULL, NULL, size );
     }
 
     GDI_ReleaseObj( hdc );
@@ -1205,36 +1186,60 @@ BOOL WINAPI GetTextExtentExPointW( HDC h
 				   INT maxExt, LPINT lpnFit,
 				   LPINT alpDx, LPSIZE size )
 {
-    int index, nFit, extent;
-    SIZE tSize;
+    INT nFit;
+    LPINT dxs;
+    HANDLE heap;
+    DC *dc;
     BOOL ret = FALSE;
 
-    TRACE("(%p, %s, %d)\n",hdc,debugstr_wn(str,count),maxExt);
+    TRACE("(%p, %s, %d)\n", hdc, debugstr_wn(str, count), maxExt);
+
+    dc = DC_GetDCPtr(hdc);
+    if (! dc)
+        return FALSE;
 
-    size->cx = size->cy = nFit = extent = 0;
-    for(index = 0; index < count; index++)
+    heap = GetProcessHeap();
+    dxs = alpDx ? alpDx : HeapAlloc(heap, 0, count * sizeof alpDx[0]);
+    if (! dxs)
     {
- 	if(!GetTextExtentPoint32W( hdc, str, index + 1, &tSize )) goto done;
-        /* GetTextExtentPoint includes intercharacter spacing. */
-        /* FIXME - justification needs doing yet.  Remember that the base
-         * data will not be in logical coordinates.
-         */
-	extent = tSize.cx;
-	if( !lpnFit || extent <= maxExt )
-        /* It is allowed to be equal. */
+        GDI_ReleaseObj(hdc);
+        SetLastError(ERROR_OUTOFMEMORY);
+        return FALSE;
+    }
+
+    if (dc->gdiFont)
+        ret = WineEngGetTextExtentExPoint(dc->gdiFont, str, count,
+                                          0, NULL, dxs, size);
+    else if (dc->funcs->pGetTextExtentExPoint)
+        ret = dc->funcs->pGetTextExtentExPoint(dc->physDev, str, count,
+                                               0, NULL, dxs, size);
+
+    nFit = 0;
+    if (ret)
+    {
+        INT i;
+        INT extra = dc->charExtra, breakRem = dc->breakRem;
+        for (i = 0; i < count; ++i)
         {
-	    nFit++;
-	    if( alpDx ) alpDx[index] = extent;
+            dxs[i] = abs(INTERNAL_XDSTOWS(dc, dxs[i]));
+            dxs[i] += (i+1) * extra + breakRem;
+            if (dxs[i] <= maxExt)
+                ++nFit;
         }
-	if( tSize.cy > size->cy ) size->cy = tSize.cy;
+        size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx));
+        size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy));
+        size->cx += count * extra + breakRem;
     }
-    size->cx = extent;
-    if(lpnFit) *lpnFit = nFit;
-    ret = TRUE;
 
-    TRACE("returning %d %ld x %ld\n",nFit,size->cx,size->cy);
+    if (lpnFit)
+        *lpnFit = nFit;
 
-done:
+    if (! alpDx)
+        HeapFree(heap, 0, dxs);
+
+    GDI_ReleaseObj( hdc );
+
+    TRACE("returning %d %ld x %ld\n", nFit, size->cx, size->cy);
     return ret;
 }
 
diff --git a/dlls/gdi/freetype.c b/dlls/gdi/freetype.c
index 9f52e60..2020d9d 100644
--- a/dlls/gdi/freetype.c
+++ b/dlls/gdi/freetype.c
@@ -3849,32 +3849,43 @@ BOOL WineEngGetCharABCWidthsI(GdiFont fo
 }
 
 /*************************************************************
- * WineEngGetTextExtentPoint
+ * WineEngGetTextExtentExPoint
  *
  */
-BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
-			       LPSIZE size)
+BOOL WineEngGetTextExtentExPoint(GdiFont font, LPCWSTR wstr, INT count,
+                                 INT max_ext, LPINT pnfit, LPINT dxs, LPSIZE size)
 {
-    INT idx;
+    INT i, nfit = 0, ext;
     GLYPHMETRICS gm;
     TEXTMETRICW tm;
     FT_UInt glyph_index;
     GdiFont linked_font;
 
-    TRACE("%p, %s, %d, %p\n", font, debugstr_wn(wstr, count), count,
-	  size);
+    TRACE("%p, %s, %d, %d, %p\n", font, debugstr_wn(wstr, count),
+          count, max_ext, size);
 
     size->cx = 0;
     WineEngGetTextMetrics(font, &tm);
     size->cy = tm.tmHeight;
 
-    for(idx = 0; idx < count; idx++) {
-        get_glyph_index_linked(font, wstr[idx], &linked_font, &glyph_index);
+    for (i = 0; i < count; ++i)
+    {
+        get_glyph_index_linked(font, wstr[i], &linked_font, &glyph_index);
         WineEngGetGlyphOutline(linked_font, glyph_index, GGO_METRICS | GGO_GLYPH_INDEX,
                                &gm, 0, NULL, NULL);
-	size->cx += linked_font->gm[glyph_index].adv;
+        ext = size->cx += linked_font->gm[glyph_index].adv;
+        if (! pnfit || ext <= max_ext)
+        {
+            ++nfit;
+            if (dxs)
+                dxs[i] = ext;
+        }
     }
-    TRACE("return %ld,%ld\n", size->cx, size->cy);
+
+    if (pnfit)
+        *pnfit = nfit;
+
+    TRACE("return %ld, %ld, %d\n", size->cx, size->cy, nfit);
     return TRUE;
 }
 
@@ -4149,8 +4160,8 @@ BOOL WineEngGetCharABCWidthsI(GdiFont fo
     return FALSE;
 }
 
-BOOL WineEngGetTextExtentPoint(GdiFont font, LPCWSTR wstr, INT count,
-			       LPSIZE size)
+BOOL WineEngGetTextExtentExPoint(GdiFont font, LPCWSTR wstr, INT count,
+                                 INT max_ext, LPINT nfit, LPINT dx, LPSIZE size)
 {
     ERR("called but we don't have FreeType\n");
     return FALSE;
diff --git a/dlls/gdi/gdi_private.h b/dlls/gdi/gdi_private.h
index 610babb..a0de444 100644
--- a/dlls/gdi/gdi_private.h
+++ b/dlls/gdi/gdi_private.h
@@ -107,7 +107,7 @@ typedef struct tagDC_FUNCS
     COLORREF (*pGetPixel)(PHYSDEV,INT,INT);
     INT      (*pGetPixelFormat)(PHYSDEV);
     UINT     (*pGetSystemPaletteEntries)(PHYSDEV,UINT,UINT,LPPALETTEENTRY);
-    BOOL     (*pGetTextExtentPoint)(PHYSDEV,LPCWSTR,INT,LPSIZE);
+    BOOL     (*pGetTextExtentExPoint)(PHYSDEV,LPCWSTR,INT,INT,LPINT,LPINT,LPSIZE);
     BOOL     (*pGetTextMetrics)(PHYSDEV,TEXTMETRICW*);
     INT      (*pIntersectClipRect)(PHYSDEV,INT,INT,INT,INT);
     BOOL     (*pInvertRgn)(PHYSDEV,HRGN);
@@ -379,7 +379,7 @@ extern DWORD WineEngGetGlyphOutline(GdiF
 extern BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph);
 extern UINT WineEngGetOutlineTextMetrics(GdiFont, UINT, LPOUTLINETEXTMETRICW);
 extern UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags);
-extern BOOL WineEngGetTextExtentPoint(GdiFont, LPCWSTR, INT, LPSIZE);
+extern BOOL WineEngGetTextExtentExPoint(GdiFont, LPCWSTR, INT, INT, LPINT, LPINT, LPSIZE);
 extern BOOL WineEngGetTextExtentPointI(GdiFont, const WORD *, INT, LPSIZE);
 extern INT  WineEngGetTextFace(GdiFont, INT, LPWSTR);
 extern BOOL WineEngGetTextMetrics(GdiFont, LPTEXTMETRICW);
diff --git a/dlls/gdi/mfdrv/init.c b/dlls/gdi/mfdrv/init.c
index bf964a7..c85501a 100644
--- a/dlls/gdi/mfdrv/init.c
+++ b/dlls/gdi/mfdrv/init.c
@@ -80,7 +80,7 @@ static const DC_FUNCTIONS MFDRV_Funcs =
     NULL,                            /* pGetPixel */
     NULL,                            /* pGetPixelFormat */
     NULL,                            /* pGetSystemPaletteEntries */
-    NULL,                            /* pGetTextExtentPoint */
+    NULL,                            /* pGetTextExtentExPoint */
     NULL,                            /* pGetTextMetrics */
     MFDRV_IntersectClipRect,         /* pIntersectClipRect */
     MFDRV_InvertRgn,                 /* pInvertRgn */
diff --git a/dlls/gdi/tests/font.c b/dlls/gdi/tests/font.c
index 393bc27..0edf0c2 100644
--- a/dlls/gdi/tests/font.c
+++ b/dlls/gdi/tests/font.c
@@ -336,11 +336,14 @@ static void test_GetCharABCWidthsW(void)
 
 static void test_text_extents(void)
 {
+    const static WCHAR wt[] = {'O','n','e','\n','t','w','o',' ','3',0};
+    LPINT extents;
+    INT i, len, fit1, fit2;
     LOGFONTA lf;
     TEXTMETRICA tm;
     HDC hdc;
     HFONT hfont;
-    SIZE sz;
+    SIZE sz, sz1, sz2;
 
     memset(&lf, 0, sizeof(lf));
     strcpy(lf.lfFaceName, "Arial");
@@ -353,6 +356,27 @@ static void test_text_extents(void)
     GetTextExtentPointA(hdc, "o", 1, &sz);
     ok(sz.cy == tm.tmHeight, "cy %ld tmHeight %ld\n", sz.cy, tm.tmHeight);
 
+    len = lstrlenW(wt);
+    extents = HeapAlloc(GetProcessHeap(), 0, len * sizeof extents[0]);
+    memset(extents, 0, len * sizeof extents[0]);
+    GetTextExtentExPointW(hdc, wt, len, 32767, &fit1, extents, &sz1);
+    GetTextExtentPointW(hdc, wt, len, &sz2);
+    ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy,
+       "results from GetTextExtentExPointW and GetTextExtentPointW differ\n");
+    for (i = 1; i < len; ++i)
+        ok(extents[i-1] <= extents[i],
+           "GetTextExtentExPointW generated a non-increasing sequence of partial extents (at position %d)\n",
+           i);
+    ok(extents[len-1] == sz1.cx, "GetTextExtentExPointW extents and size don't match\n");
+    ok(0 <= fit1 && fit1 <= len, "GetTextExtentExPointW generated illegal value %d for fit\n", fit1);
+    ok(0 < fit1, "GetTextExtentExPointW says we can't even fit one letter in 32767 logical units\n");
+    GetTextExtentExPointW(hdc, wt, len, extents[2], &fit2, NULL, &sz2);
+    ok(sz1.cx == sz2.cx && sz1.cy == sz2.cy, "GetTextExtentExPointW returned different sizes for the same string\n");
+    ok(fit2 == 3, "GetTextExtentExPointW extents isn't consistent with fit\n");
+    GetTextExtentExPointW(hdc, wt, len, extents[2]-1, &fit2, NULL, &sz2);
+    ok(fit2 == 2, "GetTextExtentExPointW extents isn't consistent with fit\n");
+    HeapFree(GetProcessHeap(), 0, extents);
+
     SelectObject(hdc, hfont);
     DeleteObject(hfont);
     ReleaseDC(NULL, hdc);
-- 
1.4.0




More information about the wine-patches mailing list