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