From 989c29870f3bdd3f67ca5bb9a2c5dfd42659f7aa Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Wed, 7 Mar 2018 11:31:01 -0600 Subject: [PATCH] gdiplus: Optimize clip region transforms. Testing shows that this affects behavior. Transforming a region turns empty rectangles (with negative width or height) into non-empty rectangles. If an empty rectangle is set, it's treated as non-empty only when there is a world transform. Signed-off-by: Vincent Povirk Signed-off-by: Alexandre Julliard --- dlls/gdiplus/graphics.c | 17 +++++-- dlls/gdiplus/tests/graphics.c | 92 +++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 3 deletions(-) diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 06fb89e5d32..acee695e9fc 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -332,15 +332,20 @@ static GpStatus get_clip_hrgn(GpGraphics *graphics, HRGN *hrgn) GpRegion *rgn; GpMatrix transform; GpStatus stat; + BOOL identity; stat = get_graphics_transform(graphics, WineCoordinateSpaceGdiDevice, CoordinateSpaceDevice, &transform); + if (stat == Ok) + stat = GdipIsMatrixIdentity(&transform, &identity); + if (stat == Ok) stat = GdipCloneRegion(graphics->clip, &rgn); if (stat == Ok) { - stat = GdipTransformRegion(rgn, &transform); + if (!identity) + stat = GdipTransformRegion(rgn, &transform); if (stat == Ok) stat = GdipGetRegionHRgn(rgn, NULL, hrgn); @@ -6333,9 +6338,12 @@ GpStatus WINGDIPAPI GdipSetClipRect(GpGraphics *graphics, REAL x, REAL y, if (status == Ok) { GpMatrix world_to_device; + BOOL identity; get_graphics_transform(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, &world_to_device); - status = GdipTransformRegion(region, &world_to_device); + status = GdipIsMatrixIdentity(&world_to_device, &identity); + if (status == Ok && !identity) + status = GdipTransformRegion(region, &world_to_device); if (status == Ok) status = GdipCombineRegionRegion(graphics->clip, region, mode); @@ -6384,9 +6392,12 @@ GpStatus WINGDIPAPI GdipSetClipRegion(GpGraphics *graphics, GpRegion *region, if (status == Ok) { GpMatrix world_to_device; + BOOL identity; get_graphics_transform(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, &world_to_device); - status = GdipTransformRegion(clip, &world_to_device); + status = GdipIsMatrixIdentity(&world_to_device, &identity); + if (status == Ok && !identity) + status = GdipTransformRegion(clip, &world_to_device); if (status == Ok) status = GdipCombineRegionRegion(graphics->clip, clip, mode); diff --git a/dlls/gdiplus/tests/graphics.c b/dlls/gdiplus/tests/graphics.c index 96df1a2743e..6acc656c8f4 100644 --- a/dlls/gdiplus/tests/graphics.c +++ b/dlls/gdiplus/tests/graphics.c @@ -2060,6 +2060,97 @@ static void test_get_set_clip(void) ReleaseDC(hwnd, hdc); } +static void test_clip_xform(void) +{ + GpStatus status; + GpGraphics *graphics = NULL; + HDC hdc = GetDC( hwnd ); + GpRegion *clip; + COLORREF color; + UINT region_data_size; + struct { + DWORD size; + DWORD checksum; + DWORD magic; + DWORD num_children; + DWORD element_type; + REAL x; + REAL y; + REAL width; + REAL height; + } region_data; + + status = GdipCreateFromHDC(hdc, &graphics); + expect(Ok, status); + status = GdipCreateRegion(&clip); + expect(Ok, status); + + status = GdipGraphicsClear(graphics, 0xff000000); + expect(Ok, status); + + status = GdipSetClipRect(graphics, 10, 10, -10, -10, CombineModeReplace); + expect(Ok, status); + status = GdipGetClip(graphics, clip); + expect(Ok, status); + status = GdipGetRegionData(clip, (BYTE*)®ion_data, sizeof(region_data), ®ion_data_size); + expect(Ok, status); + expect(36, region_data_size); + expect(28, region_data.size); + expect(0, region_data.num_children); + expect(0x10000000 /* RegionDataRect */, region_data.element_type); + expectf(0.0, region_data.x); + expectf(0.0, region_data.y); + expectf(10.0, region_data.width); + expectf(10.0, region_data.height); + + /* No effect with negative width/height */ + status = GdipGraphicsClear(graphics, 0xffff0000); + expect(Ok, status); + color = GetPixel(hdc, 5, 5); + expect(0, color); + + status = GdipScaleWorldTransform(graphics, 2.0, 2.0, MatrixOrderAppend); + expect(Ok, status); + + status = GdipGraphicsClear(graphics, 0xffff0000); + expect(Ok, status); + color = GetPixel(hdc, 5, 5); + expect(0, color); + + status = GdipResetClip(graphics); + expect(Ok, status); + status = GdipResetWorldTransform(graphics); + expect(Ok, status); + status = GdipGraphicsClear(graphics, 0xff000000); + expect(Ok, status); + + status = GdipScaleWorldTransform(graphics, 2.0, 2.0, MatrixOrderAppend); + expect(Ok, status); + + status = GdipSetClipRect(graphics, 5, 5, -5, -5, CombineModeReplace); + expect(Ok, status); + status = GdipGetClip(graphics, clip); + expect(Ok, status); + status = GdipGetRegionData(clip, (BYTE*)®ion_data, sizeof(region_data), ®ion_data_size); + expect(Ok, status); + expect(36, region_data_size); + expect(28, region_data.size); + expect(0, region_data.num_children); + expect(0x10000000 /* RegionDataRect */, region_data.element_type); + expectf(0.0, region_data.x); + expectf(0.0, region_data.y); + expectf(5.0, region_data.width); + expectf(5.0, region_data.height); + + status = GdipGraphicsClear(graphics, 0xffff0000); + expect(Ok, status); + color = GetPixel(hdc, 5, 5); + expect(0xff, color); + + GdipDeleteGraphics(graphics); + ReleaseDC(hwnd, hdc); +} + static void test_isempty(void) { GpStatus status; @@ -6713,6 +6804,7 @@ START_TEST(graphics) test_BeginContainer2(); test_transformpoints(); test_get_set_clip(); + test_clip_xform(); test_isempty(); test_clear(); test_textcontrast();