gdiplus: Add more tests for GdipMeasureString using device with custom resolution. Take 3.

Dmitry Timoshkov dmitry at baikal.ru
Tue Jul 31 04:04:17 CDT 2012


This time with even more relaxed comparison of precalculated values (0.5 => 0.6).
---
This patch replaces
[1/2] gdiplus: Don't keep a reference to HDC in the GpBitmap object.
[2/2] gdiplus: Add more tests for GdipMeasureString using device with custom resolution.

This is a test for GdipMeasureString which takes a different approach:
it tests not the absolute values returned by GdipMeasureString, but compares
a scaling factor with some base value, and helps better understand the logic
behind these APIs. It also adds the tests for GdipGetLogFontW, so that values
returned by GdipMeasureString can be compared side by side with font height
value in pixels.

create_graphics() helper intentionally leakes the created image to make sure
that there is no side effects after its destruction.
---
 dlls/gdiplus/tests/graphics.c | 370 +++++++++++++++++++++++++++++++-----------
 1 file changed, 273 insertions(+), 97 deletions(-)

diff --git a/dlls/gdiplus/tests/graphics.c b/dlls/gdiplus/tests/graphics.c
index e6b6513..edf37bf 100644
--- a/dlls/gdiplus/tests/graphics.c
+++ b/dlls/gdiplus/tests/graphics.c
@@ -18,19 +18,120 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include <math.h>
+#include <assert.h>
+
 #include "windows.h"
 #include "gdiplus.h"
 #include "wingdi.h"
 #include "wine/test.h"
-#include <math.h>
 
 #define expect(expected, got) ok((got) == (expected), "Expected %d, got %d\n", (INT)(expected), (INT)(got))
 #define expectf_(expected, got, precision) ok(fabs((expected) - (got)) < (precision), "Expected %f, got %f\n", (expected), (got))
 #define expectf(expected, got) expectf_((expected), (got), 0.001)
 #define TABLE_LEN (23)
 
+static const REAL mm_per_inch = 25.4;
+static const REAL point_per_inch = 72.0;
 static HWND hwnd;
 
+/* converts a given unit to its value in pixels */
+static REAL units_to_pixels(REAL units, GpUnit unit, REAL dpi)
+{
+    switch (unit)
+    {
+    case UnitPixel:
+    case UnitDisplay:
+        return units;
+    case UnitPoint:
+        return units * dpi / point_per_inch;
+    case UnitInch:
+        return units * dpi;
+    case UnitDocument:
+        return units * dpi / 300.0; /* Per MSDN */
+    case UnitMillimeter:
+        return units * dpi / mm_per_inch;
+    default:
+        assert(0);
+        return 0;
+    }
+}
+
+/* converts value in pixels to a given unit */
+REAL pixels_to_units(REAL pixels, GpUnit unit, REAL dpi)
+{
+    switch (unit)
+    {
+    case UnitPixel:
+    case UnitDisplay:
+        return pixels;
+    case UnitPoint:
+        return pixels * point_per_inch / dpi;
+    case UnitInch:
+        return pixels / dpi;
+        break;
+    case UnitDocument:
+        return pixels * 300.0 / dpi;
+    case UnitMillimeter:
+        return pixels * mm_per_inch / dpi;
+    default:
+        assert(0);
+        return 0;
+    }
+}
+
+static REAL units_scale(GpUnit from, GpUnit to, REAL dpi)
+{
+    REAL pixels = units_to_pixels(1.0, from, dpi);
+    return pixels_to_units(pixels, to, dpi);
+}
+
+static GpGraphics *create_graphics(REAL res_x, REAL res_y, GpUnit unit, REAL scale)
+{
+    GpStatus status;
+    union
+    {
+        GpBitmap *bitmap;
+        GpImage *image;
+    } u;
+    GpGraphics *graphics = NULL;
+    REAL res;
+
+    status = GdipCreateBitmapFromScan0(1, 1, 4, PixelFormat24bppRGB, NULL, &u.bitmap);
+    expect(Ok, status);
+
+    status = GdipBitmapSetResolution(u.bitmap, res_x, res_y);
+    expect(Ok, status);
+    status = GdipGetImageHorizontalResolution(u.image, &res);
+    expect(Ok, status);
+    expectf(res_x, res);
+    status = GdipGetImageVerticalResolution(u.image, &res);
+    expect(Ok, status);
+    expectf(res_y, res);
+
+    status = GdipGetImageGraphicsContext(u.image, &graphics);
+    expect(Ok, status);
+    /* image is intentionally leaked to make sure that there is no
+       side effects after its destruction.
+    status = GdipDisposeImage(u.image);
+    expect(Ok, status);
+    */
+
+    status = GdipGetDpiX(graphics, &res);
+    expect(Ok, status);
+    expectf(res_x, res);
+    status = GdipGetDpiY(graphics, &res);
+    expect(Ok, status);
+    expectf(res_y, res);
+
+    status = GdipSetPageUnit(graphics, unit);
+    expect(Ok, status);
+    status = GdipSetPageScale(graphics, scale);
+    expect(Ok, status);
+
+    return graphics;
+}
+
 static void test_constructor_destructor(void)
 {
     GpStatus stat;
@@ -3306,139 +3407,214 @@ static void test_getdc_scaled(void)
 
 static void test_GdipMeasureString(void)
 {
-    static const WCHAR fontname[] = { 'T','a','h','o','m','a',0 };
+    static const struct test_data
+    {
+        REAL res_x, res_y, page_scale;
+        GpUnit unit;
+    } td[] =
+    {
+        { 200.0, 200.0, 1.0, UnitPixel }, /* base */
+        { 200.0, 200.0, 2.0, UnitPixel },
+        { 200.0, 200.0, 1.0, UnitDisplay },
+        { 200.0, 200.0, 2.0, UnitDisplay },
+        { 200.0, 200.0, 1.0, UnitInch },
+        { 200.0, 200.0, 2.0, UnitInch },
+        { 200.0, 600.0, 1.0, UnitPoint },
+        { 200.0, 600.0, 2.0, UnitPoint },
+        { 200.0, 600.0, 1.0, UnitDocument },
+        { 200.0, 600.0, 2.0, UnitDocument },
+        { 200.0, 600.0, 1.0, UnitMillimeter },
+        { 200.0, 600.0, 2.0, UnitMillimeter },
+        { 200.0, 600.0, 1.0, UnitDisplay },
+        { 200.0, 600.0, 2.0, UnitDisplay },
+        { 200.0, 600.0, 1.0, UnitPixel },
+        { 200.0, 600.0, 2.0, UnitPixel },
+    };
+    static const WCHAR tahomaW[] = { 'T','a','h','o','m','a',0 };
     static const WCHAR string[] = { '1','2','3','4','5','6','7',0 };
     GpStatus status;
     GpGraphics *graphics;
     GpFontFamily *family;
     GpFont *font;
-    HDC hdc;
     GpStringFormat *format;
-    RectF bounds, rc = { 0.0, 0.0, 0.0, 0.0 };
-    REAL rval, dpi;
+    RectF bounds, rc, empty_rc = { 0.0, 0.0, 0.0, 0.0 };
+    REAL base_cx, base_cy, height;
+    INT chars, lines;
+    LOGFONTW lf;
+    HDC display;
+    UINT i, font_dpi;
+    REAL font_to_pixel_scale, font_size;
+    Unit font_unit;
+
+    display = CreateCompatibleDC(0);
+    ok(display != 0, "CreateCompatibleDC failed\n");
+    font_dpi = GetDeviceCaps(display, LOGPIXELSY);
+    DeleteDC(display);
 
-    hdc = CreateCompatibleDC(0);
-    ok(hdc != 0, "CreateCompatibleDC failed\n");
-    status = GdipCreateFromHDC(hdc, &graphics);
+    status = GdipCreateStringFormat(0, LANG_NEUTRAL, &format);
     expect(Ok, status);
-    status = GdipGetDpiY(graphics, &dpi);
+    status = GdipCreateFontFamilyFromName(tahomaW, NULL, &family);
     expect(Ok, status);
-    status = GdipCreateFontFamilyFromName(fontname, NULL, &family);
+
+    /* font size in pixels */
+    status = GdipCreateFont(family, 100.0, FontStyleRegular, UnitPixel, &font);
     expect(Ok, status);
-    status = GdipCreateFont(family, 18.0, FontStyleRegular, UnitPoint, &font);
+    status = GdipGetFontSize(font, &font_size);
     expect(Ok, status);
-    status = GdipCreateStringFormat(0, LANG_NEUTRAL, &format);
+    expectf(100.0, font_size);
+    status = GdipGetFontUnit(font, &font_unit);
     expect(Ok, status);
+    expect(UnitPixel, font_unit);
 
-    if (dpi == 96.0)
+    for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
     {
-        status = GdipSetPageUnit(graphics, UnitDisplay);
-        expect(Ok, status);
+        graphics = create_graphics(td[i].res_x, td[i].res_y, td[i].unit, td[i].page_scale);
 
-        status = GdipGetFontHeightGivenDPI(font, dpi, &rval);
+        lf.lfHeight = 0xdeadbeef;
+        status = GdipGetLogFontW(font, graphics, &lf);
         expect(Ok, status);
-        expectf(28.968750, rval);
+        height = units_to_pixels(font_size, td[i].unit, td[i].res_y);
+        if (td[i].unit != UnitDisplay)
+            height *= td[i].page_scale;
+        /* FIXME: remove once Wine is fixed */
+        if (td[i].unit == UnitDisplay || (td[i].unit == UnitPixel && td[i].page_scale == 1.0))
+        ok(-lf.lfHeight == (LONG)(height + 0.5), "%u: expected %d (%f), got %d\n",
+           i, (LONG)(height + 0.5), height, lf.lfHeight);
+        else
+        {
+        todo_wine
+        ok(-lf.lfHeight == (LONG)(height + 0.5), "%u: expected %d (%f), got %d\n",
+           i, (LONG)(height + 0.5), height, lf.lfHeight);
+            /* further testing is useless */
+            GdipDeleteGraphics(graphics);
+            continue;
+        }
 
-        status = GdipGetFontHeight(font, graphics, &rval);
-        expect(Ok, status);
-        expectf(28.968750, rval);
-        status = GdipGetFontSize(font, &rval);
+        rc = empty_rc;
+        bounds = empty_rc;
+        status = GdipMeasureString(graphics, string, -1, font, &rc, format, &bounds, &chars, &lines);
         expect(Ok, status);
-        expectf(18.0, rval);
 
-        status = GdipMeasureString(graphics, string, -1, font, &rc, format, &bounds, NULL, NULL);
+        if (i == 0)
+        {
+            base_cx = bounds.Width;
+            base_cy = bounds.Height;
+        }
+
+        expectf(0.0, bounds.X);
+        expectf(0.0, bounds.Y);
+        expectf(1.0, bounds.Width / base_cx);
+        expectf(1.0, bounds.Height / base_cy);
+        expect(7, chars);
+        expect(1, lines);
+
+        /* make sure it really fits */
+        bounds.Width += 1.0;
+        bounds.Height += 1.0;
+        rc = bounds;
+        bounds = empty_rc;
+        status = GdipMeasureString(graphics, string, -1, font, &rc, format, &bounds, &chars, &lines);
         expect(Ok, status);
         expectf(0.0, bounds.X);
         expectf(0.0, bounds.Y);
-        expectf_(102.499985, bounds.Width, 11.5);
-        expectf_(31.968744, bounds.Height, 3.1);
-    }
-    else
-        skip("screen resolution %f dpi, test runs at 96 dpi\n", dpi);
-
-    status = GdipSetPageUnit(graphics, UnitPoint);
-    expect(Ok, status);
+        expectf(1.0, bounds.Width / base_cx);
+        expectf(1.0, bounds.Height / base_cy);
+        expect(7, chars);
+        expect(1, lines);
 
-    status = GdipGetFontHeight(font, graphics, &rval);
-    expect(Ok, status);
-    expectf(21.726563, rval);
-    status = GdipGetFontSize(font, &rval);
-    expect(Ok, status);
-    expectf(18.0, rval);
-
-    status = GdipMeasureString(graphics, string, -1, font, &rc, format, &bounds, NULL, NULL);
-    expect(Ok, status);
-    expectf(0.0, bounds.X);
-    expectf(0.0, bounds.Y);
-    expectf_(76.875000, bounds.Width, 10.0);
-    expectf_(23.976563, bounds.Height, 2.1);
+        status = GdipDeleteGraphics(graphics);
+        expect(Ok, status);
+    }
 
-    status = GdipSetPageUnit(graphics, UnitMillimeter);
-    expect(Ok, status);
+    GdipDeleteFont(font);
 
-    status = GdipGetFontHeight(font, graphics, &rval);
+    /* font size in points */
+    status = GdipCreateFont(family, 100.0, FontStyleRegular, UnitPoint, &font);
     expect(Ok, status);
-    expectf(7.664648, rval);
-    status = GdipGetFontSize(font, &rval);
+    status = GdipGetFontSize(font, &font_size);
     expect(Ok, status);
-    expectf(18.0, rval);
-
-    status = GdipMeasureString(graphics, string, -1, font, &rc, format, &bounds, NULL, NULL);
+    expectf(100.0, font_size);
+    status = GdipGetFontUnit(font, &font_unit);
     expect(Ok, status);
-    expectf(0.0, bounds.X);
-    expectf(0.0, bounds.Y);
-    expectf_(27.119789, bounds.Width, 2.7);
-    expectf_(8.458398, bounds.Height, 0.8);
+    expect(UnitPoint, font_unit);
 
-    GdipDeleteStringFormat(format);
-    GdipDeleteFont(font);
-    GdipDeleteFontFamily(family);
-    GdipDeleteGraphics(graphics);
-
-    DeleteDC(hdc);
-}
+    font_to_pixel_scale = units_scale(font_unit, UnitPixel, font_dpi);
+    trace("font to pixel, %u dpi => unit_scale %f\n", font_dpi, font_to_pixel_scale);
 
-static GpGraphics *create_graphics(REAL res_x, REAL res_y, GpUnit unit, REAL scale)
-{
-    GpStatus status;
-    union
+    for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
     {
-        GpBitmap *bitmap;
-        GpImage *image;
-    } u;
-    GpGraphics *graphics = NULL;
-    REAL res;
+        REAL unit_scale;
 
-    status = GdipCreateBitmapFromScan0(1, 1, 4, PixelFormat24bppRGB, NULL, &u.bitmap);
-    expect(Ok, status);
+        graphics = create_graphics(td[i].res_x, td[i].res_y, td[i].unit, td[i].page_scale);
 
-    status = GdipBitmapSetResolution(u.bitmap, res_x, res_y);
-    expect(Ok, status);
-    status = GdipGetImageHorizontalResolution(u.image, &res);
-    expect(Ok, status);
-    expectf(res_x, res);
-    status = GdipGetImageVerticalResolution(u.image, &res);
-    expect(Ok, status);
-    expectf(res_y, res);
+        lf.lfHeight = 0xdeadbeef;
+        status = GdipGetLogFontW(font, graphics, &lf);
+        expect(Ok, status);
+        if (td[i].unit == UnitDisplay || td[i].unit == UnitPixel)
+            height = units_to_pixels(font_size, font_unit, td[i].res_x);
+        else
+            height = units_to_pixels(font_size, font_unit, td[i].res_y);
+        /*trace("%.1f points = %f pixels with %.1f dpi, scale %.1f\n", font_size, height, td[i].res_y, td[i].page_scale);*/
+todo_wine
+        ok(-lf.lfHeight == (LONG)(height + 0.5), "%u: expected %d (%f), got %d\n",
+           i, (LONG)(height + 0.5), height, lf.lfHeight);
+        /* FIXME: remove once Wine is fixed */
+        if (-lf.lfHeight != (LONG)(height + 0.5))
+        {
+            /* further testing is useless */
+            GdipDeleteGraphics(graphics);
+            continue;
+        }
 
-    status = GdipGetImageGraphicsContext(u.image, &graphics);
-    expect(Ok, status);
-    status = GdipDisposeImage(u.image);
-    expect(Ok, status);
+        if (td[i].unit == UnitDisplay || td[i].unit == UnitPixel)
+            unit_scale = units_scale(font_unit, td[i].unit, td[i].res_x);
+        else
+            unit_scale = units_scale(font_unit, td[i].unit, td[i].res_y);
+        /*trace("%u: point to %d, %.1f dpi => unit_scale %f\n", i, td[i].unit, td[i].res_y, unit_scale);*/
+        height = font_size * font_to_pixel_scale * unit_scale;
+        if (td[i].unit != UnitDisplay)
+            height /= td[i].page_scale;
+        /*trace("%u: %.1f points = %f units with %.1f dpi, page_scale %.1f\n", i, font_size, height, td[i].res_y, td[i].page_scale);*/
+
+        rc = empty_rc;
+        bounds = empty_rc;
+        status = GdipMeasureString(graphics, string, -1, font, &rc, format, &bounds, &chars, &lines);
+        expect(Ok, status);
 
-    status = GdipGetDpiX(graphics, &res);
-    expect(Ok, status);
-    expectf(res_x, res);
-    status = GdipGetDpiY(graphics, &res);
-    expect(Ok, status);
-    expectf(res_y, res);
+        if (i == 0)
+        {
+            base_cx = bounds.Width;
+            base_cy = bounds.Height;
+        }
 
-    status = GdipSetPageUnit(graphics, unit);
-    expect(Ok, status);
-    status = GdipSetPageScale(graphics, scale);
-    expect(Ok, status);
+        expectf(0.0, bounds.X);
+        expectf(0.0, bounds.Y);
+        expectf_(height, bounds.Height, 0.6);
+        expectf(bounds.Height / base_cy, bounds.Width / base_cx);
+        expect(7, chars);
+        expect(1, lines);
+
+        /* make sure it really fits */
+        bounds.Width += 1.0;
+        bounds.Height += 1.0;
+        rc = bounds;
+        bounds = empty_rc;
+        status = GdipMeasureString(graphics, string, -1, font, &rc, format, &bounds, &chars, &lines);
+        expect(Ok, status);
+        expectf(0.0, bounds.X);
+        expectf(0.0, bounds.Y);
+        expectf_(height, bounds.Height, 0.6);
+        expectf(bounds.Height / base_cy, bounds.Width / base_cx);
+        expect(7, chars);
+        expect(1, lines);
 
-    return graphics;
+        status = GdipDeleteGraphics(graphics);
+        expect(Ok, status);
+    }
+
+    GdipDeleteFont(font);
+    GdipDeleteFontFamily(family);
+    GdipDeleteStringFormat(format);
 }
 
 static void test_transform(void)
-- 
1.7.11.2




More information about the wine-patches mailing list