gdi32: Add a test for outline text metrics

Dmitry Timoshkov dmitry at codeweavers.com
Wed Jun 18 04:54:11 CDT 2008


Hello,

Changelog:
    gdi32: Add a test for outline text metrics.
---
 dlls/gdi32/font.c       |    3 +
 dlls/gdi32/freetype.c   |   15 ++-
 dlls/gdi32/tests/font.c |  301 ++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 301 insertions(+), 18 deletions(-)

diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c
index 1bfd97a..b43873a 100644
--- a/dlls/gdi32/font.c
+++ b/dlls/gdi32/font.c
@@ -1410,6 +1410,9 @@ UINT WINAPI GetOutlineTextMetricsW(
                 WineEngGetOutlineTextMetrics(dc->gdiFont, ret, output);
             }
 
+        output->otmTextMetrics.tmDigitizedAspectX = GetDeviceCaps(hdc, LOGPIXELSX);
+        output->otmTextMetrics.tmDigitizedAspectY = GetDeviceCaps(hdc, LOGPIXELSY);
+
 #define WDPTOLP(x) ((x<0)?					\
 		(-abs(INTERNAL_XDSTOWS(dc, (x)))):		\
 		(abs(INTERNAL_XDSTOWS(dc, (x)))))
diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c
index 9b5f18c..1ff5039 100644
--- a/dlls/gdi32/freetype.c
+++ b/dlls/gdi32/freetype.c
@@ -4211,6 +4211,9 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
     } else {
         if(format == GGO_METRICS && font->gm[original_index / GM_BLOCK_SIZE] != NULL && FONT_GM(font,original_index)->init ) {
             *lpgm = FONT_GM(font,original_index)->gm;
+            TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
+                  wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
+                  lpgm->gmCellIncX, lpgm->gmCellIncY);
             LeaveCriticalSection( &freetype_cs );
 	    return 1; /* FIXME */
 	}
@@ -4341,6 +4344,10 @@ DWORD WineEngGetGlyphOutline(GdiFont *incoming_font, UINT glyph, UINT format,
     lpgm->gmptGlyphOrigin.x = left >> 6;
     lpgm->gmptGlyphOrigin.y = top >> 6;
 
+    TRACE("%u,%u,%s,%d,%d\n", lpgm->gmBlackBoxX, lpgm->gmBlackBoxY,
+          wine_dbgstr_point(&lpgm->gmptGlyphOrigin),
+          lpgm->gmCellIncX, lpgm->gmCellIncY);
+
     if(format == GGO_METRICS || format == GGO_BITMAP || format ==  WINE_GGO_GRAY16_BITMAP)
     {
         FONT_GM(font,original_index)->gm = *lpgm;
@@ -4991,7 +4998,6 @@ UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
     }
 
     TM.tmCharSet = font->charset;
-#undef TM
 
     font->potm->otmFiller = 0;
     memcpy(&font->potm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
@@ -5010,9 +5016,9 @@ UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
     font->potm->otmrcFontBox.right = (pFT_MulFix(ft_face->bbox.xMax, x_scale) + 32) >> 6;
     font->potm->otmrcFontBox.top = (pFT_MulFix(ft_face->bbox.yMax, y_scale) + 32) >> 6;
     font->potm->otmrcFontBox.bottom = (pFT_MulFix(ft_face->bbox.yMin, y_scale) + 32) >> 6;
-    font->potm->otmMacAscent = 0; /* where do these come from ? */
-    font->potm->otmMacDescent = 0;
-    font->potm->otmMacLineGap = 0;
+    font->potm->otmMacAscent = TM.tmAscent;
+    font->potm->otmMacDescent = -TM.tmDescent;
+    font->potm->otmMacLineGap = font->potm->otmLineGap;
     font->potm->otmusMinimumPPEM = 0; /* TT Header */
     font->potm->otmptSubscriptSize.x = (pFT_MulFix(pOS2->ySubscriptXSize, x_scale) + 32) >> 6;
     font->potm->otmptSubscriptSize.y = (pFT_MulFix(pOS2->ySubscriptYSize, y_scale) + 32) >> 6;
@@ -5031,6 +5037,7 @@ UINT WineEngGetOutlineTextMetrics(GdiFont *font, UINT cbSize,
         font->potm->otmsUnderscoreSize = (pFT_MulFix(pPost->underlineThickness, y_scale) + 32) >> 6;
 	font->potm->otmsUnderscorePosition = (pFT_MulFix(pPost->underlinePosition, y_scale) + 32) >> 6;
     }
+#undef TM
 
     /* otmp* members should clearly have type ptrdiff_t, but M$ knows best */
     cp = (char*)font->potm + sizeof(*font->potm);
diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c
index 710148a..3c89edd 100644
--- a/dlls/gdi32/tests/font.c
+++ b/dlls/gdi32/tests/font.c
@@ -30,6 +30,7 @@
 
 #include "wine/test.h"
 
+#define near_match(a, b) (abs((a) - (b)) <= 4)
 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got)
 
 LONG  (WINAPI *pGdiGetCharDimensions)(HDC hdc, LPTEXTMETRICW lptm, LONG *height);
@@ -158,6 +159,30 @@ static INT CALLBACK font_enum_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DW
     return 1; /* continue enumeration */
 }
 
+static void compare_tm(const TEXTMETRICA *tm, const TEXTMETRICA *otm)
+{
+    ok(tm->tmHeight == otm->tmHeight, "tmHeight %d != %d\n", tm->tmHeight, otm->tmHeight);
+    ok(tm->tmAscent == otm->tmAscent, "tmAscent %d != %d\n", tm->tmAscent, otm->tmAscent);
+    ok(tm->tmDescent == otm->tmDescent, "tmDescent %d != %d\n", tm->tmDescent, otm->tmDescent);
+    ok(tm->tmInternalLeading == otm->tmInternalLeading, "tmInternalLeading %d != %d\n", tm->tmInternalLeading, otm->tmInternalLeading);
+    ok(tm->tmExternalLeading == otm->tmExternalLeading, "tmExternalLeading %d != %d\n", tm->tmExternalLeading, otm->tmExternalLeading);
+    ok(tm->tmAveCharWidth == otm->tmAveCharWidth, "tmAveCharWidth %d != %d\n", tm->tmAveCharWidth, otm->tmAveCharWidth);
+    ok(tm->tmMaxCharWidth == otm->tmMaxCharWidth, "tmMaxCharWidth %d != %d\n", tm->tmMaxCharWidth, otm->tmMaxCharWidth);
+    ok(tm->tmWeight == otm->tmWeight, "tmWeight %d != %d\n", tm->tmWeight, otm->tmWeight);
+    ok(tm->tmOverhang == otm->tmOverhang, "tmOverhang %d != %d\n", tm->tmOverhang, otm->tmOverhang);
+    ok(tm->tmDigitizedAspectX == otm->tmDigitizedAspectX, "tmDigitizedAspectX %d != %d\n", tm->tmDigitizedAspectX, otm->tmDigitizedAspectX);
+    ok(tm->tmDigitizedAspectY == otm->tmDigitizedAspectY, "tmDigitizedAspectY %d != %d\n", tm->tmDigitizedAspectY, otm->tmDigitizedAspectY);
+    ok(tm->tmFirstChar == otm->tmFirstChar, "tmFirstChar %d != %d\n", tm->tmFirstChar, otm->tmFirstChar);
+    ok(tm->tmLastChar == otm->tmLastChar, "tmLastChar %d != %d\n", tm->tmLastChar, otm->tmLastChar);
+    ok(tm->tmDefaultChar == otm->tmDefaultChar, "tmDefaultChar %d != %d\n", tm->tmDefaultChar, otm->tmDefaultChar);
+    ok(tm->tmBreakChar == otm->tmBreakChar, "tmBreakChar %d != %d\n", tm->tmBreakChar, otm->tmBreakChar);
+    ok(tm->tmItalic == otm->tmItalic, "tmItalic %d != %d\n", tm->tmItalic, otm->tmItalic);
+    ok(tm->tmUnderlined == otm->tmUnderlined, "tmUnderlined %d != %d\n", tm->tmUnderlined, otm->tmUnderlined);
+    ok(tm->tmStruckOut == otm->tmStruckOut, "tmStruckOut %d != %d\n", tm->tmStruckOut, otm->tmStruckOut);
+    ok(tm->tmPitchAndFamily == otm->tmPitchAndFamily, "tmPitchAndFamily %d != %d\n", tm->tmPitchAndFamily, otm->tmPitchAndFamily);
+    ok(tm->tmCharSet == otm->tmCharSet, "tmCharSet %d != %d\n", tm->tmCharSet, otm->tmCharSet);
+}
+
 static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
                               LONG lfWidth, const char *test_str,
 			      INT test_str_len, const TEXTMETRICA *tm_orig,
@@ -166,9 +191,11 @@ static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
 {
     HFONT old_hfont;
     LOGFONTA lf;
+    OUTLINETEXTMETRIC otm;
     TEXTMETRICA tm;
     SIZE size;
     INT width_of_A, cx, cy;
+    UINT ret;
 
     if (!hfont)
         return;
@@ -177,35 +204,72 @@ static void test_font_metrics(HDC hdc, HFONT hfont, LONG lfHeight,
 
     old_hfont = SelectObject(hdc, hfont);
 
-    GetTextMetricsA(hdc, &tm);
+    if (GetOutlineTextMetricsA(hdc, 0, NULL))
+    {
+        otm.otmSize = sizeof(otm) / 2;
+        ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
+        ok(ret == sizeof(otm)/2, "expected sizeof(otm)/2, got %u\n", ret);
+
+        memset(&otm, 0x1, sizeof(otm));
+        otm.otmSize = sizeof(otm);
+        ret = GetOutlineTextMetricsA(hdc, otm.otmSize, &otm);
+        ok(ret == sizeof(otm), "expected sizeof(otm), got %u\n", ret);
+        memset(&tm, 0x2, sizeof(tm));
+        ret = GetTextMetricsA(hdc, &tm);
+        ok(ret, "GetTextMetricsA failed\n");
+        /* the structure size is aligned */
+        if (memcmp(&tm, &otm.otmTextMetrics, FIELD_OFFSET(TEXTMETRICA, tmCharSet) + 1))
+        {
+            ok(0, "tm != otm\n");
+            compare_tm(&tm, &otm.otmTextMetrics);
+        }
+
+        tm = otm.otmTextMetrics;
+if (0) /* these metrics are scaled too, but with rounding errors */
+{
+        ok(otm.otmAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmAscent, tm.tmAscent);
+        ok(otm.otmDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmDescent, -tm.tmDescent);
+}
+        ok(otm.otmMacAscent == tm.tmAscent, "ascent %d != %d\n", otm.otmMacAscent, tm.tmAscent);
+        ok(otm.otmDescent < 0, "otm.otmDescent should be < 0\n");
+        ok(otm.otmMacDescent < 0, "otm.otmMacDescent should be < 0\n");
+        ok(tm.tmDescent > 0, "tm.tmDescent should be > 0\n");
+        ok(otm.otmMacDescent == -tm.tmDescent, "descent %d != %d\n", otm.otmMacDescent, -tm.tmDescent);
+        ok(otm.otmEMSquare == 2048, "expected 2048, got %d\n", otm.otmEMSquare);
+    }
+    else
+    {
+        ret = GetTextMetricsA(hdc, &tm);
+        ok(ret, "GetTextMetricsA failed\n");
+    }
 
     cx = tm.tmAveCharWidth / tm_orig->tmAveCharWidth;
     cy = tm.tmHeight / tm_orig->tmHeight;
     ok(cx == scale_x && cy == scale_y, "expected scale_x %d, scale_y %d, got cx %d, cy %d\n",
        scale_x, scale_y, cx, cy);
-    ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "%d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
-    ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "%d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
-    ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "%d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
-    ok(tm.tmAveCharWidth == tm_orig->tmAveCharWidth * scale_x, "%d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
-    ok(tm.tmMaxCharWidth == tm_orig->tmMaxCharWidth * scale_x, "%d != %d\n", tm.tmAveCharWidth, tm_orig->tmMaxCharWidth * scale_x);
+    ok(tm.tmHeight == tm_orig->tmHeight * scale_y, "height %d != %d\n", tm.tmHeight, tm_orig->tmHeight * scale_y);
+    ok(tm.tmAscent == tm_orig->tmAscent * scale_y, "ascent %d != %d\n", tm.tmAscent, tm_orig->tmAscent * scale_y);
+    ok(tm.tmDescent == tm_orig->tmDescent * scale_y, "descent %d != %d\n", tm.tmDescent, tm_orig->tmDescent * scale_y);
+    ok(near_match(tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x), "ave width %d != %d\n", tm.tmAveCharWidth, tm_orig->tmAveCharWidth * scale_x);
+    ok(near_match(tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x), "max width %d != %d\n", tm.tmMaxCharWidth, tm_orig->tmMaxCharWidth * scale_x);
 
-    ok(lf.lfHeight == lfHeight, "lf %d != %d\n", lf.lfHeight, lfHeight);
+    ok(lf.lfHeight == lfHeight, "lfHeight %d != %d\n", lf.lfHeight, lfHeight);
     if (lf.lfHeight)
     {
         if (lf.lfWidth)
-            ok(lf.lfWidth == tm.tmAveCharWidth, "lf %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
+            ok(lf.lfWidth == tm.tmAveCharWidth, "lfWidth %d != tm %d\n", lf.lfWidth, tm.tmAveCharWidth);
     }
     else
-        ok(lf.lfWidth == lfWidth, "lf %d != %d\n", lf.lfWidth, lfWidth);
+        ok(lf.lfWidth == lfWidth, "lfWidth %d != %d\n", lf.lfWidth, lfWidth);
 
     GetTextExtentPoint32A(hdc, test_str, test_str_len, &size);
 
-    ok(size.cx == size_orig->cx * scale_x, "%d != %d\n", size.cx, size_orig->cx * scale_x);
-    ok(size.cy == size_orig->cy * scale_y, "%d != %d\n", size.cy, size_orig->cy * scale_y);
+    ok(near_match(size.cx, size_orig->cx * scale_x), "cx %d != %d\n", size.cx, size_orig->cx * scale_x);
+    ok(size.cy == size_orig->cy * scale_y, "cy %d != %d\n", size.cy, size_orig->cy * scale_y);
 
     GetCharWidthA(hdc, 'A', 'A', &width_of_A);
 
-    ok(width_of_A == width_of_A_orig * scale_x, "%d != %d\n", width_of_A, width_of_A_orig * scale_x);
+    ok(near_match(width_of_A, width_of_A_orig * scale_x), "width A %d != %d\n", width_of_A, width_of_A_orig * scale_x);
 
     SelectObject(hdc, old_hfont);
 }
@@ -286,6 +350,214 @@ static void test_bitmap_font(void)
     ReleaseDC(0, hdc);
 }
 
+/* Test how GDI scales outline font metrics */
+static void test_outline_font(void)
+{
+    static const char test_str[11] = "Test String";
+    HDC hdc;
+    LOGFONTA lf;
+    HFONT hfont, old_hfont;
+    OUTLINETEXTMETRICA otm;
+    SIZE size_orig;
+    INT width_orig, height_orig, lfWidth;
+    XFORM xform;
+    GLYPHMETRICS gm;
+    MAT2 mat = { {0,1}, {0,0}, {0,0}, {0,1} };
+    MAT2 mat2 = { {0x8000,0}, {0,0}, {0,0}, {0x8000,0} };
+    POINT pt;
+    INT ret;
+
+    if (!is_truetype_font_installed("Arial"))
+    {
+        skip("Arial is not installed\n");
+        return;
+    }
+
+    hdc = CreateCompatibleDC(0);
+
+    memset(&lf, 0, sizeof(lf));
+    strcpy(lf.lfFaceName, "Arial");
+    lf.lfHeight = 72;
+    hfont = create_font("outline", &lf);
+    old_hfont = SelectObject(hdc, hfont);
+    otm.otmSize = sizeof(otm);
+    ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
+    ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
+    ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
+    SelectObject(hdc, old_hfont);
+
+    test_font_metrics(hdc, hfont, lf.lfHeight, otm.otmTextMetrics.tmAveCharWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
+    DeleteObject(hfont);
+
+    /* font of otmEMSquare height helps to avoid a lot of rounding errors */
+    lf.lfHeight = otm.otmEMSquare;
+    lf.lfHeight = -lf.lfHeight;
+    hfont = create_font("outline", &lf);
+    old_hfont = SelectObject(hdc, hfont);
+    otm.otmSize = sizeof(otm);
+    ok(GetOutlineTextMetricsA(hdc, sizeof(otm), &otm), "GetTextMetricsA failed\n");
+    ok(GetTextExtentPoint32A(hdc, test_str, sizeof(test_str), &size_orig), "GetTextExtentPoint32A failed\n");
+    ok(GetCharWidthA(hdc, 'A', 'A', &width_orig), "GetCharWidthA failed\n");
+    SelectObject(hdc, old_hfont);
+
+    height_orig = otm.otmTextMetrics.tmHeight;
+    lfWidth = otm.otmTextMetrics.tmAveCharWidth;
+
+    /* test integer scaling 3x2 */
+    lf.lfHeight = height_orig * 2;
+    lf.lfWidth = lfWidth * 3;
+    hfont = create_font("3x2", &lf);
+    test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 2);
+    DeleteObject(hfont);
+
+    /* test integer scaling 3x3 */
+    lf.lfHeight = height_orig * 3;
+    lf.lfWidth = lfWidth * 3;
+    hfont = create_font("3x3", &lf);
+    test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 3, 3);
+
+    /* test integer scaling 1x1 */
+    lf.lfHeight = height_orig;
+    lf.lfWidth = 0;
+    hfont = create_font("1x1", &lf);
+    test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
+
+    old_hfont = SelectObject(hdc, hfont);
+    /* with an identity matrix */
+    memset(&gm, 0, sizeof(gm));
+    SetLastError(0xdeadbeef);
+    ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
+    ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
+    trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
+    ok(gm.gmCellIncX == width_orig, "incX %d != %d\n", gm.gmCellIncX, width_orig);
+    ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
+    /* with a custom matrix */
+    memset(&gm, 0, sizeof(gm));
+    SetLastError(0xdeadbeef);
+    ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
+    ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
+    trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
+todo_wine
+    ok(gm.gmCellIncX == width_orig/2, "incX %d != %d\n", gm.gmCellIncX, width_orig/2);
+    ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
+    SelectObject(hdc, old_hfont);
+
+    if (!SetGraphicsMode(hdc, GM_ADVANCED))
+    {
+        DeleteObject(hfont);
+        DeleteDC(hdc);
+        skip("GM_ADVANCED is not supported on this platform\n");
+        return;
+    }
+
+    xform.eM11 = 20.0f;
+    xform.eM12 = 0.0f;
+    xform.eM21 = 0.0f;
+    xform.eM22 = 20.0f;
+    xform.eDx = 0.0f;
+    xform.eDy = 0.0f;
+
+    SetLastError(0xdeadbeef);
+    ret = SetWorldTransform(hdc, &xform);
+    ok(ret, "SetWorldTransform error %u\n", GetLastError());
+
+    test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
+
+    old_hfont = SelectObject(hdc, hfont);
+    /* with an identity matrix */
+    memset(&gm, 0, sizeof(gm));
+    SetLastError(0xdeadbeef);
+    ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
+    ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
+    trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
+    pt.x = width_orig; pt.y = 0;
+    LPtoDP(hdc, &pt, 1);
+    ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
+    ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
+    ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
+    /* with a custom matrix */
+    memset(&gm, 0, sizeof(gm));
+    SetLastError(0xdeadbeef);
+    ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
+    ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
+    trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
+    pt.x = width_orig; pt.y = 0;
+    LPtoDP(hdc, &pt, 1);
+todo_wine {
+    ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
+    ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
+}
+    ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
+    SelectObject(hdc, old_hfont);
+
+    SetLastError(0xdeadbeef);
+    ret = SetMapMode(hdc, MM_LOMETRIC);
+    ok(ret == MM_TEXT, "expected MM_TEXT, got %d, error %u\n", ret, GetLastError());
+
+    test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
+
+    old_hfont = SelectObject(hdc, hfont);
+    /* with an identity matrix */
+    memset(&gm, 0, sizeof(gm));
+    SetLastError(0xdeadbeef);
+    ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
+    ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
+    trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
+    pt.x = width_orig; pt.y = 0;
+    LPtoDP(hdc, &pt, 1);
+todo_wine
+    ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
+    ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
+    /* with a custom matrix */
+    memset(&gm, 0, sizeof(gm));
+    SetLastError(0xdeadbeef);
+    ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
+    ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
+    trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
+    pt.x = width_orig; pt.y = 0;
+    LPtoDP(hdc, &pt, 1);
+todo_wine
+    ok(gm.gmCellIncX == (pt.x + 1)/2, "incX %d != %d\n", gm.gmCellIncX, (pt.x + 1)/2);
+    ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
+    SelectObject(hdc, old_hfont);
+
+    SetLastError(0xdeadbeef);
+    ret = SetMapMode(hdc, MM_TEXT);
+    ok(ret == MM_LOMETRIC, "expected MM_LOMETRIC, got %d, error %u\n", ret, GetLastError());
+
+    test_font_metrics(hdc, hfont, lf.lfHeight, lf.lfWidth, test_str, sizeof(test_str), &otm.otmTextMetrics, &size_orig, width_orig, 1, 1);
+
+    old_hfont = SelectObject(hdc, hfont);
+    /* with an identity matrix */
+    memset(&gm, 0, sizeof(gm));
+    SetLastError(0xdeadbeef);
+    ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat);
+    ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
+    trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
+    pt.x = width_orig; pt.y = 0;
+    LPtoDP(hdc, &pt, 1);
+    ok(gm.gmCellIncX == pt.x, "incX %d != %d\n", gm.gmCellIncX, pt.x);
+    ok(gm.gmCellIncX == 20 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 20 * width_orig);
+    ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
+    /* with a custom matrix */
+    memset(&gm, 0, sizeof(gm));
+    SetLastError(0xdeadbeef);
+    ret = GetGlyphOutlineA(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
+    ok(ret != GDI_ERROR, "GetGlyphOutlineA error %d\n", GetLastError());
+    trace("gm.gmCellIncX %d, width_orig %d\n", gm.gmCellIncX, width_orig);
+    pt.x = width_orig; pt.y = 0;
+    LPtoDP(hdc, &pt, 1);
+todo_wine {
+    ok(gm.gmCellIncX == pt.x/2, "incX %d != %d\n", gm.gmCellIncX, pt.x/2);
+    ok(gm.gmCellIncX == 10 * width_orig, "incX %d != %d\n", gm.gmCellIncX, 10 * width_orig);
+}
+    ok(gm.gmCellIncY == 0, "incY %d != 0\n", gm.gmCellIncY);
+    SelectObject(hdc, old_hfont);
+
+    DeleteObject(hfont);
+    DeleteDC(hdc);
+}
+
 static INT CALLBACK find_font_proc(const LOGFONT *elf, const TEXTMETRIC *ntm, DWORD type, LPARAM lParam)
 {
     LOGFONT *lf = (LOGFONT *)lParam;
@@ -781,6 +1053,8 @@ static void test_GetKerningPairs(void)
            kd[i].otmDescent, otm.otmDescent);
         ok(kd[i].otmLineGap == otm.otmLineGap, "expected %u, got %u\n",
            kd[i].otmLineGap, otm.otmLineGap);
+        ok(near_match(kd[i].otmMacDescent, otm.otmMacDescent), "expected %d, got %d\n",
+           kd[i].otmMacDescent, otm.otmMacDescent);
 todo_wine {
         ok(kd[i].otmsCapEmHeight == otm.otmsCapEmHeight, "expected %u, got %u\n",
            kd[i].otmsCapEmHeight, otm.otmsCapEmHeight);
@@ -788,8 +1062,6 @@ todo_wine {
            kd[i].otmsXHeight, otm.otmsXHeight);
         ok(kd[i].otmMacAscent == otm.otmMacAscent, "expected %d, got %d\n",
            kd[i].otmMacAscent, otm.otmMacAscent);
-        ok(kd[i].otmMacDescent == otm.otmMacDescent, "expected %d, got %d\n",
-           kd[i].otmMacDescent, otm.otmMacDescent);
         /* FIXME: this one sometimes succeeds due to expected 0, enable it when removing todo */
         if (0) ok(kd[i].otmMacLineGap == otm.otmMacLineGap, "expected %u, got %u\n",
            kd[i].otmMacLineGap, otm.otmMacLineGap);
@@ -1936,6 +2208,7 @@ START_TEST(font)
 
     test_logfont();
     test_bitmap_font();
+    test_outline_font();
     test_bitmap_font_metrics();
     test_GdiGetCharDimensions();
     test_GetCharABCWidths();
-- 
1.5.5.4






More information about the wine-patches mailing list