gdiplus: Store graphics clipping region in device coordinates.

This commit is contained in:
Dmitry Timoshkov 2013-07-19 11:34:42 +09:00 committed by Alexandre Julliard
parent c8ebd4ade0
commit 14f34c15d1
3 changed files with 85 additions and 31 deletions

View File

@ -166,7 +166,7 @@ struct GpGraphics{
REAL xres, yres;
GpMatrix worldtrans; /* world transform */
BOOL busy; /* hdc handle obtained by GdipGetDC */
GpRegion *clip;
GpRegion *clip; /* in device coords */
UINT textcontrast; /* not used yet. get/set only */
struct list containers;
GraphicsContainer contid; /* last-issued container ID */

View File

@ -51,6 +51,29 @@ static GpStatus draw_driver_string(GpGraphics *graphics, GDIPCONST UINT16 *text,
GDIPCONST GpBrush *brush, GDIPCONST PointF *positions,
INT flags, GDIPCONST GpMatrix *matrix);
static GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space,
GpCoordinateSpace src_space, GpMatrix *matrix);
static void transform_rectf(GpGraphics *graphics, GpCoordinateSpace dst_space,
GpCoordinateSpace src_space, GpRectF *rect)
{
GpPointF pt[3];
pt[0].X = rect->X;
pt[0].Y = rect->Y;
pt[1].X = rect->X + rect->Width;
pt[1].Y = rect->Y;
pt[2].X = rect->X;
pt[2].Y = rect->Y + rect->Height;
GdipTransformPoints(graphics, dst_space, src_space, pt, 3);
rect->X = pt[0].X;
rect->Y = pt[0].Y;
rect->Width = sqrt((pt[1].Y - pt[0].Y) * (pt[1].Y - pt[0].Y) +
(pt[1].X - pt[0].X) * (pt[1].X - pt[0].X));
rect->Height = sqrt((pt[2].Y - pt[0].Y) * (pt[2].Y - pt[0].Y) +
(pt[2].X - pt[0].X) * (pt[2].X - pt[0].X));
}
/* Converts from gdiplus path point type to gdi path point type. */
static BYTE convert_path_point_type(BYTE type)
{
@ -283,9 +306,6 @@ static void restore_dc(GpGraphics *graphics, INT state)
RestoreDC(graphics->hdc, state);
}
static GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space,
GpCoordinateSpace src_space, GpMatrix *matrix);
/* This helper applies all the changes that the points listed in ptf need in
* order to be drawn on the device context. In the end, this should include at
* least:
@ -349,7 +369,8 @@ static void gdi_alpha_blend(GpGraphics *graphics, INT dst_x, INT dst_y, INT dst_
static GpStatus get_clip_hrgn(GpGraphics *graphics, HRGN *hrgn)
{
return GdipGetRegionHRgn(graphics->clip, graphics, hrgn);
/* clipping region is in device coords */
return GdipGetRegionHRgn(graphics->clip, NULL, hrgn);
}
/* Draw non-premultiplied ARGB data to the given graphics object */
@ -4046,6 +4067,8 @@ GpStatus WINGDIPAPI GdipFlush(GpGraphics *graphics, GpFlushIntention intention)
*/
GpStatus WINGDIPAPI GdipGetClipBounds(GpGraphics *graphics, GpRectF *rect)
{
GpStatus status;
TRACE("(%p, %p)\n", graphics, rect);
if(!graphics)
@ -4054,7 +4077,11 @@ GpStatus WINGDIPAPI GdipGetClipBounds(GpGraphics *graphics, GpRectF *rect)
if(graphics->busy)
return ObjectBusy;
return GdipGetRegionBounds(graphics->clip, graphics, rect);
status = GdipGetRegionBounds(graphics->clip, graphics, rect);
if (status == Ok)
transform_rectf(graphics, CoordinateSpaceWorld, CoordinateSpaceDevice, rect);
return status;
}
/*****************************************************************************
@ -5397,11 +5424,15 @@ GpStatus WINGDIPAPI GdipSetClipHrgn(GpGraphics *graphics, HRGN hrgn, CombineMode
if(!graphics)
return InvalidParameter;
if(graphics->busy)
return ObjectBusy;
/* hrgn is already in device units */
status = GdipCreateRegionHrgn(hrgn, &region);
if(status != Ok)
return status;
status = GdipSetClipRegion(graphics, region, mode);
status = GdipCombineRegionRegion(graphics->clip, region, mode);
GdipDeleteRegion(region);
return status;
@ -5409,6 +5440,9 @@ GpStatus WINGDIPAPI GdipSetClipHrgn(GpGraphics *graphics, HRGN hrgn, CombineMode
GpStatus WINGDIPAPI GdipSetClipPath(GpGraphics *graphics, GpPath *path, CombineMode mode)
{
GpStatus status;
GpPath *clip_path;
TRACE("(%p, %p, %d)\n", graphics, path, mode);
if(!graphics)
@ -5417,7 +5451,20 @@ GpStatus WINGDIPAPI GdipSetClipPath(GpGraphics *graphics, GpPath *path, CombineM
if(graphics->busy)
return ObjectBusy;
return GdipCombineRegionPath(graphics->clip, path, mode);
status = GdipClonePath(path, &clip_path);
if (status == Ok)
{
GpMatrix world_to_device;
get_graphics_transform(graphics, CoordinateSpaceDevice,
CoordinateSpaceWorld, &world_to_device);
status = GdipTransformPath(clip_path, &world_to_device);
if (status == Ok)
GdipCombineRegionPath(graphics->clip, clip_path, mode);
GdipDeletePath(clip_path);
}
return status;
}
GpStatus WINGDIPAPI GdipSetClipRect(GpGraphics *graphics, REAL x, REAL y,
@ -5438,6 +5485,7 @@ GpStatus WINGDIPAPI GdipSetClipRect(GpGraphics *graphics, REAL x, REAL y,
rect.Y = y;
rect.Width = width;
rect.Height = height;
transform_rectf(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, &rect);
return GdipCombineRegionRect(graphics->clip, &rect, mode);
}
@ -5460,6 +5508,9 @@ GpStatus WINGDIPAPI GdipSetClipRectI(GpGraphics *graphics, INT x, INT y,
GpStatus WINGDIPAPI GdipSetClipRegion(GpGraphics *graphics, GpRegion *region,
CombineMode mode)
{
GpStatus status;
GpRegion *clip;
TRACE("(%p, %p, %d)\n", graphics, region, mode);
if(!graphics || !region)
@ -5468,7 +5519,19 @@ GpStatus WINGDIPAPI GdipSetClipRegion(GpGraphics *graphics, GpRegion *region,
if(graphics->busy)
return ObjectBusy;
return GdipCombineRegionRegion(graphics->clip, region, mode);
status = GdipCloneRegion(region, &clip);
if (status == Ok)
{
GpMatrix world_to_device;
get_graphics_transform(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, &world_to_device);
status = GdipTransformRegion(clip, &world_to_device);
if (status == Ok)
status = GdipCombineRegionRegion(graphics->clip, clip, mode);
GdipDeleteRegion(clip);
}
return status;
}
GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile *metafile,
@ -5726,6 +5789,7 @@ GpStatus WINGDIPAPI GdipGetClip(GpGraphics *graphics, GpRegion *region)
{
GpRegion *clip;
GpStatus status;
GpMatrix device_to_world;
TRACE("(%p, %p)\n", graphics, region);
@ -5738,6 +5802,14 @@ GpStatus WINGDIPAPI GdipGetClip(GpGraphics *graphics, GpRegion *region)
if((status = GdipCloneRegion(graphics->clip, &clip)) != Ok)
return status;
get_graphics_transform(graphics, CoordinateSpaceWorld, CoordinateSpaceDevice, &device_to_world);
status = GdipTransformRegion(clip, &device_to_world);
if (status != Ok)
{
GdipDeleteRegion(clip);
return status;
}
/* free everything except root node and header */
delete_element(&region->node);
memcpy(region, clip, sizeof(GpRegion));

View File

@ -4594,7 +4594,6 @@ static void test_clipping(void)
status = GdipGetClipBounds(graphics, &rect);
expect(Ok, status);
todo_wine
ok(rect.X == 45.0 && rect.Y == 20.0 && rect.Width == 50.0 && rect.Height == 25.0,
"expected 45.0,20.0-50.0,25.0, got %.2f,%.2f-%.2f,%.2f\n", rect.X, rect.Y, rect.Width, rect.Height);
@ -4604,7 +4603,6 @@ todo_wine
expect(Ok, status);
status = GdipGetRegionBounds(region, graphics, &rect);
expect(Ok, status);
todo_wine
ok(rect.X == 45.0 && rect.Y == 20.0 && rect.Width == 50.0 && rect.Height == 25.0,
"expected 45.0,20.0-50.0,25.0, got %.2f,%.2f-%.2f,%.2f\n", rect.X, rect.Y, rect.Width, rect.Height);
@ -4617,7 +4615,6 @@ todo_wine
expect(Ok, status);
ret = GetRgnBox(hrgn, &rc);
ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
todo_wine
ok(rc.left == 45 && rc.top == 20 && rc.right == 95 && rc.bottom == 45,
"expected 45,20-95,45, got %d,%d-%d,%d\n", rc.left, rc.top, rc.right, rc.bottom);
DeleteObject(hrgn);
@ -4626,7 +4623,6 @@ todo_wine
expect(Ok, status);
ret = GetRgnBox(hrgn, &rc);
ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
todo_wine
ok(rc.left == 100 && rc.top == 100 && rc.right == 200 && rc.bottom == 200,
"expected 100,100-200,200, got %d,%d-%d,%d\n", rc.left, rc.top, rc.right, rc.bottom);
DeleteObject(hrgn);
@ -4670,7 +4666,6 @@ todo_wine
status = GdipGetClipBounds(graphics, &rect);
expect(Ok, status);
todo_wine
ok(rect.X == 45.0 && rect.Y == 20.0 && rect.Width == 50.0 && rect.Height == 25.0,
"expected 45.0,20.0-50.0,25.0, got %.2f,%.2f-%.2f,%.2f\n", rect.X, rect.Y, rect.Width, rect.Height);
@ -4680,7 +4675,6 @@ todo_wine
expect(Ok, status);
status = GdipGetRegionBounds(region, graphics, &rect);
expect(Ok, status);
todo_wine
ok(rect.X == 45.0 && rect.Y == 20.0 && rect.Width == 50.0 && rect.Height == 25.0,
"expected 45.0,20.0-50.0,25.0, got %.2f,%.2f-%.2f,%.2f\n", rect.X, rect.Y, rect.Width, rect.Height);
@ -4693,7 +4687,6 @@ todo_wine
expect(Ok, status);
ret = GetRgnBox(hrgn, &rc);
ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
todo_wine
ok(rc.left == 45 && rc.top == 20 && rc.right == 95 && rc.bottom == 45,
"expected 45,20-95,45, got %d,%d-%d,%d\n", rc.left, rc.top, rc.right, rc.bottom);
DeleteObject(hrgn);
@ -4702,7 +4695,6 @@ todo_wine
expect(Ok, status);
ret = GetRgnBox(hrgn, &rc);
ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
todo_wine
ok(rc.left == 100 && rc.top == 100 && rc.right == 200 && rc.bottom == 200,
"expected 100,100-200,200, got %d,%d-%d,%d\n", rc.left, rc.top, rc.right, rc.bottom);
DeleteObject(hrgn);
@ -4746,7 +4738,6 @@ todo_wine
status = GdipGetClipBounds(graphics, &rect);
expect(Ok, status);
todo_wine
ok((rect.X == 13.75 && rect.Y == 4.375 && rect.Width == 18.75 && rect.Height == 9.375) ||
broken(rect.X == 45.0 && rect.Y == 20.0 && rect.Width == 50.0 && rect.Height == 25.0) /* before Win7 */,
"expected 13.75,4.375-18.75,9.375, got %.2f,%.2f-%.2f,%.2f\n", rect.X, rect.Y, rect.Width, rect.Height);
@ -4757,8 +4748,9 @@ todo_wine
expect(Ok, status);
status = GdipGetRegionBounds(region, graphics, &rect);
expect(Ok, status);
todo_wine
ok((rect.X == 13.75 && rect.Y == 4.375 && rect.Width == 18.75 && rect.Height == 9.375) ||
/* rounding under Wine is slightly different */
(rect.X == 14.0 && rect.Y == 4.0 && rect.Width == 19.0 && rect.Height == 10.0) /* Wine */ ||
broken(rect.X == 45.0 && rect.Y == 20.0 && rect.Width == 50.0 && rect.Height == 25.0) /* before Win7 */,
"expected 13.75,4.375-18.75,9.375, got %.2f,%.2f-%.2f,%.2f\n", rect.X, rect.Y, rect.Width, rect.Height);
@ -4771,8 +4763,9 @@ todo_wine
expect(Ok, status);
ret = GetRgnBox(hrgn, &rc);
ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
todo_wine
ok((rc.left == 14 && rc.top == 5 && rc.right == 33 && rc.bottom == 14) ||
/* rounding under Wine is slightly different */
(rc.left == 14 && rc.top == 4 && rc.right == 33 && rc.bottom == 14) /* Wine */ ||
broken(rc.left == 45 && rc.top == 20 && rc.right == 95 && rc.bottom == 45) /* before Win7 */,
"expected 14,5-33,14, got %d,%d-%d,%d\n", rc.left, rc.top, rc.right, rc.bottom);
DeleteObject(hrgn);
@ -4781,7 +4774,6 @@ todo_wine
expect(Ok, status);
ret = GetRgnBox(hrgn, &rc);
ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
todo_wine
ok((rc.left == 100 && rc.top == 100 && rc.right == 200 && rc.bottom == 200) ||
broken(rc.left == 267 && rc.top == 267 && rc.right == 534 && rc.bottom == 534) /* before Win7 */,
"expected 100,100-200,200, got %d,%d-%d,%d\n", rc.left, rc.top, rc.right, rc.bottom);
@ -4962,7 +4954,6 @@ static void test_clipping_2(void)
expect(Ok, status);
ret = GetRgnBox(hrgn, &rc);
ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
todo_wine
ok((rc.left == 7200 && rc.top == 7200 && rc.right == 14400 && rc.bottom == 14400) ||
broken(rc.left == 100 && rc.top == 100 && rc.right == 200 && rc.bottom == 200) /* before Win7 */,
"expected 7200,7200-14400,14400, got %d,%d-%d,%d\n", rc.left, rc.top, rc.right, rc.bottom);
@ -4971,7 +4962,6 @@ todo_wine
expect(Ok, status);
ret = GetRgnBox(hrgn, &rc);
ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
todo_wine
ok((rc.left == 9600 && rc.top == 9600 && rc.right == 19200 && rc.bottom == 19200) ||
broken(rc.left == 134 && rc.top == 134 && rc.right == 267 && rc.bottom == 267) /* before Win7 */,
"expected 9600,9600-19200,19200, got %d,%d-%d,%d\n", rc.left, rc.top, rc.right, rc.bottom);
@ -5053,7 +5043,6 @@ todo_wine
expect(Ok, status);
ret = GetRgnBox(hrgn, &rc);
ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
todo_wine
ok((rc.left == 75 && rc.top == 75 && rc.right == 150 && rc.bottom == 150) ||
broken(rc.left == 2 && rc.top == 2 && rc.right == 3 && rc.bottom == 3) /* before Win7 */,
"expected 75,75-150,150, got %d,%d-%d,%d\n", rc.left, rc.top, rc.right, rc.bottom);
@ -5062,7 +5051,6 @@ todo_wine
expect(Ok, status);
ret = GetRgnBox(hrgn, &rc);
ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
todo_wine
ok((rc.left == 100 && rc.top == 100 && rc.right == 200 && rc.bottom == 200) ||
broken(rc.left == 2 && rc.top == 2 && rc.right == 3 && rc.bottom == 3) /* before Win7 */,
"expected 100,100-200,200, got %d,%d-%d,%d\n", rc.left, rc.top, rc.right, rc.bottom);
@ -5099,7 +5087,6 @@ todo_wine
expect(Ok, status);
ret = GetRgnBox(hrgn, &rc);
ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
todo_wine
ok(rc.left == 65 && rc.top == 65 && rc.right == 140 && rc.bottom == 140,
"expected 65,65-140,140, got %d,%d-%d,%d\n", rc.left, rc.top, rc.right, rc.bottom);
DeleteObject(hrgn);
@ -5107,7 +5094,6 @@ todo_wine
expect(Ok, status);
ret = GetRgnBox(hrgn, &rc);
ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
todo_wine
ok(rc.left == 100 && rc.top == 100 && rc.right == 200 && rc.bottom == 200,
"expected 100,100-200,200, got %d,%d-%d,%d\n", rc.left, rc.top, rc.right, rc.bottom);
DeleteObject(hrgn);
@ -5137,7 +5123,6 @@ todo_wine
expect(Ok, status);
ret = GetRgnBox(hrgn, &rc);
ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
todo_wine
ok(rc.left == 300 && rc.top == 150 && rc.right == 600 && rc.bottom == 300,
"expected 300,150-600,300, got %d,%d-%d,%d\n", rc.left, rc.top, rc.right, rc.bottom);
DeleteObject(hrgn);
@ -5145,7 +5130,6 @@ todo_wine
expect(Ok, status);
ret = GetRgnBox(hrgn, &rc);
ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
todo_wine
ok(rc.left == 100 && rc.top == 100 && rc.right == 200 && rc.bottom == 200,
"expected 100,100-200,200, got %d,%d-%d,%d\n", rc.left, rc.top, rc.right, rc.bottom);
DeleteObject(hrgn);
@ -5170,7 +5154,6 @@ todo_wine
expect(Ok, status);
ret = GetRgnBox(hrgn, &rc);
ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
todo_wine
ok((rc.left == 150 && rc.top == 75 && rc.right == 300 && rc.bottom == 150) ||
broken(rc.left == 300 && rc.top == 150 && rc.right == 600 && rc.bottom == 300) /* before Win7 */,
"expected 150,75-300,150, got %d,%d-%d,%d\n", rc.left, rc.top, rc.right, rc.bottom);
@ -5179,7 +5162,6 @@ todo_wine
expect(Ok, status);
ret = GetRgnBox(hrgn, &rc);
ok(ret == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", ret);
todo_wine
ok((rc.left == 100 && rc.top == 100 && rc.right == 200 && rc.bottom == 200) ||
broken(rc.left == 200 && rc.top == 200 && rc.right == 400 && rc.bottom == 400) /* before Win7 */,
"expected 100,100-200,200, got %d,%d-%d,%d\n", rc.left, rc.top, rc.right, rc.bottom);