Piotr Caban : gdiplus: Add helper for saving pens to metafile.

Alexandre Julliard julliard at winehq.org
Thu Jul 13 14:41:34 CDT 2017


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

Author: Piotr Caban <piotr at codeweavers.com>
Date:   Thu Jul 13 11:53:51 2017 +0200

gdiplus: Add helper for saving pens to metafile.

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

---

 dlls/gdiplus/metafile.c       | 276 ++++++++++++++++++++++++++++++++++++++++--
 dlls/gdiplus/tests/metafile.c |   2 +-
 2 files changed, 269 insertions(+), 9 deletions(-)

diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c
index ee1efa1..7767e39 100644
--- a/dlls/gdiplus/metafile.c
+++ b/dlls/gdiplus/metafile.c
@@ -43,6 +43,14 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
 
+typedef struct EmfPlusARGB
+{
+    BYTE Blue;
+    BYTE Green;
+    BYTE Red;
+    BYTE Alpha;
+} EmfPlusARGB;
+
 typedef struct EmfPlusRecordHeader
 {
     WORD Type;
@@ -157,6 +165,69 @@ typedef struct container
     GpRegion *clip;
 } container;
 
+enum PenDataFlags
+{
+    PenDataTransform        = 0x0001,
+    PenDataStartCap         = 0x0002,
+    PenDataEndCap           = 0x0004,
+    PenDataJoin             = 0x0008,
+    PenDataMiterLimit       = 0x0010,
+    PenDataLineStyle        = 0x0020,
+    PenDataDashedLineCap    = 0x0040,
+    PenDataDashedLineOffset = 0x0080,
+    PenDataDashedLine       = 0x0100,
+    PenDataNonCenter        = 0x0200,
+    PenDataCompoundLine     = 0x0400,
+    PenDataCustomStartCap   = 0x0800,
+    PenDataCustomEndCap     = 0x1000
+};
+
+typedef struct EmfPlusTransformMatrix
+{
+    REAL TransformMatrix[6];
+} EmfPlusTransformMatrix;
+
+enum LineStyle
+{
+    LineStyleSolid,
+    LineStyleDash,
+    LineStyleDot,
+    LineStyleDashDot,
+    LineStyleDashDotDot,
+    LineStyleCustom
+};
+
+typedef struct EmfPlusPenData
+{
+    DWORD PenDataFlags;
+    DWORD PenUnit;
+    REAL PenWidth;
+    BYTE OptionalData[1];
+} EmfPlusPenData;
+
+typedef struct EmfPlusSolidBrushData
+{
+    EmfPlusARGB SolidColor;
+} EmfPlusSolidBrushData;
+
+typedef struct EmfPlusBrush
+{
+    DWORD Version;
+    DWORD Type;
+    union {
+        EmfPlusSolidBrushData solid;
+    } BrushData;
+} EmfPlusBrush;
+
+typedef struct EmfPlusPen
+{
+    DWORD Version;
+    DWORD Type;
+    /* EmfPlusPenData */
+    /* EmfPlusBrush */
+    BYTE data[1];
+} EmfPlusPen;
+
 typedef struct EmfPlusPath
 {
     DWORD Version;
@@ -209,14 +280,6 @@ typedef struct EmfPlusImage
     } ImageData;
 } EmfPlusImage;
 
-typedef struct EmfPlusARGB
-{
-    BYTE Blue;
-    BYTE Green;
-    BYTE Red;
-    BYTE Alpha;
-} EmfPlusARGB;
-
 typedef struct EmfPlusImageAttributes
 {
     DWORD Version;
@@ -246,6 +309,7 @@ typedef struct EmfPlusObject
     EmfPlusRecordHeader Header;
     union
     {
+        EmfPlusPen pen;
         EmfPlusPath path;
         EmfPlusImage image;
         EmfPlusImageAttributes image_attributes;
@@ -2623,13 +2687,209 @@ static GpStatus METAFILE_AddPathObject(GpMetafile *metafile, GpPath *path, DWORD
     return Ok;
 }
 
+static GpStatus METAFILE_PrepareBrushData(GpBrush *brush, DWORD *size)
+{
+    if (brush->bt == BrushTypeSolidColor)
+    {
+        *size = FIELD_OFFSET(EmfPlusBrush, BrushData.solid) + sizeof(EmfPlusSolidBrushData);
+        return Ok;
+    }
+
+    FIXME("unsupported brush type: %d\n", brush->bt);
+    return NotImplemented;
+}
+
+static void METAFILE_FillBrushData(GpBrush *brush, EmfPlusBrush *data)
+{
+    if (brush->bt == BrushTypeSolidColor)
+    {
+        GpSolidFill *solid = (GpSolidFill*)brush;
+
+        data->Version = 0xDBC01002;
+        data->Type = solid->brush.bt;
+        data->BrushData.solid.SolidColor.Blue = solid->color & 0xff;
+        data->BrushData.solid.SolidColor.Green = (solid->color >> 8) & 0xff;
+        data->BrushData.solid.SolidColor.Red = (solid->color >> 16) & 0xff;
+        data->BrushData.solid.SolidColor.Alpha = solid->color >> 24;
+    }
+}
+
+static GpStatus METAFILE_AddPenObject(GpMetafile *metafile, GpPen *pen, DWORD *id)
+{
+    DWORD i, data_flags, pen_data_size, brush_size;
+    EmfPlusObject *object_record;
+    EmfPlusPenData *pen_data;
+    GpStatus stat;
+    BOOL result;
+
+    if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
+        return Ok;
+
+    data_flags = 0;
+    pen_data_size = FIELD_OFFSET(EmfPlusPenData, OptionalData);
+
+    GdipIsMatrixIdentity(&pen->transform, &result);
+    if (!result)
+    {
+        data_flags |= PenDataTransform;
+        pen_data_size += sizeof(EmfPlusTransformMatrix);
+    }
+    if (pen->startcap != LineCapFlat)
+    {
+        data_flags |= PenDataStartCap;
+        pen_data_size += sizeof(DWORD);
+    }
+    if (pen->endcap != LineCapFlat)
+    {
+        data_flags |= PenDataEndCap;
+        pen_data_size += sizeof(DWORD);
+    }
+    if (pen->join != LineJoinMiter)
+    {
+        data_flags |= PenDataJoin;
+        pen_data_size += sizeof(DWORD);
+    }
+    if (pen->miterlimit != 10.0)
+    {
+        data_flags |= PenDataMiterLimit;
+        pen_data_size += sizeof(REAL);
+    }
+    if (pen->style != GP_DEFAULT_PENSTYLE)
+    {
+        data_flags |= PenDataLineStyle;
+        pen_data_size += sizeof(DWORD);
+    }
+    if (pen->dash != (GpDashStyle)DashCapFlat)
+    {
+        data_flags |= PenDataDashedLineCap;
+        pen_data_size += sizeof(DWORD);
+    }
+    data_flags |= PenDataDashedLineOffset;
+    pen_data_size += sizeof(REAL);
+    if (pen->numdashes)
+    {
+        data_flags |= PenDataDashedLine;
+        pen_data_size += sizeof(DWORD) + pen->numdashes*sizeof(REAL);
+    }
+    if (pen->align != PenAlignmentCenter)
+    {
+        data_flags |= PenDataNonCenter;
+        pen_data_size += sizeof(DWORD);
+    }
+    /* TODO: Add support for PenDataCompoundLine */
+    if (pen->customstart)
+    {
+        FIXME("ignoring custom start cup\n");
+    }
+    if (pen->customend)
+    {
+        FIXME("ignoring custom end cup\n");
+    }
+
+    stat = METAFILE_PrepareBrushData(pen->brush, &brush_size);
+    if (stat != Ok) return stat;
+
+    stat = METAFILE_AllocateRecord(metafile,
+            FIELD_OFFSET(EmfPlusObject, ObjectData.pen.data) + pen_data_size + brush_size,
+            (void**)&object_record);
+    if (stat != Ok) return stat;
+
+    *id = METAFILE_AddObjectId(metafile);
+    object_record->Header.Type = EmfPlusRecordTypeObject;
+    object_record->Header.Flags = *id | ObjectTypePen << 8;
+    object_record->ObjectData.pen.Version = 0xDBC01002;
+    object_record->ObjectData.pen.Type = 0;
+
+    pen_data = (EmfPlusPenData*)object_record->ObjectData.pen.data;
+    pen_data->PenDataFlags = data_flags;
+    pen_data->PenUnit = pen->unit;
+    pen_data->PenWidth = pen->width;
+
+    i = 0;
+    if (data_flags & PenDataTransform)
+    {
+        EmfPlusTransformMatrix *m = (EmfPlusTransformMatrix*)(pen_data->OptionalData + i);
+        memcpy(m, &pen->transform, sizeof(*m));
+        i += sizeof(EmfPlusTransformMatrix);
+    }
+    if (data_flags & PenDataStartCap)
+    {
+        *(DWORD*)(pen_data->OptionalData + i) = pen->startcap;
+        i += sizeof(DWORD);
+    }
+    if (data_flags & PenDataEndCap)
+    {
+        *(DWORD*)(pen_data->OptionalData + i) = pen->endcap;
+        i += sizeof(DWORD);
+    }
+    if (data_flags & PenDataJoin)
+    {
+        *(DWORD*)(pen_data->OptionalData + i) = pen->join;
+        i += sizeof(DWORD);
+    }
+    if (data_flags & PenDataMiterLimit)
+    {
+        *(REAL*)(pen_data->OptionalData + i) = pen->miterlimit;
+        i += sizeof(REAL);
+    }
+    if (data_flags & PenDataLineStyle)
+    {
+        switch (pen->style & PS_STYLE_MASK)
+        {
+        case PS_SOLID: *(DWORD*)(pen_data->OptionalData + i) = LineStyleSolid; break;
+        case PS_DASH: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDash; break;
+        case PS_DOT: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDot; break;
+        case PS_DASHDOT: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDashDot; break;
+        case PS_DASHDOTDOT: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDashDotDot; break;
+        default: *(DWORD*)(pen_data->OptionalData + i) = LineStyleCustom; break;
+        }
+        i += sizeof(DWORD);
+    }
+    if (data_flags & PenDataDashedLineCap)
+    {
+        *(DWORD*)(pen_data->OptionalData + i) = pen->dash;
+        i += sizeof(DWORD);
+    }
+    if (data_flags & PenDataDashedLineOffset)
+    {
+        *(REAL*)(pen_data->OptionalData + i) = pen->offset;
+        i += sizeof(REAL);
+    }
+    if (data_flags & PenDataDashedLine)
+    {
+        int j;
+
+        *(DWORD*)(pen_data->OptionalData + i) = pen->numdashes;
+        i += sizeof(DWORD);
+
+        for (j=0; j<pen->numdashes; j++)
+        {
+            *(REAL*)(pen_data->OptionalData + i) = pen->dashes[j];
+            i += sizeof(REAL);
+        }
+    }
+    if (data_flags & PenDataNonCenter)
+    {
+        *(REAL*)(pen_data->OptionalData + i) = pen->align;
+        i += sizeof(DWORD);
+    }
+
+    METAFILE_FillBrushData(pen->brush,
+            (EmfPlusBrush*)(object_record->ObjectData.pen.data + pen_data_size));
+    return Ok;
+}
+
 GpStatus METAFILE_DrawPath(GpMetafile *metafile, GpPen *pen, GpPath *path)
 {
     DWORD path_id;
+    DWORD pen_id;
     GpStatus stat;
 
     FIXME("stub!\n");
 
+    stat = METAFILE_AddPenObject(metafile, pen, &pen_id);
+    if (stat != Ok) return stat;
+
     stat = METAFILE_AddPathObject(metafile, path, &path_id);
     if (stat != Ok) return stat;
 
diff --git a/dlls/gdiplus/tests/metafile.c b/dlls/gdiplus/tests/metafile.c
index 1d3a35d..7dd5234 100644
--- a/dlls/gdiplus/tests/metafile.c
+++ b/dlls/gdiplus/tests/metafile.c
@@ -2487,7 +2487,7 @@ static const emfplus_record draw_path_records[] = {
     {0, EMR_HEADER},
     {0, EmfPlusRecordTypeHeader},
     {0, EmfPlusRecordTypeObject},
-    {1, EmfPlusRecordTypeObject},
+    {0, EmfPlusRecordTypeObject},
     {1, EmfPlusRecordTypeDrawPath},
     {1, EMR_SAVEDC},
     {1, EMR_SETICMMODE},




More information about the wine-cvs mailing list