[v3 PATCH] gdiplus/metafile: Support linear gradient brushes in playback
Nikolay Sivov
nsivov at codeweavers.com
Wed Nov 8 04:12:44 CST 2017
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
v3: improve error handling
dlls/gdiplus/metafile.c | 110 +++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 99 insertions(+), 11 deletions(-)
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c
index d76441290d..77673a7ea3 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;
@@ -2011,7 +2024,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;
@@ -2035,11 +2051,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;
@@ -2063,6 +2077,80 @@ 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)
+ {
+ if (transform)
+ status = GdipSetLineTransform(gradient, (const GpMatrix *)transform);
+
+ if (status == Ok)
+ {
+ 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