Vincent Povirk : gdiplus: Implement playback/recording for SetClipRect.

Alexandre Julliard julliard at winehq.org
Wed Aug 17 10:24:24 CDT 2016


Module: wine
Branch: master
Commit: 3f6faddd565b3465c17da6748e069a3ceb320316
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=3f6faddd565b3465c17da6748e069a3ceb320316

Author: Vincent Povirk <vincent at codeweavers.com>
Date:   Tue Aug 16 16:00:26 2016 -0500

gdiplus: Implement playback/recording for SetClipRect.

Signed-off-by: Vincent Povirk <vincent at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/gdiplus/gdiplus_private.h |  6 +++
 dlls/gdiplus/graphics.c        | 12 ++++--
 dlls/gdiplus/metafile.c        | 83 +++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 96 insertions(+), 5 deletions(-)

diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
index 4ad49ca..678daed 100644
--- a/dlls/gdiplus/gdiplus_private.h
+++ b/dlls/gdiplus/gdiplus_private.h
@@ -81,6 +81,9 @@ extern REAL units_to_pixels(REAL units, GpUnit unit, REAL dpi) DECLSPEC_HIDDEN;
 extern REAL pixels_to_units(REAL pixels, GpUnit unit, REAL dpi) DECLSPEC_HIDDEN;
 extern REAL units_scale(GpUnit from, GpUnit to, REAL dpi) DECLSPEC_HIDDEN;
 
+extern GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space,
+        GpCoordinateSpace src_space, GpMatrix *matrix) DECLSPEC_HIDDEN;
+
 extern GpStatus graphics_from_image(GpImage *image, GpGraphics **graphics) DECLSPEC_HIDDEN;
 
 extern GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result) DECLSPEC_HIDDEN;
@@ -89,6 +92,8 @@ extern GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc) DECLSPEC_HIDDE
 extern GpStatus METAFILE_GraphicsClear(GpMetafile* metafile, ARGB color) DECLSPEC_HIDDEN;
 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_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;
@@ -372,6 +377,7 @@ struct GpMetafile{
     GpUnit page_unit;
     REAL page_scale;
     GpRegion *base_clip; /* clip region in device space for all metafile output */
+    GpRegion *clip; /* clip region within the metafile */
     struct list containers;
 };
 
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index 370fa88..84afee1 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -51,9 +51,6 @@ 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);
-
 /* Converts from gdiplus path point type to gdi path point type. */
 static BYTE convert_path_point_type(BYTE type)
 {
@@ -5642,6 +5639,13 @@ GpStatus WINGDIPAPI GdipSetClipRect(GpGraphics *graphics, REAL x, REAL y,
     if(graphics->busy)
         return ObjectBusy;
 
+    if (graphics->image && graphics->image->type == ImageTypeMetafile)
+    {
+        status = METAFILE_SetClipRect((GpMetafile*)graphics->image, x, y, width, height, mode);
+        if (status != Ok)
+            return status;
+    }
+
     rect.X = x;
     rect.Y = y;
     rect.Width  = width;
@@ -5983,7 +5987,7 @@ GpStatus WINGDIPAPI GdipGetClip(GpGraphics *graphics, GpRegion *region)
     return Ok;
 }
 
-static GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space,
+GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space,
         GpCoordinateSpace src_space, GpMatrix *matrix)
 {
     GpStatus stat = Ok;
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c
index a854e55..02cacb2 100644
--- a/dlls/gdiplus/metafile.c
+++ b/dlls/gdiplus/metafile.c
@@ -70,6 +70,12 @@ typedef struct EmfPlusFillRects
     DWORD Count;
 } EmfPlusFillRects;
 
+typedef struct EmfPlusSetClipRect
+{
+    EmfPlusRecordHeader Header;
+    GpRectF ClipRect;
+} EmfPlusSetClipRect;
+
 typedef struct EmfPlusSetPageTransform
 {
     EmfPlusRecordHeader Header;
@@ -137,6 +143,7 @@ typedef struct container
     GpMatrix world_transform;
     GpUnit page_unit;
     REAL page_scale;
+    GpRegion *clip;
 } container;
 
 static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result)
@@ -588,6 +595,32 @@ GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush,
     return Ok;
 }
 
+GpStatus METAFILE_SetClipRect(GpMetafile* metafile, REAL x, REAL y, REAL width, REAL height, CombineMode mode)
+{
+    if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
+    {
+        EmfPlusSetClipRect *record;
+        GpStatus stat;
+
+        stat = METAFILE_AllocateRecord(metafile,
+            sizeof(EmfPlusSetClipRect),
+            (void**)&record);
+        if (stat != Ok)
+            return stat;
+
+        record->Header.Type = EmfPlusRecordTypeSetClipRect;
+        record->Header.Flags = (mode & 0xf) << 8;
+        record->ClipRect.X = x;
+        record->ClipRect.Y = y;
+        record->ClipRect.Width = width;
+        record->ClipRect.Height = height;
+
+        METAFILE_WriteRecords(metafile);
+    }
+
+    return Ok;
+}
+
 GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale)
 {
     if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
@@ -1014,7 +1047,11 @@ static void METAFILE_PlaybackReleaseDC(GpMetafile *metafile)
 
 static GpStatus METAFILE_PlaybackUpdateClip(GpMetafile *metafile)
 {
-    return GdipCombineRegionRegion(metafile->playback_graphics->clip, metafile->base_clip, CombineModeReplace);
+    GpStatus stat;
+    stat = GdipCombineRegionRegion(metafile->playback_graphics->clip, metafile->base_clip, CombineModeReplace);
+    if (stat == Ok)
+        stat = GdipCombineRegionRegion(metafile->playback_graphics->clip, metafile->clip, CombineModeIntersect);
+    return stat;
 }
 
 static GpStatus METAFILE_PlaybackUpdateWorldTransform(GpMetafile *metafile)
@@ -1166,6 +1203,32 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
 
             return stat;
         }
+        case EmfPlusRecordTypeSetClipRect:
+        {
+            EmfPlusSetClipRect *record = (EmfPlusSetClipRect*)header;
+            CombineMode mode = (CombineMode)((flags >> 8) & 0xf);
+            GpRegion *region;
+            GpMatrix world_to_device;
+
+            if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(*record))
+                return InvalidParameter;
+
+            stat = GdipCreateRegionRect(&record->ClipRect, &region);
+
+            if (stat == Ok)
+            {
+                get_graphics_transform(real_metafile->playback_graphics,
+                    CoordinateSpaceDevice, CoordinateSpaceWorld, &world_to_device);
+
+                GdipTransformRegion(region, &world_to_device);
+
+                GdipCombineRegionRegion(real_metafile->clip, region, mode);
+
+                GdipDeleteRegion(region);
+            }
+
+            return METAFILE_PlaybackUpdateClip(real_metafile);
+        }
         case EmfPlusRecordTypeSetPageTransform:
         {
             EmfPlusSetPageTransform *record = (EmfPlusSetPageTransform*)header;
@@ -1257,6 +1320,13 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
             if (!cont)
                 return OutOfMemory;
 
+            stat = GdipCloneRegion(metafile->clip, &cont->clip);
+            if (stat != Ok)
+            {
+                heap_free(cont);
+                return stat;
+            }
+
             if (recordType == EmfPlusRecordTypeBeginContainerNoParams)
                 stat = GdipBeginContainer2(metafile->playback_graphics, &cont->state);
             else
@@ -1264,6 +1334,7 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
 
             if (stat != Ok)
             {
+                GdipDeleteRegion(cont->clip);
                 heap_free(cont);
                 return stat;
             }
@@ -1310,6 +1381,7 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
                 while ((cont2 = LIST_ENTRY(list_head(&real_metafile->containers), container, entry)) != cont)
                 {
                     list_remove(&cont2->entry);
+                    GdipDeleteRegion(cont2->clip);
                     heap_free(cont2);
                 }
 
@@ -1321,8 +1393,10 @@ GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
                 *real_metafile->world_transform = cont->world_transform;
                 real_metafile->page_unit = cont->page_unit;
                 real_metafile->page_scale = cont->page_scale;
+                GdipCombineRegionRegion(real_metafile->clip, cont->clip, CombineModeReplace);
 
                 list_remove(&cont->entry);
+                GdipDeleteRegion(cont->clip);
                 heap_free(cont);
             }
 
@@ -1453,6 +1527,9 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics,
             stat = GdipGetClip(graphics, real_metafile->base_clip);
 
         if (stat == Ok)
+            stat = GdipCreateRegion(&real_metafile->clip);
+
+        if (stat == Ok)
             stat = GdipCreatePath(FillModeAlternate, &dst_path);
 
         if (stat == Ok)
@@ -1506,10 +1583,14 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics,
         GdipDeleteRegion(real_metafile->base_clip);
         real_metafile->base_clip = NULL;
 
+        GdipDeleteRegion(real_metafile->clip);
+        real_metafile->clip = NULL;
+
         while (list_head(&real_metafile->containers))
         {
             container* cont = LIST_ENTRY(list_head(&real_metafile->containers), container, entry);
             list_remove(&cont->entry);
+            GdipDeleteRegion(cont->clip);
             heap_free(cont);
         }
 




More information about the wine-cvs mailing list