2 * Copyright (C) 2011 Vincent Povirk for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define NONAMELESSUNION
39 #include "gdiplus_private.h"
40 #include "wine/debug.h"
41 #include "wine/list.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus
);
45 HRESULT WINAPI
WICCreateImagingFactory_Proxy(UINT
, IWICImagingFactory
**);
47 typedef ARGB EmfPlusARGB
;
49 typedef struct EmfPlusPointF
55 typedef struct EmfPlusRecordHeader
61 } EmfPlusRecordHeader
;
63 typedef struct EmfPlusHeader
65 EmfPlusRecordHeader Header
;
72 typedef struct EmfPlusClear
74 EmfPlusRecordHeader Header
;
78 typedef struct EmfPlusFillRects
80 EmfPlusRecordHeader Header
;
85 typedef struct EmfPlusSetClipRect
87 EmfPlusRecordHeader Header
;
91 typedef struct EmfPlusSetPageTransform
93 EmfPlusRecordHeader Header
;
95 } EmfPlusSetPageTransform
;
97 typedef struct EmfPlusRect
105 typedef struct EmfPlusSetWorldTransform
107 EmfPlusRecordHeader Header
;
109 } EmfPlusSetWorldTransform
;
111 typedef struct EmfPlusScaleWorldTransform
113 EmfPlusRecordHeader Header
;
116 } EmfPlusScaleWorldTransform
;
118 typedef struct EmfPlusMultiplyWorldTransform
120 EmfPlusRecordHeader Header
;
122 } EmfPlusMultiplyWorldTransform
;
124 typedef struct EmfPlusRotateWorldTransform
126 EmfPlusRecordHeader Header
;
128 } EmfPlusRotateWorldTransform
;
130 typedef struct EmfPlusTranslateWorldTransform
132 EmfPlusRecordHeader Header
;
135 } EmfPlusTranslateWorldTransform
;
137 typedef struct EmfPlusBeginContainer
139 EmfPlusRecordHeader Header
;
143 } EmfPlusBeginContainer
;
145 typedef struct EmfPlusContainerRecord
147 EmfPlusRecordHeader Header
;
149 } EmfPlusContainerRecord
;
157 typedef struct container
161 enum container_type type
;
162 GraphicsContainer state
;
163 GpMatrix world_transform
;
171 PenDataTransform
= 0x0001,
172 PenDataStartCap
= 0x0002,
173 PenDataEndCap
= 0x0004,
174 PenDataJoin
= 0x0008,
175 PenDataMiterLimit
= 0x0010,
176 PenDataLineStyle
= 0x0020,
177 PenDataDashedLineCap
= 0x0040,
178 PenDataDashedLineOffset
= 0x0080,
179 PenDataDashedLine
= 0x0100,
180 PenDataNonCenter
= 0x0200,
181 PenDataCompoundLine
= 0x0400,
182 PenDataCustomStartCap
= 0x0800,
183 PenDataCustomEndCap
= 0x1000
186 enum CustomLineCapData
188 CustomLineCapDataFillPath
= 0x1,
189 CustomLineCapDataLinePath
= 0x2,
192 typedef struct EmfPlusTransformMatrix
194 REAL TransformMatrix
[6];
195 } EmfPlusTransformMatrix
;
207 typedef struct EmfPlusDashedLineData
209 DWORD DashedLineDataSize
;
211 } EmfPlusDashedLineData
;
213 typedef struct EmfPlusCompoundLineData
215 DWORD CompoundLineDataSize
;
217 } EmfPlusCompoundLineData
;
219 typedef struct EmfPlusCustomStartCapData
221 DWORD CustomStartCapSize
;
223 } EmfPlusCustomStartCapData
;
225 typedef struct EmfPlusCustomEndCapData
227 DWORD CustomEndCapSize
;
229 } EmfPlusCustomEndCapData
;
231 typedef struct EmfPlusPenData
236 BYTE OptionalData
[1];
241 BrushDataPath
= 1 << 0,
242 BrushDataTransform
= 1 << 1,
243 BrushDataPresetColors
= 1 << 2,
244 BrushDataBlendFactorsH
= 1 << 3,
245 BrushDataBlendFactorsV
= 1 << 4,
246 BrushDataFocusScales
= 1 << 6,
247 BrushDataIsGammaCorrected
= 1 << 7,
248 BrushDataDoNotTransform
= 1 << 8,
251 typedef struct EmfPlusSolidBrushData
253 EmfPlusARGB SolidColor
;
254 } EmfPlusSolidBrushData
;
256 typedef struct EmfPlusHatchBrushData
259 EmfPlusARGB ForeColor
;
260 EmfPlusARGB BackColor
;
261 } EmfPlusHatchBrushData
;
263 typedef struct EmfPlusTextureBrushData
265 DWORD BrushDataFlags
;
267 BYTE OptionalData
[1];
268 } EmfPlusTextureBrushData
;
270 typedef struct EmfPlusRectF
278 typedef struct EmfPlusLinearGradientBrushData
280 DWORD BrushDataFlags
;
283 EmfPlusARGB StartColor
;
284 EmfPlusARGB EndColor
;
287 BYTE OptionalData
[1];
288 } EmfPlusLinearGradientBrushData
;
290 typedef struct EmfPlusBrush
295 EmfPlusSolidBrushData solid
;
296 EmfPlusHatchBrushData hatch
;
297 EmfPlusTextureBrushData texture
;
298 EmfPlusLinearGradientBrushData lineargradient
;
302 typedef struct EmfPlusCustomLineCapArrowData
313 EmfPlusPointF FillHotSpot
;
314 EmfPlusPointF LineHotSpot
;
315 } EmfPlusCustomLineCapArrowData
;
317 typedef struct EmfPlusPath
320 DWORD PathPointCount
;
321 DWORD PathPointFlags
;
323 /* PathPointTypes[] */
324 /* AlignmentPadding */
328 typedef struct EmfPlusCustomLineCapDataFillPath
333 } EmfPlusCustomLineCapDataFillPath
;
335 typedef struct EmfPlusCustomLineCapDataLinePath
340 } EmfPlusCustomLineCapDataLinePath
;
342 typedef struct EmfPlusCustomLineCapData
344 DWORD CustomLineCapDataFlags
;
347 DWORD StrokeStartCap
;
350 REAL StrokeMiterLimit
;
352 EmfPlusPointF FillHotSpot
;
353 EmfPlusPointF LineHotSpot
;
354 /* EmfPlusCustomLineCapDataFillPath */
355 /* EmfPlusCustomLineCapDataLinePath */
356 BYTE OptionalData
[1];
357 } EmfPlusCustomLineCapData
;
359 typedef struct EmfPlusCustomLineCap
363 /* EmfPlusCustomLineCapArrowData */
364 /* EmfPlusCustomLineCapData */
365 BYTE CustomLineCapData
[1];
366 } EmfPlusCustomLineCap
;
368 typedef struct EmfPlusPen
377 typedef struct EmfPlusRegionNodePath
379 DWORD RegionNodePathLength
;
380 EmfPlusPath RegionNodePath
;
381 } EmfPlusRegionNodePath
;
383 typedef struct EmfPlusRegion
386 DWORD RegionNodeCount
;
390 typedef struct EmfPlusPalette
392 DWORD PaletteStyleFlags
;
394 BYTE PaletteEntries
[1];
400 BitmapDataTypeCompressed
,
403 typedef struct EmfPlusBitmap
413 typedef struct EmfPlusMetafile
416 DWORD MetafileDataSize
;
417 BYTE MetafileData
[1];
420 typedef enum ImageDataType
422 ImageDataTypeUnknown
,
424 ImageDataTypeMetafile
,
427 typedef struct EmfPlusImage
433 EmfPlusBitmap bitmap
;
434 EmfPlusMetafile metafile
;
438 typedef struct EmfPlusImageAttributes
443 EmfPlusARGB ClampColor
;
446 } EmfPlusImageAttributes
;
448 typedef struct EmfPlusFont
453 DWORD FontStyleFlags
;
459 typedef struct EmfPlusObject
461 EmfPlusRecordHeader Header
;
467 EmfPlusRegion region
;
469 EmfPlusImageAttributes image_attributes
;
474 typedef struct EmfPlusPointR7
480 typedef struct EmfPlusPoint
486 typedef struct EmfPlusDrawImage
488 EmfPlusRecordHeader Header
;
489 DWORD ImageAttributesID
;
491 EmfPlusRectF SrcRect
;
499 typedef struct EmfPlusDrawImagePoints
501 EmfPlusRecordHeader Header
;
502 DWORD ImageAttributesID
;
504 EmfPlusRectF SrcRect
;
508 EmfPlusPointR7 pointsR
[3];
509 EmfPlusPoint points
[3];
510 EmfPlusPointF pointsF
[3];
512 } EmfPlusDrawImagePoints
;
514 typedef struct EmfPlusDrawPath
516 EmfPlusRecordHeader Header
;
520 typedef struct EmfPlusDrawArc
522 EmfPlusRecordHeader Header
;
532 typedef struct EmfPlusDrawEllipse
534 EmfPlusRecordHeader Header
;
540 } EmfPlusDrawEllipse
;
542 typedef struct EmfPlusDrawPie
544 EmfPlusRecordHeader Header
;
554 typedef struct EmfPlusDrawRects
556 EmfPlusRecordHeader Header
;
561 EmfPlusRectF rectF
[1];
565 typedef struct EmfPlusFillPath
567 EmfPlusRecordHeader Header
;
575 typedef struct EmfPlusFillClosedCurve
577 EmfPlusRecordHeader Header
;
583 EmfPlusPointR7 pointsR
[1];
584 EmfPlusPoint points
[1];
585 EmfPlusPointF pointsF
[1];
587 } EmfPlusFillClosedCurve
;
589 typedef struct EmfPlusFillEllipse
591 EmfPlusRecordHeader Header
;
598 } EmfPlusFillEllipse
;
600 typedef struct EmfPlusFillPie
602 EmfPlusRecordHeader Header
;
613 typedef struct EmfPlusDrawDriverString
615 EmfPlusRecordHeader Header
;
621 DWORD DriverStringOptionsFlags
;
624 BYTE VariableData
[1];
625 } EmfPlusDrawDriverString
;
627 typedef struct EmfPlusFillRegion
629 EmfPlusRecordHeader Header
;
637 typedef struct EmfPlusOffsetClip
639 EmfPlusRecordHeader Header
;
644 typedef struct EmfPlusSetRenderingOrigin
646 EmfPlusRecordHeader Header
;
649 } EmfPlusSetRenderingOrigin
;
651 static void metafile_free_object_table_entry(GpMetafile
*metafile
, BYTE id
)
653 struct emfplus_object
*object
= &metafile
->objtable
[id
];
655 switch (object
->type
)
657 case ObjectTypeInvalid
:
659 case ObjectTypeBrush
:
660 GdipDeleteBrush(object
->u
.brush
);
663 GdipDeletePen(object
->u
.pen
);
666 GdipDeletePath(object
->u
.path
);
668 case ObjectTypeRegion
:
669 GdipDeleteRegion(object
->u
.region
);
671 case ObjectTypeImage
:
672 GdipDisposeImage(object
->u
.image
);
675 GdipDeleteFont(object
->u
.font
);
677 case ObjectTypeImageAttributes
:
678 GdipDisposeImageAttributes(object
->u
.image_attributes
);
681 FIXME("not implemented for object type %u.\n", object
->type
);
685 object
->type
= ObjectTypeInvalid
;
686 object
->u
.object
= NULL
;
689 void METAFILE_Free(GpMetafile
*metafile
)
693 heap_free(metafile
->comment_data
);
694 DeleteEnhMetaFile(CloseEnhMetaFile(metafile
->record_dc
));
695 if (!metafile
->preserve_hemf
)
696 DeleteEnhMetaFile(metafile
->hemf
);
697 if (metafile
->record_graphics
)
699 WARN("metafile closed while recording\n");
700 /* not sure what to do here; for now just prevent the graphics from functioning or using this object */
701 metafile
->record_graphics
->image
= NULL
;
702 metafile
->record_graphics
->busy
= TRUE
;
705 if (metafile
->record_stream
)
706 IStream_Release(metafile
->record_stream
);
708 for (i
= 0; i
< ARRAY_SIZE(metafile
->objtable
); i
++)
709 metafile_free_object_table_entry(metafile
, i
);
712 static DWORD
METAFILE_AddObjectId(GpMetafile
*metafile
)
714 return (metafile
->next_object_id
++) % EmfPlusObjectTableSize
;
717 static GpStatus
METAFILE_AllocateRecord(GpMetafile
*metafile
, EmfPlusRecordType record_type
,
718 DWORD size
, void **result
)
721 EmfPlusRecordHeader
*record
;
723 if (!metafile
->comment_data_size
)
725 DWORD data_size
= max(256, size
* 2 + 4);
726 metafile
->comment_data
= heap_alloc_zero(data_size
);
728 if (!metafile
->comment_data
)
731 memcpy(metafile
->comment_data
, "EMF+", 4);
733 metafile
->comment_data_size
= data_size
;
734 metafile
->comment_data_length
= 4;
737 size_needed
= size
+ metafile
->comment_data_length
;
739 if (size_needed
> metafile
->comment_data_size
)
741 DWORD data_size
= size_needed
* 2;
742 BYTE
*new_data
= heap_alloc_zero(data_size
);
747 memcpy(new_data
, metafile
->comment_data
, metafile
->comment_data_length
);
749 metafile
->comment_data_size
= data_size
;
750 heap_free(metafile
->comment_data
);
751 metafile
->comment_data
= new_data
;
754 *result
= metafile
->comment_data
+ metafile
->comment_data_length
;
755 metafile
->comment_data_length
+= size
;
757 record
= (EmfPlusRecordHeader
*)*result
;
758 record
->Type
= record_type
;
761 record
->DataSize
= size
- sizeof(EmfPlusRecordHeader
);
766 static void METAFILE_RemoveLastRecord(GpMetafile
*metafile
, EmfPlusRecordHeader
*record
)
768 assert(metafile
->comment_data
+ metafile
->comment_data_length
== (BYTE
*)record
+ record
->Size
);
769 metafile
->comment_data_length
-= record
->Size
;
772 static void METAFILE_WriteRecords(GpMetafile
*metafile
)
774 if (metafile
->comment_data_length
> 4)
776 GdiComment(metafile
->record_dc
, metafile
->comment_data_length
, metafile
->comment_data
);
777 metafile
->comment_data_length
= 4;
781 static GpStatus
METAFILE_WriteHeader(GpMetafile
*metafile
, HDC hdc
)
785 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
787 EmfPlusHeader
*header
;
789 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeHeader
, sizeof(EmfPlusHeader
), (void**)&header
);
793 if (metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
794 header
->Header
.Flags
= 1;
796 header
->Version
= VERSION_MAGIC2
;
798 if (GetDeviceCaps(hdc
, TECHNOLOGY
) == DT_RASDISPLAY
)
799 header
->EmfPlusFlags
= 1;
801 header
->EmfPlusFlags
= 0;
803 header
->LogicalDpiX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
804 header
->LogicalDpiY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
806 METAFILE_WriteRecords(metafile
);
812 static GpStatus
METAFILE_WriteEndOfFile(GpMetafile
*metafile
)
816 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
818 EmfPlusRecordHeader
*record
;
820 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeEndOfFile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
824 METAFILE_WriteRecords(metafile
);
830 GpStatus WINGDIPAPI
GdipRecordMetafile(HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
831 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
834 TRACE("(%p %d %s %d %p %p)\n", hdc
, type
, debugstr_rectf(frameRect
), frameUnit
, desc
, metafile
);
836 return GdipRecordMetafileFileName(NULL
, hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
839 /*****************************************************************************
840 * GdipRecordMetafileI [GDIPLUS.@]
842 GpStatus WINGDIPAPI
GdipRecordMetafileI(HDC hdc
, EmfType type
, GDIPCONST GpRect
*frameRect
,
843 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
845 GpRectF frameRectF
, *pFrameRectF
;
847 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
851 set_rect(&frameRectF
, frameRect
->X
, frameRect
->Y
, frameRect
->Width
, frameRect
->Height
);
852 pFrameRectF
= &frameRectF
;
857 return GdipRecordMetafile(hdc
, type
, pFrameRectF
, frameUnit
, desc
, metafile
);
860 GpStatus WINGDIPAPI
GdipRecordMetafileStreamI(IStream
*stream
, HDC hdc
, EmfType type
, GDIPCONST GpRect
*frameRect
,
861 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
863 GpRectF frameRectF
, *pFrameRectF
;
865 TRACE("(%p %p %d %p %d %p %p)\n", stream
, hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
869 set_rect(&frameRectF
, frameRect
->X
, frameRect
->Y
, frameRect
->Width
, frameRect
->Height
);
870 pFrameRectF
= &frameRectF
;
875 return GdipRecordMetafileStream(stream
, hdc
, type
, pFrameRectF
, frameUnit
, desc
, metafile
);
878 GpStatus WINGDIPAPI
GdipRecordMetafileStream(IStream
*stream
, HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
879 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
883 TRACE("(%p %p %d %s %d %p %p)\n", stream
, hdc
, type
, debugstr_rectf(frameRect
), frameUnit
, desc
, metafile
);
886 return InvalidParameter
;
888 stat
= GdipRecordMetafile(hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
892 (*metafile
)->record_stream
= stream
;
893 IStream_AddRef(stream
);
899 static void METAFILE_AdjustFrame(GpMetafile
* metafile
, const GpPointF
*points
,
904 if (!metafile
->auto_frame
|| !num_points
)
907 if (metafile
->auto_frame_max
.X
< metafile
->auto_frame_min
.X
)
908 metafile
->auto_frame_max
= metafile
->auto_frame_min
= points
[0];
910 for (i
=0; i
<num_points
; i
++)
912 if (points
[i
].X
< metafile
->auto_frame_min
.X
)
913 metafile
->auto_frame_min
.X
= points
[i
].X
;
914 if (points
[i
].X
> metafile
->auto_frame_max
.X
)
915 metafile
->auto_frame_max
.X
= points
[i
].X
;
916 if (points
[i
].Y
< metafile
->auto_frame_min
.Y
)
917 metafile
->auto_frame_min
.Y
= points
[i
].Y
;
918 if (points
[i
].Y
> metafile
->auto_frame_max
.Y
)
919 metafile
->auto_frame_max
.Y
= points
[i
].Y
;
923 GpStatus
METAFILE_GetGraphicsContext(GpMetafile
* metafile
, GpGraphics
**result
)
927 if (!metafile
->record_dc
|| metafile
->record_graphics
)
928 return InvalidParameter
;
930 stat
= graphics_from_image((GpImage
*)metafile
, &metafile
->record_graphics
);
934 *result
= metafile
->record_graphics
;
935 metafile
->record_graphics
->xres
= metafile
->logical_dpix
;
936 metafile
->record_graphics
->yres
= metafile
->logical_dpiy
;
937 metafile
->record_graphics
->printer_display
= metafile
->printer_display
;
943 GpStatus
METAFILE_GetDC(GpMetafile
* metafile
, HDC
*hdc
)
945 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
947 EmfPlusRecordHeader
*record
;
950 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeGetDC
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
954 METAFILE_WriteRecords(metafile
);
957 *hdc
= metafile
->record_dc
;
962 GpStatus
METAFILE_GraphicsClear(GpMetafile
* metafile
, ARGB color
)
964 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
966 EmfPlusClear
*record
;
969 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeClear
, sizeof(EmfPlusClear
), (void**)&record
);
973 record
->Color
= color
;
975 METAFILE_WriteRecords(metafile
);
981 static BOOL
is_integer_rect(const GpRectF
*rect
)
983 SHORT x
, y
, width
, height
;
987 height
= rect
->Height
;
988 if (rect
->X
!= (REAL
)x
|| rect
->Y
!= (REAL
)y
||
989 rect
->Width
!= (REAL
)width
|| rect
->Height
!= (REAL
)height
)
994 static GpStatus
METAFILE_PrepareBrushData(GDIPCONST GpBrush
*brush
, DWORD
*size
)
998 case BrushTypeSolidColor
:
999 *size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
) + sizeof(EmfPlusSolidBrushData
);
1001 case BrushTypeHatchFill
:
1002 *size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
) + sizeof(EmfPlusHatchBrushData
);
1004 case BrushTypeLinearGradient
:
1007 GpLineGradient
*gradient
= (GpLineGradient
*)brush
;
1009 *size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
.lineargradient
.OptionalData
);
1011 GdipIsMatrixIdentity(&gradient
->transform
, &ignore_xform
);
1013 *size
+= sizeof(gradient
->transform
);
1015 if (gradient
->pblendcount
> 1 && gradient
->pblendcolor
&& gradient
->pblendpos
)
1016 *size
+= sizeof(DWORD
) + gradient
->pblendcount
*
1017 (sizeof(*gradient
->pblendcolor
) + sizeof(*gradient
->pblendpos
));
1018 else if (gradient
->blendcount
> 1 && gradient
->blendfac
&& gradient
->blendpos
)
1019 *size
+= sizeof(DWORD
) + gradient
->blendcount
*
1020 (sizeof(*gradient
->blendfac
) + sizeof(*gradient
->blendpos
));
1025 FIXME("unsupported brush type: %d\n", brush
->bt
);
1026 return NotImplemented
;
1032 static void METAFILE_FillBrushData(GDIPCONST GpBrush
*brush
, EmfPlusBrush
*data
)
1034 data
->Version
= VERSION_MAGIC2
;
1035 data
->Type
= brush
->bt
;
1039 case BrushTypeSolidColor
:
1041 GpSolidFill
*solid
= (GpSolidFill
*)brush
;
1042 data
->BrushData
.solid
.SolidColor
= solid
->color
;
1045 case BrushTypeHatchFill
:
1047 GpHatch
*hatch
= (GpHatch
*)brush
;
1048 data
->BrushData
.hatch
.HatchStyle
= hatch
->hatchstyle
;
1049 data
->BrushData
.hatch
.ForeColor
= hatch
->forecol
;
1050 data
->BrushData
.hatch
.BackColor
= hatch
->backcol
;
1053 case BrushTypeLinearGradient
:
1057 GpLineGradient
*gradient
= (GpLineGradient
*)brush
;
1059 data
->BrushData
.lineargradient
.BrushDataFlags
= 0;
1060 data
->BrushData
.lineargradient
.WrapMode
= gradient
->wrap
;
1061 data
->BrushData
.lineargradient
.RectF
.X
= gradient
->rect
.X
;
1062 data
->BrushData
.lineargradient
.RectF
.Y
= gradient
->rect
.Y
;
1063 data
->BrushData
.lineargradient
.RectF
.Width
= gradient
->rect
.Width
;
1064 data
->BrushData
.lineargradient
.RectF
.Height
= gradient
->rect
.Height
;
1065 data
->BrushData
.lineargradient
.StartColor
= gradient
->startcolor
;
1066 data
->BrushData
.lineargradient
.EndColor
= gradient
->endcolor
;
1067 data
->BrushData
.lineargradient
.Reserved1
= gradient
->startcolor
;
1068 data
->BrushData
.lineargradient
.Reserved2
= gradient
->endcolor
;
1070 if (gradient
->gamma
)
1071 data
->BrushData
.lineargradient
.BrushDataFlags
|= BrushDataIsGammaCorrected
;
1073 cursor
= &data
->BrushData
.lineargradient
.OptionalData
[0];
1075 GdipIsMatrixIdentity(&gradient
->transform
, &ignore_xform
);
1078 data
->BrushData
.lineargradient
.BrushDataFlags
|= BrushDataTransform
;
1079 memcpy(cursor
, &gradient
->transform
, sizeof(gradient
->transform
));
1080 cursor
+= sizeof(gradient
->transform
);
1083 if (gradient
->pblendcount
> 1 && gradient
->pblendcolor
&& gradient
->pblendpos
)
1085 const DWORD count
= gradient
->pblendcount
;
1087 data
->BrushData
.lineargradient
.BrushDataFlags
|= BrushDataPresetColors
;
1089 memcpy(cursor
, &count
, sizeof(count
));
1090 cursor
+= sizeof(count
);
1092 memcpy(cursor
, gradient
->pblendpos
, count
* sizeof(*gradient
->pblendpos
));
1093 cursor
+= count
* sizeof(*gradient
->pblendpos
);
1095 memcpy(cursor
, gradient
->pblendcolor
, count
* sizeof(*gradient
->pblendcolor
));
1097 else if (gradient
->blendcount
> 1 && gradient
->blendfac
&& gradient
->blendpos
)
1099 const DWORD count
= gradient
->blendcount
;
1101 data
->BrushData
.lineargradient
.BrushDataFlags
|= BrushDataBlendFactorsH
;
1103 memcpy(cursor
, &count
, sizeof(count
));
1104 cursor
+= sizeof(count
);
1106 memcpy(cursor
, gradient
->blendpos
, count
* sizeof(*gradient
->blendpos
));
1107 cursor
+= count
* sizeof(*gradient
->blendpos
);
1109 memcpy(cursor
, gradient
->blendfac
, count
* sizeof(*gradient
->blendfac
));
1115 FIXME("unsupported brush type: %d\n", brush
->bt
);
1119 static void METAFILE_PrepareCustomLineCapData(GDIPCONST GpCustomLineCap
*cap
, DWORD
*ret_cap_size
,
1120 DWORD
*ret_cap_data_size
, DWORD
*ret_path_size
)
1122 DWORD cap_size
, path_size
= 0;
1124 /* EmfPlusCustomStartCapData */
1125 cap_size
= FIELD_OFFSET(EmfPlusCustomStartCapData
, data
);
1126 /* -> EmfPlusCustomLineCap */
1127 cap_size
+= FIELD_OFFSET(EmfPlusCustomLineCap
, CustomLineCapData
);
1128 /* -> EmfPlusCustomLineCapArrowData */
1129 if (cap
->type
== CustomLineCapTypeAdjustableArrow
)
1130 cap_size
+= sizeof(EmfPlusCustomLineCapArrowData
);
1131 /* -> EmfPlusCustomLineCapData */
1134 /* -> EmfPlusCustomLineCapOptionalData */
1135 cap_size
+= FIELD_OFFSET(EmfPlusCustomLineCapData
, OptionalData
);
1137 /* -> EmfPlusCustomLineCapDataFillPath */
1138 cap_size
+= FIELD_OFFSET(EmfPlusCustomLineCapDataFillPath
, FillPath
);
1140 /* -> EmfPlusCustomLineCapDataLinePath */
1141 cap_size
+= FIELD_OFFSET(EmfPlusCustomLineCapDataLinePath
, LinePath
);
1143 /* -> EmfPlusPath in EmfPlusCustomLineCapDataFillPath and EmfPlusCustomLineCapDataLinePath */
1144 path_size
= FIELD_OFFSET(EmfPlusPath
, data
);
1145 path_size
+= sizeof(PointF
) * cap
->pathdata
.Count
;
1146 path_size
+= sizeof(BYTE
) * cap
->pathdata
.Count
;
1147 path_size
= (path_size
+ 3) & ~3;
1149 cap_size
+= path_size
;
1152 *ret_cap_size
= cap_size
;
1153 *ret_cap_data_size
= cap_size
- FIELD_OFFSET(EmfPlusCustomStartCapData
, data
);
1154 *ret_path_size
= path_size
;
1157 static void METAFILE_FillCustomLineCapData(GDIPCONST GpCustomLineCap
*cap
, BYTE
*ptr
,
1158 REAL line_miter_limit
, DWORD data_size
, DWORD path_size
)
1160 EmfPlusCustomStartCapData
*cap_data
;
1161 EmfPlusCustomLineCap
*line_cap
;
1164 cap_data
= (EmfPlusCustomStartCapData
*)ptr
;
1165 cap_data
->CustomStartCapSize
= data_size
;
1166 i
= FIELD_OFFSET(EmfPlusCustomStartCapData
, data
);
1168 line_cap
= (EmfPlusCustomLineCap
*)(ptr
+ i
);
1169 line_cap
->Version
= VERSION_MAGIC2
;
1170 line_cap
->Type
= cap
->type
;
1171 i
+= FIELD_OFFSET(EmfPlusCustomLineCap
, CustomLineCapData
);
1173 if (cap
->type
== CustomLineCapTypeAdjustableArrow
)
1175 EmfPlusCustomLineCapArrowData
*arrow_data
;
1176 GpAdjustableArrowCap
*arrow_cap
;
1178 arrow_data
= (EmfPlusCustomLineCapArrowData
*)(ptr
+ i
);
1179 arrow_cap
= (GpAdjustableArrowCap
*)cap
;
1180 arrow_data
->Width
= arrow_cap
->width
;
1181 arrow_data
->Height
= arrow_cap
->height
;
1182 arrow_data
->MiddleInset
= arrow_cap
->middle_inset
;
1183 arrow_data
->FillState
= arrow_cap
->cap
.fill
;
1184 arrow_data
->LineStartCap
= arrow_cap
->cap
.strokeStartCap
;
1185 arrow_data
->LineEndCap
= arrow_cap
->cap
.strokeEndCap
;
1186 arrow_data
->LineJoin
= arrow_cap
->cap
.join
;
1187 arrow_data
->LineMiterLimit
= line_miter_limit
;
1188 arrow_data
->WidthScale
= arrow_cap
->cap
.scale
;
1189 arrow_data
->FillHotSpot
.X
= 0;
1190 arrow_data
->FillHotSpot
.Y
= 0;
1191 arrow_data
->LineHotSpot
.X
= 0;
1192 arrow_data
->LineHotSpot
.Y
= 0;
1196 EmfPlusCustomLineCapData
*line_cap_data
= (EmfPlusCustomLineCapData
*)(ptr
+ i
);
1200 line_cap_data
->CustomLineCapDataFlags
= CustomLineCapDataFillPath
;
1202 line_cap_data
->CustomLineCapDataFlags
= CustomLineCapDataLinePath
;
1203 line_cap_data
->BaseCap
= cap
->basecap
;
1204 line_cap_data
->BaseInset
= cap
->inset
;
1205 line_cap_data
->StrokeStartCap
= cap
->strokeStartCap
;
1206 line_cap_data
->StrokeEndCap
= cap
->strokeEndCap
;
1207 line_cap_data
->StrokeJoin
= cap
->join
;
1208 line_cap_data
->StrokeMiterLimit
= line_miter_limit
;
1209 line_cap_data
->WidthScale
= cap
->scale
;
1210 line_cap_data
->FillHotSpot
.X
= 0;
1211 line_cap_data
->FillHotSpot
.Y
= 0;
1212 line_cap_data
->LineHotSpot
.X
= 0;
1213 line_cap_data
->LineHotSpot
.Y
= 0;
1214 i
+= FIELD_OFFSET(EmfPlusCustomLineCapData
, OptionalData
);
1218 EmfPlusCustomLineCapDataFillPath
*fill_path
= (EmfPlusCustomLineCapDataFillPath
*)(ptr
+ i
);
1219 fill_path
->FillPathLength
= path_size
;
1220 i
+= FIELD_OFFSET(EmfPlusCustomLineCapDataFillPath
, FillPath
);
1224 EmfPlusCustomLineCapDataLinePath
*line_path
= (EmfPlusCustomLineCapDataLinePath
*)(ptr
+ i
);
1225 line_path
->LinePathLength
= path_size
;
1226 i
+= FIELD_OFFSET(EmfPlusCustomLineCapDataLinePath
, LinePath
);
1229 path
= (EmfPlusPath
*)(ptr
+ i
);
1230 path
->Version
= VERSION_MAGIC2
;
1231 path
->PathPointCount
= cap
->pathdata
.Count
;
1232 path
->PathPointFlags
= 0;
1233 i
+= FIELD_OFFSET(EmfPlusPath
, data
);
1234 memcpy(ptr
+ i
, cap
->pathdata
.Points
, cap
->pathdata
.Count
* sizeof(PointF
));
1235 i
+= cap
->pathdata
.Count
* sizeof(PointF
);
1236 memcpy(ptr
+ i
, cap
->pathdata
.Types
, cap
->pathdata
.Count
* sizeof(BYTE
));
1240 static GpStatus
METAFILE_AddBrushObject(GpMetafile
*metafile
, GDIPCONST GpBrush
*brush
, DWORD
*id
)
1242 EmfPlusObject
*object_record
;
1247 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
1250 stat
= METAFILE_PrepareBrushData(brush
, &size
);
1251 if (stat
!= Ok
) return stat
;
1253 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
1254 FIELD_OFFSET(EmfPlusObject
, ObjectData
) + size
, (void**)&object_record
);
1255 if (stat
!= Ok
) return stat
;
1257 *id
= METAFILE_AddObjectId(metafile
);
1258 object_record
->Header
.Flags
= *id
| ObjectTypeBrush
<< 8;
1259 METAFILE_FillBrushData(brush
, &object_record
->ObjectData
.brush
);
1263 GpStatus
METAFILE_FillRectangles(GpMetafile
* metafile
, GpBrush
* brush
,
1264 GDIPCONST GpRectF
* rects
, INT count
)
1266 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1268 EmfPlusFillRects
*record
;
1270 BOOL integer_rects
= TRUE
;
1275 if (brush
->bt
== BrushTypeSolidColor
)
1278 brushid
= ((GpSolidFill
*)brush
)->color
;
1282 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brushid
);
1287 for (i
=0; i
<count
; i
++)
1289 if (!is_integer_rect(&rects
[i
]))
1291 integer_rects
= FALSE
;
1299 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeFillRects
,
1300 sizeof(EmfPlusFillRects
) + count
* (integer_rects
? sizeof(EmfPlusRect
) : sizeof(GpRectF
)),
1305 record
->Header
.Flags
= flags
;
1306 record
->BrushID
= brushid
;
1307 record
->Count
= count
;
1311 EmfPlusRect
*record_rects
= (EmfPlusRect
*)(record
+1);
1312 for (i
=0; i
<count
; i
++)
1314 record_rects
[i
].X
= (SHORT
)rects
[i
].X
;
1315 record_rects
[i
].Y
= (SHORT
)rects
[i
].Y
;
1316 record_rects
[i
].Width
= (SHORT
)rects
[i
].Width
;
1317 record_rects
[i
].Height
= (SHORT
)rects
[i
].Height
;
1321 memcpy(record
+1, rects
, sizeof(GpRectF
) * count
);
1323 METAFILE_WriteRecords(metafile
);
1326 if (metafile
->auto_frame
)
1328 GpPointF corners
[4];
1331 for (i
=0; i
<count
; i
++)
1333 corners
[0].X
= rects
[i
].X
;
1334 corners
[0].Y
= rects
[i
].Y
;
1335 corners
[1].X
= rects
[i
].X
+ rects
[i
].Width
;
1336 corners
[1].Y
= rects
[i
].Y
;
1337 corners
[2].X
= rects
[i
].X
;
1338 corners
[2].Y
= rects
[i
].Y
+ rects
[i
].Height
;
1339 corners
[3].X
= rects
[i
].X
+ rects
[i
].Width
;
1340 corners
[3].Y
= rects
[i
].Y
+ rects
[i
].Height
;
1342 GdipTransformPoints(metafile
->record_graphics
, CoordinateSpaceDevice
,
1343 CoordinateSpaceWorld
, corners
, 4);
1345 METAFILE_AdjustFrame(metafile
, corners
, 4);
1352 GpStatus
METAFILE_SetClipRect(GpMetafile
* metafile
, REAL x
, REAL y
, REAL width
, REAL height
, CombineMode mode
)
1354 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1356 EmfPlusSetClipRect
*record
;
1359 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSetClipRect
,
1360 sizeof(EmfPlusSetClipRect
), (void **)&record
);
1364 record
->Header
.Flags
= (mode
& 0xf) << 8;
1365 record
->ClipRect
.X
= x
;
1366 record
->ClipRect
.Y
= y
;
1367 record
->ClipRect
.Width
= width
;
1368 record
->ClipRect
.Height
= height
;
1370 METAFILE_WriteRecords(metafile
);
1376 static GpStatus
METAFILE_AddRegionObject(GpMetafile
*metafile
, GpRegion
*region
, DWORD
*id
)
1378 EmfPlusObject
*object_record
;
1383 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
1386 size
= write_region_data(region
, NULL
);
1387 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
1388 FIELD_OFFSET(EmfPlusObject
, ObjectData
.region
) + size
, (void**)&object_record
);
1389 if (stat
!= Ok
) return stat
;
1391 *id
= METAFILE_AddObjectId(metafile
);
1392 object_record
->Header
.Flags
= *id
| ObjectTypeRegion
<< 8;
1393 write_region_data(region
, &object_record
->ObjectData
.region
);
1397 GpStatus
METAFILE_SetClipRegion(GpMetafile
* metafile
, GpRegion
* region
, CombineMode mode
)
1399 EmfPlusRecordHeader
*record
;
1403 if (metafile
->metafile_type
== MetafileTypeEmf
)
1406 return NotImplemented
;
1409 stat
= METAFILE_AddRegionObject(metafile
, region
, ®ion_id
);
1410 if (stat
!= Ok
) return stat
;
1412 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSetClipRegion
, sizeof(*record
), (void**)&record
);
1413 if (stat
!= Ok
) return stat
;
1415 record
->Flags
= region_id
| mode
<< 8;
1417 METAFILE_WriteRecords(metafile
);
1421 GpStatus
METAFILE_SetPageTransform(GpMetafile
* metafile
, GpUnit unit
, REAL scale
)
1423 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1425 EmfPlusSetPageTransform
*record
;
1428 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSetPageTransform
,
1429 sizeof(EmfPlusSetPageTransform
), (void **)&record
);
1433 record
->Header
.Flags
= unit
;
1434 record
->PageScale
= scale
;
1436 METAFILE_WriteRecords(metafile
);
1442 GpStatus
METAFILE_SetWorldTransform(GpMetafile
* metafile
, GDIPCONST GpMatrix
* transform
)
1444 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1446 EmfPlusSetWorldTransform
*record
;
1449 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSetWorldTransform
,
1450 sizeof(EmfPlusSetWorldTransform
), (void **)&record
);
1454 memcpy(record
->MatrixData
, transform
->matrix
, sizeof(record
->MatrixData
));
1456 METAFILE_WriteRecords(metafile
);
1462 GpStatus
METAFILE_ScaleWorldTransform(GpMetafile
* metafile
, REAL sx
, REAL sy
, MatrixOrder order
)
1464 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1466 EmfPlusScaleWorldTransform
*record
;
1469 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeScaleWorldTransform
,
1470 sizeof(EmfPlusScaleWorldTransform
), (void **)&record
);
1474 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1478 METAFILE_WriteRecords(metafile
);
1484 GpStatus
METAFILE_MultiplyWorldTransform(GpMetafile
* metafile
, GDIPCONST GpMatrix
* matrix
, MatrixOrder order
)
1486 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1488 EmfPlusMultiplyWorldTransform
*record
;
1491 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeMultiplyWorldTransform
,
1492 sizeof(EmfPlusMultiplyWorldTransform
), (void **)&record
);
1496 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1497 memcpy(record
->MatrixData
, matrix
->matrix
, sizeof(record
->MatrixData
));
1499 METAFILE_WriteRecords(metafile
);
1505 GpStatus
METAFILE_RotateWorldTransform(GpMetafile
* metafile
, REAL angle
, MatrixOrder order
)
1507 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1509 EmfPlusRotateWorldTransform
*record
;
1512 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeRotateWorldTransform
,
1513 sizeof(EmfPlusRotateWorldTransform
), (void **)&record
);
1517 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1518 record
->Angle
= angle
;
1520 METAFILE_WriteRecords(metafile
);
1526 GpStatus
METAFILE_TranslateWorldTransform(GpMetafile
* metafile
, REAL dx
, REAL dy
, MatrixOrder order
)
1528 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1530 EmfPlusTranslateWorldTransform
*record
;
1533 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeTranslateWorldTransform
,
1534 sizeof(EmfPlusTranslateWorldTransform
), (void **)&record
);
1538 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1542 METAFILE_WriteRecords(metafile
);
1548 GpStatus
METAFILE_ResetWorldTransform(GpMetafile
* metafile
)
1550 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1552 EmfPlusRecordHeader
*record
;
1555 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeResetWorldTransform
,
1556 sizeof(EmfPlusRecordHeader
), (void **)&record
);
1560 METAFILE_WriteRecords(metafile
);
1566 GpStatus
METAFILE_BeginContainer(GpMetafile
* metafile
, GDIPCONST GpRectF
*dstrect
,
1567 GDIPCONST GpRectF
*srcrect
, GpUnit unit
, DWORD StackIndex
)
1569 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1571 EmfPlusBeginContainer
*record
;
1574 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeBeginContainer
, sizeof(*record
), (void**)&record
);
1578 record
->Header
.Flags
= unit
& 0xff;
1579 record
->DestRect
= *dstrect
;
1580 record
->SrcRect
= *srcrect
;
1581 record
->StackIndex
= StackIndex
;
1583 METAFILE_WriteRecords(metafile
);
1589 GpStatus
METAFILE_BeginContainerNoParams(GpMetafile
* metafile
, DWORD StackIndex
)
1591 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1593 EmfPlusContainerRecord
*record
;
1596 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeBeginContainerNoParams
,
1597 sizeof(EmfPlusContainerRecord
), (void **)&record
);
1601 record
->StackIndex
= StackIndex
;
1603 METAFILE_WriteRecords(metafile
);
1609 GpStatus
METAFILE_EndContainer(GpMetafile
* metafile
, DWORD StackIndex
)
1611 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1613 EmfPlusContainerRecord
*record
;
1616 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeEndContainer
,
1617 sizeof(EmfPlusContainerRecord
), (void **)&record
);
1621 record
->StackIndex
= StackIndex
;
1623 METAFILE_WriteRecords(metafile
);
1629 GpStatus
METAFILE_SaveGraphics(GpMetafile
* metafile
, DWORD StackIndex
)
1631 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1633 EmfPlusContainerRecord
*record
;
1636 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSave
,
1637 sizeof(EmfPlusContainerRecord
), (void **)&record
);
1641 record
->StackIndex
= StackIndex
;
1643 METAFILE_WriteRecords(metafile
);
1649 GpStatus
METAFILE_RestoreGraphics(GpMetafile
* metafile
, DWORD StackIndex
)
1651 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1653 EmfPlusContainerRecord
*record
;
1656 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeRestore
,
1657 sizeof(EmfPlusContainerRecord
), (void **)&record
);
1661 record
->StackIndex
= StackIndex
;
1663 METAFILE_WriteRecords(metafile
);
1669 GpStatus
METAFILE_ReleaseDC(GpMetafile
* metafile
, HDC hdc
)
1671 if (hdc
!= metafile
->record_dc
)
1672 return InvalidParameter
;
1677 GpStatus
METAFILE_GraphicsDeleted(GpMetafile
* metafile
)
1681 stat
= METAFILE_WriteEndOfFile(metafile
);
1682 metafile
->record_graphics
= NULL
;
1684 metafile
->hemf
= CloseEnhMetaFile(metafile
->record_dc
);
1685 metafile
->record_dc
= NULL
;
1687 heap_free(metafile
->comment_data
);
1688 metafile
->comment_data
= NULL
;
1689 metafile
->comment_data_size
= 0;
1693 MetafileHeader header
;
1695 stat
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, &header
);
1696 if (stat
== Ok
&& metafile
->auto_frame
&&
1697 metafile
->auto_frame_max
.X
>= metafile
->auto_frame_min
.X
)
1699 RECTL bounds_rc
, gdi_bounds_rc
;
1700 REAL x_scale
= 2540.0 / header
.DpiX
;
1701 REAL y_scale
= 2540.0 / header
.DpiY
;
1705 gdi_bounds_rc
= header
.u
.EmfHeader
.rclBounds
;
1706 if (gdi_bounds_rc
.right
> gdi_bounds_rc
.left
&&
1707 gdi_bounds_rc
.bottom
> gdi_bounds_rc
.top
)
1709 GpPointF
*af_min
= &metafile
->auto_frame_min
;
1710 GpPointF
*af_max
= &metafile
->auto_frame_max
;
1712 af_min
->X
= fmin(af_min
->X
, gdi_bounds_rc
.left
);
1713 af_min
->Y
= fmin(af_min
->Y
, gdi_bounds_rc
.top
);
1714 af_max
->X
= fmax(af_max
->X
, gdi_bounds_rc
.right
);
1715 af_max
->Y
= fmax(af_max
->Y
, gdi_bounds_rc
.bottom
);
1718 bounds_rc
.left
= floorf(metafile
->auto_frame_min
.X
* x_scale
);
1719 bounds_rc
.top
= floorf(metafile
->auto_frame_min
.Y
* y_scale
);
1720 bounds_rc
.right
= ceilf(metafile
->auto_frame_max
.X
* x_scale
);
1721 bounds_rc
.bottom
= ceilf(metafile
->auto_frame_max
.Y
* y_scale
);
1723 buffer_size
= GetEnhMetaFileBits(metafile
->hemf
, 0, NULL
);
1724 buffer
= heap_alloc(buffer_size
);
1727 HENHMETAFILE new_hemf
;
1729 GetEnhMetaFileBits(metafile
->hemf
, buffer_size
, buffer
);
1731 ((ENHMETAHEADER
*)buffer
)->rclFrame
= bounds_rc
;
1733 new_hemf
= SetEnhMetaFileBits(buffer_size
, buffer
);
1737 DeleteEnhMetaFile(metafile
->hemf
);
1738 metafile
->hemf
= new_hemf
;
1749 stat
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, &header
);
1753 metafile
->bounds
.X
= header
.X
;
1754 metafile
->bounds
.Y
= header
.Y
;
1755 metafile
->bounds
.Width
= header
.Width
;
1756 metafile
->bounds
.Height
= header
.Height
;
1760 if (stat
== Ok
&& metafile
->record_stream
)
1765 buffer_size
= GetEnhMetaFileBits(metafile
->hemf
, 0, NULL
);
1767 buffer
= heap_alloc(buffer_size
);
1772 GetEnhMetaFileBits(metafile
->hemf
, buffer_size
, buffer
);
1774 hr
= IStream_Write(metafile
->record_stream
, buffer
, buffer_size
, NULL
);
1777 stat
= hresult_to_status(hr
);
1785 if (metafile
->record_stream
)
1787 IStream_Release(metafile
->record_stream
);
1788 metafile
->record_stream
= NULL
;
1794 GpStatus WINGDIPAPI
GdipGetHemfFromMetafile(GpMetafile
*metafile
, HENHMETAFILE
*hEmf
)
1796 TRACE("(%p,%p)\n", metafile
, hEmf
);
1798 if (!metafile
|| !hEmf
|| !metafile
->hemf
)
1799 return InvalidParameter
;
1801 *hEmf
= metafile
->hemf
;
1802 metafile
->hemf
= NULL
;
1807 static GpStatus
METAFILE_PlaybackGetDC(GpMetafile
*metafile
)
1811 stat
= GdipGetDC(metafile
->playback_graphics
, &metafile
->playback_dc
);
1816 static void METAFILE_PlaybackReleaseDC(GpMetafile
*metafile
)
1818 if (metafile
->playback_dc
)
1820 GdipReleaseDC(metafile
->playback_graphics
, metafile
->playback_dc
);
1821 metafile
->playback_dc
= NULL
;
1825 static GpStatus
METAFILE_PlaybackUpdateClip(GpMetafile
*metafile
)
1828 stat
= GdipCombineRegionRegion(metafile
->playback_graphics
->clip
, metafile
->base_clip
, CombineModeReplace
);
1830 stat
= GdipCombineRegionRegion(metafile
->playback_graphics
->clip
, metafile
->clip
, CombineModeIntersect
);
1834 static GpStatus
METAFILE_PlaybackUpdateWorldTransform(GpMetafile
*metafile
)
1836 GpMatrix
*real_transform
;
1839 stat
= GdipCreateMatrix3(&metafile
->src_rect
, metafile
->playback_points
, &real_transform
);
1843 REAL scale_x
= units_to_pixels(1.0, metafile
->page_unit
, metafile
->logical_dpix
, metafile
->printer_display
);
1844 REAL scale_y
= units_to_pixels(1.0, metafile
->page_unit
, metafile
->logical_dpiy
, metafile
->printer_display
);
1846 if (metafile
->page_unit
!= UnitDisplay
)
1848 scale_x
*= metafile
->page_scale
;
1849 scale_y
*= metafile
->page_scale
;
1852 stat
= GdipScaleMatrix(real_transform
, scale_x
, scale_y
, MatrixOrderPrepend
);
1855 stat
= GdipMultiplyMatrix(real_transform
, metafile
->world_transform
, MatrixOrderPrepend
);
1858 stat
= GdipSetWorldTransform(metafile
->playback_graphics
, real_transform
);
1860 GdipDeleteMatrix(real_transform
);
1866 static void metafile_set_object_table_entry(GpMetafile
*metafile
, BYTE id
, BYTE type
, void *object
)
1868 metafile_free_object_table_entry(metafile
, id
);
1869 metafile
->objtable
[id
].type
= type
;
1870 metafile
->objtable
[id
].u
.object
= object
;
1873 static GpStatus
metafile_deserialize_image(const BYTE
*record_data
, UINT data_size
, GpImage
**image
)
1875 EmfPlusImage
*data
= (EmfPlusImage
*)record_data
;
1880 if (data_size
< FIELD_OFFSET(EmfPlusImage
, ImageData
))
1881 return InvalidParameter
;
1882 data_size
-= FIELD_OFFSET(EmfPlusImage
, ImageData
);
1886 case ImageDataTypeBitmap
:
1888 EmfPlusBitmap
*bitmapdata
= &data
->ImageData
.bitmap
;
1890 if (data_size
<= FIELD_OFFSET(EmfPlusBitmap
, BitmapData
))
1891 return InvalidParameter
;
1892 data_size
-= FIELD_OFFSET(EmfPlusBitmap
, BitmapData
);
1894 switch (bitmapdata
->Type
)
1896 case BitmapDataTypePixel
:
1898 ColorPalette
*palette
;
1901 if (bitmapdata
->PixelFormat
& PixelFormatIndexed
)
1903 EmfPlusPalette
*palette_obj
= (EmfPlusPalette
*)bitmapdata
->BitmapData
;
1904 UINT palette_size
= FIELD_OFFSET(EmfPlusPalette
, PaletteEntries
);
1906 if (data_size
<= palette_size
)
1907 return InvalidParameter
;
1908 palette_size
+= palette_obj
->PaletteCount
* sizeof(EmfPlusARGB
);
1910 if (data_size
< palette_size
)
1911 return InvalidParameter
;
1912 data_size
-= palette_size
;
1914 palette
= (ColorPalette
*)bitmapdata
->BitmapData
;
1915 scan0
= (BYTE
*)bitmapdata
->BitmapData
+ palette_size
;
1920 scan0
= bitmapdata
->BitmapData
;
1923 if (data_size
< bitmapdata
->Height
* bitmapdata
->Stride
)
1924 return InvalidParameter
;
1926 status
= GdipCreateBitmapFromScan0(bitmapdata
->Width
, bitmapdata
->Height
, bitmapdata
->Stride
,
1927 bitmapdata
->PixelFormat
, scan0
, (GpBitmap
**)image
);
1928 if (status
== Ok
&& palette
)
1930 status
= GdipSetImagePalette(*image
, palette
);
1933 GdipDisposeImage(*image
);
1939 case BitmapDataTypeCompressed
:
1941 IWICImagingFactory
*factory
;
1945 if (WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION
, &factory
) != S_OK
)
1946 return GenericError
;
1948 hr
= IWICImagingFactory_CreateStream(factory
, &stream
);
1949 IWICImagingFactory_Release(factory
);
1951 return GenericError
;
1953 if (IWICStream_InitializeFromMemory(stream
, bitmapdata
->BitmapData
, data_size
) == S_OK
)
1954 status
= GdipCreateBitmapFromStream((IStream
*)stream
, (GpBitmap
**)image
);
1956 status
= GenericError
;
1958 IWICStream_Release(stream
);
1962 WARN("Invalid bitmap type %ld.\n", bitmapdata
->Type
);
1963 return InvalidParameter
;
1967 case ImageDataTypeMetafile
:
1969 EmfPlusMetafile
*metafiledata
= &data
->ImageData
.metafile
;
1971 if (data_size
<= FIELD_OFFSET(EmfPlusMetafile
, MetafileData
))
1972 return InvalidParameter
;
1973 data_size
-= FIELD_OFFSET(EmfPlusMetafile
, MetafileData
);
1975 switch (metafiledata
->Type
) {
1976 case MetafileTypeEmf
:
1977 case MetafileTypeEmfPlusOnly
:
1978 case MetafileTypeEmfPlusDual
:
1982 hemf
= SetEnhMetaFileBits(data_size
, metafiledata
->MetafileData
);
1985 return GenericError
;
1987 status
= GdipCreateMetafileFromEmf(hemf
, TRUE
, (GpMetafile
**)image
);
1990 DeleteEnhMetaFile(hemf
);
1995 FIXME("metafile type %ld not supported.\n", metafiledata
->Type
);
1996 return NotImplemented
;
2001 FIXME("image type %d not supported.\n", data
->Type
);
2002 return NotImplemented
;
2008 static GpStatus
metafile_deserialize_path(const BYTE
*record_data
, UINT data_size
, GpPath
**path
)
2010 EmfPlusPath
*data
= (EmfPlusPath
*)record_data
;
2018 if (data_size
<= FIELD_OFFSET(EmfPlusPath
, data
))
2019 return InvalidParameter
;
2020 data_size
-= FIELD_OFFSET(EmfPlusPath
, data
);
2022 if (data
->PathPointFlags
& 0x800) /* R */
2024 FIXME("RLE encoded path data is not supported.\n");
2025 return NotImplemented
;
2029 if (data
->PathPointFlags
& 0x4000) /* C */
2030 size
= sizeof(EmfPlusPoint
);
2032 size
= sizeof(EmfPlusPointF
);
2033 size
+= sizeof(BYTE
); /* EmfPlusPathPointType */
2034 size
*= data
->PathPointCount
;
2037 if (data_size
< size
)
2038 return InvalidParameter
;
2040 status
= GdipCreatePath(FillModeAlternate
, path
);
2044 (*path
)->pathdata
.Count
= data
->PathPointCount
;
2045 (*path
)->pathdata
.Points
= GdipAlloc(data
->PathPointCount
* sizeof(*(*path
)->pathdata
.Points
));
2046 (*path
)->pathdata
.Types
= GdipAlloc(data
->PathPointCount
* sizeof(*(*path
)->pathdata
.Types
));
2047 (*path
)->datalen
= (*path
)->pathdata
.Count
;
2049 if (!(*path
)->pathdata
.Points
|| !(*path
)->pathdata
.Types
)
2051 GdipDeletePath(*path
);
2055 if (data
->PathPointFlags
& 0x4000) /* C */
2057 EmfPlusPoint
*points
= (EmfPlusPoint
*)data
->data
;
2058 for (i
= 0; i
< data
->PathPointCount
; i
++)
2060 (*path
)->pathdata
.Points
[i
].X
= points
[i
].X
;
2061 (*path
)->pathdata
.Points
[i
].Y
= points
[i
].Y
;
2063 types
= (BYTE
*)(points
+ i
);
2067 EmfPlusPointF
*points
= (EmfPlusPointF
*)data
->data
;
2068 memcpy((*path
)->pathdata
.Points
, points
, sizeof(*points
) * data
->PathPointCount
);
2069 types
= (BYTE
*)(points
+ data
->PathPointCount
);
2072 memcpy((*path
)->pathdata
.Types
, types
, sizeof(*types
) * data
->PathPointCount
);
2077 static GpStatus
metafile_read_region_node(struct memory_buffer
*mbuf
, GpRegion
*region
, region_element
*node
, UINT
*count
)
2082 type
= buffer_read(mbuf
, sizeof(*type
));
2083 if (!type
) return Ok
;
2089 case CombineModeReplace
:
2090 case CombineModeIntersect
:
2091 case CombineModeUnion
:
2092 case CombineModeXor
:
2093 case CombineModeExclude
:
2094 case CombineModeComplement
:
2096 region_element
*left
, *right
;
2098 left
= heap_alloc_zero(sizeof(*left
));
2102 right
= heap_alloc_zero(sizeof(*right
));
2109 status
= metafile_read_region_node(mbuf
, region
, left
, count
);
2112 status
= metafile_read_region_node(mbuf
, region
, right
, count
);
2115 node
->elementdata
.combine
.left
= left
;
2116 node
->elementdata
.combine
.right
= right
;
2117 region
->num_children
+= 2;
2126 case RegionDataRect
:
2128 const EmfPlusRectF
*rect
;
2130 rect
= buffer_read(mbuf
, sizeof(*rect
));
2132 return InvalidParameter
;
2134 memcpy(&node
->elementdata
.rect
, rect
, sizeof(*rect
));
2138 case RegionDataPath
:
2140 const BYTE
*path_data
;
2141 const UINT
*data_size
;
2144 data_size
= buffer_read(mbuf
, FIELD_OFFSET(EmfPlusRegionNodePath
, RegionNodePath
));
2146 return InvalidParameter
;
2148 path_data
= buffer_read(mbuf
, *data_size
);
2150 return InvalidParameter
;
2152 status
= metafile_deserialize_path(path_data
, *data_size
, &path
);
2155 node
->elementdata
.path
= path
;
2160 case RegionDataEmptyRect
:
2161 case RegionDataInfiniteRect
:
2165 FIXME("element type %#lx is not supported\n", *type
);
2169 return InvalidParameter
;
2172 static GpStatus
metafile_deserialize_region(const BYTE
*record_data
, UINT data_size
, GpRegion
**region
)
2174 struct memory_buffer mbuf
;
2180 init_memory_buffer(&mbuf
, record_data
, data_size
);
2182 if (!buffer_read(&mbuf
, FIELD_OFFSET(EmfPlusRegion
, RegionNode
)))
2183 return InvalidParameter
;
2185 status
= GdipCreateRegion(region
);
2190 status
= metafile_read_region_node(&mbuf
, *region
, &(*region
)->node
, &count
);
2191 if (status
== Ok
&& !count
)
2192 status
= InvalidParameter
;
2196 GdipDeleteRegion(*region
);
2203 static GpStatus
metafile_deserialize_brush(const BYTE
*record_data
, UINT data_size
, GpBrush
**brush
)
2205 static const UINT header_size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
);
2206 EmfPlusBrush
*data
= (EmfPlusBrush
*)record_data
;
2207 EmfPlusTransformMatrix
*transform
= NULL
;
2214 if (data_size
< header_size
)
2215 return InvalidParameter
;
2219 case BrushTypeSolidColor
:
2220 if (data_size
!= header_size
+ sizeof(EmfPlusSolidBrushData
))
2221 return InvalidParameter
;
2223 status
= GdipCreateSolidFill(data
->BrushData
.solid
.SolidColor
, (GpSolidFill
**)brush
);
2225 case BrushTypeHatchFill
:
2226 if (data_size
!= header_size
+ sizeof(EmfPlusHatchBrushData
))
2227 return InvalidParameter
;
2229 status
= GdipCreateHatchBrush(data
->BrushData
.hatch
.HatchStyle
, data
->BrushData
.hatch
.ForeColor
,
2230 data
->BrushData
.hatch
.BackColor
, (GpHatch
**)brush
);
2232 case BrushTypeTextureFill
:
2236 offset
= header_size
+ FIELD_OFFSET(EmfPlusTextureBrushData
, OptionalData
);
2237 if (data_size
<= offset
)
2238 return InvalidParameter
;
2240 brushflags
= data
->BrushData
.texture
.BrushDataFlags
;
2241 if (brushflags
& BrushDataTransform
)
2243 if (data_size
<= offset
+ sizeof(EmfPlusTransformMatrix
))
2244 return InvalidParameter
;
2245 transform
= (EmfPlusTransformMatrix
*)(record_data
+ offset
);
2246 offset
+= sizeof(EmfPlusTransformMatrix
);
2249 status
= metafile_deserialize_image(record_data
+ offset
, data_size
- offset
, &image
);
2253 status
= GdipCreateTexture(image
, data
->BrushData
.texture
.WrapMode
, (GpTexture
**)brush
);
2254 if (status
== Ok
&& transform
&& !(brushflags
& BrushDataDoNotTransform
))
2255 GdipSetTextureTransform((GpTexture
*)*brush
, (const GpMatrix
*)transform
);
2257 GdipDisposeImage(image
);
2260 case BrushTypeLinearGradient
:
2262 GpLineGradient
*gradient
= NULL
;
2264 UINT position_count
= 0;
2266 offset
= header_size
+ FIELD_OFFSET(EmfPlusLinearGradientBrushData
, OptionalData
);
2267 if (data_size
< offset
)
2268 return InvalidParameter
;
2270 brushflags
= data
->BrushData
.lineargradient
.BrushDataFlags
;
2271 if ((brushflags
& BrushDataPresetColors
) && (brushflags
& (BrushDataBlendFactorsH
| BrushDataBlendFactorsV
)))
2272 return InvalidParameter
;
2274 if (brushflags
& BrushDataTransform
)
2276 if (data_size
< offset
+ sizeof(EmfPlusTransformMatrix
))
2277 return InvalidParameter
;
2278 transform
= (EmfPlusTransformMatrix
*)(record_data
+ offset
);
2279 offset
+= sizeof(EmfPlusTransformMatrix
);
2282 if (brushflags
& (BrushDataPresetColors
| BrushDataBlendFactorsH
| BrushDataBlendFactorsV
))
2284 if (data_size
<= offset
+ sizeof(DWORD
)) /* Number of factors/preset colors. */
2285 return InvalidParameter
;
2286 position_count
= *(DWORD
*)(record_data
+ offset
);
2287 offset
+= sizeof(DWORD
);
2290 if (brushflags
& BrushDataPresetColors
)
2292 if (data_size
!= offset
+ position_count
* (sizeof(float) + sizeof(EmfPlusARGB
)))
2293 return InvalidParameter
;
2295 else if (brushflags
& BrushDataBlendFactorsH
)
2297 if (data_size
!= offset
+ position_count
* 2 * sizeof(float))
2298 return InvalidParameter
;
2301 rect
.X
= data
->BrushData
.lineargradient
.RectF
.X
;
2302 rect
.Y
= data
->BrushData
.lineargradient
.RectF
.Y
;
2303 rect
.Width
= data
->BrushData
.lineargradient
.RectF
.Width
;
2304 rect
.Height
= data
->BrushData
.lineargradient
.RectF
.Height
;
2306 status
= GdipCreateLineBrushFromRect(&rect
, data
->BrushData
.lineargradient
.StartColor
,
2307 data
->BrushData
.lineargradient
.EndColor
, LinearGradientModeHorizontal
,
2308 data
->BrushData
.lineargradient
.WrapMode
, &gradient
);
2312 status
= GdipSetLineTransform(gradient
, (const GpMatrix
*)transform
);
2316 if (brushflags
& BrushDataPresetColors
)
2317 status
= GdipSetLinePresetBlend(gradient
, (ARGB
*)(record_data
+ offset
+
2318 position_count
* sizeof(REAL
)), (REAL
*)(record_data
+ offset
), position_count
);
2319 else if (brushflags
& BrushDataBlendFactorsH
)
2320 status
= GdipSetLineBlend(gradient
, (REAL
*)(record_data
+ offset
+ position_count
* sizeof(REAL
)),
2321 (REAL
*)(record_data
+ offset
), position_count
);
2323 if (brushflags
& BrushDataIsGammaCorrected
)
2324 FIXME("BrushDataIsGammaCorrected is not handled.\n");
2329 *brush
= (GpBrush
*)gradient
;
2331 GdipDeleteBrush((GpBrush
*)gradient
);
2336 FIXME("brush type %lu is not supported.\n", data
->Type
);
2337 return NotImplemented
;
2343 static GpStatus
metafile_deserialize_custom_line_cap(const BYTE
*record_data
, UINT data_size
, GpCustomLineCap
**cap
)
2345 EmfPlusCustomStartCapData
*custom_cap_data
= (EmfPlusCustomStartCapData
*)record_data
;
2346 EmfPlusCustomLineCap
*line_cap
;
2352 if (data_size
< FIELD_OFFSET(EmfPlusCustomStartCapData
, data
))
2353 return InvalidParameter
;
2354 if (data_size
< FIELD_OFFSET(EmfPlusCustomStartCapData
, data
) + custom_cap_data
->CustomStartCapSize
)
2355 return InvalidParameter
;
2356 offset
= FIELD_OFFSET(EmfPlusCustomStartCapData
, data
);
2357 line_cap
= (EmfPlusCustomLineCap
*)(record_data
+ offset
);
2359 if (data_size
< offset
+ FIELD_OFFSET(EmfPlusCustomLineCap
, CustomLineCapData
))
2360 return InvalidParameter
;
2361 offset
+= FIELD_OFFSET(EmfPlusCustomLineCap
, CustomLineCapData
);
2363 if (line_cap
->Type
== CustomLineCapTypeAdjustableArrow
)
2365 EmfPlusCustomLineCapArrowData
*arrow_data
;
2366 GpAdjustableArrowCap
*arrow_cap
;
2368 arrow_data
= (EmfPlusCustomLineCapArrowData
*)(record_data
+ offset
);
2370 if (data_size
< offset
+ sizeof(EmfPlusCustomLineCapArrowData
))
2371 return InvalidParameter
;
2373 if ((status
= GdipCreateAdjustableArrowCap(arrow_data
->Height
, arrow_data
->Width
,
2374 arrow_data
->FillState
, &arrow_cap
)))
2377 if ((status
= GdipSetAdjustableArrowCapMiddleInset(arrow_cap
, arrow_data
->MiddleInset
)))
2378 goto arrow_cap_failed
;
2379 if ((status
= GdipSetCustomLineCapStrokeCaps((GpCustomLineCap
*)arrow_cap
, arrow_data
->LineStartCap
, arrow_data
->LineEndCap
)))
2380 goto arrow_cap_failed
;
2381 if ((status
= GdipSetCustomLineCapStrokeJoin((GpCustomLineCap
*)arrow_cap
, arrow_data
->LineJoin
)))
2382 goto arrow_cap_failed
;
2383 if ((status
= GdipSetCustomLineCapWidthScale((GpCustomLineCap
*)arrow_cap
, arrow_data
->WidthScale
)))
2384 goto arrow_cap_failed
;
2386 *cap
= (GpCustomLineCap
*)arrow_cap
;
2390 GdipDeleteCustomLineCap((GpCustomLineCap
*)arrow_cap
);
2395 GpPath
*path
, *fill_path
= NULL
, *stroke_path
= NULL
;
2396 EmfPlusCustomLineCapData
*line_cap_data
;
2397 GpCustomLineCap
*line_cap
= NULL
;
2400 line_cap_data
= (EmfPlusCustomLineCapData
*)(record_data
+ offset
);
2402 if (data_size
< offset
+ FIELD_OFFSET(EmfPlusCustomLineCapData
, OptionalData
))
2403 return InvalidParameter
;
2404 offset
+= FIELD_OFFSET(EmfPlusCustomLineCapData
, OptionalData
);
2406 if (line_cap_data
->CustomLineCapDataFlags
== CustomLineCapDataFillPath
)
2408 EmfPlusCustomLineCapDataFillPath
*fill_path
= (EmfPlusCustomLineCapDataFillPath
*)(record_data
+ offset
);
2410 if (data_size
< offset
+ FIELD_OFFSET(EmfPlusCustomLineCapDataFillPath
, FillPath
))
2411 return InvalidParameter
;
2412 if (data_size
< offset
+ fill_path
->FillPathLength
)
2413 return InvalidParameter
;
2415 offset
+= FIELD_OFFSET(EmfPlusCustomLineCapDataFillPath
, FillPath
);
2419 EmfPlusCustomLineCapDataLinePath
*line_path
= (EmfPlusCustomLineCapDataLinePath
*)(record_data
+ offset
);
2421 if (data_size
< offset
+ FIELD_OFFSET(EmfPlusCustomLineCapDataLinePath
, LinePath
))
2422 return InvalidParameter
;
2423 if (data_size
< offset
+ line_path
->LinePathLength
)
2424 return InvalidParameter
;
2426 offset
+= FIELD_OFFSET(EmfPlusCustomLineCapDataLinePath
, LinePath
);
2429 if ((status
= metafile_deserialize_path(record_data
+ offset
, data_size
- offset
, &path
)))
2432 if (line_cap_data
->CustomLineCapDataFlags
== CustomLineCapDataFillPath
)
2437 if ((status
= GdipCreateCustomLineCap(fill_path
, stroke_path
, line_cap_data
->BaseCap
,
2438 line_cap_data
->BaseInset
, &line_cap
)))
2439 goto default_cap_failed
;
2440 if ((status
= GdipSetCustomLineCapStrokeCaps(line_cap
, line_cap_data
->StrokeStartCap
, line_cap_data
->StrokeEndCap
)))
2441 goto default_cap_failed
;
2442 if ((status
= GdipSetCustomLineCapStrokeJoin(line_cap
, line_cap_data
->StrokeJoin
)))
2443 goto default_cap_failed
;
2444 if ((status
= GdipSetCustomLineCapWidthScale(line_cap
, line_cap_data
->WidthScale
)))
2445 goto default_cap_failed
;
2447 GdipDeletePath(path
);
2453 GdipDeleteCustomLineCap(line_cap
);
2454 GdipDeletePath(path
);
2459 static GpStatus
metafile_get_pen_brush_data_offset(EmfPlusPen
*data
, UINT data_size
, DWORD
*ret
)
2461 EmfPlusPenData
*pendata
= (EmfPlusPenData
*)data
->data
;
2462 DWORD offset
= FIELD_OFFSET(EmfPlusPen
, data
);
2464 if (data_size
<= offset
)
2465 return InvalidParameter
;
2467 offset
+= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
2468 if (data_size
<= offset
)
2469 return InvalidParameter
;
2471 if (pendata
->PenDataFlags
& PenDataTransform
)
2472 offset
+= sizeof(EmfPlusTransformMatrix
);
2474 if (pendata
->PenDataFlags
& PenDataStartCap
)
2475 offset
+= sizeof(DWORD
);
2477 if (pendata
->PenDataFlags
& PenDataEndCap
)
2478 offset
+= sizeof(DWORD
);
2480 if (pendata
->PenDataFlags
& PenDataJoin
)
2481 offset
+= sizeof(DWORD
);
2483 if (pendata
->PenDataFlags
& PenDataMiterLimit
)
2484 offset
+= sizeof(REAL
);
2486 if (pendata
->PenDataFlags
& PenDataLineStyle
)
2487 offset
+= sizeof(DWORD
);
2489 if (pendata
->PenDataFlags
& PenDataDashedLineCap
)
2490 offset
+= sizeof(DWORD
);
2492 if (pendata
->PenDataFlags
& PenDataDashedLineOffset
)
2493 offset
+= sizeof(REAL
);
2495 if (pendata
->PenDataFlags
& PenDataDashedLine
)
2497 EmfPlusDashedLineData
*dashedline
= (EmfPlusDashedLineData
*)((BYTE
*)data
+ offset
);
2499 offset
+= FIELD_OFFSET(EmfPlusDashedLineData
, data
);
2500 if (data_size
<= offset
)
2501 return InvalidParameter
;
2503 offset
+= dashedline
->DashedLineDataSize
* sizeof(float);
2506 if (pendata
->PenDataFlags
& PenDataNonCenter
)
2507 offset
+= sizeof(DWORD
);
2509 if (pendata
->PenDataFlags
& PenDataCompoundLine
)
2511 EmfPlusCompoundLineData
*compoundline
= (EmfPlusCompoundLineData
*)((BYTE
*)data
+ offset
);
2513 offset
+= FIELD_OFFSET(EmfPlusCompoundLineData
, data
);
2514 if (data_size
<= offset
)
2515 return InvalidParameter
;
2517 offset
+= compoundline
->CompoundLineDataSize
* sizeof(float);
2520 if (pendata
->PenDataFlags
& PenDataCustomStartCap
)
2522 EmfPlusCustomStartCapData
*startcap
= (EmfPlusCustomStartCapData
*)((BYTE
*)data
+ offset
);
2524 offset
+= FIELD_OFFSET(EmfPlusCustomStartCapData
, data
);
2525 if (data_size
<= offset
)
2526 return InvalidParameter
;
2528 offset
+= startcap
->CustomStartCapSize
;
2531 if (pendata
->PenDataFlags
& PenDataCustomEndCap
)
2533 EmfPlusCustomEndCapData
*endcap
= (EmfPlusCustomEndCapData
*)((BYTE
*)data
+ offset
);
2535 offset
+= FIELD_OFFSET(EmfPlusCustomEndCapData
, data
);
2536 if (data_size
<= offset
)
2537 return InvalidParameter
;
2539 offset
+= endcap
->CustomEndCapSize
;
2546 static GpStatus
METAFILE_PlaybackObject(GpMetafile
*metafile
, UINT flags
, UINT data_size
, const BYTE
*record_data
)
2548 BYTE type
= (flags
>> 8) & 0xff;
2549 BYTE id
= flags
& 0xff;
2550 void *object
= NULL
;
2553 if (type
> ObjectTypeMax
|| id
>= EmfPlusObjectTableSize
)
2554 return InvalidParameter
;
2558 case ObjectTypeBrush
:
2559 status
= metafile_deserialize_brush(record_data
, data_size
, (GpBrush
**)&object
);
2563 EmfPlusPen
*data
= (EmfPlusPen
*)record_data
;
2564 EmfPlusPenData
*pendata
= (EmfPlusPenData
*)data
->data
;
2565 GpCustomLineCap
*custom_line_cap
;
2570 status
= metafile_get_pen_brush_data_offset(data
, data_size
, &offset
);
2574 status
= metafile_deserialize_brush(record_data
+ offset
, data_size
- offset
, &brush
);
2578 status
= GdipCreatePen2(brush
, pendata
->PenWidth
, pendata
->PenUnit
, &pen
);
2579 GdipDeleteBrush(brush
);
2583 offset
= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
2585 if (pendata
->PenDataFlags
& PenDataTransform
)
2587 FIXME("PenDataTransform is not supported.\n");
2588 offset
+= sizeof(EmfPlusTransformMatrix
);
2591 if (pendata
->PenDataFlags
& PenDataStartCap
)
2593 if ((status
= GdipSetPenStartCap(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2595 offset
+= sizeof(DWORD
);
2598 if (pendata
->PenDataFlags
& PenDataEndCap
)
2600 if ((status
= GdipSetPenEndCap(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2602 offset
+= sizeof(DWORD
);
2605 if (pendata
->PenDataFlags
& PenDataJoin
)
2607 if ((status
= GdipSetPenLineJoin(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2609 offset
+= sizeof(DWORD
);
2612 if (pendata
->PenDataFlags
& PenDataMiterLimit
)
2614 if ((status
= GdipSetPenMiterLimit(pen
, *(REAL
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2616 offset
+= sizeof(REAL
);
2619 if (pendata
->PenDataFlags
& PenDataLineStyle
)
2621 if ((status
= GdipSetPenDashStyle(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2623 offset
+= sizeof(DWORD
);
2626 if (pendata
->PenDataFlags
& PenDataDashedLineCap
)
2628 FIXME("PenDataDashedLineCap is not supported.\n");
2629 offset
+= sizeof(DWORD
);
2632 if (pendata
->PenDataFlags
& PenDataDashedLineOffset
)
2634 if ((status
= GdipSetPenDashOffset(pen
, *(REAL
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2636 offset
+= sizeof(REAL
);
2639 if (pendata
->PenDataFlags
& PenDataDashedLine
)
2641 EmfPlusDashedLineData
*dashedline
= (EmfPlusDashedLineData
*)((BYTE
*)pendata
+ offset
);
2642 FIXME("PenDataDashedLine is not supported.\n");
2643 offset
+= FIELD_OFFSET(EmfPlusDashedLineData
, data
) + dashedline
->DashedLineDataSize
* sizeof(float);
2646 if (pendata
->PenDataFlags
& PenDataNonCenter
)
2648 FIXME("PenDataNonCenter is not supported.\n");
2649 offset
+= sizeof(DWORD
);
2652 if (pendata
->PenDataFlags
& PenDataCompoundLine
)
2654 EmfPlusCompoundLineData
*compoundline
= (EmfPlusCompoundLineData
*)((BYTE
*)pendata
+ offset
);
2655 FIXME("PenDataCompoundLine is not supported.\n");
2656 offset
+= FIELD_OFFSET(EmfPlusCompoundLineData
, data
) + compoundline
->CompoundLineDataSize
* sizeof(float);
2659 if (pendata
->PenDataFlags
& PenDataCustomStartCap
)
2661 EmfPlusCustomStartCapData
*startcap
= (EmfPlusCustomStartCapData
*)((BYTE
*)pendata
+ offset
);
2662 if ((status
= metafile_deserialize_custom_line_cap((BYTE
*)startcap
, data_size
, &custom_line_cap
)) != Ok
)
2664 status
= GdipSetPenCustomStartCap(pen
, custom_line_cap
);
2665 GdipDeleteCustomLineCap(custom_line_cap
);
2668 offset
+= FIELD_OFFSET(EmfPlusCustomStartCapData
, data
) + startcap
->CustomStartCapSize
;
2671 if (pendata
->PenDataFlags
& PenDataCustomEndCap
)
2673 EmfPlusCustomEndCapData
*endcap
= (EmfPlusCustomEndCapData
*)((BYTE
*)pendata
+ offset
);
2674 if ((status
= metafile_deserialize_custom_line_cap((BYTE
*)endcap
, data_size
, &custom_line_cap
)) != Ok
)
2676 status
= GdipSetPenCustomEndCap(pen
, custom_line_cap
);
2677 GdipDeleteCustomLineCap(custom_line_cap
);
2680 offset
+= FIELD_OFFSET(EmfPlusCustomEndCapData
, data
) + endcap
->CustomEndCapSize
;
2690 case ObjectTypePath
:
2691 status
= metafile_deserialize_path(record_data
, data_size
, (GpPath
**)&object
);
2693 case ObjectTypeRegion
:
2694 status
= metafile_deserialize_region(record_data
, data_size
, (GpRegion
**)&object
);
2696 case ObjectTypeImage
:
2697 status
= metafile_deserialize_image(record_data
, data_size
, (GpImage
**)&object
);
2699 case ObjectTypeFont
:
2701 EmfPlusFont
*data
= (EmfPlusFont
*)record_data
;
2702 GpFontFamily
*family
;
2705 if (data_size
<= FIELD_OFFSET(EmfPlusFont
, FamilyName
))
2706 return InvalidParameter
;
2707 data_size
-= FIELD_OFFSET(EmfPlusFont
, FamilyName
);
2709 if (data_size
< data
->Length
* sizeof(WCHAR
))
2710 return InvalidParameter
;
2712 if (!(familyname
= GdipAlloc((data
->Length
+ 1) * sizeof(*familyname
))))
2715 memcpy(familyname
, data
->FamilyName
, data
->Length
* sizeof(*familyname
));
2716 familyname
[data
->Length
] = 0;
2718 status
= GdipCreateFontFamilyFromName(familyname
, NULL
, &family
);
2719 GdipFree(familyname
);
2721 /* If a font family cannot be created from family name, native
2722 falls back to a sans serif font. */
2724 status
= GdipGetGenericFontFamilySansSerif(&family
);
2728 status
= GdipCreateFont(family
, data
->EmSize
, data
->FontStyleFlags
, data
->SizeUnit
, (GpFont
**)&object
);
2729 GdipDeleteFontFamily(family
);
2732 case ObjectTypeImageAttributes
:
2734 EmfPlusImageAttributes
*data
= (EmfPlusImageAttributes
*)record_data
;
2735 GpImageAttributes
*attributes
= NULL
;
2737 if (data_size
!= sizeof(*data
))
2738 return InvalidParameter
;
2740 if ((status
= GdipCreateImageAttributes(&attributes
)) != Ok
)
2743 status
= GdipSetImageAttributesWrapMode(attributes
, data
->WrapMode
, *(DWORD
*)&data
->ClampColor
,
2744 !!data
->ObjectClamp
);
2746 object
= attributes
;
2748 GdipDisposeImageAttributes(attributes
);
2752 FIXME("not implemented for object type %d.\n", type
);
2753 return NotImplemented
;
2757 metafile_set_object_table_entry(metafile
, id
, type
, object
);
2762 static GpStatus
metafile_set_clip_region(GpMetafile
*metafile
, GpRegion
*region
, CombineMode mode
)
2764 GpMatrix world_to_device
;
2766 get_graphics_transform(metafile
->playback_graphics
, CoordinateSpaceDevice
, CoordinateSpaceWorld
, &world_to_device
);
2768 GdipTransformRegion(region
, &world_to_device
);
2769 GdipCombineRegionRegion(metafile
->clip
, region
, mode
);
2771 return METAFILE_PlaybackUpdateClip(metafile
);
2774 GpStatus WINGDIPAPI
GdipPlayMetafileRecord(GDIPCONST GpMetafile
*metafile
,
2775 EmfPlusRecordType recordType
, UINT flags
, UINT dataSize
, GDIPCONST BYTE
*data
)
2778 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
;
2780 TRACE("(%p,%x,%x,%d,%p)\n", metafile
, recordType
, flags
, dataSize
, data
);
2782 if (!metafile
|| (dataSize
&& !data
) || !metafile
->playback_graphics
)
2783 return InvalidParameter
;
2785 if (recordType
>= 1 && recordType
<= 0x7a)
2787 /* regular EMF record */
2788 if (metafile
->playback_dc
)
2790 ENHMETARECORD
*record
= heap_alloc_zero(dataSize
+ 8);
2794 record
->iType
= recordType
;
2795 record
->nSize
= dataSize
+ 8;
2796 memcpy(record
->dParm
, data
, dataSize
);
2798 if (record
->iType
== EMR_BITBLT
|| record
->iType
== EMR_STRETCHBLT
)
2799 SetStretchBltMode(metafile
->playback_dc
, STRETCH_HALFTONE
);
2801 if(PlayEnhMetaFileRecord(metafile
->playback_dc
, metafile
->handle_table
,
2802 record
, metafile
->handle_count
) == 0)
2803 ERR("PlayEnhMetaFileRecord failed\n");
2813 EmfPlusRecordHeader
*header
= (EmfPlusRecordHeader
*)(data
)-1;
2815 METAFILE_PlaybackReleaseDC((GpMetafile
*)metafile
);
2819 case EmfPlusRecordTypeHeader
:
2820 case EmfPlusRecordTypeEndOfFile
:
2822 case EmfPlusRecordTypeGetDC
:
2823 METAFILE_PlaybackGetDC((GpMetafile
*)metafile
);
2825 case EmfPlusRecordTypeClear
:
2827 EmfPlusClear
*record
= (EmfPlusClear
*)header
;
2829 if (dataSize
!= sizeof(record
->Color
))
2830 return InvalidParameter
;
2832 return GdipGraphicsClear(metafile
->playback_graphics
, record
->Color
);
2834 case EmfPlusRecordTypeFillRects
:
2836 EmfPlusFillRects
*record
= (EmfPlusFillRects
*)header
;
2837 GpBrush
*brush
, *temp_brush
=NULL
;
2838 GpRectF
*rects
, *temp_rects
=NULL
;
2840 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
))
2841 return InvalidParameter
;
2845 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(EmfPlusRect
) * record
->Count
)
2846 return InvalidParameter
;
2850 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(GpRectF
) * record
->Count
)
2851 return InvalidParameter
;
2856 stat
= GdipCreateSolidFill(record
->BrushID
, (GpSolidFill
**)&temp_brush
);
2861 if (record
->BrushID
>= EmfPlusObjectTableSize
||
2862 real_metafile
->objtable
[record
->BrushID
].type
!= ObjectTypeBrush
)
2863 return InvalidParameter
;
2865 brush
= real_metafile
->objtable
[record
->BrushID
].u
.brush
;
2873 EmfPlusRect
*int_rects
= (EmfPlusRect
*)(record
+1);
2876 rects
= temp_rects
= heap_alloc_zero(sizeof(GpRectF
) * record
->Count
);
2879 for (i
=0; i
<record
->Count
; i
++)
2881 rects
[i
].X
= int_rects
[i
].X
;
2882 rects
[i
].Y
= int_rects
[i
].Y
;
2883 rects
[i
].Width
= int_rects
[i
].Width
;
2884 rects
[i
].Height
= int_rects
[i
].Height
;
2891 rects
= (GpRectF
*)(record
+1);
2896 stat
= GdipFillRectangles(metafile
->playback_graphics
, brush
, rects
, record
->Count
);
2899 GdipDeleteBrush(temp_brush
);
2900 heap_free(temp_rects
);
2904 case EmfPlusRecordTypeSetClipRect
:
2906 EmfPlusSetClipRect
*record
= (EmfPlusSetClipRect
*)header
;
2907 CombineMode mode
= (CombineMode
)((flags
>> 8) & 0xf);
2910 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(*record
))
2911 return InvalidParameter
;
2913 stat
= GdipCreateRegionRect(&record
->ClipRect
, ®ion
);
2917 stat
= metafile_set_clip_region(real_metafile
, region
, mode
);
2918 GdipDeleteRegion(region
);
2923 case EmfPlusRecordTypeSetClipRegion
:
2925 CombineMode mode
= (flags
>> 8) & 0xf;
2926 BYTE regionid
= flags
& 0xff;
2930 return InvalidParameter
;
2932 if (regionid
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[regionid
].type
!= ObjectTypeRegion
)
2933 return InvalidParameter
;
2935 stat
= GdipCloneRegion(real_metafile
->objtable
[regionid
].u
.region
, ®ion
);
2938 stat
= metafile_set_clip_region(real_metafile
, region
, mode
);
2939 GdipDeleteRegion(region
);
2944 case EmfPlusRecordTypeSetClipPath
:
2946 CombineMode mode
= (flags
>> 8) & 0xf;
2947 BYTE pathid
= flags
& 0xff;
2951 return InvalidParameter
;
2953 if (pathid
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pathid
].type
!= ObjectTypePath
)
2954 return InvalidParameter
;
2956 stat
= GdipCreateRegionPath(real_metafile
->objtable
[pathid
].u
.path
, ®ion
);
2959 stat
= metafile_set_clip_region(real_metafile
, region
, mode
);
2960 GdipDeleteRegion(region
);
2965 case EmfPlusRecordTypeSetPageTransform
:
2967 EmfPlusSetPageTransform
*record
= (EmfPlusSetPageTransform
*)header
;
2968 GpUnit unit
= (GpUnit
)flags
;
2970 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetPageTransform
))
2971 return InvalidParameter
;
2973 real_metafile
->page_unit
= unit
;
2974 real_metafile
->page_scale
= record
->PageScale
;
2976 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2978 case EmfPlusRecordTypeSetWorldTransform
:
2980 EmfPlusSetWorldTransform
*record
= (EmfPlusSetWorldTransform
*)header
;
2982 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetWorldTransform
))
2983 return InvalidParameter
;
2985 memcpy(real_metafile
->world_transform
->matrix
, record
->MatrixData
, sizeof(record
->MatrixData
));
2987 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2989 case EmfPlusRecordTypeScaleWorldTransform
:
2991 EmfPlusScaleWorldTransform
*record
= (EmfPlusScaleWorldTransform
*)header
;
2992 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2994 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusScaleWorldTransform
))
2995 return InvalidParameter
;
2997 GdipScaleMatrix(real_metafile
->world_transform
, record
->Sx
, record
->Sy
, order
);
2999 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
3001 case EmfPlusRecordTypeMultiplyWorldTransform
:
3003 EmfPlusMultiplyWorldTransform
*record
= (EmfPlusMultiplyWorldTransform
*)header
;
3004 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
3007 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusMultiplyWorldTransform
))
3008 return InvalidParameter
;
3010 memcpy(matrix
.matrix
, record
->MatrixData
, sizeof(matrix
.matrix
));
3012 GdipMultiplyMatrix(real_metafile
->world_transform
, &matrix
, order
);
3014 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
3016 case EmfPlusRecordTypeRotateWorldTransform
:
3018 EmfPlusRotateWorldTransform
*record
= (EmfPlusRotateWorldTransform
*)header
;
3019 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
3021 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusRotateWorldTransform
))
3022 return InvalidParameter
;
3024 GdipRotateMatrix(real_metafile
->world_transform
, record
->Angle
, order
);
3026 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
3028 case EmfPlusRecordTypeTranslateWorldTransform
:
3030 EmfPlusTranslateWorldTransform
*record
= (EmfPlusTranslateWorldTransform
*)header
;
3031 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
3033 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusTranslateWorldTransform
))
3034 return InvalidParameter
;
3036 GdipTranslateMatrix(real_metafile
->world_transform
, record
->dx
, record
->dy
, order
);
3038 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
3040 case EmfPlusRecordTypeResetWorldTransform
:
3042 GdipSetMatrixElements(real_metafile
->world_transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
3044 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
3046 case EmfPlusRecordTypeBeginContainer
:
3048 EmfPlusBeginContainer
*record
= (EmfPlusBeginContainer
*)header
;
3051 REAL scale_x
, scale_y
;
3052 GpRectF scaled_srcrect
;
3055 cont
= heap_alloc_zero(sizeof(*cont
));
3059 stat
= GdipCloneRegion(metafile
->clip
, &cont
->clip
);
3066 stat
= GdipBeginContainer2(metafile
->playback_graphics
, &cont
->state
);
3070 GdipDeleteRegion(cont
->clip
);
3075 cont
->id
= record
->StackIndex
;
3076 cont
->type
= BEGIN_CONTAINER
;
3077 cont
->world_transform
= *metafile
->world_transform
;
3078 cont
->page_unit
= metafile
->page_unit
;
3079 cont
->page_scale
= metafile
->page_scale
;
3080 list_add_head(&real_metafile
->containers
, &cont
->entry
);
3082 unit
= record
->Header
.Flags
& 0xff;
3084 scale_x
= units_to_pixels(1.0, unit
, metafile
->image
.xres
, metafile
->printer_display
);
3085 scale_y
= units_to_pixels(1.0, unit
, metafile
->image
.yres
, metafile
->printer_display
);
3087 scaled_srcrect
.X
= scale_x
* record
->SrcRect
.X
;
3088 scaled_srcrect
.Y
= scale_y
* record
->SrcRect
.Y
;
3089 scaled_srcrect
.Width
= scale_x
* record
->SrcRect
.Width
;
3090 scaled_srcrect
.Height
= scale_y
* record
->SrcRect
.Height
;
3092 transform
.matrix
[0] = record
->DestRect
.Width
/ scaled_srcrect
.Width
;
3093 transform
.matrix
[1] = 0.0;
3094 transform
.matrix
[2] = 0.0;
3095 transform
.matrix
[3] = record
->DestRect
.Height
/ scaled_srcrect
.Height
;
3096 transform
.matrix
[4] = record
->DestRect
.X
- scaled_srcrect
.X
;
3097 transform
.matrix
[5] = record
->DestRect
.Y
- scaled_srcrect
.Y
;
3099 GdipMultiplyMatrix(real_metafile
->world_transform
, &transform
, MatrixOrderPrepend
);
3101 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
3103 case EmfPlusRecordTypeBeginContainerNoParams
:
3104 case EmfPlusRecordTypeSave
:
3106 EmfPlusContainerRecord
*record
= (EmfPlusContainerRecord
*)header
;
3109 cont
= heap_alloc_zero(sizeof(*cont
));
3113 stat
= GdipCloneRegion(metafile
->clip
, &cont
->clip
);
3120 if (recordType
== EmfPlusRecordTypeBeginContainerNoParams
)
3121 stat
= GdipBeginContainer2(metafile
->playback_graphics
, &cont
->state
);
3123 stat
= GdipSaveGraphics(metafile
->playback_graphics
, &cont
->state
);
3127 GdipDeleteRegion(cont
->clip
);
3132 cont
->id
= record
->StackIndex
;
3133 if (recordType
== EmfPlusRecordTypeBeginContainerNoParams
)
3134 cont
->type
= BEGIN_CONTAINER
;
3136 cont
->type
= SAVE_GRAPHICS
;
3137 cont
->world_transform
= *metafile
->world_transform
;
3138 cont
->page_unit
= metafile
->page_unit
;
3139 cont
->page_scale
= metafile
->page_scale
;
3140 list_add_head(&real_metafile
->containers
, &cont
->entry
);
3144 case EmfPlusRecordTypeEndContainer
:
3145 case EmfPlusRecordTypeRestore
:
3147 EmfPlusContainerRecord
*record
= (EmfPlusContainerRecord
*)header
;
3149 enum container_type type
;
3152 if (recordType
== EmfPlusRecordTypeEndContainer
)
3153 type
= BEGIN_CONTAINER
;
3155 type
= SAVE_GRAPHICS
;
3157 LIST_FOR_EACH_ENTRY(cont
, &real_metafile
->containers
, container
, entry
)
3159 if (cont
->id
== record
->StackIndex
&& cont
->type
== type
)
3170 /* pop any newer items on the stack */
3171 while ((cont2
= LIST_ENTRY(list_head(&real_metafile
->containers
), container
, entry
)) != cont
)
3173 list_remove(&cont2
->entry
);
3174 GdipDeleteRegion(cont2
->clip
);
3178 if (type
== BEGIN_CONTAINER
)
3179 GdipEndContainer(real_metafile
->playback_graphics
, cont
->state
);
3181 GdipRestoreGraphics(real_metafile
->playback_graphics
, cont
->state
);
3183 *real_metafile
->world_transform
= cont
->world_transform
;
3184 real_metafile
->page_unit
= cont
->page_unit
;
3185 real_metafile
->page_scale
= cont
->page_scale
;
3186 GdipCombineRegionRegion(real_metafile
->clip
, cont
->clip
, CombineModeReplace
);
3188 list_remove(&cont
->entry
);
3189 GdipDeleteRegion(cont
->clip
);
3195 case EmfPlusRecordTypeSetPixelOffsetMode
:
3197 return GdipSetPixelOffsetMode(real_metafile
->playback_graphics
, flags
& 0xff);
3199 case EmfPlusRecordTypeSetCompositingQuality
:
3201 return GdipSetCompositingQuality(real_metafile
->playback_graphics
, flags
& 0xff);
3203 case EmfPlusRecordTypeSetInterpolationMode
:
3205 return GdipSetInterpolationMode(real_metafile
->playback_graphics
, flags
& 0xff);
3207 case EmfPlusRecordTypeSetTextRenderingHint
:
3209 return GdipSetTextRenderingHint(real_metafile
->playback_graphics
, flags
& 0xff);
3211 case EmfPlusRecordTypeSetAntiAliasMode
:
3213 return GdipSetSmoothingMode(real_metafile
->playback_graphics
, (flags
>> 1) & 0xff);
3215 case EmfPlusRecordTypeSetCompositingMode
:
3217 return GdipSetCompositingMode(real_metafile
->playback_graphics
, flags
& 0xff);
3219 case EmfPlusRecordTypeObject
:
3221 return METAFILE_PlaybackObject(real_metafile
, flags
, dataSize
, data
);
3223 case EmfPlusRecordTypeDrawImage
:
3225 EmfPlusDrawImage
*draw
= (EmfPlusDrawImage
*)header
;
3226 BYTE image
= flags
& 0xff;
3229 if (image
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[image
].type
!= ObjectTypeImage
)
3230 return InvalidParameter
;
3232 if (dataSize
!= FIELD_OFFSET(EmfPlusDrawImage
, RectData
) - sizeof(EmfPlusRecordHeader
) +
3233 (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3234 return InvalidParameter
;
3236 if (draw
->ImageAttributesID
>= EmfPlusObjectTableSize
||
3237 real_metafile
->objtable
[draw
->ImageAttributesID
].type
!= ObjectTypeImageAttributes
)
3238 return InvalidParameter
;
3240 if (flags
& 0x4000) /* C */
3242 points
[0].X
= draw
->RectData
.rect
.X
;
3243 points
[0].Y
= draw
->RectData
.rect
.Y
;
3244 points
[1].X
= points
[0].X
+ draw
->RectData
.rect
.Width
;
3245 points
[1].Y
= points
[0].Y
;
3246 points
[2].X
= points
[1].X
;
3247 points
[2].Y
= points
[1].Y
+ draw
->RectData
.rect
.Height
;
3251 points
[0].X
= draw
->RectData
.rectF
.X
;
3252 points
[0].Y
= draw
->RectData
.rectF
.Y
;
3253 points
[1].X
= points
[0].X
+ draw
->RectData
.rectF
.Width
;
3254 points
[1].Y
= points
[0].Y
;
3255 points
[2].X
= points
[1].X
;
3256 points
[2].Y
= points
[1].Y
+ draw
->RectData
.rectF
.Height
;
3259 return GdipDrawImagePointsRect(real_metafile
->playback_graphics
, real_metafile
->objtable
[image
].u
.image
,
3260 points
, 3, draw
->SrcRect
.X
, draw
->SrcRect
.Y
, draw
->SrcRect
.Width
, draw
->SrcRect
.Height
, draw
->SrcUnit
,
3261 real_metafile
->objtable
[draw
->ImageAttributesID
].u
.image_attributes
, NULL
, NULL
);
3263 case EmfPlusRecordTypeDrawImagePoints
:
3265 EmfPlusDrawImagePoints
*draw
= (EmfPlusDrawImagePoints
*)header
;
3266 static const UINT fixed_part_size
= FIELD_OFFSET(EmfPlusDrawImagePoints
, PointData
) -
3267 FIELD_OFFSET(EmfPlusDrawImagePoints
, ImageAttributesID
);
3268 BYTE image
= flags
& 0xff;
3273 if (image
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[image
].type
!= ObjectTypeImage
)
3274 return InvalidParameter
;
3276 if (dataSize
<= fixed_part_size
)
3277 return InvalidParameter
;
3278 dataSize
-= fixed_part_size
;
3280 if (draw
->ImageAttributesID
>= EmfPlusObjectTableSize
||
3281 real_metafile
->objtable
[draw
->ImageAttributesID
].type
!= ObjectTypeImageAttributes
)
3282 return InvalidParameter
;
3284 if (draw
->count
!= 3)
3285 return InvalidParameter
;
3287 if ((flags
>> 13) & 1) /* E */
3288 FIXME("image effects are not supported.\n");
3290 if ((flags
>> 11) & 1) /* P */
3291 size
= sizeof(EmfPlusPointR7
) * draw
->count
;
3292 else if ((flags
>> 14) & 1) /* C */
3293 size
= sizeof(EmfPlusPoint
) * draw
->count
;
3295 size
= sizeof(EmfPlusPointF
) * draw
->count
;
3297 if (dataSize
!= size
)
3298 return InvalidParameter
;
3300 if ((flags
>> 11) & 1) /* P */
3302 points
[0].X
= draw
->PointData
.pointsR
[0].X
;
3303 points
[0].Y
= draw
->PointData
.pointsR
[0].Y
;
3304 for (i
= 1; i
< 3; i
++)
3306 points
[i
].X
= points
[i
-1].X
+ draw
->PointData
.pointsR
[i
].X
;
3307 points
[i
].Y
= points
[i
-1].Y
+ draw
->PointData
.pointsR
[i
].Y
;
3310 else if ((flags
>> 14) & 1) /* C */
3312 for (i
= 0; i
< 3; i
++)
3314 points
[i
].X
= draw
->PointData
.points
[i
].X
;
3315 points
[i
].Y
= draw
->PointData
.points
[i
].Y
;
3319 memcpy(points
, draw
->PointData
.pointsF
, sizeof(points
));
3321 return GdipDrawImagePointsRect(real_metafile
->playback_graphics
, real_metafile
->objtable
[image
].u
.image
,
3322 points
, 3, draw
->SrcRect
.X
, draw
->SrcRect
.Y
, draw
->SrcRect
.Width
, draw
->SrcRect
.Height
, draw
->SrcUnit
,
3323 real_metafile
->objtable
[draw
->ImageAttributesID
].u
.image_attributes
, NULL
, NULL
);
3325 case EmfPlusRecordTypeFillPath
:
3327 EmfPlusFillPath
*fill
= (EmfPlusFillPath
*)header
;
3328 GpSolidFill
*solidfill
= NULL
;
3329 BYTE path
= flags
& 0xff;
3332 if (path
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[path
].type
!= ObjectTypePath
)
3333 return InvalidParameter
;
3335 if (dataSize
!= sizeof(fill
->data
.BrushId
))
3336 return InvalidParameter
;
3340 stat
= GdipCreateSolidFill(fill
->data
.Color
, &solidfill
);
3343 brush
= (GpBrush
*)solidfill
;
3347 if (fill
->data
.BrushId
>= EmfPlusObjectTableSize
||
3348 real_metafile
->objtable
[fill
->data
.BrushId
].type
!= ObjectTypeBrush
)
3349 return InvalidParameter
;
3351 brush
= real_metafile
->objtable
[fill
->data
.BrushId
].u
.brush
;
3354 stat
= GdipFillPath(real_metafile
->playback_graphics
, brush
, real_metafile
->objtable
[path
].u
.path
);
3355 GdipDeleteBrush((GpBrush
*)solidfill
);
3358 case EmfPlusRecordTypeFillClosedCurve
:
3360 static const UINT fixed_part_size
= FIELD_OFFSET(EmfPlusFillClosedCurve
, PointData
) -
3361 sizeof(EmfPlusRecordHeader
);
3362 EmfPlusFillClosedCurve
*fill
= (EmfPlusFillClosedCurve
*)header
;
3363 GpSolidFill
*solidfill
= NULL
;
3368 if (dataSize
<= fixed_part_size
)
3369 return InvalidParameter
;
3371 if (fill
->Count
== 0)
3372 return InvalidParameter
;
3374 if (flags
& 0x800) /* P */
3375 size
= (fixed_part_size
+ sizeof(EmfPlusPointR7
) * fill
->Count
+ 3) & ~3;
3376 else if (flags
& 0x4000) /* C */
3377 size
= fixed_part_size
+ sizeof(EmfPlusPoint
) * fill
->Count
;
3379 size
= fixed_part_size
+ sizeof(EmfPlusPointF
) * fill
->Count
;
3381 if (dataSize
!= size
)
3382 return InvalidParameter
;
3384 mode
= flags
& 0x200 ? FillModeWinding
: FillModeAlternate
; /* W */
3386 if (flags
& 0x8000) /* S */
3388 stat
= GdipCreateSolidFill(fill
->BrushId
, &solidfill
);
3391 brush
= (GpBrush
*)solidfill
;
3395 if (fill
->BrushId
>= EmfPlusObjectTableSize
||
3396 real_metafile
->objtable
[fill
->BrushId
].type
!= ObjectTypeBrush
)
3397 return InvalidParameter
;
3399 brush
= real_metafile
->objtable
[fill
->BrushId
].u
.brush
;
3402 if (flags
& (0x800 | 0x4000))
3404 GpPointF
*points
= GdipAlloc(fill
->Count
* sizeof(*points
));
3407 if (flags
& 0x800) /* P */
3409 for (i
= 1; i
< fill
->Count
; i
++)
3411 points
[i
].X
= points
[i
- 1].X
+ fill
->PointData
.pointsR
[i
].X
;
3412 points
[i
].Y
= points
[i
- 1].Y
+ fill
->PointData
.pointsR
[i
].Y
;
3417 for (i
= 0; i
< fill
->Count
; i
++)
3419 points
[i
].X
= fill
->PointData
.points
[i
].X
;
3420 points
[i
].Y
= fill
->PointData
.points
[i
].Y
;
3424 stat
= GdipFillClosedCurve2(real_metafile
->playback_graphics
, brush
,
3425 points
, fill
->Count
, fill
->Tension
, mode
);
3432 stat
= GdipFillClosedCurve2(real_metafile
->playback_graphics
, brush
,
3433 (const GpPointF
*)fill
->PointData
.pointsF
, fill
->Count
, fill
->Tension
, mode
);
3435 GdipDeleteBrush((GpBrush
*)solidfill
);
3438 case EmfPlusRecordTypeFillEllipse
:
3440 EmfPlusFillEllipse
*fill
= (EmfPlusFillEllipse
*)header
;
3441 GpSolidFill
*solidfill
= NULL
;
3444 if (dataSize
<= FIELD_OFFSET(EmfPlusFillEllipse
, RectData
) - sizeof(EmfPlusRecordHeader
))
3445 return InvalidParameter
;
3446 dataSize
-= FIELD_OFFSET(EmfPlusFillEllipse
, RectData
) - sizeof(EmfPlusRecordHeader
);
3448 if (dataSize
!= (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3449 return InvalidParameter
;
3453 stat
= GdipCreateSolidFill(fill
->BrushId
, &solidfill
);
3456 brush
= (GpBrush
*)solidfill
;
3460 if (fill
->BrushId
>= EmfPlusObjectTableSize
||
3461 real_metafile
->objtable
[fill
->BrushId
].type
!= ObjectTypeBrush
)
3462 return InvalidParameter
;
3464 brush
= real_metafile
->objtable
[fill
->BrushId
].u
.brush
;
3468 stat
= GdipFillEllipseI(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rect
.X
,
3469 fill
->RectData
.rect
.Y
, fill
->RectData
.rect
.Width
, fill
->RectData
.rect
.Height
);
3471 stat
= GdipFillEllipse(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rectF
.X
,
3472 fill
->RectData
.rectF
.Y
, fill
->RectData
.rectF
.Width
, fill
->RectData
.rectF
.Height
);
3474 GdipDeleteBrush((GpBrush
*)solidfill
);
3477 case EmfPlusRecordTypeFillPie
:
3479 EmfPlusFillPie
*fill
= (EmfPlusFillPie
*)header
;
3480 GpSolidFill
*solidfill
= NULL
;
3483 if (dataSize
<= FIELD_OFFSET(EmfPlusFillPie
, RectData
) - sizeof(EmfPlusRecordHeader
))
3484 return InvalidParameter
;
3485 dataSize
-= FIELD_OFFSET(EmfPlusFillPie
, RectData
) - sizeof(EmfPlusRecordHeader
);
3487 if (dataSize
!= (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3488 return InvalidParameter
;
3490 if (flags
& 0x8000) /* S */
3492 stat
= GdipCreateSolidFill(fill
->BrushId
, &solidfill
);
3495 brush
= (GpBrush
*)solidfill
;
3499 if (fill
->BrushId
>= EmfPlusObjectTableSize
||
3500 real_metafile
->objtable
[fill
->BrushId
].type
!= ObjectTypeBrush
)
3501 return InvalidParameter
;
3503 brush
= real_metafile
->objtable
[fill
->BrushId
].u
.brush
;
3506 if (flags
& 0x4000) /* C */
3507 stat
= GdipFillPieI(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rect
.X
,
3508 fill
->RectData
.rect
.Y
, fill
->RectData
.rect
.Width
, fill
->RectData
.rect
.Height
,
3509 fill
->StartAngle
, fill
->SweepAngle
);
3511 stat
= GdipFillPie(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rectF
.X
,
3512 fill
->RectData
.rectF
.Y
, fill
->RectData
.rectF
.Width
, fill
->RectData
.rectF
.Height
,
3513 fill
->StartAngle
, fill
->SweepAngle
);
3515 GdipDeleteBrush((GpBrush
*)solidfill
);
3518 case EmfPlusRecordTypeDrawPath
:
3520 EmfPlusDrawPath
*draw
= (EmfPlusDrawPath
*)header
;
3521 BYTE path
= flags
& 0xff;
3523 if (dataSize
!= sizeof(draw
->PenId
))
3524 return InvalidParameter
;
3526 if (path
>= EmfPlusObjectTableSize
|| draw
->PenId
>= EmfPlusObjectTableSize
)
3527 return InvalidParameter
;
3529 if (real_metafile
->objtable
[path
].type
!= ObjectTypePath
||
3530 real_metafile
->objtable
[draw
->PenId
].type
!= ObjectTypePen
)
3531 return InvalidParameter
;
3533 return GdipDrawPath(real_metafile
->playback_graphics
, real_metafile
->objtable
[draw
->PenId
].u
.pen
,
3534 real_metafile
->objtable
[path
].u
.path
);
3536 case EmfPlusRecordTypeDrawArc
:
3538 EmfPlusDrawArc
*draw
= (EmfPlusDrawArc
*)header
;
3539 BYTE pen
= flags
& 0xff;
3541 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3542 return InvalidParameter
;
3544 if (dataSize
!= FIELD_OFFSET(EmfPlusDrawArc
, RectData
) - sizeof(EmfPlusRecordHeader
) +
3545 (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3546 return InvalidParameter
;
3548 if (flags
& 0x4000) /* C */
3549 return GdipDrawArcI(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3550 draw
->RectData
.rect
.X
, draw
->RectData
.rect
.Y
, draw
->RectData
.rect
.Width
,
3551 draw
->RectData
.rect
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3553 return GdipDrawArc(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3554 draw
->RectData
.rectF
.X
, draw
->RectData
.rectF
.Y
, draw
->RectData
.rectF
.Width
,
3555 draw
->RectData
.rectF
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3557 case EmfPlusRecordTypeDrawEllipse
:
3559 EmfPlusDrawEllipse
*draw
= (EmfPlusDrawEllipse
*)header
;
3560 BYTE pen
= flags
& 0xff;
3562 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3563 return InvalidParameter
;
3565 if (dataSize
!= (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3566 return InvalidParameter
;
3568 if (flags
& 0x4000) /* C */
3569 return GdipDrawEllipseI(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3570 draw
->RectData
.rect
.X
, draw
->RectData
.rect
.Y
, draw
->RectData
.rect
.Width
,
3571 draw
->RectData
.rect
.Height
);
3573 return GdipDrawEllipse(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3574 draw
->RectData
.rectF
.X
, draw
->RectData
.rectF
.Y
, draw
->RectData
.rectF
.Width
,
3575 draw
->RectData
.rectF
.Height
);
3577 case EmfPlusRecordTypeDrawPie
:
3579 EmfPlusDrawPie
*draw
= (EmfPlusDrawPie
*)header
;
3580 BYTE pen
= flags
& 0xff;
3582 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3583 return InvalidParameter
;
3585 if (dataSize
!= FIELD_OFFSET(EmfPlusDrawPie
, RectData
) - sizeof(EmfPlusRecordHeader
) +
3586 (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3587 return InvalidParameter
;
3589 if (flags
& 0x4000) /* C */
3590 return GdipDrawPieI(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3591 draw
->RectData
.rect
.X
, draw
->RectData
.rect
.Y
, draw
->RectData
.rect
.Width
,
3592 draw
->RectData
.rect
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3594 return GdipDrawPie(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3595 draw
->RectData
.rectF
.X
, draw
->RectData
.rectF
.Y
, draw
->RectData
.rectF
.Width
,
3596 draw
->RectData
.rectF
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3598 case EmfPlusRecordTypeDrawRects
:
3600 EmfPlusDrawRects
*draw
= (EmfPlusDrawRects
*)header
;
3601 BYTE pen
= flags
& 0xff;
3602 GpRectF
*rects
= NULL
;
3604 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3605 return InvalidParameter
;
3607 if (dataSize
<= FIELD_OFFSET(EmfPlusDrawRects
, RectData
) - sizeof(EmfPlusRecordHeader
))
3608 return InvalidParameter
;
3609 dataSize
-= FIELD_OFFSET(EmfPlusDrawRects
, RectData
) - sizeof(EmfPlusRecordHeader
);
3611 if (dataSize
!= draw
->Count
* (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3612 return InvalidParameter
;
3618 rects
= GdipAlloc(draw
->Count
* sizeof(*rects
));
3622 for (i
= 0; i
< draw
->Count
; i
++)
3624 rects
[i
].X
= draw
->RectData
.rect
[i
].X
;
3625 rects
[i
].Y
= draw
->RectData
.rect
[i
].Y
;
3626 rects
[i
].Width
= draw
->RectData
.rect
[i
].Width
;
3627 rects
[i
].Height
= draw
->RectData
.rect
[i
].Height
;
3631 stat
= GdipDrawRectangles(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3632 rects
? rects
: (GpRectF
*)draw
->RectData
.rectF
, draw
->Count
);
3636 case EmfPlusRecordTypeDrawDriverString
:
3639 DWORD expected_size
;
3642 GpSolidFill
*solidfill
= NULL
;
3643 void* alignedmem
= NULL
;
3644 GpMatrix
*matrix
= NULL
;
3645 BYTE font
= flags
& 0xff;
3646 EmfPlusDrawDriverString
*draw
= (EmfPlusDrawDriverString
*)header
;
3648 if (font
>= EmfPlusObjectTableSize
||
3649 real_metafile
->objtable
[font
].type
!= ObjectTypeFont
)
3650 return InvalidParameter
;
3652 expected_size
= FIELD_OFFSET(EmfPlusDrawDriverString
, VariableData
) -
3653 sizeof(EmfPlusRecordHeader
);
3654 if (dataSize
< expected_size
|| draw
->GlyphCount
<= 0)
3655 return InvalidParameter
;
3657 expected_size
+= draw
->GlyphCount
* (sizeof(*text
) + sizeof(*positions
));
3658 if (draw
->MatrixPresent
)
3659 expected_size
+= sizeof(*matrix
);
3661 /* Pad expected size to DWORD alignment. */
3662 expected_size
= (expected_size
+ 3) & ~3;
3664 if (dataSize
!= expected_size
)
3665 return InvalidParameter
;
3669 stat
= GdipCreateSolidFill(draw
->brush
.Color
, &solidfill
);
3672 return InvalidParameter
;
3674 brush
= (GpBrush
*)solidfill
;
3678 if (draw
->brush
.BrushId
>= EmfPlusObjectTableSize
||
3679 real_metafile
->objtable
[draw
->brush
.BrushId
].type
!= ObjectTypeBrush
)
3680 return InvalidParameter
;
3682 brush
= real_metafile
->objtable
[draw
->brush
.BrushId
].u
.brush
;
3685 text
= (UINT16
*)&draw
->VariableData
[0];
3687 /* If GlyphCount is odd, all subsequent fields will be 2-byte
3688 aligned rather than 4-byte aligned, which may lead to access
3689 issues. Handle this case by making our own copy of positions. */
3690 if (draw
->GlyphCount
% 2)
3692 SIZE_T alloc_size
= draw
->GlyphCount
* sizeof(*positions
);
3694 if (draw
->MatrixPresent
)
3695 alloc_size
+= sizeof(*matrix
);
3697 positions
= alignedmem
= heap_alloc(alloc_size
);
3700 GdipDeleteBrush((GpBrush
*)solidfill
);
3704 memcpy(positions
, &text
[draw
->GlyphCount
], alloc_size
);
3707 positions
= (PointF
*)&text
[draw
->GlyphCount
];
3709 if (draw
->MatrixPresent
)
3710 matrix
= (GpMatrix
*)&positions
[draw
->GlyphCount
];
3712 stat
= GdipDrawDriverString(real_metafile
->playback_graphics
, text
, draw
->GlyphCount
,
3713 real_metafile
->objtable
[font
].u
.font
, brush
, positions
,
3714 draw
->DriverStringOptionsFlags
, matrix
);
3716 GdipDeleteBrush((GpBrush
*)solidfill
);
3717 heap_free(alignedmem
);
3721 case EmfPlusRecordTypeFillRegion
:
3723 EmfPlusFillRegion
* const fill
= (EmfPlusFillRegion
*)header
;
3724 GpSolidFill
*solidfill
= NULL
;
3726 BYTE region
= flags
& 0xff;
3728 if (dataSize
!= sizeof(EmfPlusFillRegion
) - sizeof(EmfPlusRecordHeader
))
3729 return InvalidParameter
;
3731 if (region
>= EmfPlusObjectTableSize
||
3732 real_metafile
->objtable
[region
].type
!= ObjectTypeRegion
)
3733 return InvalidParameter
;
3737 stat
= GdipCreateSolidFill(fill
->data
.Color
, &solidfill
);
3740 brush
= (GpBrush
*)solidfill
;
3744 if (fill
->data
.BrushId
>= EmfPlusObjectTableSize
||
3745 real_metafile
->objtable
[fill
->data
.BrushId
].type
!= ObjectTypeBrush
)
3746 return InvalidParameter
;
3748 brush
= real_metafile
->objtable
[fill
->data
.BrushId
].u
.brush
;
3751 stat
= GdipFillRegion(real_metafile
->playback_graphics
, brush
,
3752 real_metafile
->objtable
[region
].u
.region
);
3753 GdipDeleteBrush((GpBrush
*)solidfill
);
3758 FIXME("Not implemented for record type %x\n", recordType
);
3759 return NotImplemented
;
3766 struct enum_metafile_data
3768 EnumerateMetafileProc callback
;
3769 void *callback_data
;
3770 GpMetafile
*metafile
;
3773 static int CALLBACK
enum_metafile_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
3774 int nObj
, LPARAM lpData
)
3777 struct enum_metafile_data
*data
= (struct enum_metafile_data
*)lpData
;
3780 data
->metafile
->handle_table
= lpHTable
;
3781 data
->metafile
->handle_count
= nObj
;
3783 /* First check for an EMF+ record. */
3784 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
3786 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
3788 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
3792 while (offset
+ sizeof(EmfPlusRecordHeader
) <= comment
->cbData
)
3794 const EmfPlusRecordHeader
*record
= (const EmfPlusRecordHeader
*)&comment
->Data
[offset
];
3796 if (record
->DataSize
)
3797 pStr
= (const BYTE
*)(record
+1);
3801 ret
= data
->callback(record
->Type
, record
->Flags
, record
->DataSize
,
3802 pStr
, data
->callback_data
);
3807 offset
+= record
->Size
;
3814 if (lpEMFR
->nSize
!= 8)
3815 pStr
= (const BYTE
*)lpEMFR
->dParm
;
3819 return data
->callback(lpEMFR
->iType
, 0, lpEMFR
->nSize
-8,
3820 pStr
, data
->callback_data
);
3823 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestPoints(GpGraphics
*graphics
,
3824 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*destPoints
, INT count
,
3825 GDIPCONST GpRectF
*srcRect
, Unit srcUnit
, EnumerateMetafileProc callback
,
3826 VOID
*callbackData
, GDIPCONST GpImageAttributes
*imageAttributes
)
3828 struct enum_metafile_data data
;
3830 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
; /* whoever made this const was joking */
3831 GraphicsContainer state
;
3835 TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics
, metafile
,
3836 destPoints
, count
, srcRect
, srcUnit
, callback
, callbackData
,
3839 if (!graphics
|| !metafile
|| !destPoints
|| count
!= 3 || !srcRect
)
3840 return InvalidParameter
;
3842 if (!metafile
->hemf
)
3843 return InvalidParameter
;
3845 if (metafile
->playback_graphics
)
3848 TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect
), srcUnit
,
3849 debugstr_pointf(&destPoints
[0]), debugstr_pointf(&destPoints
[1]),
3850 debugstr_pointf(&destPoints
[2]));
3852 data
.callback
= callback
;
3853 data
.callback_data
= callbackData
;
3854 data
.metafile
= real_metafile
;
3856 real_metafile
->playback_graphics
= graphics
;
3857 real_metafile
->playback_dc
= NULL
;
3858 real_metafile
->src_rect
= *srcRect
;
3860 memcpy(real_metafile
->playback_points
, destPoints
, sizeof(PointF
) * 3);
3861 stat
= GdipTransformPoints(graphics
, CoordinateSpaceDevice
, CoordinateSpaceWorld
, real_metafile
->playback_points
, 3);
3864 stat
= GdipBeginContainer2(graphics
, &state
);
3868 stat
= GdipSetPageScale(graphics
, 1.0);
3871 stat
= GdipSetPageUnit(graphics
, UnitPixel
);
3874 stat
= GdipResetWorldTransform(graphics
);
3877 stat
= GdipCreateRegion(&real_metafile
->base_clip
);
3880 stat
= GdipGetClip(graphics
, real_metafile
->base_clip
);
3883 stat
= GdipCreateRegion(&real_metafile
->clip
);
3886 stat
= GdipCreatePath(FillModeAlternate
, &dst_path
);
3890 GpPointF clip_points
[4];
3892 clip_points
[0] = real_metafile
->playback_points
[0];
3893 clip_points
[1] = real_metafile
->playback_points
[1];
3894 clip_points
[2].X
= real_metafile
->playback_points
[1].X
+ real_metafile
->playback_points
[2].X
3895 - real_metafile
->playback_points
[0].X
;
3896 clip_points
[2].Y
= real_metafile
->playback_points
[1].Y
+ real_metafile
->playback_points
[2].Y
3897 - real_metafile
->playback_points
[0].Y
;
3898 clip_points
[3] = real_metafile
->playback_points
[2];
3900 stat
= GdipAddPathPolygon(dst_path
, clip_points
, 4);
3903 stat
= GdipCombineRegionPath(real_metafile
->base_clip
, dst_path
, CombineModeIntersect
);
3905 GdipDeletePath(dst_path
);
3909 stat
= GdipCreateMatrix(&real_metafile
->world_transform
);
3913 real_metafile
->page_unit
= UnitDisplay
;
3914 real_metafile
->page_scale
= 1.0;
3915 stat
= METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
3920 stat
= METAFILE_PlaybackUpdateClip(real_metafile
);
3925 stat
= METAFILE_PlaybackGetDC(real_metafile
);
3927 dst_bounds
.left
= real_metafile
->playback_points
[0].X
;
3928 dst_bounds
.right
= real_metafile
->playback_points
[1].X
;
3929 dst_bounds
.top
= real_metafile
->playback_points
[0].Y
;
3930 dst_bounds
.bottom
= real_metafile
->playback_points
[2].Y
;
3934 EnumEnhMetaFile(real_metafile
->playback_dc
, metafile
->hemf
, enum_metafile_proc
,
3935 &data
, &dst_bounds
);
3937 METAFILE_PlaybackReleaseDC(real_metafile
);
3939 GdipDeleteMatrix(real_metafile
->world_transform
);
3940 real_metafile
->world_transform
= NULL
;
3942 GdipDeleteRegion(real_metafile
->base_clip
);
3943 real_metafile
->base_clip
= NULL
;
3945 GdipDeleteRegion(real_metafile
->clip
);
3946 real_metafile
->clip
= NULL
;
3948 while (list_head(&real_metafile
->containers
))
3950 container
* cont
= LIST_ENTRY(list_head(&real_metafile
->containers
), container
, entry
);
3951 list_remove(&cont
->entry
);
3952 GdipDeleteRegion(cont
->clip
);
3956 GdipEndContainer(graphics
, state
);
3959 real_metafile
->playback_graphics
= NULL
;
3964 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestRect( GpGraphics
*graphics
,
3965 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRectF
*dest
,
3966 GDIPCONST GpRectF
*src
, Unit srcUnit
, EnumerateMetafileProc callback
,
3967 VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3971 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
3973 points
[0].X
= points
[2].X
= dest
->X
;
3974 points
[0].Y
= points
[1].Y
= dest
->Y
;
3975 points
[1].X
= dest
->X
+ dest
->Width
;
3976 points
[2].Y
= dest
->Y
+ dest
->Height
;
3978 return GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, points
, 3,
3979 src
, srcUnit
, callback
, cb_data
, attrs
);
3981 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestRectI( GpGraphics
* graphics
,
3982 GDIPCONST GpMetafile
*metafile
, GDIPCONST Rect
*destRect
,
3983 GDIPCONST Rect
*srcRect
, Unit srcUnit
, EnumerateMetafileProc callback
,
3984 VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3986 GpRectF destRectF
, srcRectF
;
3988 destRectF
.X
= destRect
->X
;
3989 destRectF
.Y
= destRect
->Y
;
3990 destRectF
.Width
= destRect
->Width
;
3991 destRectF
.Height
= destRect
->Height
;
3993 srcRectF
.X
= srcRect
->X
;
3994 srcRectF
.Y
= srcRect
->Y
;
3995 srcRectF
.Width
= srcRect
->Width
;
3996 srcRectF
.Height
= srcRect
->Height
;
3998 return GdipEnumerateMetafileSrcRectDestRect( graphics
, metafile
, &destRectF
, &srcRectF
, srcUnit
, callback
, cb_data
, attrs
);
4001 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRect(GpGraphics
*graphics
,
4002 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRectF
*dest
,
4003 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
4007 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
4009 points
[0].X
= points
[2].X
= dest
->X
;
4010 points
[0].Y
= points
[1].Y
= dest
->Y
;
4011 points
[1].X
= dest
->X
+ dest
->Width
;
4012 points
[2].Y
= dest
->Y
+ dest
->Height
;
4014 return GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, points
, 3,
4015 &metafile
->bounds
, metafile
->unit
, callback
, cb_data
, attrs
);
4018 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRectI(GpGraphics
*graphics
,
4019 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRect
*dest
,
4020 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
4024 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
4028 destf
.Width
= dest
->Width
;
4029 destf
.Height
= dest
->Height
;
4031 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
4034 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPoint(GpGraphics
*graphics
,
4035 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*dest
,
4036 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
4040 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
4044 destf
.Width
= units_to_pixels(metafile
->bounds
.Width
, metafile
->unit
,
4045 metafile
->image
.xres
, metafile
->printer_display
);
4046 destf
.Height
= units_to_pixels(metafile
->bounds
.Height
, metafile
->unit
,
4047 metafile
->image
.yres
, metafile
->printer_display
);
4049 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
4052 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPointI(GpGraphics
*graphics
,
4053 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPoint
*dest
,
4054 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
4058 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
4063 return GdipEnumerateMetafileDestPoint(graphics
, metafile
, &ptf
, callback
, cb_data
, attrs
);
4066 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromMetafile(GpMetafile
* metafile
,
4067 MetafileHeader
* header
)
4071 TRACE("(%p, %p)\n", metafile
, header
);
4073 if(!metafile
|| !header
)
4074 return InvalidParameter
;
4078 status
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, header
);
4079 if (status
!= Ok
) return status
;
4083 memset(header
, 0, sizeof(*header
));
4084 header
->Version
= VERSION_MAGIC2
;
4087 header
->Type
= metafile
->metafile_type
;
4088 header
->DpiX
= metafile
->image
.xres
;
4089 header
->DpiY
= metafile
->image
.yres
;
4090 header
->Width
= gdip_round(metafile
->bounds
.Width
);
4091 header
->Height
= gdip_round(metafile
->bounds
.Height
);
4096 static int CALLBACK
get_emfplus_header_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
4097 int nObj
, LPARAM lpData
)
4099 EmfPlusHeader
*dst_header
= (EmfPlusHeader
*)lpData
;
4101 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
4103 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
4105 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
4107 const EmfPlusRecordHeader
*header
= (const EmfPlusRecordHeader
*)&comment
->Data
[4];
4109 if (4 + sizeof(EmfPlusHeader
) <= comment
->cbData
&&
4110 header
->Type
== EmfPlusRecordTypeHeader
)
4112 memcpy(dst_header
, header
, sizeof(*dst_header
));
4116 else if (lpEMFR
->iType
== EMR_HEADER
)
4122 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromEmf(HENHMETAFILE hemf
,
4123 MetafileHeader
*header
)
4125 ENHMETAHEADER3 emfheader
;
4126 EmfPlusHeader emfplusheader
;
4127 MetafileType metafile_type
;
4129 TRACE("(%p,%p)\n", hemf
, header
);
4131 if(!hemf
|| !header
)
4132 return InvalidParameter
;
4134 if (GetEnhMetaFileHeader(hemf
, sizeof(emfheader
), (ENHMETAHEADER
*)&emfheader
) == 0)
4135 return GenericError
;
4137 emfplusheader
.Header
.Type
= 0;
4139 EnumEnhMetaFile(NULL
, hemf
, get_emfplus_header_proc
, &emfplusheader
, NULL
);
4141 if (emfplusheader
.Header
.Type
== EmfPlusRecordTypeHeader
)
4143 if ((emfplusheader
.Header
.Flags
& 1) == 1)
4144 metafile_type
= MetafileTypeEmfPlusDual
;
4146 metafile_type
= MetafileTypeEmfPlusOnly
;
4149 metafile_type
= MetafileTypeEmf
;
4151 header
->Type
= metafile_type
;
4152 header
->Size
= emfheader
.nBytes
;
4153 header
->DpiX
= (REAL
)emfheader
.szlDevice
.cx
* 25.4 / emfheader
.szlMillimeters
.cx
;
4154 header
->DpiY
= (REAL
)emfheader
.szlDevice
.cy
* 25.4 / emfheader
.szlMillimeters
.cy
;
4155 header
->X
= gdip_round((REAL
)emfheader
.rclFrame
.left
/ 2540.0 * header
->DpiX
);
4156 header
->Y
= gdip_round((REAL
)emfheader
.rclFrame
.top
/ 2540.0 * header
->DpiY
);
4157 header
->Width
= gdip_round((REAL
)(emfheader
.rclFrame
.right
- emfheader
.rclFrame
.left
) / 2540.0 * header
->DpiX
);
4158 header
->Height
= gdip_round((REAL
)(emfheader
.rclFrame
.bottom
- emfheader
.rclFrame
.top
) / 2540.0 * header
->DpiY
);
4159 header
->u
.EmfHeader
= emfheader
;
4161 if (metafile_type
== MetafileTypeEmfPlusDual
|| metafile_type
== MetafileTypeEmfPlusOnly
)
4163 header
->Version
= emfplusheader
.Version
;
4164 header
->EmfPlusFlags
= emfplusheader
.EmfPlusFlags
;
4165 header
->EmfPlusHeaderSize
= emfplusheader
.Header
.Size
;
4166 header
->LogicalDpiX
= emfplusheader
.LogicalDpiX
;
4167 header
->LogicalDpiY
= emfplusheader
.LogicalDpiY
;
4171 header
->Version
= emfheader
.nVersion
;
4172 header
->EmfPlusFlags
= 0;
4173 header
->EmfPlusHeaderSize
= 0;
4174 header
->LogicalDpiX
= 0;
4175 header
->LogicalDpiY
= 0;
4181 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromWmf(HMETAFILE hwmf
,
4182 GDIPCONST WmfPlaceableFileHeader
*placeable
, MetafileHeader
*header
)
4185 GpMetafile
*metafile
;
4187 TRACE("(%p,%p,%p)\n", hwmf
, placeable
, header
);
4189 status
= GdipCreateMetafileFromWmf(hwmf
, FALSE
, placeable
, &metafile
);
4192 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
4193 GdipDisposeImage(&metafile
->image
);
4198 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR
*filename
,
4199 MetafileHeader
*header
)
4202 GpMetafile
*metafile
;
4204 TRACE("(%s,%p)\n", debugstr_w(filename
), header
);
4206 if (!filename
|| !header
)
4207 return InvalidParameter
;
4209 status
= GdipCreateMetafileFromFile(filename
, &metafile
);
4212 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
4213 GdipDisposeImage(&metafile
->image
);
4218 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromStream(IStream
*stream
,
4219 MetafileHeader
*header
)
4222 GpMetafile
*metafile
;
4224 TRACE("(%p,%p)\n", stream
, header
);
4226 if (!stream
|| !header
)
4227 return InvalidParameter
;
4229 status
= GdipCreateMetafileFromStream(stream
, &metafile
);
4232 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
4233 GdipDisposeImage(&metafile
->image
);
4238 GpStatus WINGDIPAPI
GdipCreateMetafileFromEmf(HENHMETAFILE hemf
, BOOL
delete,
4239 GpMetafile
**metafile
)
4242 MetafileHeader header
;
4244 TRACE("(%p,%i,%p)\n", hemf
, delete, metafile
);
4246 if(!hemf
|| !metafile
)
4247 return InvalidParameter
;
4249 stat
= GdipGetMetafileHeaderFromEmf(hemf
, &header
);
4253 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
4257 (*metafile
)->image
.type
= ImageTypeMetafile
;
4258 (*metafile
)->image
.format
= ImageFormatEMF
;
4259 (*metafile
)->image
.frame_count
= 1;
4260 (*metafile
)->image
.xres
= header
.DpiX
;
4261 (*metafile
)->image
.yres
= header
.DpiY
;
4262 (*metafile
)->bounds
.X
= (REAL
)header
.u
.EmfHeader
.rclFrame
.left
/ 2540.0 * header
.DpiX
;
4263 (*metafile
)->bounds
.Y
= (REAL
)header
.u
.EmfHeader
.rclFrame
.top
/ 2540.0 * header
.DpiY
;
4264 (*metafile
)->bounds
.Width
= (REAL
)(header
.u
.EmfHeader
.rclFrame
.right
- header
.u
.EmfHeader
.rclFrame
.left
)
4265 / 2540.0 * header
.DpiX
;
4266 (*metafile
)->bounds
.Height
= (REAL
)(header
.u
.EmfHeader
.rclFrame
.bottom
- header
.u
.EmfHeader
.rclFrame
.top
)
4267 / 2540.0 * header
.DpiY
;
4268 (*metafile
)->unit
= UnitPixel
;
4269 (*metafile
)->metafile_type
= header
.Type
;
4270 (*metafile
)->hemf
= hemf
;
4271 (*metafile
)->preserve_hemf
= !delete;
4272 /* If the 31th bit of EmfPlusFlags was set, metafile was recorded with a DC for a video display.
4273 * If clear, metafile was recorded with a DC for a printer */
4274 (*metafile
)->printer_display
= !(header
.EmfPlusFlags
& (1u << 31));
4275 (*metafile
)->logical_dpix
= header
.LogicalDpiX
;
4276 (*metafile
)->logical_dpiy
= header
.LogicalDpiY
;
4277 list_init(&(*metafile
)->containers
);
4279 TRACE("<-- %p\n", *metafile
);
4284 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmf(HMETAFILE hwmf
, BOOL
delete,
4285 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
4290 GpStatus retval
= Ok
;
4292 TRACE("(%p, %d, %p, %p)\n", hwmf
, delete, placeable
, metafile
);
4294 if(!hwmf
|| !metafile
)
4295 return InvalidParameter
;
4298 read
= GetMetaFileBitsEx(hwmf
, 0, NULL
);
4300 return GenericError
;
4301 copy
= heap_alloc_zero(read
);
4302 GetMetaFileBitsEx(hwmf
, read
, copy
);
4304 hemf
= SetWinMetaFileBits(read
, copy
, NULL
, NULL
);
4307 /* FIXME: We should store and use hwmf instead of converting to hemf */
4308 retval
= GdipCreateMetafileFromEmf(hemf
, TRUE
, metafile
);
4314 (*metafile
)->image
.xres
= (REAL
)placeable
->Inch
;
4315 (*metafile
)->image
.yres
= (REAL
)placeable
->Inch
;
4316 (*metafile
)->bounds
.X
= ((REAL
)placeable
->BoundingBox
.Left
) / ((REAL
)placeable
->Inch
);
4317 (*metafile
)->bounds
.Y
= ((REAL
)placeable
->BoundingBox
.Top
) / ((REAL
)placeable
->Inch
);
4318 (*metafile
)->bounds
.Width
= (REAL
)(placeable
->BoundingBox
.Right
-
4319 placeable
->BoundingBox
.Left
);
4320 (*metafile
)->bounds
.Height
= (REAL
)(placeable
->BoundingBox
.Bottom
-
4321 placeable
->BoundingBox
.Top
);
4322 (*metafile
)->metafile_type
= MetafileTypeWmfPlaceable
;
4325 (*metafile
)->metafile_type
= MetafileTypeWmf
;
4326 (*metafile
)->image
.format
= ImageFormatWMF
;
4328 if (delete) DeleteMetaFile(hwmf
);
4331 DeleteEnhMetaFile(hemf
);
4335 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR
*file
,
4336 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
4341 TRACE("(%s, %p, %p)\n", debugstr_w(file
), placeable
, metafile
);
4343 hmf
= GetMetaFileW(file
);
4345 return GdipCreateMetafileFromWmf(hmf
, TRUE
, placeable
, metafile
);
4347 emf
= GetEnhMetaFileW(file
);
4349 return GdipCreateMetafileFromEmf(emf
, TRUE
, metafile
);
4351 return GenericError
;
4354 GpStatus WINGDIPAPI
GdipCreateMetafileFromFile(GDIPCONST WCHAR
*file
,
4355 GpMetafile
**metafile
)
4360 TRACE("(%p, %p)\n", file
, metafile
);
4362 if (!file
|| !metafile
) return InvalidParameter
;
4366 status
= GdipCreateStreamOnFile(file
, GENERIC_READ
, &stream
);
4369 status
= GdipCreateMetafileFromStream(stream
, metafile
);
4370 IStream_Release(stream
);
4375 GpStatus WINGDIPAPI
GdipCreateMetafileFromStream(IStream
*stream
,
4376 GpMetafile
**metafile
)
4380 TRACE("%p %p\n", stream
, metafile
);
4382 stat
= GdipLoadImageFromStream(stream
, (GpImage
**)metafile
);
4383 if (stat
!= Ok
) return stat
;
4385 if ((*metafile
)->image
.type
!= ImageTypeMetafile
)
4387 GdipDisposeImage(&(*metafile
)->image
);
4389 return GenericError
;
4395 GpStatus WINGDIPAPI
GdipGetMetafileDownLevelRasterizationLimit(GDIPCONST GpMetafile
*metafile
,
4398 TRACE("(%p,%p)\n", metafile
, limitDpi
);
4400 if (!metafile
|| !limitDpi
)
4401 return InvalidParameter
;
4403 if (!metafile
->record_dc
)
4406 *limitDpi
= metafile
->limit_dpi
;
4411 GpStatus WINGDIPAPI
GdipSetMetafileDownLevelRasterizationLimit(GpMetafile
*metafile
,
4414 TRACE("(%p,%u)\n", metafile
, limitDpi
);
4419 if (!metafile
|| limitDpi
< 10)
4420 return InvalidParameter
;
4422 if (!metafile
->record_dc
)
4425 metafile
->limit_dpi
= limitDpi
;
4430 GpStatus WINGDIPAPI
GdipConvertToEmfPlus(const GpGraphics
* ref
,
4431 GpMetafile
* metafile
, BOOL
* succ
, EmfType emfType
,
4432 const WCHAR
* description
, GpMetafile
** out_metafile
)
4436 TRACE("(%p,%p,%p,%u,%s,%p)\n", ref
, metafile
, succ
, emfType
,
4437 debugstr_w(description
), out_metafile
);
4439 if(!ref
|| !metafile
|| !out_metafile
|| emfType
< EmfTypeEmfOnly
|| emfType
> EmfTypeEmfPlusDual
)
4440 return InvalidParameter
;
4444 *out_metafile
= NULL
;
4447 FIXME("not implemented\n");
4449 return NotImplemented
;
4452 GpStatus WINGDIPAPI
GdipEmfToWmfBits(HENHMETAFILE hemf
, UINT cbData16
,
4453 LPBYTE pData16
, INT iMapMode
, INT eFlags
)
4455 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf
, cbData16
, pData16
, iMapMode
, eFlags
);
4456 return NotImplemented
;
4459 GpStatus WINGDIPAPI
GdipRecordMetafileFileName(GDIPCONST WCHAR
* fileName
,
4460 HDC hdc
, EmfType type
, GDIPCONST GpRectF
*pFrameRect
,
4461 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
,
4462 GpMetafile
**metafile
)
4466 REAL framerect_factor_x
, framerect_factor_y
;
4470 TRACE("%s %p %d %s %d %s %p\n", debugstr_w(fileName
), hdc
, type
, debugstr_rectf(pFrameRect
),
4471 frameUnit
, debugstr_w(desc
), metafile
);
4473 if (!hdc
|| type
< EmfTypeEmfOnly
|| type
> EmfTypeEmfPlusDual
|| !metafile
)
4474 return InvalidParameter
;
4476 dpix
= (REAL
)GetDeviceCaps(hdc
, HORZRES
) / GetDeviceCaps(hdc
, HORZSIZE
) * 25.4;
4477 dpiy
= (REAL
)GetDeviceCaps(hdc
, VERTRES
) / GetDeviceCaps(hdc
, VERTSIZE
) * 25.4;
4483 case MetafileFrameUnitPixel
:
4484 framerect_factor_x
= 2540.0 / dpix
;
4485 framerect_factor_y
= 2540.0 / dpiy
;
4487 case MetafileFrameUnitPoint
:
4488 framerect_factor_x
= framerect_factor_y
= 2540.0 / 72.0;
4490 case MetafileFrameUnitInch
:
4491 framerect_factor_x
= framerect_factor_y
= 2540.0;
4493 case MetafileFrameUnitDocument
:
4494 framerect_factor_x
= framerect_factor_y
= 2540.0 / 300.0;
4496 case MetafileFrameUnitMillimeter
:
4497 framerect_factor_x
= framerect_factor_y
= 100.0;
4499 case MetafileFrameUnitGdi
:
4500 framerect_factor_x
= framerect_factor_y
= 1.0;
4503 return InvalidParameter
;
4506 rc
.left
= framerect_factor_x
* pFrameRect
->X
;
4507 rc
.top
= framerect_factor_y
* pFrameRect
->Y
;
4508 rc
.right
= rc
.left
+ framerect_factor_x
* pFrameRect
->Width
;
4509 rc
.bottom
= rc
.top
+ framerect_factor_y
* pFrameRect
->Height
;
4516 record_dc
= CreateEnhMetaFileW(hdc
, fileName
, lprc
, desc
);
4519 return GenericError
;
4521 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
4524 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
4528 (*metafile
)->image
.type
= ImageTypeMetafile
;
4529 (*metafile
)->image
.flags
= ImageFlagsNone
;
4530 (*metafile
)->image
.palette
= NULL
;
4531 (*metafile
)->image
.xres
= dpix
;
4532 (*metafile
)->image
.yres
= dpiy
;
4533 (*metafile
)->bounds
.X
= (*metafile
)->bounds
.Y
= 0.0;
4534 (*metafile
)->bounds
.Width
= (*metafile
)->bounds
.Height
= 1.0;
4535 (*metafile
)->unit
= UnitPixel
;
4536 (*metafile
)->metafile_type
= type
;
4537 (*metafile
)->record_dc
= record_dc
;
4538 (*metafile
)->comment_data
= NULL
;
4539 (*metafile
)->comment_data_size
= 0;
4540 (*metafile
)->comment_data_length
= 0;
4541 (*metafile
)->limit_dpi
= 96;
4542 (*metafile
)->hemf
= NULL
;
4543 (*metafile
)->printer_display
= (GetDeviceCaps(record_dc
, TECHNOLOGY
) == DT_RASPRINTER
);
4544 (*metafile
)->logical_dpix
= (REAL
)GetDeviceCaps(record_dc
, LOGPIXELSX
);
4545 (*metafile
)->logical_dpiy
= (REAL
)GetDeviceCaps(record_dc
, LOGPIXELSY
);
4546 list_init(&(*metafile
)->containers
);
4550 (*metafile
)->auto_frame
= TRUE
;
4551 (*metafile
)->auto_frame_min
.X
= 0;
4552 (*metafile
)->auto_frame_min
.Y
= 0;
4553 (*metafile
)->auto_frame_max
.X
= -1;
4554 (*metafile
)->auto_frame_max
.Y
= -1;
4557 stat
= METAFILE_WriteHeader(*metafile
, hdc
);
4561 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
4562 heap_free(*metafile
);
4570 GpStatus WINGDIPAPI
GdipRecordMetafileFileNameI(GDIPCONST WCHAR
* fileName
, HDC hdc
, EmfType type
,
4571 GDIPCONST GpRect
*pFrameRect
, MetafileFrameUnit frameUnit
,
4572 GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
4574 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
4575 frameUnit
, debugstr_w(desc
), metafile
);
4577 return NotImplemented
;
4580 /*****************************************************************************
4581 * GdipConvertToEmfPlusToFile [GDIPLUS.@]
4584 GpStatus WINGDIPAPI
GdipConvertToEmfPlusToFile(const GpGraphics
* refGraphics
,
4585 GpMetafile
* metafile
, BOOL
* conversionSuccess
,
4586 const WCHAR
* filename
, EmfType emfType
,
4587 const WCHAR
* description
, GpMetafile
** out_metafile
)
4589 FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics
, metafile
, conversionSuccess
, filename
, emfType
, description
, out_metafile
);
4590 return NotImplemented
;
4593 static GpStatus
METAFILE_CreateCompressedImageStream(GpImage
*image
, IStream
**stream
, DWORD
*size
)
4602 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, stream
);
4603 if (FAILED(hr
)) return hresult_to_status(hr
);
4605 stat
= encode_image_png(image
, *stream
, NULL
);
4608 IStream_Release(*stream
);
4612 hr
= IStream_Stat(*stream
, &statstg
, 1);
4615 IStream_Release(*stream
);
4616 return hresult_to_status(hr
);
4618 *size
= statstg
.cbSize
.u
.LowPart
;
4621 hr
= IStream_Seek(*stream
, zero
, STREAM_SEEK_SET
, NULL
);
4624 IStream_Release(*stream
);
4625 return hresult_to_status(hr
);
4631 static GpStatus
METAFILE_FillEmfPlusBitmap(EmfPlusBitmap
*record
, IStream
*stream
, DWORD size
)
4638 record
->PixelFormat
= 0;
4639 record
->Type
= BitmapDataTypeCompressed
;
4641 hr
= IStream_Read(stream
, record
->BitmapData
, size
, NULL
);
4642 if (FAILED(hr
)) return hresult_to_status(hr
);
4646 static GpStatus
METAFILE_AddImageObject(GpMetafile
*metafile
, GpImage
*image
, DWORD
*id
)
4648 EmfPlusObject
*object_record
;
4654 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4657 if (image
->type
== ImageTypeBitmap
)
4662 stat
= METAFILE_CreateCompressedImageStream(image
, &stream
, &size
);
4663 if (stat
!= Ok
) return stat
;
4664 aligned_size
= (size
+ 3) & ~3;
4666 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
4667 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image
.ImageData
.bitmap
.BitmapData
[aligned_size
]),
4668 (void**)&object_record
);
4671 IStream_Release(stream
);
4674 memset(object_record
->ObjectData
.image
.ImageData
.bitmap
.BitmapData
+ size
, 0, aligned_size
- size
);
4676 *id
= METAFILE_AddObjectId(metafile
);
4677 object_record
->Header
.Flags
= *id
| ObjectTypeImage
<< 8;
4678 object_record
->ObjectData
.image
.Version
= VERSION_MAGIC2
;
4679 object_record
->ObjectData
.image
.Type
= ImageDataTypeBitmap
;
4681 stat
= METAFILE_FillEmfPlusBitmap(&object_record
->ObjectData
.image
.ImageData
.bitmap
, stream
, size
);
4682 IStream_Release(stream
);
4683 if (stat
!= Ok
) METAFILE_RemoveLastRecord(metafile
, &object_record
->Header
);
4686 else if (image
->type
== ImageTypeMetafile
)
4688 HENHMETAFILE hemf
= ((GpMetafile
*)image
)->hemf
;
4689 EmfPlusMetafile
*metafile_record
;
4691 if (!hemf
) return InvalidParameter
;
4693 size
= GetEnhMetaFileBits(hemf
, 0, NULL
);
4694 if (!size
) return GenericError
;
4696 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
4697 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image
.ImageData
.metafile
.MetafileData
[size
]),
4698 (void**)&object_record
);
4699 if (stat
!= Ok
) return stat
;
4701 *id
= METAFILE_AddObjectId(metafile
);
4702 object_record
->Header
.Flags
= *id
| ObjectTypeImage
<< 8;
4703 object_record
->ObjectData
.image
.Version
= VERSION_MAGIC2
;
4704 object_record
->ObjectData
.image
.Type
= ImageDataTypeMetafile
;
4705 metafile_record
= &object_record
->ObjectData
.image
.ImageData
.metafile
;
4706 metafile_record
->Type
= ((GpMetafile
*)image
)->metafile_type
;
4707 metafile_record
->MetafileDataSize
= size
;
4708 if (GetEnhMetaFileBits(hemf
, size
, metafile_record
->MetafileData
) != size
)
4710 METAFILE_RemoveLastRecord(metafile
, &object_record
->Header
);
4711 return GenericError
;
4717 FIXME("not supported image type (%d)\n", image
->type
);
4718 return NotImplemented
;
4722 static GpStatus
METAFILE_AddImageAttributesObject(GpMetafile
*metafile
, const GpImageAttributes
*attrs
, DWORD
*id
)
4724 EmfPlusObject
*object_record
;
4725 EmfPlusImageAttributes
*attrs_record
;
4730 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4736 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
4737 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image_attributes
) + sizeof(EmfPlusImageAttributes
),
4738 (void**)&object_record
);
4739 if (stat
!= Ok
) return stat
;
4741 *id
= METAFILE_AddObjectId(metafile
);
4742 object_record
->Header
.Flags
= *id
| (ObjectTypeImageAttributes
<< 8);
4743 attrs_record
= &object_record
->ObjectData
.image_attributes
;
4744 attrs_record
->Version
= VERSION_MAGIC2
;
4745 attrs_record
->Reserved1
= 0;
4746 attrs_record
->WrapMode
= attrs
->wrap
;
4747 attrs_record
->ClampColor
= attrs
->outside_color
;
4748 attrs_record
->ObjectClamp
= attrs
->clamp
;
4749 attrs_record
->Reserved2
= 0;
4753 GpStatus
METAFILE_DrawImagePointsRect(GpMetafile
*metafile
, GpImage
*image
,
4754 GDIPCONST GpPointF
*points
, INT count
, REAL srcx
, REAL srcy
, REAL srcwidth
,
4755 REAL srcheight
, GpUnit srcUnit
, GDIPCONST GpImageAttributes
* imageAttributes
,
4756 DrawImageAbort callback
, VOID
*callbackData
)
4758 EmfPlusDrawImagePoints
*draw_image_record
;
4759 DWORD image_id
, attributes_id
;
4762 if (count
!= 3) return InvalidParameter
;
4764 if (metafile
->metafile_type
== MetafileTypeEmf
)
4766 FIXME("MetafileTypeEmf metafiles not supported\n");
4767 return NotImplemented
;
4770 FIXME("semi-stub\n");
4772 if (!imageAttributes
)
4774 stat
= METAFILE_AddImageObject(metafile
, image
, &image_id
);
4776 else if (image
->type
== ImageTypeBitmap
)
4778 INT width
= ((GpBitmap
*)image
)->width
;
4779 INT height
= ((GpBitmap
*)image
)->height
;
4780 GpGraphics
*graphics
;
4783 stat
= GdipCreateBitmapFromScan0(width
, height
,
4784 0, PixelFormat32bppARGB
, NULL
, &bitmap
);
4785 if (stat
!= Ok
) return stat
;
4787 stat
= GdipGetImageGraphicsContext((GpImage
*)bitmap
, &graphics
);
4790 GdipDisposeImage((GpImage
*)bitmap
);
4794 stat
= GdipDrawImageRectRectI(graphics
, image
, 0, 0, width
, height
,
4795 0, 0, width
, height
, UnitPixel
, imageAttributes
, NULL
, NULL
);
4796 GdipDeleteGraphics(graphics
);
4799 GdipDisposeImage((GpImage
*)bitmap
);
4803 stat
= METAFILE_AddImageObject(metafile
, (GpImage
*)bitmap
, &image_id
);
4804 GdipDisposeImage((GpImage
*)bitmap
);
4808 FIXME("imageAttributes not supported (image type %d)\n", image
->type
);
4809 return NotImplemented
;
4811 if (stat
!= Ok
) return stat
;
4813 stat
= METAFILE_AddImageAttributesObject(metafile
, imageAttributes
, &attributes_id
);
4814 if (stat
!= Ok
) return stat
;
4816 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeDrawImagePoints
,
4817 sizeof(EmfPlusDrawImagePoints
), (void **)&draw_image_record
);
4818 if (stat
!= Ok
) return stat
;
4820 draw_image_record
->Header
.Flags
= image_id
;
4821 draw_image_record
->ImageAttributesID
= attributes_id
;
4822 draw_image_record
->SrcUnit
= UnitPixel
;
4823 draw_image_record
->SrcRect
.X
= units_to_pixels(srcx
, srcUnit
, metafile
->image
.xres
, metafile
->printer_display
);
4824 draw_image_record
->SrcRect
.Y
= units_to_pixels(srcy
, srcUnit
, metafile
->image
.yres
, metafile
->printer_display
);
4825 draw_image_record
->SrcRect
.Width
= units_to_pixels(srcwidth
, srcUnit
, metafile
->image
.xres
, metafile
->printer_display
);
4826 draw_image_record
->SrcRect
.Height
= units_to_pixels(srcheight
, srcUnit
, metafile
->image
.yres
, metafile
->printer_display
);
4827 draw_image_record
->count
= 3;
4828 memcpy(draw_image_record
->PointData
.pointsF
, points
, 3 * sizeof(*points
));
4829 METAFILE_WriteRecords(metafile
);
4833 GpStatus
METAFILE_AddSimpleProperty(GpMetafile
*metafile
, SHORT prop
, SHORT val
)
4835 EmfPlusRecordHeader
*record
;
4838 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4841 stat
= METAFILE_AllocateRecord(metafile
, prop
, sizeof(*record
), (void**)&record
);
4842 if (stat
!= Ok
) return stat
;
4844 record
->Flags
= val
;
4846 METAFILE_WriteRecords(metafile
);
4850 static GpStatus
METAFILE_AddPathObject(GpMetafile
*metafile
, GpPath
*path
, DWORD
*id
)
4852 EmfPlusObject
*object_record
;
4857 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4860 size
= write_path_data(path
, NULL
);
4861 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
4862 FIELD_OFFSET(EmfPlusObject
, ObjectData
.path
) + size
,
4863 (void**)&object_record
);
4864 if (stat
!= Ok
) return stat
;
4866 *id
= METAFILE_AddObjectId(metafile
);
4867 object_record
->Header
.Flags
= *id
| ObjectTypePath
<< 8;
4868 write_path_data(path
, &object_record
->ObjectData
.path
);
4872 static GpStatus
METAFILE_AddPenObject(GpMetafile
*metafile
, GpPen
*pen
, DWORD
*id
)
4874 DWORD custom_start_cap_size
= 0, custom_start_cap_data_size
= 0, custom_start_cap_path_size
= 0;
4875 DWORD custom_end_cap_size
= 0, custom_end_cap_data_size
= 0, custom_end_cap_path_size
= 0;
4876 DWORD i
, data_flags
, pen_data_size
, brush_size
;
4877 EmfPlusObject
*object_record
;
4878 EmfPlusPenData
*pen_data
;
4883 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4887 pen_data_size
= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
4889 GdipIsMatrixIdentity(&pen
->transform
, &result
);
4892 data_flags
|= PenDataTransform
;
4893 pen_data_size
+= sizeof(EmfPlusTransformMatrix
);
4895 if (pen
->startcap
!= LineCapFlat
)
4897 data_flags
|= PenDataStartCap
;
4898 pen_data_size
+= sizeof(DWORD
);
4900 if (pen
->endcap
!= LineCapFlat
)
4902 data_flags
|= PenDataEndCap
;
4903 pen_data_size
+= sizeof(DWORD
);
4905 if (pen
->join
!= LineJoinMiter
)
4907 data_flags
|= PenDataJoin
;
4908 pen_data_size
+= sizeof(DWORD
);
4910 if (pen
->miterlimit
!= 10.0)
4912 data_flags
|= PenDataMiterLimit
;
4913 pen_data_size
+= sizeof(REAL
);
4915 if (pen
->style
!= GP_DEFAULT_PENSTYLE
)
4917 data_flags
|= PenDataLineStyle
;
4918 pen_data_size
+= sizeof(DWORD
);
4920 if (pen
->dashcap
!= DashCapFlat
)
4922 data_flags
|= PenDataDashedLineCap
;
4923 pen_data_size
+= sizeof(DWORD
);
4925 data_flags
|= PenDataDashedLineOffset
;
4926 pen_data_size
+= sizeof(REAL
);
4929 data_flags
|= PenDataDashedLine
;
4930 pen_data_size
+= sizeof(DWORD
) + pen
->numdashes
*sizeof(REAL
);
4932 if (pen
->align
!= PenAlignmentCenter
)
4934 data_flags
|= PenDataNonCenter
;
4935 pen_data_size
+= sizeof(DWORD
);
4937 /* TODO: Add support for PenDataCompoundLine */
4938 if (pen
->customstart
)
4940 data_flags
|= PenDataCustomStartCap
;
4941 METAFILE_PrepareCustomLineCapData(pen
->customstart
, &custom_start_cap_size
,
4942 &custom_start_cap_data_size
, &custom_start_cap_path_size
);
4943 pen_data_size
+= custom_start_cap_size
;
4947 data_flags
|= PenDataCustomEndCap
;
4948 METAFILE_PrepareCustomLineCapData(pen
->customend
, &custom_end_cap_size
,
4949 &custom_end_cap_data_size
, &custom_end_cap_path_size
);
4950 pen_data_size
+= custom_end_cap_size
;
4953 stat
= METAFILE_PrepareBrushData(pen
->brush
, &brush_size
);
4954 if (stat
!= Ok
) return stat
;
4956 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
4957 FIELD_OFFSET(EmfPlusObject
, ObjectData
.pen
.data
) + pen_data_size
+ brush_size
,
4958 (void**)&object_record
);
4959 if (stat
!= Ok
) return stat
;
4961 *id
= METAFILE_AddObjectId(metafile
);
4962 object_record
->Header
.Flags
= *id
| ObjectTypePen
<< 8;
4963 object_record
->ObjectData
.pen
.Version
= VERSION_MAGIC2
;
4964 object_record
->ObjectData
.pen
.Type
= 0;
4966 pen_data
= (EmfPlusPenData
*)object_record
->ObjectData
.pen
.data
;
4967 pen_data
->PenDataFlags
= data_flags
;
4968 pen_data
->PenUnit
= pen
->unit
;
4969 pen_data
->PenWidth
= pen
->width
;
4972 if (data_flags
& PenDataTransform
)
4974 EmfPlusTransformMatrix
*m
= (EmfPlusTransformMatrix
*)(pen_data
->OptionalData
+ i
);
4975 memcpy(m
, &pen
->transform
, sizeof(*m
));
4976 i
+= sizeof(EmfPlusTransformMatrix
);
4978 if (data_flags
& PenDataStartCap
)
4980 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->startcap
;
4983 if (data_flags
& PenDataEndCap
)
4985 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->endcap
;
4988 if (data_flags
& PenDataJoin
)
4990 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->join
;
4993 if (data_flags
& PenDataMiterLimit
)
4995 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->miterlimit
;
4998 if (data_flags
& PenDataLineStyle
)
5000 switch (pen
->style
& PS_STYLE_MASK
)
5002 case PS_SOLID
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleSolid
; break;
5003 case PS_DASH
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDash
; break;
5004 case PS_DOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDot
; break;
5005 case PS_DASHDOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDashDot
; break;
5006 case PS_DASHDOTDOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDashDotDot
; break;
5007 default: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleCustom
; break;
5011 if (data_flags
& PenDataDashedLineCap
)
5013 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->dashcap
;
5016 if (data_flags
& PenDataDashedLineOffset
)
5018 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->offset
;
5021 if (data_flags
& PenDataDashedLine
)
5025 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->numdashes
;
5028 for (j
=0; j
<pen
->numdashes
; j
++)
5030 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->dashes
[j
];
5034 if (data_flags
& PenDataNonCenter
)
5036 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->align
;
5039 if (data_flags
& PenDataCustomStartCap
)
5041 METAFILE_FillCustomLineCapData(pen
->customstart
, pen_data
->OptionalData
+ i
,
5042 pen
->miterlimit
, custom_start_cap_data_size
,
5043 custom_start_cap_path_size
);
5044 i
+= custom_start_cap_size
;
5046 if (data_flags
& PenDataCustomEndCap
)
5048 METAFILE_FillCustomLineCapData(pen
->customend
, pen_data
->OptionalData
+ i
,
5049 pen
->miterlimit
, custom_end_cap_data_size
,
5050 custom_end_cap_path_size
);
5051 i
+= custom_end_cap_size
;
5054 METAFILE_FillBrushData(pen
->brush
,
5055 (EmfPlusBrush
*)(object_record
->ObjectData
.pen
.data
+ pen_data_size
));
5059 GpStatus
METAFILE_DrawPath(GpMetafile
*metafile
, GpPen
*pen
, GpPath
*path
)
5061 EmfPlusDrawPath
*draw_path_record
;
5066 if (metafile
->metafile_type
== MetafileTypeEmf
)
5069 return NotImplemented
;
5072 stat
= METAFILE_AddPenObject(metafile
, pen
, &pen_id
);
5073 if (stat
!= Ok
) return stat
;
5075 stat
= METAFILE_AddPathObject(metafile
, path
, &path_id
);
5076 if (stat
!= Ok
) return stat
;
5078 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeDrawPath
,
5079 sizeof(EmfPlusDrawPath
), (void **)&draw_path_record
);
5080 if (stat
!= Ok
) return stat
;
5081 draw_path_record
->Header
.Type
= EmfPlusRecordTypeDrawPath
;
5082 draw_path_record
->Header
.Flags
= path_id
;
5083 draw_path_record
->PenId
= pen_id
;
5085 METAFILE_WriteRecords(metafile
);
5089 GpStatus
METAFILE_DrawEllipse(GpMetafile
*metafile
, GpPen
*pen
, GpRectF
*rect
)
5091 EmfPlusDrawEllipse
*record
;
5095 if (metafile
->metafile_type
== MetafileTypeEmf
)
5098 return NotImplemented
;
5101 stat
= METAFILE_AddPenObject(metafile
, pen
, &pen_id
);
5102 if (stat
!= Ok
) return stat
;
5104 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeDrawEllipse
,
5105 sizeof(EmfPlusDrawEllipse
), (void **)&record
);
5106 if (stat
!= Ok
) return stat
;
5107 record
->Header
.Type
= EmfPlusRecordTypeDrawEllipse
;
5108 record
->Header
.Flags
= pen_id
;
5109 if (is_integer_rect(rect
))
5111 record
->Header
.Flags
|= 0x4000;
5112 record
->RectData
.rect
.X
= (SHORT
)rect
->X
;
5113 record
->RectData
.rect
.Y
= (SHORT
)rect
->Y
;
5114 record
->RectData
.rect
.Width
= (SHORT
)rect
->Width
;
5115 record
->RectData
.rect
.Height
= (SHORT
)rect
->Height
;
5118 memcpy(&record
->RectData
.rectF
, rect
, sizeof(*rect
));
5120 METAFILE_WriteRecords(metafile
);
5124 GpStatus
METAFILE_FillPath(GpMetafile
*metafile
, GpBrush
*brush
, GpPath
*path
)
5126 EmfPlusFillPath
*fill_path_record
;
5127 DWORD brush_id
= -1, path_id
;
5131 if (metafile
->metafile_type
== MetafileTypeEmf
)
5134 return NotImplemented
;
5137 inline_color
= brush
->bt
== BrushTypeSolidColor
;
5140 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
5141 if (stat
!= Ok
) return stat
;
5144 stat
= METAFILE_AddPathObject(metafile
, path
, &path_id
);
5145 if (stat
!= Ok
) return stat
;
5147 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeFillPath
,
5148 sizeof(EmfPlusFillPath
), (void**)&fill_path_record
);
5149 if (stat
!= Ok
) return stat
;
5152 fill_path_record
->Header
.Flags
= 0x8000 | path_id
;
5153 fill_path_record
->data
.Color
= ((GpSolidFill
*)brush
)->color
;
5157 fill_path_record
->Header
.Flags
= path_id
;
5158 fill_path_record
->data
.BrushId
= brush_id
;
5161 METAFILE_WriteRecords(metafile
);
5165 GpStatus
METAFILE_FillEllipse(GpMetafile
*metafile
, GpBrush
*brush
, GpRectF
*rect
)
5167 EmfPlusFillEllipse
*record
;
5168 DWORD brush_id
= -1;
5172 if (metafile
->metafile_type
== MetafileTypeEmf
)
5175 return NotImplemented
;
5178 inline_color
= brush
->bt
== BrushTypeSolidColor
;
5181 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
5182 if (stat
!= Ok
) return stat
;
5185 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeFillEllipse
, sizeof(EmfPlusFillEllipse
), (void **)&record
);
5186 if (stat
!= Ok
) return stat
;
5189 record
->Header
.Flags
= 0x8000;
5190 record
->BrushId
= ((GpSolidFill
*)brush
)->color
;
5193 record
->BrushId
= brush_id
;
5195 if (is_integer_rect(rect
))
5197 record
->Header
.Flags
|= 0x4000;
5198 record
->RectData
.rect
.X
= (SHORT
)rect
->X
;
5199 record
->RectData
.rect
.Y
= (SHORT
)rect
->Y
;
5200 record
->RectData
.rect
.Width
= (SHORT
)rect
->Width
;
5201 record
->RectData
.rect
.Height
= (SHORT
)rect
->Height
;
5204 memcpy(&record
->RectData
.rectF
, rect
, sizeof(*rect
));
5206 METAFILE_WriteRecords(metafile
);
5210 GpStatus
METAFILE_FillPie(GpMetafile
*metafile
, GpBrush
*brush
, const GpRectF
*rect
,
5211 REAL startAngle
, REAL sweepAngle
)
5213 BOOL is_int_rect
, inline_color
;
5214 EmfPlusFillPie
*record
;
5215 DWORD brush_id
= -1;
5218 if (metafile
->metafile_type
== MetafileTypeEmf
)
5221 return NotImplemented
;
5224 inline_color
= brush
->bt
== BrushTypeSolidColor
;
5227 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
5228 if (stat
!= Ok
) return stat
;
5231 is_int_rect
= is_integer_rect(rect
);
5233 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeFillPie
,
5234 FIELD_OFFSET(EmfPlusFillPie
, RectData
) + is_int_rect
? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
),
5236 if (stat
!= Ok
) return stat
;
5239 record
->Header
.Flags
= 0x8000;
5240 record
->BrushId
= ((GpSolidFill
*)brush
)->color
;
5243 record
->BrushId
= brush_id
;
5245 record
->StartAngle
= startAngle
;
5246 record
->SweepAngle
= sweepAngle
;
5250 record
->Header
.Flags
|= 0x4000;
5251 record
->RectData
.rect
.X
= (SHORT
)rect
->X
;
5252 record
->RectData
.rect
.Y
= (SHORT
)rect
->Y
;
5253 record
->RectData
.rect
.Width
= (SHORT
)rect
->Width
;
5254 record
->RectData
.rect
.Height
= (SHORT
)rect
->Height
;
5257 memcpy(&record
->RectData
.rectF
, rect
, sizeof(*rect
));
5259 METAFILE_WriteRecords(metafile
);
5263 static GpStatus
METAFILE_AddFontObject(GpMetafile
*metafile
, GDIPCONST GpFont
*font
, DWORD
*id
)
5265 EmfPlusObject
*object_record
;
5266 EmfPlusFont
*font_record
;
5273 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&&
5274 metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
5277 /* The following cast is ugly, but GdipGetFontStyle does treat
5278 its first parameter as const. */
5279 stat
= GdipGetFontStyle((GpFont
*)font
, &style
);
5283 fn_len
= lstrlenW(font
->family
->FamilyName
);
5284 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
5285 FIELD_OFFSET(EmfPlusObject
, ObjectData
.font
.FamilyName
[(fn_len
+ 1) & ~1]),
5286 (void**)&object_record
);
5290 *id
= METAFILE_AddObjectId(metafile
);
5292 object_record
->Header
.Flags
= *id
| ObjectTypeFont
<< 8;
5294 font_record
= &object_record
->ObjectData
.font
;
5295 font_record
->Version
= VERSION_MAGIC2
;
5296 font_record
->EmSize
= font
->emSize
;
5297 font_record
->SizeUnit
= font
->unit
;
5298 font_record
->FontStyleFlags
= style
;
5299 font_record
->Reserved
= 0;
5300 font_record
->Length
= fn_len
;
5302 memcpy(font_record
->FamilyName
, font
->family
->FamilyName
,
5303 fn_len
* sizeof(*font
->family
->FamilyName
));
5308 GpStatus
METAFILE_DrawDriverString(GpMetafile
*metafile
, GDIPCONST UINT16
*text
, INT length
,
5309 GDIPCONST GpFont
*font
, GDIPCONST GpStringFormat
*format
, GDIPCONST GpBrush
*brush
,
5310 GDIPCONST PointF
*positions
, INT flags
, GDIPCONST GpMatrix
*matrix
)
5316 EmfPlusDrawDriverString
*draw_string_record
;
5319 BOOL include_matrix
= FALSE
;
5322 return InvalidParameter
;
5324 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&&
5325 metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
5327 FIXME("metafile type not supported: %i\n", metafile
->metafile_type
);
5328 return NotImplemented
;
5331 stat
= METAFILE_AddFontObject(metafile
, font
, &font_id
);
5335 inline_color
= (brush
->bt
== BrushTypeSolidColor
);
5338 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
5347 stat
= GdipIsMatrixIdentity(matrix
, &identity
);
5351 include_matrix
= !identity
;
5354 alloc_size
= FIELD_OFFSET(EmfPlusDrawDriverString
, VariableData
) +
5355 length
* (sizeof(*text
) + sizeof(*positions
));
5358 alloc_size
+= sizeof(*matrix
);
5360 /* Pad record to DWORD alignment. */
5361 alloc_size
= (alloc_size
+ 3) & ~3;
5363 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeDrawDriverString
, alloc_size
, (void**)&draw_string_record
);
5367 draw_string_record
->Header
.Flags
= font_id
;
5368 draw_string_record
->DriverStringOptionsFlags
= flags
;
5369 draw_string_record
->MatrixPresent
= include_matrix
;
5370 draw_string_record
->GlyphCount
= length
;
5374 draw_string_record
->Header
.Flags
|= 0x8000;
5375 draw_string_record
->brush
.Color
= ((GpSolidFill
*)brush
)->color
;
5378 draw_string_record
->brush
.BrushId
= brush_id
;
5380 cursor
= &draw_string_record
->VariableData
[0];
5382 memcpy(cursor
, text
, length
* sizeof(*text
));
5383 cursor
+= length
* sizeof(*text
);
5385 if (flags
& DriverStringOptionsRealizedAdvance
)
5387 static BOOL fixme_written
= FALSE
;
5389 /* Native never writes DriverStringOptionsRealizedAdvance. Instead,
5390 in the case of RealizedAdvance, each glyph position is computed
5393 While native GDI+ is capable of playing back metafiles with this
5394 flag set, it is possible that some application might rely on
5395 metafiles produced from GDI+ not setting this flag. Ideally we
5396 would also compute the position of each glyph here, serialize those
5397 values, and not set DriverStringOptionsRealizedAdvance. */
5400 fixme_written
= TRUE
;
5401 FIXME("serializing RealizedAdvance flag and single GlyphPos with padding\n");
5404 *((PointF
*)cursor
) = *positions
;
5407 memcpy(cursor
, positions
, length
* sizeof(*positions
));
5411 cursor
+= length
* sizeof(*positions
);
5412 memcpy(cursor
, matrix
, sizeof(*matrix
));
5415 METAFILE_WriteRecords(metafile
);
5420 GpStatus
METAFILE_FillRegion(GpMetafile
* metafile
, GpBrush
* brush
, GpRegion
* region
)
5425 EmfPlusFillRegion
*fill_region_record
;
5428 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&&
5429 metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
5431 FIXME("metafile type not supported: %i\n", metafile
->metafile_type
);
5432 return NotImplemented
;
5435 inline_color
= (brush
->bt
== BrushTypeSolidColor
);
5438 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
5443 stat
= METAFILE_AddRegionObject(metafile
, region
, ®ion_id
);
5447 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeFillRegion
, sizeof(EmfPlusFillRegion
),
5448 (void**)&fill_region_record
);
5452 fill_region_record
->Header
.Flags
= region_id
;
5456 fill_region_record
->Header
.Flags
|= 0x8000;
5457 fill_region_record
->data
.Color
= ((GpSolidFill
*)brush
)->color
;
5460 fill_region_record
->data
.BrushId
= brush_id
;
5462 METAFILE_WriteRecords(metafile
);
5467 GpStatus
METAFILE_DrawRectangles(GpMetafile
*metafile
, GpPen
*pen
, const GpRectF
*rects
, INT count
)
5469 EmfPlusDrawRects
*record
;
5471 BOOL integer_rects
= TRUE
;
5475 if (metafile
->metafile_type
== MetafileTypeEmf
)
5478 return NotImplemented
;
5481 stat
= METAFILE_AddPenObject(metafile
, pen
, &pen_id
);
5482 if (stat
!= Ok
) return stat
;
5484 for (i
= 0; i
< count
; i
++)
5486 if (!is_integer_rect(&rects
[i
]))
5488 integer_rects
= FALSE
;
5493 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeDrawRects
, FIELD_OFFSET(EmfPlusDrawRects
, RectData
) +
5494 count
* (integer_rects
? sizeof(record
->RectData
.rect
) : sizeof(record
->RectData
.rectF
)),
5499 record
->Header
.Flags
= pen_id
;
5501 record
->Header
.Flags
|= 0x4000;
5502 record
->Count
= count
;
5506 for (i
= 0; i
< count
; i
++)
5508 record
->RectData
.rect
[i
].X
= (SHORT
)rects
[i
].X
;
5509 record
->RectData
.rect
[i
].Y
= (SHORT
)rects
[i
].Y
;
5510 record
->RectData
.rect
[i
].Width
= (SHORT
)rects
[i
].Width
;
5511 record
->RectData
.rect
[i
].Height
= (SHORT
)rects
[i
].Height
;
5515 memcpy(record
->RectData
.rectF
, rects
, sizeof(*rects
) * count
);
5517 METAFILE_WriteRecords(metafile
);
5522 GpStatus
METAFILE_DrawArc(GpMetafile
*metafile
, GpPen
*pen
, const GpRectF
*rect
, REAL startAngle
, REAL sweepAngle
)
5524 EmfPlusDrawArc
*record
;
5529 if (metafile
->metafile_type
== MetafileTypeEmf
)
5532 return NotImplemented
;
5535 stat
= METAFILE_AddPenObject(metafile
, pen
, &pen_id
);
5536 if (stat
!= Ok
) return stat
;
5538 integer_rect
= is_integer_rect(rect
);
5540 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeDrawArc
, FIELD_OFFSET(EmfPlusDrawArc
, RectData
) +
5541 integer_rect
? sizeof(record
->RectData
.rect
) : sizeof(record
->RectData
.rectF
),
5546 record
->Header
.Flags
= pen_id
;
5548 record
->Header
.Flags
|= 0x4000;
5549 record
->StartAngle
= startAngle
;
5550 record
->SweepAngle
= sweepAngle
;
5554 record
->RectData
.rect
.X
= (SHORT
)rect
->X
;
5555 record
->RectData
.rect
.Y
= (SHORT
)rect
->Y
;
5556 record
->RectData
.rect
.Width
= (SHORT
)rect
->Width
;
5557 record
->RectData
.rect
.Height
= (SHORT
)rect
->Height
;
5560 memcpy(&record
->RectData
.rectF
, rect
, sizeof(*rect
));
5562 METAFILE_WriteRecords(metafile
);
5567 GpStatus
METAFILE_OffsetClip(GpMetafile
*metafile
, REAL dx
, REAL dy
)
5569 EmfPlusOffsetClip
*record
;
5572 if (metafile
->metafile_type
== MetafileTypeEmf
)
5575 return NotImplemented
;
5578 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeOffsetClip
,
5579 sizeof(*record
), (void **)&record
);
5586 METAFILE_WriteRecords(metafile
);
5591 GpStatus
METAFILE_ResetClip(GpMetafile
*metafile
)
5593 EmfPlusRecordHeader
*record
;
5596 if (metafile
->metafile_type
== MetafileTypeEmf
)
5599 return NotImplemented
;
5602 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeResetClip
,
5603 sizeof(*record
), (void **)&record
);
5607 METAFILE_WriteRecords(metafile
);
5612 GpStatus
METAFILE_SetClipPath(GpMetafile
*metafile
, GpPath
*path
, CombineMode mode
)
5614 EmfPlusRecordHeader
*record
;
5618 if (metafile
->metafile_type
== MetafileTypeEmf
)
5621 return NotImplemented
;
5624 stat
= METAFILE_AddPathObject(metafile
, path
, &path_id
);
5625 if (stat
!= Ok
) return stat
;
5627 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSetClipPath
,
5628 sizeof(*record
), (void **)&record
);
5632 record
->Flags
= ((mode
& 0xf) << 8) | path_id
;
5634 METAFILE_WriteRecords(metafile
);
5639 GpStatus
METAFILE_SetRenderingOrigin(GpMetafile
*metafile
, INT x
, INT y
)
5641 EmfPlusSetRenderingOrigin
*record
;
5644 if (metafile
->metafile_type
== MetafileTypeEmf
)
5647 return NotImplemented
;
5650 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSetRenderingOrigin
,
5651 sizeof(*record
), (void **)&record
);
5658 METAFILE_WriteRecords(metafile
);