[v2 PATCH 1/3] gdiplus/metafile: Support linear gradient brushes in playback

Nikolay Sivov nsivov at codeweavers.com
Tue Nov 7 03:28:00 CST 2017


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---

v2: fixed potential freeing uninitialized brush pointer

 dlls/gdiplus/metafile.c | 104 +++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 93 insertions(+), 11 deletions(-)

diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c
index 989ecd0691..0bf152967c 100644
--- a/dlls/gdiplus/metafile.c
+++ b/dlls/gdiplus/metafile.c
@@ -256,6 +256,26 @@ typedef struct EmfPlusTextureBrushData
     BYTE OptionalData[1];
 } EmfPlusTextureBrushData;
 
+typedef struct EmfPlusRectF
+{
+    float X;
+    float Y;
+    float Width;
+    float Height;
+} EmfPlusRectF;
+
+typedef struct EmfPlusLinearGradientBrushData
+{
+    DWORD BrushDataFlags;
+    INT WrapMode;
+    EmfPlusRectF RectF;
+    EmfPlusARGB StartColor;
+    EmfPlusARGB EndColor;
+    DWORD Reserved1;
+    DWORD Reserved2;
+    BYTE OptionalData[1];
+} EmfPlusLinearGradientBrushData;
+
 typedef struct EmfPlusBrush
 {
     DWORD Version;
@@ -264,6 +284,7 @@ typedef struct EmfPlusBrush
         EmfPlusSolidBrushData solid;
         EmfPlusHatchBrushData hatch;
         EmfPlusTextureBrushData texture;
+        EmfPlusLinearGradientBrushData lineargradient;
     } BrushData;
 } EmfPlusBrush;
 
@@ -372,14 +393,6 @@ typedef struct EmfPlusObject
     } ObjectData;
 } EmfPlusObject;
 
-typedef struct EmfPlusRectF
-{
-    float X;
-    float Y;
-    float Width;
-    float Height;
-} EmfPlusRectF;
-
 typedef struct EmfPlusPointR7
 {
     BYTE X;
@@ -1997,7 +2010,10 @@ static GpStatus metafile_deserialize_brush(const BYTE *record_data, UINT data_si
 {
     static const UINT header_size = FIELD_OFFSET(EmfPlusBrush, BrushData);
     EmfPlusBrush *data = (EmfPlusBrush *)record_data;
+    EmfPlusTransformMatrix *transform = NULL;
+    DWORD brushflags;
     GpStatus status;
+    UINT offset;
 
     *brush = NULL;
 
@@ -2021,11 +2037,9 @@ static GpStatus metafile_deserialize_brush(const BYTE *record_data, UINT data_si
         break;
     case BrushTypeTextureFill:
     {
-        UINT offset = header_size + FIELD_OFFSET(EmfPlusTextureBrushData, OptionalData);
-        EmfPlusTransformMatrix *transform = NULL;
-        DWORD brushflags;
         GpImage *image;
 
+        offset = header_size + FIELD_OFFSET(EmfPlusTextureBrushData, OptionalData);
         if (data_size <= offset)
             return InvalidParameter;
 
@@ -2049,6 +2063,74 @@ static GpStatus metafile_deserialize_brush(const BYTE *record_data, UINT data_si
         GdipDisposeImage(image);
         break;
     }
+    case BrushTypeLinearGradient:
+    {
+        GpLineGradient *gradient = NULL;
+        GpPointF startpoint, endpoint;
+        UINT position_count = 0;
+
+        offset = header_size + FIELD_OFFSET(EmfPlusLinearGradientBrushData, OptionalData);
+        if (data_size <= offset)
+            return InvalidParameter;
+
+        brushflags = data->BrushData.lineargradient.BrushDataFlags;
+        if ((brushflags & BrushDataPresetColors) && (brushflags & (BrushDataBlendFactorsH | BrushDataBlendFactorsV)))
+            return InvalidParameter;
+
+        if (brushflags & BrushDataTransform)
+        {
+            if (data_size <= offset + sizeof(EmfPlusTransformMatrix))
+                return InvalidParameter;
+            transform = (EmfPlusTransformMatrix *)(record_data + offset);
+            offset += sizeof(EmfPlusTransformMatrix);
+        }
+
+        if (brushflags & (BrushDataPresetColors | BrushDataBlendFactorsH | BrushDataBlendFactorsV))
+        {
+            if (data_size <= offset + sizeof(DWORD)) /* Number of factors/preset colors. */
+                return InvalidParameter;
+            position_count = *(DWORD *)(record_data + offset);
+            offset += sizeof(DWORD);
+        }
+
+        if (brushflags & BrushDataPresetColors)
+        {
+            if (data_size != offset + position_count * (sizeof(float) + sizeof(EmfPlusARGB)))
+                return InvalidParameter;
+        }
+        else if (brushflags & BrushDataBlendFactorsH)
+        {
+            if (data_size != offset + position_count * 2 * sizeof(float))
+                return InvalidParameter;
+        }
+
+        startpoint.X = data->BrushData.lineargradient.RectF.X;
+        startpoint.Y = data->BrushData.lineargradient.RectF.Y;
+        endpoint.X = startpoint.X + data->BrushData.lineargradient.RectF.Width;
+        endpoint.Y = startpoint.Y + data->BrushData.lineargradient.RectF.Height;
+
+        status = GdipCreateLineBrush(&startpoint, &endpoint, data->BrushData.lineargradient.StartColor,
+            data->BrushData.lineargradient.EndColor, data->BrushData.lineargradient.WrapMode, &gradient);
+        if (status == Ok && transform)
+            status = GdipSetLineTransform(gradient, (const GpMatrix *)transform);
+
+        if (brushflags & BrushDataPresetColors)
+            status = GdipSetLinePresetBlend(gradient, (ARGB *)(record_data + offset + position_count * sizeof(REAL)),
+                (REAL *)(record_data + offset), position_count);
+        else if (brushflags & BrushDataBlendFactorsH)
+            status = GdipSetLineBlend(gradient, (REAL *)(record_data + offset + position_count * sizeof(REAL)),
+                (REAL *)(record_data + offset), position_count);
+
+        if (brushflags & BrushDataIsGammaCorrected)
+            FIXME("BrushDataIsGammaCorrected is not handled.\n");
+
+        if (status == Ok)
+            *brush = (GpBrush *)gradient;
+        else
+            GdipDeleteBrush((GpBrush *)gradient);
+
+        break;
+    }
     default:
         FIXME("brush type %u is not supported.\n", data->Type);
         return NotImplemented;
-- 
2.14.2




More information about the wine-patches mailing list