diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index 762aa135a75..33966767cc6 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -93,6 +93,7 @@ extern GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush, GDIPCONST GpRectF* rects, INT count) DECLSPEC_HIDDEN; extern GpStatus METAFILE_SetClipRect(GpMetafile* metafile, REAL x, REAL y, REAL width, REAL height, CombineMode mode) DECLSPEC_HIDDEN; +extern GpStatus METAFILE_SetClipRegion(GpMetafile* metafile, GpRegion* region, CombineMode mode) DECLSPEC_HIDDEN; extern GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale) DECLSPEC_HIDDEN; extern GpStatus METAFILE_SetWorldTransform(GpMetafile* metafile, GDIPCONST GpMatrix* transform) DECLSPEC_HIDDEN; extern GpStatus METAFILE_ScaleWorldTransform(GpMetafile* metafile, REAL sx, REAL sy, MatrixOrder order) DECLSPEC_HIDDEN; @@ -124,6 +125,7 @@ extern void free_installed_fonts(void) DECLSPEC_HIDDEN; extern BOOL lengthen_path(GpPath *path, INT len) DECLSPEC_HIDDEN; +extern DWORD write_region_data(const GpRegion *region, void *data) DECLSPEC_HIDDEN; extern DWORD write_path_data(GpPath *path, void *data) DECLSPEC_HIDDEN; extern GpStatus trace_path(GpGraphics *graphics, GpPath *path) DECLSPEC_HIDDEN; diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 4b2ae498844..e45618eefec 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -6269,6 +6269,13 @@ GpStatus WINGDIPAPI GdipSetClipRegion(GpGraphics *graphics, GpRegion *region, if(graphics->busy) return ObjectBusy; + if (graphics->image && graphics->image->type == ImageTypeMetafile) + { + status = METAFILE_SetClipRegion((GpMetafile*)graphics->image, region, mode); + if (status != Ok) + return status; + } + status = GdipCloneRegion(region, &clip); if (status == Ok) { diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index 99e54837e45..41355bc3d2d 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -239,6 +239,13 @@ typedef struct EmfPlusPath BYTE data[1]; } EmfPlusPath; +typedef struct EmfPlusRegion +{ + DWORD Version; + DWORD RegionNodeCount; + BYTE RegionNode[1]; +} EmfPlusRegion; + typedef enum { BitmapDataTypePixel, @@ -312,6 +319,7 @@ typedef struct EmfPlusObject EmfPlusBrush brush; EmfPlusPen pen; EmfPlusPath path; + EmfPlusRegion region; EmfPlusImage image; EmfPlusImageAttributes image_attributes; } ObjectData; @@ -847,6 +855,53 @@ GpStatus METAFILE_SetClipRect(GpMetafile* metafile, REAL x, REAL y, REAL width, return Ok; } +static GpStatus METAFILE_AddRegionObject(GpMetafile *metafile, GpRegion *region, DWORD *id) +{ + EmfPlusObject *object_record; + DWORD size; + GpStatus stat; + + *id = -1; + if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual) + return Ok; + + size = write_region_data(region, NULL); + stat = METAFILE_AllocateRecord(metafile, + FIELD_OFFSET(EmfPlusObject, ObjectData.region) + size, (void**)&object_record); + if (stat != Ok) return stat; + + *id = METAFILE_AddObjectId(metafile); + object_record->Header.Type = EmfPlusRecordTypeObject; + object_record->Header.Flags = *id | ObjectTypeRegion << 8; + write_region_data(region, &object_record->ObjectData.region); + return Ok; +} + +GpStatus METAFILE_SetClipRegion(GpMetafile* metafile, GpRegion* region, CombineMode mode) +{ + EmfPlusRecordHeader *record; + DWORD region_id; + GpStatus stat; + + if (metafile->metafile_type == MetafileTypeEmf) + { + FIXME("stub!\n"); + return NotImplemented; + } + + stat = METAFILE_AddRegionObject(metafile, region, ®ion_id); + if (stat != Ok) return stat; + + stat = METAFILE_AllocateRecord(metafile, sizeof(*record), (void**)&record); + if (stat != Ok) return stat; + + record->Type = EmfPlusRecordTypeSetClipRegion; + record->Flags = region_id | mode << 8; + + METAFILE_WriteRecords(metafile); + return Ok; +} + GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale) { if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) diff --git a/dlls/gdiplus/region.c b/dlls/gdiplus/region.c index d133afa539f..015b67788e0 100644 --- a/dlls/gdiplus/region.c +++ b/dlls/gdiplus/region.c @@ -699,7 +699,7 @@ static void write_element(const region_element* element, DWORD *buffer, } } -static DWORD write_region_data(const GpRegion *region, void *data) +DWORD write_region_data(const GpRegion *region, void *data) { struct region_header *header = data; INT filled = 0; diff --git a/dlls/gdiplus/tests/metafile.c b/dlls/gdiplus/tests/metafile.c index 26716c40404..1d36d9e4574 100644 --- a/dlls/gdiplus/tests/metafile.c +++ b/dlls/gdiplus/tests/metafile.c @@ -2154,6 +2154,8 @@ static const emfplus_record clipping_records[] = { {0, EmfPlusRecordTypeRestore}, {0, EmfPlusRecordTypeSetClipRect}, {0, EmfPlusRecordTypeFillRects}, + {0, EmfPlusRecordTypeObject, 1}, + {0, EmfPlusRecordTypeSetClipRegion, 1}, {0, EmfPlusRecordTypeEndOfFile}, {0, EMR_EOF}, {0} @@ -2165,6 +2167,7 @@ static void test_clipping(void) GpMetafile *metafile; GpGraphics *graphics; GpBitmap *bitmap; + GpRegion *region; GpBrush *brush; GpRectF rect; ARGB color; @@ -2231,6 +2234,15 @@ static void test_clipping(void) stat = GdipDeleteBrush(brush); expect(Ok, stat); + stat = GdipCreateRegionRect(&rect, ®ion); + expect(Ok, stat); + + stat = GdipSetClipRegion(graphics, region, CombineModeIntersect); + expect(Ok, stat); + + stat = GdipDeleteRegion(region); + expect(Ok, stat); + stat = GdipDeleteGraphics(graphics); expect(Ok, stat);