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 EmfPlusRecordHeader
55 } EmfPlusRecordHeader
;
57 typedef struct EmfPlusHeader
59 EmfPlusRecordHeader Header
;
66 typedef struct EmfPlusClear
68 EmfPlusRecordHeader Header
;
72 typedef struct EmfPlusFillRects
74 EmfPlusRecordHeader Header
;
79 typedef struct EmfPlusSetClipRect
81 EmfPlusRecordHeader Header
;
85 typedef struct EmfPlusSetPageTransform
87 EmfPlusRecordHeader Header
;
89 } EmfPlusSetPageTransform
;
91 typedef struct EmfPlusRect
99 typedef struct EmfPlusSetWorldTransform
101 EmfPlusRecordHeader Header
;
103 } EmfPlusSetWorldTransform
;
105 typedef struct EmfPlusScaleWorldTransform
107 EmfPlusRecordHeader Header
;
110 } EmfPlusScaleWorldTransform
;
112 typedef struct EmfPlusMultiplyWorldTransform
114 EmfPlusRecordHeader Header
;
116 } EmfPlusMultiplyWorldTransform
;
118 typedef struct EmfPlusRotateWorldTransform
120 EmfPlusRecordHeader Header
;
122 } EmfPlusRotateWorldTransform
;
124 typedef struct EmfPlusTranslateWorldTransform
126 EmfPlusRecordHeader Header
;
129 } EmfPlusTranslateWorldTransform
;
131 typedef struct EmfPlusBeginContainer
133 EmfPlusRecordHeader Header
;
137 } EmfPlusBeginContainer
;
139 typedef struct EmfPlusContainerRecord
141 EmfPlusRecordHeader Header
;
143 } EmfPlusContainerRecord
;
151 typedef struct container
155 enum container_type type
;
156 GraphicsContainer state
;
157 GpMatrix world_transform
;
165 PenDataTransform
= 0x0001,
166 PenDataStartCap
= 0x0002,
167 PenDataEndCap
= 0x0004,
168 PenDataJoin
= 0x0008,
169 PenDataMiterLimit
= 0x0010,
170 PenDataLineStyle
= 0x0020,
171 PenDataDashedLineCap
= 0x0040,
172 PenDataDashedLineOffset
= 0x0080,
173 PenDataDashedLine
= 0x0100,
174 PenDataNonCenter
= 0x0200,
175 PenDataCompoundLine
= 0x0400,
176 PenDataCustomStartCap
= 0x0800,
177 PenDataCustomEndCap
= 0x1000
180 typedef struct EmfPlusTransformMatrix
182 REAL TransformMatrix
[6];
183 } EmfPlusTransformMatrix
;
195 typedef struct EmfPlusDashedLineData
197 DWORD DashedLineDataSize
;
199 } EmfPlusDashedLineData
;
201 typedef struct EmfPlusCompoundLineData
203 DWORD CompoundLineDataSize
;
205 } EmfPlusCompoundLineData
;
207 typedef struct EmfPlusCustomStartCapData
209 DWORD CustomStartCapSize
;
211 } EmfPlusCustomStartCapData
;
213 typedef struct EmfPlusCustomEndCapData
215 DWORD CustomEndCapSize
;
217 } EmfPlusCustomEndCapData
;
219 typedef struct EmfPlusPenData
224 BYTE OptionalData
[1];
229 BrushDataPath
= 1 << 0,
230 BrushDataTransform
= 1 << 1,
231 BrushDataPresetColors
= 1 << 2,
232 BrushDataBlendFactorsH
= 1 << 3,
233 BrushDataBlendFactorsV
= 1 << 4,
234 BrushDataFocusScales
= 1 << 6,
235 BrushDataIsGammaCorrected
= 1 << 7,
236 BrushDataDoNotTransform
= 1 << 8,
239 typedef struct EmfPlusSolidBrushData
241 EmfPlusARGB SolidColor
;
242 } EmfPlusSolidBrushData
;
244 typedef struct EmfPlusHatchBrushData
247 EmfPlusARGB ForeColor
;
248 EmfPlusARGB BackColor
;
249 } EmfPlusHatchBrushData
;
251 typedef struct EmfPlusTextureBrushData
253 DWORD BrushDataFlags
;
255 BYTE OptionalData
[1];
256 } EmfPlusTextureBrushData
;
258 typedef struct EmfPlusRectF
266 typedef struct EmfPlusLinearGradientBrushData
268 DWORD BrushDataFlags
;
271 EmfPlusARGB StartColor
;
272 EmfPlusARGB EndColor
;
275 BYTE OptionalData
[1];
276 } EmfPlusLinearGradientBrushData
;
278 typedef struct EmfPlusBrush
283 EmfPlusSolidBrushData solid
;
284 EmfPlusHatchBrushData hatch
;
285 EmfPlusTextureBrushData texture
;
286 EmfPlusLinearGradientBrushData lineargradient
;
290 typedef struct EmfPlusPen
299 typedef struct EmfPlusPath
302 DWORD PathPointCount
;
303 DWORD PathPointFlags
;
305 /* PathPointTypes[] */
306 /* AlignmentPadding */
310 typedef struct EmfPlusRegionNodePath
312 DWORD RegionNodePathLength
;
313 EmfPlusPath RegionNodePath
;
314 } EmfPlusRegionNodePath
;
316 typedef struct EmfPlusRegion
319 DWORD RegionNodeCount
;
323 typedef struct EmfPlusPalette
325 DWORD PaletteStyleFlags
;
327 BYTE PaletteEntries
[1];
333 BitmapDataTypeCompressed
,
336 typedef struct EmfPlusBitmap
346 typedef struct EmfPlusMetafile
349 DWORD MetafileDataSize
;
350 BYTE MetafileData
[1];
353 typedef enum ImageDataType
355 ImageDataTypeUnknown
,
357 ImageDataTypeMetafile
,
360 typedef struct EmfPlusImage
366 EmfPlusBitmap bitmap
;
367 EmfPlusMetafile metafile
;
371 typedef struct EmfPlusImageAttributes
376 EmfPlusARGB ClampColor
;
379 } EmfPlusImageAttributes
;
381 typedef struct EmfPlusFont
386 DWORD FontStyleFlags
;
392 typedef struct EmfPlusObject
394 EmfPlusRecordHeader Header
;
400 EmfPlusRegion region
;
402 EmfPlusImageAttributes image_attributes
;
407 typedef struct EmfPlusPointR7
413 typedef struct EmfPlusPoint
419 typedef struct EmfPlusPointF
425 typedef struct EmfPlusDrawImage
427 EmfPlusRecordHeader Header
;
428 DWORD ImageAttributesID
;
430 EmfPlusRectF SrcRect
;
438 typedef struct EmfPlusDrawImagePoints
440 EmfPlusRecordHeader Header
;
441 DWORD ImageAttributesID
;
443 EmfPlusRectF SrcRect
;
447 EmfPlusPointR7 pointsR
[3];
448 EmfPlusPoint points
[3];
449 EmfPlusPointF pointsF
[3];
451 } EmfPlusDrawImagePoints
;
453 typedef struct EmfPlusDrawPath
455 EmfPlusRecordHeader Header
;
459 typedef struct EmfPlusDrawArc
461 EmfPlusRecordHeader Header
;
471 typedef struct EmfPlusDrawEllipse
473 EmfPlusRecordHeader Header
;
479 } EmfPlusDrawEllipse
;
481 typedef struct EmfPlusDrawPie
483 EmfPlusRecordHeader Header
;
493 typedef struct EmfPlusDrawRects
495 EmfPlusRecordHeader Header
;
500 EmfPlusRectF rectF
[1];
504 typedef struct EmfPlusFillPath
506 EmfPlusRecordHeader Header
;
514 typedef struct EmfPlusFillClosedCurve
516 EmfPlusRecordHeader Header
;
522 EmfPlusPointR7 pointsR
[1];
523 EmfPlusPoint points
[1];
524 EmfPlusPointF pointsF
[1];
526 } EmfPlusFillClosedCurve
;
528 typedef struct EmfPlusFillEllipse
530 EmfPlusRecordHeader Header
;
537 } EmfPlusFillEllipse
;
539 typedef struct EmfPlusFillPie
541 EmfPlusRecordHeader Header
;
552 typedef struct EmfPlusDrawDriverString
554 EmfPlusRecordHeader Header
;
560 DWORD DriverStringOptionsFlags
;
563 BYTE VariableData
[1];
564 } EmfPlusDrawDriverString
;
566 typedef struct EmfPlusFillRegion
568 EmfPlusRecordHeader Header
;
576 static void metafile_free_object_table_entry(GpMetafile
*metafile
, BYTE id
)
578 struct emfplus_object
*object
= &metafile
->objtable
[id
];
580 switch (object
->type
)
582 case ObjectTypeInvalid
:
584 case ObjectTypeBrush
:
585 GdipDeleteBrush(object
->u
.brush
);
588 GdipDeletePen(object
->u
.pen
);
591 GdipDeletePath(object
->u
.path
);
593 case ObjectTypeRegion
:
594 GdipDeleteRegion(object
->u
.region
);
596 case ObjectTypeImage
:
597 GdipDisposeImage(object
->u
.image
);
600 GdipDeleteFont(object
->u
.font
);
602 case ObjectTypeImageAttributes
:
603 GdipDisposeImageAttributes(object
->u
.image_attributes
);
606 FIXME("not implemented for object type %u.\n", object
->type
);
610 object
->type
= ObjectTypeInvalid
;
611 object
->u
.object
= NULL
;
614 void METAFILE_Free(GpMetafile
*metafile
)
618 heap_free(metafile
->comment_data
);
619 DeleteEnhMetaFile(CloseEnhMetaFile(metafile
->record_dc
));
620 if (!metafile
->preserve_hemf
)
621 DeleteEnhMetaFile(metafile
->hemf
);
622 if (metafile
->record_graphics
)
624 WARN("metafile closed while recording\n");
625 /* not sure what to do here; for now just prevent the graphics from functioning or using this object */
626 metafile
->record_graphics
->image
= NULL
;
627 metafile
->record_graphics
->busy
= TRUE
;
630 if (metafile
->record_stream
)
631 IStream_Release(metafile
->record_stream
);
633 for (i
= 0; i
< ARRAY_SIZE(metafile
->objtable
); i
++)
634 metafile_free_object_table_entry(metafile
, i
);
637 static DWORD
METAFILE_AddObjectId(GpMetafile
*metafile
)
639 return (metafile
->next_object_id
++) % EmfPlusObjectTableSize
;
642 static GpStatus
METAFILE_AllocateRecord(GpMetafile
*metafile
, DWORD size
, void **result
)
645 EmfPlusRecordHeader
*record
;
647 if (!metafile
->comment_data_size
)
649 DWORD data_size
= max(256, size
* 2 + 4);
650 metafile
->comment_data
= heap_alloc_zero(data_size
);
652 if (!metafile
->comment_data
)
655 memcpy(metafile
->comment_data
, "EMF+", 4);
657 metafile
->comment_data_size
= data_size
;
658 metafile
->comment_data_length
= 4;
661 size_needed
= size
+ metafile
->comment_data_length
;
663 if (size_needed
> metafile
->comment_data_size
)
665 DWORD data_size
= size_needed
* 2;
666 BYTE
*new_data
= heap_alloc_zero(data_size
);
671 memcpy(new_data
, metafile
->comment_data
, metafile
->comment_data_length
);
673 metafile
->comment_data_size
= data_size
;
674 heap_free(metafile
->comment_data
);
675 metafile
->comment_data
= new_data
;
678 *result
= metafile
->comment_data
+ metafile
->comment_data_length
;
679 metafile
->comment_data_length
+= size
;
681 record
= (EmfPlusRecordHeader
*)*result
;
683 record
->DataSize
= size
- sizeof(EmfPlusRecordHeader
);
688 static void METAFILE_RemoveLastRecord(GpMetafile
*metafile
, EmfPlusRecordHeader
*record
)
690 assert(metafile
->comment_data
+ metafile
->comment_data_length
== (BYTE
*)record
+ record
->Size
);
691 metafile
->comment_data_length
-= record
->Size
;
694 static void METAFILE_WriteRecords(GpMetafile
*metafile
)
696 if (metafile
->comment_data_length
> 4)
698 GdiComment(metafile
->record_dc
, metafile
->comment_data_length
, metafile
->comment_data
);
699 metafile
->comment_data_length
= 4;
703 static GpStatus
METAFILE_WriteHeader(GpMetafile
*metafile
, HDC hdc
)
707 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
709 EmfPlusHeader
*header
;
711 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusHeader
), (void**)&header
);
715 header
->Header
.Type
= EmfPlusRecordTypeHeader
;
717 if (metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
718 header
->Header
.Flags
= 1;
720 header
->Header
.Flags
= 0;
722 header
->Version
= VERSION_MAGIC2
;
724 if (GetDeviceCaps(hdc
, TECHNOLOGY
) == DT_RASDISPLAY
)
725 header
->EmfPlusFlags
= 1;
727 header
->EmfPlusFlags
= 0;
729 header
->LogicalDpiX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
730 header
->LogicalDpiY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
732 METAFILE_WriteRecords(metafile
);
738 static GpStatus
METAFILE_WriteEndOfFile(GpMetafile
*metafile
)
742 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
744 EmfPlusRecordHeader
*record
;
746 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
750 record
->Type
= EmfPlusRecordTypeEndOfFile
;
753 METAFILE_WriteRecords(metafile
);
759 GpStatus WINGDIPAPI
GdipRecordMetafile(HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
760 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
764 REAL framerect_factor_x
, framerect_factor_y
;
768 TRACE("(%p %d %s %d %p %p)\n", hdc
, type
, debugstr_rectf(frameRect
), frameUnit
, desc
, metafile
);
770 if (!hdc
|| type
< EmfTypeEmfOnly
|| type
> EmfTypeEmfPlusDual
|| !metafile
)
771 return InvalidParameter
;
773 dpix
= (REAL
)GetDeviceCaps(hdc
, HORZRES
) / GetDeviceCaps(hdc
, HORZSIZE
) * 25.4;
774 dpiy
= (REAL
)GetDeviceCaps(hdc
, VERTRES
) / GetDeviceCaps(hdc
, VERTSIZE
) * 25.4;
780 case MetafileFrameUnitPixel
:
781 framerect_factor_x
= 2540.0 / dpix
;
782 framerect_factor_y
= 2540.0 / dpiy
;
784 case MetafileFrameUnitPoint
:
785 framerect_factor_x
= framerect_factor_y
= 2540.0 / 72.0;
787 case MetafileFrameUnitInch
:
788 framerect_factor_x
= framerect_factor_y
= 2540.0;
790 case MetafileFrameUnitDocument
:
791 framerect_factor_x
= framerect_factor_y
= 2540.0 / 300.0;
793 case MetafileFrameUnitMillimeter
:
794 framerect_factor_x
= framerect_factor_y
= 100.0;
796 case MetafileFrameUnitGdi
:
797 framerect_factor_x
= framerect_factor_y
= 1.0;
800 return InvalidParameter
;
803 rc
.left
= framerect_factor_x
* frameRect
->X
;
804 rc
.top
= framerect_factor_y
* frameRect
->Y
;
805 rc
.right
= rc
.left
+ framerect_factor_x
* frameRect
->Width
;
806 rc
.bottom
= rc
.top
+ framerect_factor_y
* frameRect
->Height
;
813 record_dc
= CreateEnhMetaFileW(hdc
, NULL
, lprc
, desc
);
818 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
821 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
825 (*metafile
)->image
.type
= ImageTypeMetafile
;
826 (*metafile
)->image
.flags
= ImageFlagsNone
;
827 (*metafile
)->image
.palette
= NULL
;
828 (*metafile
)->image
.xres
= dpix
;
829 (*metafile
)->image
.yres
= dpiy
;
830 (*metafile
)->bounds
.X
= (*metafile
)->bounds
.Y
= 0.0;
831 (*metafile
)->bounds
.Width
= (*metafile
)->bounds
.Height
= 1.0;
832 (*metafile
)->unit
= UnitPixel
;
833 (*metafile
)->metafile_type
= type
;
834 (*metafile
)->record_dc
= record_dc
;
835 (*metafile
)->comment_data
= NULL
;
836 (*metafile
)->comment_data_size
= 0;
837 (*metafile
)->comment_data_length
= 0;
838 (*metafile
)->limit_dpi
= 96;
839 (*metafile
)->hemf
= NULL
;
840 list_init(&(*metafile
)->containers
);
844 (*metafile
)->auto_frame
= TRUE
;
845 (*metafile
)->auto_frame_min
.X
= 0;
846 (*metafile
)->auto_frame_min
.Y
= 0;
847 (*metafile
)->auto_frame_max
.X
= -1;
848 (*metafile
)->auto_frame_max
.Y
= -1;
851 stat
= METAFILE_WriteHeader(*metafile
, hdc
);
855 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
856 heap_free(*metafile
);
864 /*****************************************************************************
865 * GdipRecordMetafileI [GDIPLUS.@]
867 GpStatus WINGDIPAPI
GdipRecordMetafileI(HDC hdc
, EmfType type
, GDIPCONST GpRect
*frameRect
,
868 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
870 GpRectF frameRectF
, *pFrameRectF
;
872 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
876 frameRectF
.X
= frameRect
->X
;
877 frameRectF
.Y
= frameRect
->Y
;
878 frameRectF
.Width
= frameRect
->Width
;
879 frameRectF
.Height
= frameRect
->Height
;
880 pFrameRectF
= &frameRectF
;
885 return GdipRecordMetafile(hdc
, type
, pFrameRectF
, frameUnit
, desc
, metafile
);
888 GpStatus WINGDIPAPI
GdipRecordMetafileStreamI(IStream
*stream
, HDC hdc
, EmfType type
, GDIPCONST GpRect
*frameRect
,
889 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
891 GpRectF frameRectF
, *pFrameRectF
;
893 TRACE("(%p %p %d %p %d %p %p)\n", stream
, hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
897 frameRectF
.X
= frameRect
->X
;
898 frameRectF
.Y
= frameRect
->Y
;
899 frameRectF
.Width
= frameRect
->Width
;
900 frameRectF
.Height
= frameRect
->Height
;
901 pFrameRectF
= &frameRectF
;
906 return GdipRecordMetafileStream(stream
, hdc
, type
, pFrameRectF
, frameUnit
, desc
, metafile
);
909 GpStatus WINGDIPAPI
GdipRecordMetafileStream(IStream
*stream
, HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
910 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
914 TRACE("(%p %p %d %s %d %p %p)\n", stream
, hdc
, type
, debugstr_rectf(frameRect
), frameUnit
, desc
, metafile
);
917 return InvalidParameter
;
919 stat
= GdipRecordMetafile(hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
923 (*metafile
)->record_stream
= stream
;
924 IStream_AddRef(stream
);
930 static void METAFILE_AdjustFrame(GpMetafile
* metafile
, const GpPointF
*points
,
935 if (!metafile
->auto_frame
|| !num_points
)
938 if (metafile
->auto_frame_max
.X
< metafile
->auto_frame_min
.X
)
939 metafile
->auto_frame_max
= metafile
->auto_frame_min
= points
[0];
941 for (i
=0; i
<num_points
; i
++)
943 if (points
[i
].X
< metafile
->auto_frame_min
.X
)
944 metafile
->auto_frame_min
.X
= points
[i
].X
;
945 if (points
[i
].X
> metafile
->auto_frame_max
.X
)
946 metafile
->auto_frame_max
.X
= points
[i
].X
;
947 if (points
[i
].Y
< metafile
->auto_frame_min
.Y
)
948 metafile
->auto_frame_min
.Y
= points
[i
].Y
;
949 if (points
[i
].Y
> metafile
->auto_frame_max
.Y
)
950 metafile
->auto_frame_max
.Y
= points
[i
].Y
;
954 GpStatus
METAFILE_GetGraphicsContext(GpMetafile
* metafile
, GpGraphics
**result
)
958 if (!metafile
->record_dc
|| metafile
->record_graphics
)
959 return InvalidParameter
;
961 stat
= graphics_from_image((GpImage
*)metafile
, &metafile
->record_graphics
);
965 *result
= metafile
->record_graphics
;
966 metafile
->record_graphics
->xres
= 96.0;
967 metafile
->record_graphics
->yres
= 96.0;
973 GpStatus
METAFILE_GetDC(GpMetafile
* metafile
, HDC
*hdc
)
975 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
977 EmfPlusRecordHeader
*record
;
980 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
984 record
->Type
= EmfPlusRecordTypeGetDC
;
987 METAFILE_WriteRecords(metafile
);
990 *hdc
= metafile
->record_dc
;
995 GpStatus
METAFILE_GraphicsClear(GpMetafile
* metafile
, ARGB color
)
997 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
999 EmfPlusClear
*record
;
1002 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusClear
), (void**)&record
);
1006 record
->Header
.Type
= EmfPlusRecordTypeClear
;
1007 record
->Header
.Flags
= 0;
1008 record
->Color
= color
;
1010 METAFILE_WriteRecords(metafile
);
1016 static BOOL
is_integer_rect(const GpRectF
*rect
)
1018 SHORT x
, y
, width
, height
;
1021 width
= rect
->Width
;
1022 height
= rect
->Height
;
1023 if (rect
->X
!= (REAL
)x
|| rect
->Y
!= (REAL
)y
||
1024 rect
->Width
!= (REAL
)width
|| rect
->Height
!= (REAL
)height
)
1029 static GpStatus
METAFILE_PrepareBrushData(GDIPCONST GpBrush
*brush
, DWORD
*size
)
1033 case BrushTypeSolidColor
:
1034 *size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
) + sizeof(EmfPlusSolidBrushData
);
1036 case BrushTypeHatchFill
:
1037 *size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
) + sizeof(EmfPlusHatchBrushData
);
1039 case BrushTypeLinearGradient
:
1042 GpLineGradient
*gradient
= (GpLineGradient
*)brush
;
1044 *size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
.lineargradient
.OptionalData
);
1046 GdipIsMatrixIdentity(&gradient
->transform
, &ignore_xform
);
1048 *size
+= sizeof(gradient
->transform
);
1050 if (gradient
->pblendcount
> 1 && gradient
->pblendcolor
&& gradient
->pblendpos
)
1051 *size
+= sizeof(DWORD
) + gradient
->pblendcount
*
1052 (sizeof(*gradient
->pblendcolor
) + sizeof(*gradient
->pblendpos
));
1053 else if (gradient
->blendcount
> 1 && gradient
->blendfac
&& gradient
->blendpos
)
1054 *size
+= sizeof(DWORD
) + gradient
->blendcount
*
1055 (sizeof(*gradient
->blendfac
) + sizeof(*gradient
->blendpos
));
1060 FIXME("unsupported brush type: %d\n", brush
->bt
);
1061 return NotImplemented
;
1067 static void METAFILE_FillBrushData(GDIPCONST GpBrush
*brush
, EmfPlusBrush
*data
)
1069 data
->Version
= VERSION_MAGIC2
;
1070 data
->Type
= brush
->bt
;
1074 case BrushTypeSolidColor
:
1076 GpSolidFill
*solid
= (GpSolidFill
*)brush
;
1077 data
->BrushData
.solid
.SolidColor
= solid
->color
;
1080 case BrushTypeHatchFill
:
1082 GpHatch
*hatch
= (GpHatch
*)brush
;
1083 data
->BrushData
.hatch
.HatchStyle
= hatch
->hatchstyle
;
1084 data
->BrushData
.hatch
.ForeColor
= hatch
->forecol
;
1085 data
->BrushData
.hatch
.BackColor
= hatch
->backcol
;
1088 case BrushTypeLinearGradient
:
1092 GpLineGradient
*gradient
= (GpLineGradient
*)brush
;
1094 data
->BrushData
.lineargradient
.BrushDataFlags
= 0;
1095 data
->BrushData
.lineargradient
.WrapMode
= gradient
->wrap
;
1096 data
->BrushData
.lineargradient
.RectF
.X
= gradient
->rect
.X
;
1097 data
->BrushData
.lineargradient
.RectF
.Y
= gradient
->rect
.Y
;
1098 data
->BrushData
.lineargradient
.RectF
.Width
= gradient
->rect
.Width
;
1099 data
->BrushData
.lineargradient
.RectF
.Height
= gradient
->rect
.Height
;
1100 data
->BrushData
.lineargradient
.StartColor
= gradient
->startcolor
;
1101 data
->BrushData
.lineargradient
.EndColor
= gradient
->endcolor
;
1102 data
->BrushData
.lineargradient
.Reserved1
= gradient
->startcolor
;
1103 data
->BrushData
.lineargradient
.Reserved2
= gradient
->endcolor
;
1105 if (gradient
->gamma
)
1106 data
->BrushData
.lineargradient
.BrushDataFlags
|= BrushDataIsGammaCorrected
;
1108 cursor
= &data
->BrushData
.lineargradient
.OptionalData
[0];
1110 GdipIsMatrixIdentity(&gradient
->transform
, &ignore_xform
);
1113 data
->BrushData
.lineargradient
.BrushDataFlags
|= BrushDataTransform
;
1114 memcpy(cursor
, &gradient
->transform
, sizeof(gradient
->transform
));
1115 cursor
+= sizeof(gradient
->transform
);
1118 if (gradient
->pblendcount
> 1 && gradient
->pblendcolor
&& gradient
->pblendpos
)
1120 const DWORD count
= gradient
->pblendcount
;
1122 data
->BrushData
.lineargradient
.BrushDataFlags
|= BrushDataPresetColors
;
1124 memcpy(cursor
, &count
, sizeof(count
));
1125 cursor
+= sizeof(count
);
1127 memcpy(cursor
, gradient
->pblendpos
, count
* sizeof(*gradient
->pblendpos
));
1128 cursor
+= count
* sizeof(*gradient
->pblendpos
);
1130 memcpy(cursor
, gradient
->pblendcolor
, count
* sizeof(*gradient
->pblendcolor
));
1132 else if (gradient
->blendcount
> 1 && gradient
->blendfac
&& gradient
->blendpos
)
1134 const DWORD count
= gradient
->blendcount
;
1136 data
->BrushData
.lineargradient
.BrushDataFlags
|= BrushDataBlendFactorsH
;
1138 memcpy(cursor
, &count
, sizeof(count
));
1139 cursor
+= sizeof(count
);
1141 memcpy(cursor
, gradient
->blendpos
, count
* sizeof(*gradient
->blendpos
));
1142 cursor
+= count
* sizeof(*gradient
->blendpos
);
1144 memcpy(cursor
, gradient
->blendfac
, count
* sizeof(*gradient
->blendfac
));
1150 FIXME("unsupported brush type: %d\n", brush
->bt
);
1154 static GpStatus
METAFILE_AddBrushObject(GpMetafile
*metafile
, GDIPCONST GpBrush
*brush
, DWORD
*id
)
1156 EmfPlusObject
*object_record
;
1161 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
1164 stat
= METAFILE_PrepareBrushData(brush
, &size
);
1165 if (stat
!= Ok
) return stat
;
1167 stat
= METAFILE_AllocateRecord(metafile
,
1168 FIELD_OFFSET(EmfPlusObject
, ObjectData
) + size
, (void**)&object_record
);
1169 if (stat
!= Ok
) return stat
;
1171 *id
= METAFILE_AddObjectId(metafile
);
1172 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
1173 object_record
->Header
.Flags
= *id
| ObjectTypeBrush
<< 8;
1174 METAFILE_FillBrushData(brush
, &object_record
->ObjectData
.brush
);
1178 GpStatus
METAFILE_FillRectangles(GpMetafile
* metafile
, GpBrush
* brush
,
1179 GDIPCONST GpRectF
* rects
, INT count
)
1181 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1183 EmfPlusFillRects
*record
;
1185 BOOL integer_rects
= TRUE
;
1190 if (brush
->bt
== BrushTypeSolidColor
)
1193 brushid
= ((GpSolidFill
*)brush
)->color
;
1197 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brushid
);
1202 for (i
=0; i
<count
; i
++)
1204 if (!is_integer_rect(&rects
[i
]))
1206 integer_rects
= FALSE
;
1214 stat
= METAFILE_AllocateRecord(metafile
,
1215 sizeof(EmfPlusFillRects
) + count
* (integer_rects
? sizeof(EmfPlusRect
) : sizeof(GpRectF
)),
1220 record
->Header
.Type
= EmfPlusRecordTypeFillRects
;
1221 record
->Header
.Flags
= flags
;
1222 record
->BrushID
= brushid
;
1223 record
->Count
= count
;
1227 EmfPlusRect
*record_rects
= (EmfPlusRect
*)(record
+1);
1228 for (i
=0; i
<count
; i
++)
1230 record_rects
[i
].X
= (SHORT
)rects
[i
].X
;
1231 record_rects
[i
].Y
= (SHORT
)rects
[i
].Y
;
1232 record_rects
[i
].Width
= (SHORT
)rects
[i
].Width
;
1233 record_rects
[i
].Height
= (SHORT
)rects
[i
].Height
;
1237 memcpy(record
+1, rects
, sizeof(GpRectF
) * count
);
1239 METAFILE_WriteRecords(metafile
);
1242 if (metafile
->auto_frame
)
1244 GpPointF corners
[4];
1247 for (i
=0; i
<count
; i
++)
1249 corners
[0].X
= rects
[i
].X
;
1250 corners
[0].Y
= rects
[i
].Y
;
1251 corners
[1].X
= rects
[i
].X
+ rects
[i
].Width
;
1252 corners
[1].Y
= rects
[i
].Y
;
1253 corners
[2].X
= rects
[i
].X
;
1254 corners
[2].Y
= rects
[i
].Y
+ rects
[i
].Height
;
1255 corners
[3].X
= rects
[i
].X
+ rects
[i
].Width
;
1256 corners
[3].Y
= rects
[i
].Y
+ rects
[i
].Height
;
1258 GdipTransformPoints(metafile
->record_graphics
, CoordinateSpaceDevice
,
1259 CoordinateSpaceWorld
, corners
, 4);
1261 METAFILE_AdjustFrame(metafile
, corners
, 4);
1268 GpStatus
METAFILE_SetClipRect(GpMetafile
* metafile
, REAL x
, REAL y
, REAL width
, REAL height
, CombineMode mode
)
1270 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1272 EmfPlusSetClipRect
*record
;
1275 stat
= METAFILE_AllocateRecord(metafile
,
1276 sizeof(EmfPlusSetClipRect
),
1281 record
->Header
.Type
= EmfPlusRecordTypeSetClipRect
;
1282 record
->Header
.Flags
= (mode
& 0xf) << 8;
1283 record
->ClipRect
.X
= x
;
1284 record
->ClipRect
.Y
= y
;
1285 record
->ClipRect
.Width
= width
;
1286 record
->ClipRect
.Height
= height
;
1288 METAFILE_WriteRecords(metafile
);
1294 static GpStatus
METAFILE_AddRegionObject(GpMetafile
*metafile
, GpRegion
*region
, DWORD
*id
)
1296 EmfPlusObject
*object_record
;
1301 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
1304 size
= write_region_data(region
, NULL
);
1305 stat
= METAFILE_AllocateRecord(metafile
,
1306 FIELD_OFFSET(EmfPlusObject
, ObjectData
.region
) + size
, (void**)&object_record
);
1307 if (stat
!= Ok
) return stat
;
1309 *id
= METAFILE_AddObjectId(metafile
);
1310 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
1311 object_record
->Header
.Flags
= *id
| ObjectTypeRegion
<< 8;
1312 write_region_data(region
, &object_record
->ObjectData
.region
);
1316 GpStatus
METAFILE_SetClipRegion(GpMetafile
* metafile
, GpRegion
* region
, CombineMode mode
)
1318 EmfPlusRecordHeader
*record
;
1322 if (metafile
->metafile_type
== MetafileTypeEmf
)
1325 return NotImplemented
;
1328 stat
= METAFILE_AddRegionObject(metafile
, region
, ®ion_id
);
1329 if (stat
!= Ok
) return stat
;
1331 stat
= METAFILE_AllocateRecord(metafile
, sizeof(*record
), (void**)&record
);
1332 if (stat
!= Ok
) return stat
;
1334 record
->Type
= EmfPlusRecordTypeSetClipRegion
;
1335 record
->Flags
= region_id
| mode
<< 8;
1337 METAFILE_WriteRecords(metafile
);
1341 GpStatus
METAFILE_SetPageTransform(GpMetafile
* metafile
, GpUnit unit
, REAL scale
)
1343 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1345 EmfPlusSetPageTransform
*record
;
1348 stat
= METAFILE_AllocateRecord(metafile
,
1349 sizeof(EmfPlusSetPageTransform
),
1354 record
->Header
.Type
= EmfPlusRecordTypeSetPageTransform
;
1355 record
->Header
.Flags
= unit
;
1356 record
->PageScale
= scale
;
1358 METAFILE_WriteRecords(metafile
);
1364 GpStatus
METAFILE_SetWorldTransform(GpMetafile
* metafile
, GDIPCONST GpMatrix
* transform
)
1366 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1368 EmfPlusSetWorldTransform
*record
;
1371 stat
= METAFILE_AllocateRecord(metafile
,
1372 sizeof(EmfPlusSetWorldTransform
),
1377 record
->Header
.Type
= EmfPlusRecordTypeSetWorldTransform
;
1378 record
->Header
.Flags
= 0;
1379 memcpy(record
->MatrixData
, transform
->matrix
, sizeof(record
->MatrixData
));
1381 METAFILE_WriteRecords(metafile
);
1387 GpStatus
METAFILE_ScaleWorldTransform(GpMetafile
* metafile
, REAL sx
, REAL sy
, MatrixOrder order
)
1389 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1391 EmfPlusScaleWorldTransform
*record
;
1394 stat
= METAFILE_AllocateRecord(metafile
,
1395 sizeof(EmfPlusScaleWorldTransform
),
1400 record
->Header
.Type
= EmfPlusRecordTypeScaleWorldTransform
;
1401 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1405 METAFILE_WriteRecords(metafile
);
1411 GpStatus
METAFILE_MultiplyWorldTransform(GpMetafile
* metafile
, GDIPCONST GpMatrix
* matrix
, MatrixOrder order
)
1413 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1415 EmfPlusMultiplyWorldTransform
*record
;
1418 stat
= METAFILE_AllocateRecord(metafile
,
1419 sizeof(EmfPlusMultiplyWorldTransform
),
1424 record
->Header
.Type
= EmfPlusRecordTypeMultiplyWorldTransform
;
1425 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1426 memcpy(record
->MatrixData
, matrix
->matrix
, sizeof(record
->MatrixData
));
1428 METAFILE_WriteRecords(metafile
);
1434 GpStatus
METAFILE_RotateWorldTransform(GpMetafile
* metafile
, REAL angle
, MatrixOrder order
)
1436 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1438 EmfPlusRotateWorldTransform
*record
;
1441 stat
= METAFILE_AllocateRecord(metafile
,
1442 sizeof(EmfPlusRotateWorldTransform
),
1447 record
->Header
.Type
= EmfPlusRecordTypeRotateWorldTransform
;
1448 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1449 record
->Angle
= angle
;
1451 METAFILE_WriteRecords(metafile
);
1457 GpStatus
METAFILE_TranslateWorldTransform(GpMetafile
* metafile
, REAL dx
, REAL dy
, MatrixOrder order
)
1459 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1461 EmfPlusTranslateWorldTransform
*record
;
1464 stat
= METAFILE_AllocateRecord(metafile
,
1465 sizeof(EmfPlusTranslateWorldTransform
),
1470 record
->Header
.Type
= EmfPlusRecordTypeTranslateWorldTransform
;
1471 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1475 METAFILE_WriteRecords(metafile
);
1481 GpStatus
METAFILE_ResetWorldTransform(GpMetafile
* metafile
)
1483 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1485 EmfPlusRecordHeader
*record
;
1488 stat
= METAFILE_AllocateRecord(metafile
,
1489 sizeof(EmfPlusRecordHeader
),
1494 record
->Type
= EmfPlusRecordTypeResetWorldTransform
;
1497 METAFILE_WriteRecords(metafile
);
1503 GpStatus
METAFILE_BeginContainer(GpMetafile
* metafile
, GDIPCONST GpRectF
*dstrect
,
1504 GDIPCONST GpRectF
*srcrect
, GpUnit unit
, DWORD StackIndex
)
1506 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1508 EmfPlusBeginContainer
*record
;
1511 stat
= METAFILE_AllocateRecord(metafile
, sizeof(*record
), (void**)&record
);
1515 record
->Header
.Type
= EmfPlusRecordTypeBeginContainer
;
1516 record
->Header
.Flags
= unit
& 0xff;
1517 record
->DestRect
= *dstrect
;
1518 record
->SrcRect
= *srcrect
;
1519 record
->StackIndex
= StackIndex
;
1521 METAFILE_WriteRecords(metafile
);
1527 GpStatus
METAFILE_BeginContainerNoParams(GpMetafile
* metafile
, DWORD StackIndex
)
1529 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1531 EmfPlusContainerRecord
*record
;
1534 stat
= METAFILE_AllocateRecord(metafile
,
1535 sizeof(EmfPlusContainerRecord
),
1540 record
->Header
.Type
= EmfPlusRecordTypeBeginContainerNoParams
;
1541 record
->Header
.Flags
= 0;
1542 record
->StackIndex
= StackIndex
;
1544 METAFILE_WriteRecords(metafile
);
1550 GpStatus
METAFILE_EndContainer(GpMetafile
* metafile
, DWORD StackIndex
)
1552 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1554 EmfPlusContainerRecord
*record
;
1557 stat
= METAFILE_AllocateRecord(metafile
,
1558 sizeof(EmfPlusContainerRecord
),
1563 record
->Header
.Type
= EmfPlusRecordTypeEndContainer
;
1564 record
->Header
.Flags
= 0;
1565 record
->StackIndex
= StackIndex
;
1567 METAFILE_WriteRecords(metafile
);
1573 GpStatus
METAFILE_SaveGraphics(GpMetafile
* metafile
, DWORD StackIndex
)
1575 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1577 EmfPlusContainerRecord
*record
;
1580 stat
= METAFILE_AllocateRecord(metafile
,
1581 sizeof(EmfPlusContainerRecord
),
1586 record
->Header
.Type
= EmfPlusRecordTypeSave
;
1587 record
->Header
.Flags
= 0;
1588 record
->StackIndex
= StackIndex
;
1590 METAFILE_WriteRecords(metafile
);
1596 GpStatus
METAFILE_RestoreGraphics(GpMetafile
* metafile
, DWORD StackIndex
)
1598 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1600 EmfPlusContainerRecord
*record
;
1603 stat
= METAFILE_AllocateRecord(metafile
,
1604 sizeof(EmfPlusContainerRecord
),
1609 record
->Header
.Type
= EmfPlusRecordTypeRestore
;
1610 record
->Header
.Flags
= 0;
1611 record
->StackIndex
= StackIndex
;
1613 METAFILE_WriteRecords(metafile
);
1619 GpStatus
METAFILE_ReleaseDC(GpMetafile
* metafile
, HDC hdc
)
1621 if (hdc
!= metafile
->record_dc
)
1622 return InvalidParameter
;
1627 GpStatus
METAFILE_GraphicsDeleted(GpMetafile
* metafile
)
1631 stat
= METAFILE_WriteEndOfFile(metafile
);
1632 metafile
->record_graphics
= NULL
;
1634 metafile
->hemf
= CloseEnhMetaFile(metafile
->record_dc
);
1635 metafile
->record_dc
= NULL
;
1637 heap_free(metafile
->comment_data
);
1638 metafile
->comment_data
= NULL
;
1639 metafile
->comment_data_size
= 0;
1643 MetafileHeader header
;
1645 stat
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, &header
);
1646 if (stat
== Ok
&& metafile
->auto_frame
&&
1647 metafile
->auto_frame_max
.X
>= metafile
->auto_frame_min
.X
)
1649 RECTL bounds_rc
, gdi_bounds_rc
;
1650 REAL x_scale
= 2540.0 / header
.DpiX
;
1651 REAL y_scale
= 2540.0 / header
.DpiY
;
1655 bounds_rc
.left
= floorf(metafile
->auto_frame_min
.X
* x_scale
);
1656 bounds_rc
.top
= floorf(metafile
->auto_frame_min
.Y
* y_scale
);
1657 bounds_rc
.right
= ceilf(metafile
->auto_frame_max
.X
* x_scale
);
1658 bounds_rc
.bottom
= ceilf(metafile
->auto_frame_max
.Y
* y_scale
);
1660 gdi_bounds_rc
= header
.u
.EmfHeader
.rclBounds
;
1661 if (gdi_bounds_rc
.right
> gdi_bounds_rc
.left
&& gdi_bounds_rc
.bottom
> gdi_bounds_rc
.top
)
1663 bounds_rc
.left
= min(bounds_rc
.left
, gdi_bounds_rc
.left
);
1664 bounds_rc
.top
= min(bounds_rc
.top
, gdi_bounds_rc
.top
);
1665 bounds_rc
.right
= max(bounds_rc
.right
, gdi_bounds_rc
.right
);
1666 bounds_rc
.bottom
= max(bounds_rc
.bottom
, gdi_bounds_rc
.bottom
);
1669 buffer_size
= GetEnhMetaFileBits(metafile
->hemf
, 0, NULL
);
1670 buffer
= heap_alloc(buffer_size
);
1673 HENHMETAFILE new_hemf
;
1675 GetEnhMetaFileBits(metafile
->hemf
, buffer_size
, buffer
);
1677 ((ENHMETAHEADER
*)buffer
)->rclFrame
= bounds_rc
;
1679 new_hemf
= SetEnhMetaFileBits(buffer_size
, buffer
);
1683 DeleteEnhMetaFile(metafile
->hemf
);
1684 metafile
->hemf
= new_hemf
;
1695 stat
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, &header
);
1699 metafile
->bounds
.X
= header
.X
;
1700 metafile
->bounds
.Y
= header
.Y
;
1701 metafile
->bounds
.Width
= header
.Width
;
1702 metafile
->bounds
.Height
= header
.Height
;
1706 if (stat
== Ok
&& metafile
->record_stream
)
1711 buffer_size
= GetEnhMetaFileBits(metafile
->hemf
, 0, NULL
);
1713 buffer
= heap_alloc(buffer_size
);
1718 GetEnhMetaFileBits(metafile
->hemf
, buffer_size
, buffer
);
1720 hr
= IStream_Write(metafile
->record_stream
, buffer
, buffer_size
, NULL
);
1723 stat
= hresult_to_status(hr
);
1731 if (metafile
->record_stream
)
1733 IStream_Release(metafile
->record_stream
);
1734 metafile
->record_stream
= NULL
;
1740 GpStatus WINGDIPAPI
GdipGetHemfFromMetafile(GpMetafile
*metafile
, HENHMETAFILE
*hEmf
)
1742 TRACE("(%p,%p)\n", metafile
, hEmf
);
1744 if (!metafile
|| !hEmf
|| !metafile
->hemf
)
1745 return InvalidParameter
;
1747 *hEmf
= metafile
->hemf
;
1748 metafile
->hemf
= NULL
;
1753 static GpStatus
METAFILE_PlaybackGetDC(GpMetafile
*metafile
)
1757 stat
= GdipGetDC(metafile
->playback_graphics
, &metafile
->playback_dc
);
1762 static void METAFILE_PlaybackReleaseDC(GpMetafile
*metafile
)
1764 if (metafile
->playback_dc
)
1766 GdipReleaseDC(metafile
->playback_graphics
, metafile
->playback_dc
);
1767 metafile
->playback_dc
= NULL
;
1771 static GpStatus
METAFILE_PlaybackUpdateClip(GpMetafile
*metafile
)
1774 stat
= GdipCombineRegionRegion(metafile
->playback_graphics
->clip
, metafile
->base_clip
, CombineModeReplace
);
1776 stat
= GdipCombineRegionRegion(metafile
->playback_graphics
->clip
, metafile
->clip
, CombineModeIntersect
);
1780 static GpStatus
METAFILE_PlaybackUpdateWorldTransform(GpMetafile
*metafile
)
1782 GpMatrix
*real_transform
;
1785 stat
= GdipCreateMatrix3(&metafile
->src_rect
, metafile
->playback_points
, &real_transform
);
1789 REAL scale
= units_to_pixels(1.0, metafile
->page_unit
, 96.0);
1791 if (metafile
->page_unit
!= UnitDisplay
)
1792 scale
*= metafile
->page_scale
;
1794 stat
= GdipScaleMatrix(real_transform
, scale
, scale
, MatrixOrderPrepend
);
1797 stat
= GdipMultiplyMatrix(real_transform
, metafile
->world_transform
, MatrixOrderPrepend
);
1800 stat
= GdipSetWorldTransform(metafile
->playback_graphics
, real_transform
);
1802 GdipDeleteMatrix(real_transform
);
1808 static void metafile_set_object_table_entry(GpMetafile
*metafile
, BYTE id
, BYTE type
, void *object
)
1810 metafile_free_object_table_entry(metafile
, id
);
1811 metafile
->objtable
[id
].type
= type
;
1812 metafile
->objtable
[id
].u
.object
= object
;
1815 static GpStatus
metafile_deserialize_image(const BYTE
*record_data
, UINT data_size
, GpImage
**image
)
1817 EmfPlusImage
*data
= (EmfPlusImage
*)record_data
;
1822 if (data_size
< FIELD_OFFSET(EmfPlusImage
, ImageData
))
1823 return InvalidParameter
;
1824 data_size
-= FIELD_OFFSET(EmfPlusImage
, ImageData
);
1828 case ImageDataTypeBitmap
:
1830 EmfPlusBitmap
*bitmapdata
= &data
->ImageData
.bitmap
;
1832 if (data_size
<= FIELD_OFFSET(EmfPlusBitmap
, BitmapData
))
1833 return InvalidParameter
;
1834 data_size
-= FIELD_OFFSET(EmfPlusBitmap
, BitmapData
);
1836 switch (bitmapdata
->Type
)
1838 case BitmapDataTypePixel
:
1840 ColorPalette
*palette
;
1843 if (bitmapdata
->PixelFormat
& PixelFormatIndexed
)
1845 EmfPlusPalette
*palette_obj
= (EmfPlusPalette
*)bitmapdata
->BitmapData
;
1846 UINT palette_size
= FIELD_OFFSET(EmfPlusPalette
, PaletteEntries
);
1848 if (data_size
<= palette_size
)
1849 return InvalidParameter
;
1850 palette_size
+= palette_obj
->PaletteCount
* sizeof(EmfPlusARGB
);
1852 if (data_size
< palette_size
)
1853 return InvalidParameter
;
1854 data_size
-= palette_size
;
1856 palette
= (ColorPalette
*)bitmapdata
->BitmapData
;
1857 scan0
= (BYTE
*)bitmapdata
->BitmapData
+ palette_size
;
1862 scan0
= bitmapdata
->BitmapData
;
1865 if (data_size
< bitmapdata
->Height
* bitmapdata
->Stride
)
1866 return InvalidParameter
;
1868 status
= GdipCreateBitmapFromScan0(bitmapdata
->Width
, bitmapdata
->Height
, bitmapdata
->Stride
,
1869 bitmapdata
->PixelFormat
, scan0
, (GpBitmap
**)image
);
1870 if (status
== Ok
&& palette
)
1872 status
= GdipSetImagePalette(*image
, palette
);
1875 GdipDisposeImage(*image
);
1881 case BitmapDataTypeCompressed
:
1883 IWICImagingFactory
*factory
;
1887 if (WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION
, &factory
) != S_OK
)
1888 return GenericError
;
1890 hr
= IWICImagingFactory_CreateStream(factory
, &stream
);
1891 IWICImagingFactory_Release(factory
);
1893 return GenericError
;
1895 if (IWICStream_InitializeFromMemory(stream
, bitmapdata
->BitmapData
, data_size
) == S_OK
)
1896 status
= GdipCreateBitmapFromStream((IStream
*)stream
, (GpBitmap
**)image
);
1898 status
= GenericError
;
1900 IWICStream_Release(stream
);
1904 WARN("Invalid bitmap type %d.\n", bitmapdata
->Type
);
1905 return InvalidParameter
;
1909 case ImageDataTypeMetafile
:
1911 EmfPlusMetafile
*metafiledata
= &data
->ImageData
.metafile
;
1913 if (data_size
<= FIELD_OFFSET(EmfPlusMetafile
, MetafileData
))
1914 return InvalidParameter
;
1915 data_size
-= FIELD_OFFSET(EmfPlusMetafile
, MetafileData
);
1917 switch (metafiledata
->Type
) {
1918 case MetafileTypeEmf
:
1919 case MetafileTypeEmfPlusOnly
:
1920 case MetafileTypeEmfPlusDual
:
1924 hemf
= SetEnhMetaFileBits(data_size
, metafiledata
->MetafileData
);
1927 return GenericError
;
1929 status
= GdipCreateMetafileFromEmf(hemf
, TRUE
, (GpMetafile
**)image
);
1932 DeleteEnhMetaFile(hemf
);
1937 FIXME("metafile type %d not supported.\n", metafiledata
->Type
);
1938 return NotImplemented
;
1943 FIXME("image type %d not supported.\n", data
->Type
);
1944 return NotImplemented
;
1950 static GpStatus
metafile_deserialize_path(const BYTE
*record_data
, UINT data_size
, GpPath
**path
)
1952 EmfPlusPath
*data
= (EmfPlusPath
*)record_data
;
1960 if (data_size
<= FIELD_OFFSET(EmfPlusPath
, data
))
1961 return InvalidParameter
;
1962 data_size
-= FIELD_OFFSET(EmfPlusPath
, data
);
1964 if (data
->PathPointFlags
& 0x800) /* R */
1966 FIXME("RLE encoded path data is not supported.\n");
1967 return NotImplemented
;
1971 if (data
->PathPointFlags
& 0x4000) /* C */
1972 size
= sizeof(EmfPlusPoint
);
1974 size
= sizeof(EmfPlusPointF
);
1975 size
+= sizeof(BYTE
); /* EmfPlusPathPointType */
1976 size
*= data
->PathPointCount
;
1979 if (data_size
< size
)
1980 return InvalidParameter
;
1982 status
= GdipCreatePath(FillModeAlternate
, path
);
1986 (*path
)->pathdata
.Count
= data
->PathPointCount
;
1987 (*path
)->pathdata
.Points
= GdipAlloc(data
->PathPointCount
* sizeof(*(*path
)->pathdata
.Points
));
1988 (*path
)->pathdata
.Types
= GdipAlloc(data
->PathPointCount
* sizeof(*(*path
)->pathdata
.Types
));
1989 (*path
)->datalen
= (*path
)->pathdata
.Count
;
1991 if (!(*path
)->pathdata
.Points
|| !(*path
)->pathdata
.Types
)
1993 GdipDeletePath(*path
);
1997 if (data
->PathPointFlags
& 0x4000) /* C */
1999 EmfPlusPoint
*points
= (EmfPlusPoint
*)data
->data
;
2000 for (i
= 0; i
< data
->PathPointCount
; i
++)
2002 (*path
)->pathdata
.Points
[i
].X
= points
[i
].X
;
2003 (*path
)->pathdata
.Points
[i
].Y
= points
[i
].Y
;
2005 types
= (BYTE
*)(points
+ i
);
2009 EmfPlusPointF
*points
= (EmfPlusPointF
*)data
->data
;
2010 memcpy((*path
)->pathdata
.Points
, points
, sizeof(*points
) * data
->PathPointCount
);
2011 types
= (BYTE
*)(points
+ data
->PathPointCount
);
2014 memcpy((*path
)->pathdata
.Types
, types
, sizeof(*types
) * data
->PathPointCount
);
2019 static GpStatus
metafile_read_region_node(struct memory_buffer
*mbuf
, GpRegion
*region
, region_element
*node
, UINT
*count
)
2024 type
= buffer_read(mbuf
, sizeof(*type
));
2025 if (!type
) return Ok
;
2031 case CombineModeReplace
:
2032 case CombineModeIntersect
:
2033 case CombineModeUnion
:
2034 case CombineModeXor
:
2035 case CombineModeExclude
:
2036 case CombineModeComplement
:
2038 region_element
*left
, *right
;
2040 left
= heap_alloc_zero(sizeof(*left
));
2044 right
= heap_alloc_zero(sizeof(*right
));
2051 status
= metafile_read_region_node(mbuf
, region
, left
, count
);
2054 status
= metafile_read_region_node(mbuf
, region
, right
, count
);
2057 node
->elementdata
.combine
.left
= left
;
2058 node
->elementdata
.combine
.right
= right
;
2059 region
->num_children
+= 2;
2068 case RegionDataRect
:
2070 const EmfPlusRectF
*rect
;
2072 rect
= buffer_read(mbuf
, sizeof(*rect
));
2074 return InvalidParameter
;
2076 memcpy(&node
->elementdata
.rect
, rect
, sizeof(*rect
));
2080 case RegionDataPath
:
2082 const BYTE
*path_data
;
2083 const UINT
*data_size
;
2086 data_size
= buffer_read(mbuf
, FIELD_OFFSET(EmfPlusRegionNodePath
, RegionNodePath
));
2088 return InvalidParameter
;
2090 path_data
= buffer_read(mbuf
, *data_size
);
2092 return InvalidParameter
;
2094 status
= metafile_deserialize_path(path_data
, *data_size
, &path
);
2097 node
->elementdata
.path
= path
;
2102 case RegionDataEmptyRect
:
2103 case RegionDataInfiniteRect
:
2107 FIXME("element type %#x is not supported\n", *type
);
2111 return InvalidParameter
;
2114 static GpStatus
metafile_deserialize_region(const BYTE
*record_data
, UINT data_size
, GpRegion
**region
)
2116 struct memory_buffer mbuf
;
2122 init_memory_buffer(&mbuf
, record_data
, data_size
);
2124 if (!buffer_read(&mbuf
, FIELD_OFFSET(EmfPlusRegion
, RegionNode
)))
2125 return InvalidParameter
;
2127 status
= GdipCreateRegion(region
);
2132 status
= metafile_read_region_node(&mbuf
, *region
, &(*region
)->node
, &count
);
2133 if (status
== Ok
&& !count
)
2134 status
= InvalidParameter
;
2138 GdipDeleteRegion(*region
);
2145 static GpStatus
metafile_deserialize_brush(const BYTE
*record_data
, UINT data_size
, GpBrush
**brush
)
2147 static const UINT header_size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
);
2148 EmfPlusBrush
*data
= (EmfPlusBrush
*)record_data
;
2149 EmfPlusTransformMatrix
*transform
= NULL
;
2156 if (data_size
< header_size
)
2157 return InvalidParameter
;
2161 case BrushTypeSolidColor
:
2162 if (data_size
!= header_size
+ sizeof(EmfPlusSolidBrushData
))
2163 return InvalidParameter
;
2165 status
= GdipCreateSolidFill(data
->BrushData
.solid
.SolidColor
, (GpSolidFill
**)brush
);
2167 case BrushTypeHatchFill
:
2168 if (data_size
!= header_size
+ sizeof(EmfPlusHatchBrushData
))
2169 return InvalidParameter
;
2171 status
= GdipCreateHatchBrush(data
->BrushData
.hatch
.HatchStyle
, data
->BrushData
.hatch
.ForeColor
,
2172 data
->BrushData
.hatch
.BackColor
, (GpHatch
**)brush
);
2174 case BrushTypeTextureFill
:
2178 offset
= header_size
+ FIELD_OFFSET(EmfPlusTextureBrushData
, OptionalData
);
2179 if (data_size
<= offset
)
2180 return InvalidParameter
;
2182 brushflags
= data
->BrushData
.texture
.BrushDataFlags
;
2183 if (brushflags
& BrushDataTransform
)
2185 if (data_size
<= offset
+ sizeof(EmfPlusTransformMatrix
))
2186 return InvalidParameter
;
2187 transform
= (EmfPlusTransformMatrix
*)(record_data
+ offset
);
2188 offset
+= sizeof(EmfPlusTransformMatrix
);
2191 status
= metafile_deserialize_image(record_data
+ offset
, data_size
- offset
, &image
);
2195 status
= GdipCreateTexture(image
, data
->BrushData
.texture
.WrapMode
, (GpTexture
**)brush
);
2196 if (status
== Ok
&& transform
&& !(brushflags
& BrushDataDoNotTransform
))
2197 GdipSetTextureTransform((GpTexture
*)*brush
, (const GpMatrix
*)transform
);
2199 GdipDisposeImage(image
);
2202 case BrushTypeLinearGradient
:
2204 GpLineGradient
*gradient
= NULL
;
2206 UINT position_count
= 0;
2208 offset
= header_size
+ FIELD_OFFSET(EmfPlusLinearGradientBrushData
, OptionalData
);
2209 if (data_size
< offset
)
2210 return InvalidParameter
;
2212 brushflags
= data
->BrushData
.lineargradient
.BrushDataFlags
;
2213 if ((brushflags
& BrushDataPresetColors
) && (brushflags
& (BrushDataBlendFactorsH
| BrushDataBlendFactorsV
)))
2214 return InvalidParameter
;
2216 if (brushflags
& BrushDataTransform
)
2218 if (data_size
< offset
+ sizeof(EmfPlusTransformMatrix
))
2219 return InvalidParameter
;
2220 transform
= (EmfPlusTransformMatrix
*)(record_data
+ offset
);
2221 offset
+= sizeof(EmfPlusTransformMatrix
);
2224 if (brushflags
& (BrushDataPresetColors
| BrushDataBlendFactorsH
| BrushDataBlendFactorsV
))
2226 if (data_size
<= offset
+ sizeof(DWORD
)) /* Number of factors/preset colors. */
2227 return InvalidParameter
;
2228 position_count
= *(DWORD
*)(record_data
+ offset
);
2229 offset
+= sizeof(DWORD
);
2232 if (brushflags
& BrushDataPresetColors
)
2234 if (data_size
!= offset
+ position_count
* (sizeof(float) + sizeof(EmfPlusARGB
)))
2235 return InvalidParameter
;
2237 else if (brushflags
& BrushDataBlendFactorsH
)
2239 if (data_size
!= offset
+ position_count
* 2 * sizeof(float))
2240 return InvalidParameter
;
2243 rect
.X
= data
->BrushData
.lineargradient
.RectF
.X
;
2244 rect
.Y
= data
->BrushData
.lineargradient
.RectF
.Y
;
2245 rect
.Width
= data
->BrushData
.lineargradient
.RectF
.Width
;
2246 rect
.Height
= data
->BrushData
.lineargradient
.RectF
.Height
;
2248 status
= GdipCreateLineBrushFromRect(&rect
, data
->BrushData
.lineargradient
.StartColor
,
2249 data
->BrushData
.lineargradient
.EndColor
, LinearGradientModeHorizontal
,
2250 data
->BrushData
.lineargradient
.WrapMode
, &gradient
);
2254 status
= GdipSetLineTransform(gradient
, (const GpMatrix
*)transform
);
2258 if (brushflags
& BrushDataPresetColors
)
2259 status
= GdipSetLinePresetBlend(gradient
, (ARGB
*)(record_data
+ offset
+
2260 position_count
* sizeof(REAL
)), (REAL
*)(record_data
+ offset
), position_count
);
2261 else if (brushflags
& BrushDataBlendFactorsH
)
2262 status
= GdipSetLineBlend(gradient
, (REAL
*)(record_data
+ offset
+ position_count
* sizeof(REAL
)),
2263 (REAL
*)(record_data
+ offset
), position_count
);
2265 if (brushflags
& BrushDataIsGammaCorrected
)
2266 FIXME("BrushDataIsGammaCorrected is not handled.\n");
2271 *brush
= (GpBrush
*)gradient
;
2273 GdipDeleteBrush((GpBrush
*)gradient
);
2278 FIXME("brush type %u is not supported.\n", data
->Type
);
2279 return NotImplemented
;
2285 static GpStatus
metafile_get_pen_brush_data_offset(EmfPlusPen
*data
, UINT data_size
, DWORD
*ret
)
2287 EmfPlusPenData
*pendata
= (EmfPlusPenData
*)data
->data
;
2288 DWORD offset
= FIELD_OFFSET(EmfPlusPen
, data
);
2290 if (data_size
<= offset
)
2291 return InvalidParameter
;
2293 offset
+= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
2294 if (data_size
<= offset
)
2295 return InvalidParameter
;
2297 if (pendata
->PenDataFlags
& PenDataTransform
)
2298 offset
+= sizeof(EmfPlusTransformMatrix
);
2300 if (pendata
->PenDataFlags
& PenDataStartCap
)
2301 offset
+= sizeof(DWORD
);
2303 if (pendata
->PenDataFlags
& PenDataEndCap
)
2304 offset
+= sizeof(DWORD
);
2306 if (pendata
->PenDataFlags
& PenDataJoin
)
2307 offset
+= sizeof(DWORD
);
2309 if (pendata
->PenDataFlags
& PenDataMiterLimit
)
2310 offset
+= sizeof(REAL
);
2312 if (pendata
->PenDataFlags
& PenDataLineStyle
)
2313 offset
+= sizeof(DWORD
);
2315 if (pendata
->PenDataFlags
& PenDataDashedLineCap
)
2316 offset
+= sizeof(DWORD
);
2318 if (pendata
->PenDataFlags
& PenDataDashedLineOffset
)
2319 offset
+= sizeof(REAL
);
2321 if (pendata
->PenDataFlags
& PenDataDashedLine
)
2323 EmfPlusDashedLineData
*dashedline
= (EmfPlusDashedLineData
*)((BYTE
*)data
+ offset
);
2325 offset
+= FIELD_OFFSET(EmfPlusDashedLineData
, data
);
2326 if (data_size
<= offset
)
2327 return InvalidParameter
;
2329 offset
+= dashedline
->DashedLineDataSize
* sizeof(float);
2332 if (pendata
->PenDataFlags
& PenDataNonCenter
)
2333 offset
+= sizeof(DWORD
);
2335 if (pendata
->PenDataFlags
& PenDataCompoundLine
)
2337 EmfPlusCompoundLineData
*compoundline
= (EmfPlusCompoundLineData
*)((BYTE
*)data
+ offset
);
2339 offset
+= FIELD_OFFSET(EmfPlusCompoundLineData
, data
);
2340 if (data_size
<= offset
)
2341 return InvalidParameter
;
2343 offset
+= compoundline
->CompoundLineDataSize
* sizeof(float);
2346 if (pendata
->PenDataFlags
& PenDataCustomStartCap
)
2348 EmfPlusCustomStartCapData
*startcap
= (EmfPlusCustomStartCapData
*)((BYTE
*)data
+ offset
);
2350 offset
+= FIELD_OFFSET(EmfPlusCustomStartCapData
, data
);
2351 if (data_size
<= offset
)
2352 return InvalidParameter
;
2354 offset
+= startcap
->CustomStartCapSize
;
2357 if (pendata
->PenDataFlags
& PenDataCustomEndCap
)
2359 EmfPlusCustomEndCapData
*endcap
= (EmfPlusCustomEndCapData
*)((BYTE
*)data
+ offset
);
2361 offset
+= FIELD_OFFSET(EmfPlusCustomEndCapData
, data
);
2362 if (data_size
<= offset
)
2363 return InvalidParameter
;
2365 offset
+= endcap
->CustomEndCapSize
;
2372 static GpStatus
METAFILE_PlaybackObject(GpMetafile
*metafile
, UINT flags
, UINT data_size
, const BYTE
*record_data
)
2374 BYTE type
= (flags
>> 8) & 0xff;
2375 BYTE id
= flags
& 0xff;
2376 void *object
= NULL
;
2379 if (type
> ObjectTypeMax
|| id
>= EmfPlusObjectTableSize
)
2380 return InvalidParameter
;
2384 case ObjectTypeBrush
:
2385 status
= metafile_deserialize_brush(record_data
, data_size
, (GpBrush
**)&object
);
2389 EmfPlusPen
*data
= (EmfPlusPen
*)record_data
;
2390 EmfPlusPenData
*pendata
= (EmfPlusPenData
*)data
->data
;
2395 status
= metafile_get_pen_brush_data_offset(data
, data_size
, &offset
);
2399 status
= metafile_deserialize_brush(record_data
+ offset
, data_size
- offset
, &brush
);
2403 status
= GdipCreatePen2(brush
, pendata
->PenWidth
, pendata
->PenUnit
, &pen
);
2404 GdipDeleteBrush(brush
);
2408 offset
= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
2410 if (pendata
->PenDataFlags
& PenDataTransform
)
2412 FIXME("PenDataTransform is not supported.\n");
2413 offset
+= sizeof(EmfPlusTransformMatrix
);
2416 if (pendata
->PenDataFlags
& PenDataStartCap
)
2418 if ((status
= GdipSetPenStartCap(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2420 offset
+= sizeof(DWORD
);
2423 if (pendata
->PenDataFlags
& PenDataEndCap
)
2425 if ((status
= GdipSetPenEndCap(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2427 offset
+= sizeof(DWORD
);
2430 if (pendata
->PenDataFlags
& PenDataJoin
)
2432 if ((status
= GdipSetPenLineJoin(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2434 offset
+= sizeof(DWORD
);
2437 if (pendata
->PenDataFlags
& PenDataMiterLimit
)
2439 if ((status
= GdipSetPenMiterLimit(pen
, *(REAL
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2441 offset
+= sizeof(REAL
);
2444 if (pendata
->PenDataFlags
& PenDataLineStyle
)
2446 if ((status
= GdipSetPenDashStyle(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2448 offset
+= sizeof(DWORD
);
2451 if (pendata
->PenDataFlags
& PenDataDashedLineCap
)
2453 FIXME("PenDataDashedLineCap is not supported.\n");
2454 offset
+= sizeof(DWORD
);
2457 if (pendata
->PenDataFlags
& PenDataDashedLineOffset
)
2459 if ((status
= GdipSetPenDashOffset(pen
, *(REAL
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2461 offset
+= sizeof(REAL
);
2464 if (pendata
->PenDataFlags
& PenDataDashedLine
)
2466 EmfPlusDashedLineData
*dashedline
= (EmfPlusDashedLineData
*)((BYTE
*)pendata
+ offset
);
2467 FIXME("PenDataDashedLine is not supported.\n");
2468 offset
+= FIELD_OFFSET(EmfPlusDashedLineData
, data
) + dashedline
->DashedLineDataSize
* sizeof(float);
2471 if (pendata
->PenDataFlags
& PenDataNonCenter
)
2473 FIXME("PenDataNonCenter is not supported.\n");
2474 offset
+= sizeof(DWORD
);
2477 if (pendata
->PenDataFlags
& PenDataCompoundLine
)
2479 EmfPlusCompoundLineData
*compoundline
= (EmfPlusCompoundLineData
*)((BYTE
*)pendata
+ offset
);
2480 FIXME("PenDataCompoundLine is not supported.\n");
2481 offset
+= FIELD_OFFSET(EmfPlusCompoundLineData
, data
) + compoundline
->CompoundLineDataSize
* sizeof(float);
2484 if (pendata
->PenDataFlags
& PenDataCustomStartCap
)
2486 EmfPlusCustomStartCapData
*startcap
= (EmfPlusCustomStartCapData
*)((BYTE
*)pendata
+ offset
);
2487 FIXME("PenDataCustomStartCap is not supported.\n");
2488 offset
+= FIELD_OFFSET(EmfPlusCustomStartCapData
, data
) + startcap
->CustomStartCapSize
;
2491 if (pendata
->PenDataFlags
& PenDataCustomEndCap
)
2493 EmfPlusCustomEndCapData
*endcap
= (EmfPlusCustomEndCapData
*)((BYTE
*)pendata
+ offset
);
2494 FIXME("PenDataCustomEndCap is not supported.\n");
2495 offset
+= FIELD_OFFSET(EmfPlusCustomEndCapData
, data
) + endcap
->CustomEndCapSize
;
2505 case ObjectTypePath
:
2506 status
= metafile_deserialize_path(record_data
, data_size
, (GpPath
**)&object
);
2508 case ObjectTypeRegion
:
2509 status
= metafile_deserialize_region(record_data
, data_size
, (GpRegion
**)&object
);
2511 case ObjectTypeImage
:
2512 status
= metafile_deserialize_image(record_data
, data_size
, (GpImage
**)&object
);
2514 case ObjectTypeFont
:
2516 EmfPlusFont
*data
= (EmfPlusFont
*)record_data
;
2517 GpFontFamily
*family
;
2520 if (data_size
<= FIELD_OFFSET(EmfPlusFont
, FamilyName
))
2521 return InvalidParameter
;
2522 data_size
-= FIELD_OFFSET(EmfPlusFont
, FamilyName
);
2524 if (data_size
< data
->Length
* sizeof(WCHAR
))
2525 return InvalidParameter
;
2527 if (!(familyname
= GdipAlloc((data
->Length
+ 1) * sizeof(*familyname
))))
2530 memcpy(familyname
, data
->FamilyName
, data
->Length
* sizeof(*familyname
));
2531 familyname
[data
->Length
] = 0;
2533 status
= GdipCreateFontFamilyFromName(familyname
, NULL
, &family
);
2534 GdipFree(familyname
);
2536 /* If a font family cannot be created from family name, native
2537 falls back to a sans serif font. */
2539 status
= GdipGetGenericFontFamilySansSerif(&family
);
2543 status
= GdipCreateFont(family
, data
->EmSize
, data
->FontStyleFlags
, data
->SizeUnit
, (GpFont
**)&object
);
2544 GdipDeleteFontFamily(family
);
2547 case ObjectTypeImageAttributes
:
2549 EmfPlusImageAttributes
*data
= (EmfPlusImageAttributes
*)record_data
;
2550 GpImageAttributes
*attributes
= NULL
;
2552 if (data_size
!= sizeof(*data
))
2553 return InvalidParameter
;
2555 if ((status
= GdipCreateImageAttributes(&attributes
)) != Ok
)
2558 status
= GdipSetImageAttributesWrapMode(attributes
, data
->WrapMode
, *(DWORD
*)&data
->ClampColor
,
2559 !!data
->ObjectClamp
);
2561 object
= attributes
;
2563 GdipDisposeImageAttributes(attributes
);
2567 FIXME("not implemented for object type %d.\n", type
);
2568 return NotImplemented
;
2572 metafile_set_object_table_entry(metafile
, id
, type
, object
);
2577 static GpStatus
metafile_set_clip_region(GpMetafile
*metafile
, GpRegion
*region
, CombineMode mode
)
2579 GpMatrix world_to_device
;
2581 get_graphics_transform(metafile
->playback_graphics
, CoordinateSpaceDevice
, CoordinateSpaceWorld
, &world_to_device
);
2583 GdipTransformRegion(region
, &world_to_device
);
2584 GdipCombineRegionRegion(metafile
->clip
, region
, mode
);
2586 return METAFILE_PlaybackUpdateClip(metafile
);
2589 GpStatus WINGDIPAPI
GdipPlayMetafileRecord(GDIPCONST GpMetafile
*metafile
,
2590 EmfPlusRecordType recordType
, UINT flags
, UINT dataSize
, GDIPCONST BYTE
*data
)
2593 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
;
2595 TRACE("(%p,%x,%x,%d,%p)\n", metafile
, recordType
, flags
, dataSize
, data
);
2597 if (!metafile
|| (dataSize
&& !data
) || !metafile
->playback_graphics
)
2598 return InvalidParameter
;
2600 if (recordType
>= 1 && recordType
<= 0x7a)
2602 /* regular EMF record */
2603 if (metafile
->playback_dc
)
2605 ENHMETARECORD
*record
= heap_alloc_zero(dataSize
+ 8);
2609 record
->iType
= recordType
;
2610 record
->nSize
= dataSize
+ 8;
2611 memcpy(record
->dParm
, data
, dataSize
);
2613 if(PlayEnhMetaFileRecord(metafile
->playback_dc
, metafile
->handle_table
,
2614 record
, metafile
->handle_count
) == 0)
2615 ERR("PlayEnhMetaFileRecord failed\n");
2625 EmfPlusRecordHeader
*header
= (EmfPlusRecordHeader
*)(data
)-1;
2627 METAFILE_PlaybackReleaseDC((GpMetafile
*)metafile
);
2631 case EmfPlusRecordTypeHeader
:
2632 case EmfPlusRecordTypeEndOfFile
:
2634 case EmfPlusRecordTypeGetDC
:
2635 METAFILE_PlaybackGetDC((GpMetafile
*)metafile
);
2637 case EmfPlusRecordTypeClear
:
2639 EmfPlusClear
*record
= (EmfPlusClear
*)header
;
2641 if (dataSize
!= sizeof(record
->Color
))
2642 return InvalidParameter
;
2644 return GdipGraphicsClear(metafile
->playback_graphics
, record
->Color
);
2646 case EmfPlusRecordTypeFillRects
:
2648 EmfPlusFillRects
*record
= (EmfPlusFillRects
*)header
;
2649 GpBrush
*brush
, *temp_brush
=NULL
;
2650 GpRectF
*rects
, *temp_rects
=NULL
;
2652 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
))
2653 return InvalidParameter
;
2657 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(EmfPlusRect
) * record
->Count
)
2658 return InvalidParameter
;
2662 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(GpRectF
) * record
->Count
)
2663 return InvalidParameter
;
2668 stat
= GdipCreateSolidFill(record
->BrushID
, (GpSolidFill
**)&temp_brush
);
2673 if (record
->BrushID
>= EmfPlusObjectTableSize
||
2674 real_metafile
->objtable
[record
->BrushID
].type
!= ObjectTypeBrush
)
2675 return InvalidParameter
;
2677 brush
= real_metafile
->objtable
[record
->BrushID
].u
.brush
;
2685 EmfPlusRect
*int_rects
= (EmfPlusRect
*)(record
+1);
2688 rects
= temp_rects
= heap_alloc_zero(sizeof(GpRectF
) * record
->Count
);
2691 for (i
=0; i
<record
->Count
; i
++)
2693 rects
[i
].X
= int_rects
[i
].X
;
2694 rects
[i
].Y
= int_rects
[i
].Y
;
2695 rects
[i
].Width
= int_rects
[i
].Width
;
2696 rects
[i
].Height
= int_rects
[i
].Height
;
2703 rects
= (GpRectF
*)(record
+1);
2708 stat
= GdipFillRectangles(metafile
->playback_graphics
, brush
, rects
, record
->Count
);
2711 GdipDeleteBrush(temp_brush
);
2712 heap_free(temp_rects
);
2716 case EmfPlusRecordTypeSetClipRect
:
2718 EmfPlusSetClipRect
*record
= (EmfPlusSetClipRect
*)header
;
2719 CombineMode mode
= (CombineMode
)((flags
>> 8) & 0xf);
2722 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(*record
))
2723 return InvalidParameter
;
2725 stat
= GdipCreateRegionRect(&record
->ClipRect
, ®ion
);
2729 stat
= metafile_set_clip_region(real_metafile
, region
, mode
);
2730 GdipDeleteRegion(region
);
2735 case EmfPlusRecordTypeSetClipRegion
:
2737 CombineMode mode
= (flags
>> 8) & 0xf;
2738 BYTE regionid
= flags
& 0xff;
2742 return InvalidParameter
;
2744 if (regionid
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[regionid
].type
!= ObjectTypeRegion
)
2745 return InvalidParameter
;
2747 stat
= GdipCloneRegion(real_metafile
->objtable
[regionid
].u
.region
, ®ion
);
2750 stat
= metafile_set_clip_region(real_metafile
, region
, mode
);
2751 GdipDeleteRegion(region
);
2756 case EmfPlusRecordTypeSetClipPath
:
2758 CombineMode mode
= (flags
>> 8) & 0xf;
2759 BYTE pathid
= flags
& 0xff;
2763 return InvalidParameter
;
2765 if (pathid
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pathid
].type
!= ObjectTypePath
)
2766 return InvalidParameter
;
2768 stat
= GdipCreateRegionPath(real_metafile
->objtable
[pathid
].u
.path
, ®ion
);
2771 stat
= metafile_set_clip_region(real_metafile
, region
, mode
);
2772 GdipDeleteRegion(region
);
2777 case EmfPlusRecordTypeSetPageTransform
:
2779 EmfPlusSetPageTransform
*record
= (EmfPlusSetPageTransform
*)header
;
2780 GpUnit unit
= (GpUnit
)flags
;
2782 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetPageTransform
))
2783 return InvalidParameter
;
2785 real_metafile
->page_unit
= unit
;
2786 real_metafile
->page_scale
= record
->PageScale
;
2788 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2790 case EmfPlusRecordTypeSetWorldTransform
:
2792 EmfPlusSetWorldTransform
*record
= (EmfPlusSetWorldTransform
*)header
;
2794 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetWorldTransform
))
2795 return InvalidParameter
;
2797 memcpy(real_metafile
->world_transform
->matrix
, record
->MatrixData
, sizeof(record
->MatrixData
));
2799 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2801 case EmfPlusRecordTypeScaleWorldTransform
:
2803 EmfPlusScaleWorldTransform
*record
= (EmfPlusScaleWorldTransform
*)header
;
2804 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2806 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusScaleWorldTransform
))
2807 return InvalidParameter
;
2809 GdipScaleMatrix(real_metafile
->world_transform
, record
->Sx
, record
->Sy
, order
);
2811 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2813 case EmfPlusRecordTypeMultiplyWorldTransform
:
2815 EmfPlusMultiplyWorldTransform
*record
= (EmfPlusMultiplyWorldTransform
*)header
;
2816 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2819 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusMultiplyWorldTransform
))
2820 return InvalidParameter
;
2822 memcpy(matrix
.matrix
, record
->MatrixData
, sizeof(matrix
.matrix
));
2824 GdipMultiplyMatrix(real_metafile
->world_transform
, &matrix
, order
);
2826 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2828 case EmfPlusRecordTypeRotateWorldTransform
:
2830 EmfPlusRotateWorldTransform
*record
= (EmfPlusRotateWorldTransform
*)header
;
2831 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2833 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusRotateWorldTransform
))
2834 return InvalidParameter
;
2836 GdipRotateMatrix(real_metafile
->world_transform
, record
->Angle
, order
);
2838 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2840 case EmfPlusRecordTypeTranslateWorldTransform
:
2842 EmfPlusTranslateWorldTransform
*record
= (EmfPlusTranslateWorldTransform
*)header
;
2843 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2845 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusTranslateWorldTransform
))
2846 return InvalidParameter
;
2848 GdipTranslateMatrix(real_metafile
->world_transform
, record
->dx
, record
->dy
, order
);
2850 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2852 case EmfPlusRecordTypeResetWorldTransform
:
2854 GdipSetMatrixElements(real_metafile
->world_transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
2856 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2858 case EmfPlusRecordTypeBeginContainer
:
2860 EmfPlusBeginContainer
*record
= (EmfPlusBeginContainer
*)header
;
2863 REAL scale_x
, scale_y
;
2864 GpRectF scaled_srcrect
;
2867 cont
= heap_alloc_zero(sizeof(*cont
));
2871 stat
= GdipCloneRegion(metafile
->clip
, &cont
->clip
);
2878 stat
= GdipBeginContainer2(metafile
->playback_graphics
, &cont
->state
);
2882 GdipDeleteRegion(cont
->clip
);
2887 cont
->id
= record
->StackIndex
;
2888 cont
->type
= BEGIN_CONTAINER
;
2889 cont
->world_transform
= *metafile
->world_transform
;
2890 cont
->page_unit
= metafile
->page_unit
;
2891 cont
->page_scale
= metafile
->page_scale
;
2892 list_add_head(&real_metafile
->containers
, &cont
->entry
);
2894 unit
= record
->Header
.Flags
& 0xff;
2896 scale_x
= units_to_pixels(1.0, unit
, metafile
->image
.xres
);
2897 scale_y
= units_to_pixels(1.0, unit
, metafile
->image
.yres
);
2899 scaled_srcrect
.X
= scale_x
* record
->SrcRect
.X
;
2900 scaled_srcrect
.Y
= scale_y
* record
->SrcRect
.Y
;
2901 scaled_srcrect
.Width
= scale_x
* record
->SrcRect
.Width
;
2902 scaled_srcrect
.Height
= scale_y
* record
->SrcRect
.Height
;
2904 transform
.matrix
[0] = record
->DestRect
.Width
/ scaled_srcrect
.Width
;
2905 transform
.matrix
[1] = 0.0;
2906 transform
.matrix
[2] = 0.0;
2907 transform
.matrix
[3] = record
->DestRect
.Height
/ scaled_srcrect
.Height
;
2908 transform
.matrix
[4] = record
->DestRect
.X
- scaled_srcrect
.X
;
2909 transform
.matrix
[5] = record
->DestRect
.Y
- scaled_srcrect
.Y
;
2911 GdipMultiplyMatrix(real_metafile
->world_transform
, &transform
, MatrixOrderPrepend
);
2913 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2915 case EmfPlusRecordTypeBeginContainerNoParams
:
2916 case EmfPlusRecordTypeSave
:
2918 EmfPlusContainerRecord
*record
= (EmfPlusContainerRecord
*)header
;
2921 cont
= heap_alloc_zero(sizeof(*cont
));
2925 stat
= GdipCloneRegion(metafile
->clip
, &cont
->clip
);
2932 if (recordType
== EmfPlusRecordTypeBeginContainerNoParams
)
2933 stat
= GdipBeginContainer2(metafile
->playback_graphics
, &cont
->state
);
2935 stat
= GdipSaveGraphics(metafile
->playback_graphics
, &cont
->state
);
2939 GdipDeleteRegion(cont
->clip
);
2944 cont
->id
= record
->StackIndex
;
2945 if (recordType
== EmfPlusRecordTypeBeginContainerNoParams
)
2946 cont
->type
= BEGIN_CONTAINER
;
2948 cont
->type
= SAVE_GRAPHICS
;
2949 cont
->world_transform
= *metafile
->world_transform
;
2950 cont
->page_unit
= metafile
->page_unit
;
2951 cont
->page_scale
= metafile
->page_scale
;
2952 list_add_head(&real_metafile
->containers
, &cont
->entry
);
2956 case EmfPlusRecordTypeEndContainer
:
2957 case EmfPlusRecordTypeRestore
:
2959 EmfPlusContainerRecord
*record
= (EmfPlusContainerRecord
*)header
;
2961 enum container_type type
;
2964 if (recordType
== EmfPlusRecordTypeEndContainer
)
2965 type
= BEGIN_CONTAINER
;
2967 type
= SAVE_GRAPHICS
;
2969 LIST_FOR_EACH_ENTRY(cont
, &real_metafile
->containers
, container
, entry
)
2971 if (cont
->id
== record
->StackIndex
&& cont
->type
== type
)
2982 /* pop any newer items on the stack */
2983 while ((cont2
= LIST_ENTRY(list_head(&real_metafile
->containers
), container
, entry
)) != cont
)
2985 list_remove(&cont2
->entry
);
2986 GdipDeleteRegion(cont2
->clip
);
2990 if (type
== BEGIN_CONTAINER
)
2991 GdipEndContainer(real_metafile
->playback_graphics
, cont
->state
);
2993 GdipRestoreGraphics(real_metafile
->playback_graphics
, cont
->state
);
2995 *real_metafile
->world_transform
= cont
->world_transform
;
2996 real_metafile
->page_unit
= cont
->page_unit
;
2997 real_metafile
->page_scale
= cont
->page_scale
;
2998 GdipCombineRegionRegion(real_metafile
->clip
, cont
->clip
, CombineModeReplace
);
3000 list_remove(&cont
->entry
);
3001 GdipDeleteRegion(cont
->clip
);
3007 case EmfPlusRecordTypeSetPixelOffsetMode
:
3009 return GdipSetPixelOffsetMode(real_metafile
->playback_graphics
, flags
& 0xff);
3011 case EmfPlusRecordTypeSetCompositingQuality
:
3013 return GdipSetCompositingQuality(real_metafile
->playback_graphics
, flags
& 0xff);
3015 case EmfPlusRecordTypeSetInterpolationMode
:
3017 return GdipSetInterpolationMode(real_metafile
->playback_graphics
, flags
& 0xff);
3019 case EmfPlusRecordTypeSetTextRenderingHint
:
3021 return GdipSetTextRenderingHint(real_metafile
->playback_graphics
, flags
& 0xff);
3023 case EmfPlusRecordTypeSetAntiAliasMode
:
3025 return GdipSetSmoothingMode(real_metafile
->playback_graphics
, (flags
>> 1) & 0xff);
3027 case EmfPlusRecordTypeSetCompositingMode
:
3029 return GdipSetCompositingMode(real_metafile
->playback_graphics
, flags
& 0xff);
3031 case EmfPlusRecordTypeObject
:
3033 return METAFILE_PlaybackObject(real_metafile
, flags
, dataSize
, data
);
3035 case EmfPlusRecordTypeDrawImage
:
3037 EmfPlusDrawImage
*draw
= (EmfPlusDrawImage
*)header
;
3038 BYTE image
= flags
& 0xff;
3041 if (image
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[image
].type
!= ObjectTypeImage
)
3042 return InvalidParameter
;
3044 if (dataSize
!= FIELD_OFFSET(EmfPlusDrawImage
, RectData
) - sizeof(EmfPlusRecordHeader
) +
3045 (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3046 return InvalidParameter
;
3048 if (draw
->ImageAttributesID
>= EmfPlusObjectTableSize
||
3049 real_metafile
->objtable
[draw
->ImageAttributesID
].type
!= ObjectTypeImageAttributes
)
3050 return InvalidParameter
;
3052 if (flags
& 0x4000) /* C */
3054 points
[0].X
= draw
->RectData
.rect
.X
;
3055 points
[0].Y
= draw
->RectData
.rect
.Y
;
3056 points
[1].X
= points
[0].X
+ draw
->RectData
.rect
.Width
;
3057 points
[1].Y
= points
[0].Y
;
3058 points
[2].X
= points
[1].X
;
3059 points
[2].Y
= points
[1].Y
+ draw
->RectData
.rect
.Height
;
3063 points
[0].X
= draw
->RectData
.rectF
.X
;
3064 points
[0].Y
= draw
->RectData
.rectF
.Y
;
3065 points
[1].X
= points
[0].X
+ draw
->RectData
.rectF
.Width
;
3066 points
[1].Y
= points
[0].Y
;
3067 points
[2].X
= points
[1].X
;
3068 points
[2].Y
= points
[1].Y
+ draw
->RectData
.rectF
.Height
;
3071 return GdipDrawImagePointsRect(real_metafile
->playback_graphics
, real_metafile
->objtable
[image
].u
.image
,
3072 points
, 3, draw
->SrcRect
.X
, draw
->SrcRect
.Y
, draw
->SrcRect
.Width
, draw
->SrcRect
.Height
, draw
->SrcUnit
,
3073 real_metafile
->objtable
[draw
->ImageAttributesID
].u
.image_attributes
, NULL
, NULL
);
3075 case EmfPlusRecordTypeDrawImagePoints
:
3077 EmfPlusDrawImagePoints
*draw
= (EmfPlusDrawImagePoints
*)header
;
3078 static const UINT fixed_part_size
= FIELD_OFFSET(EmfPlusDrawImagePoints
, PointData
) -
3079 FIELD_OFFSET(EmfPlusDrawImagePoints
, ImageAttributesID
);
3080 BYTE image
= flags
& 0xff;
3085 if (image
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[image
].type
!= ObjectTypeImage
)
3086 return InvalidParameter
;
3088 if (dataSize
<= fixed_part_size
)
3089 return InvalidParameter
;
3090 dataSize
-= fixed_part_size
;
3092 if (draw
->ImageAttributesID
>= EmfPlusObjectTableSize
||
3093 real_metafile
->objtable
[draw
->ImageAttributesID
].type
!= ObjectTypeImageAttributes
)
3094 return InvalidParameter
;
3096 if (draw
->count
!= 3)
3097 return InvalidParameter
;
3099 if ((flags
>> 13) & 1) /* E */
3100 FIXME("image effects are not supported.\n");
3102 if ((flags
>> 11) & 1) /* P */
3103 size
= sizeof(EmfPlusPointR7
) * draw
->count
;
3104 else if ((flags
>> 14) & 1) /* C */
3105 size
= sizeof(EmfPlusPoint
) * draw
->count
;
3107 size
= sizeof(EmfPlusPointF
) * draw
->count
;
3109 if (dataSize
!= size
)
3110 return InvalidParameter
;
3112 if ((flags
>> 11) & 1) /* P */
3114 points
[0].X
= draw
->PointData
.pointsR
[0].X
;
3115 points
[0].Y
= draw
->PointData
.pointsR
[0].Y
;
3116 for (i
= 1; i
< 3; i
++)
3118 points
[i
].X
= points
[i
-1].X
+ draw
->PointData
.pointsR
[i
].X
;
3119 points
[i
].Y
= points
[i
-1].Y
+ draw
->PointData
.pointsR
[i
].Y
;
3122 else if ((flags
>> 14) & 1) /* C */
3124 for (i
= 0; i
< 3; i
++)
3126 points
[i
].X
= draw
->PointData
.points
[i
].X
;
3127 points
[i
].Y
= draw
->PointData
.points
[i
].Y
;
3131 memcpy(points
, draw
->PointData
.pointsF
, sizeof(points
));
3133 return GdipDrawImagePointsRect(real_metafile
->playback_graphics
, real_metafile
->objtable
[image
].u
.image
,
3134 points
, 3, draw
->SrcRect
.X
, draw
->SrcRect
.Y
, draw
->SrcRect
.Width
, draw
->SrcRect
.Height
, draw
->SrcUnit
,
3135 real_metafile
->objtable
[draw
->ImageAttributesID
].u
.image_attributes
, NULL
, NULL
);
3137 case EmfPlusRecordTypeFillPath
:
3139 EmfPlusFillPath
*fill
= (EmfPlusFillPath
*)header
;
3140 GpSolidFill
*solidfill
= NULL
;
3141 BYTE path
= flags
& 0xff;
3144 if (path
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[path
].type
!= ObjectTypePath
)
3145 return InvalidParameter
;
3147 if (dataSize
!= sizeof(fill
->data
.BrushId
))
3148 return InvalidParameter
;
3152 stat
= GdipCreateSolidFill(fill
->data
.Color
, &solidfill
);
3155 brush
= (GpBrush
*)solidfill
;
3159 if (fill
->data
.BrushId
>= EmfPlusObjectTableSize
||
3160 real_metafile
->objtable
[fill
->data
.BrushId
].type
!= ObjectTypeBrush
)
3161 return InvalidParameter
;
3163 brush
= real_metafile
->objtable
[fill
->data
.BrushId
].u
.brush
;
3166 stat
= GdipFillPath(real_metafile
->playback_graphics
, brush
, real_metafile
->objtable
[path
].u
.path
);
3167 GdipDeleteBrush((GpBrush
*)solidfill
);
3170 case EmfPlusRecordTypeFillClosedCurve
:
3172 static const UINT fixed_part_size
= FIELD_OFFSET(EmfPlusFillClosedCurve
, PointData
) -
3173 sizeof(EmfPlusRecordHeader
);
3174 EmfPlusFillClosedCurve
*fill
= (EmfPlusFillClosedCurve
*)header
;
3175 GpSolidFill
*solidfill
= NULL
;
3180 if (dataSize
<= fixed_part_size
)
3181 return InvalidParameter
;
3183 if (fill
->Count
== 0)
3184 return InvalidParameter
;
3186 if (flags
& 0x800) /* P */
3187 size
= (fixed_part_size
+ sizeof(EmfPlusPointR7
) * fill
->Count
+ 3) & ~3;
3188 else if (flags
& 0x4000) /* C */
3189 size
= fixed_part_size
+ sizeof(EmfPlusPoint
) * fill
->Count
;
3191 size
= fixed_part_size
+ sizeof(EmfPlusPointF
) * fill
->Count
;
3193 if (dataSize
!= size
)
3194 return InvalidParameter
;
3196 mode
= flags
& 0x200 ? FillModeWinding
: FillModeAlternate
; /* W */
3198 if (flags
& 0x8000) /* S */
3200 stat
= GdipCreateSolidFill(fill
->BrushId
, &solidfill
);
3203 brush
= (GpBrush
*)solidfill
;
3207 if (fill
->BrushId
>= EmfPlusObjectTableSize
||
3208 real_metafile
->objtable
[fill
->BrushId
].type
!= ObjectTypeBrush
)
3209 return InvalidParameter
;
3211 brush
= real_metafile
->objtable
[fill
->BrushId
].u
.brush
;
3214 if (flags
& (0x800 | 0x4000))
3216 GpPointF
*points
= GdipAlloc(fill
->Count
* sizeof(*points
));
3219 if (flags
& 0x800) /* P */
3221 for (i
= 1; i
< fill
->Count
; i
++)
3223 points
[i
].X
= points
[i
- 1].X
+ fill
->PointData
.pointsR
[i
].X
;
3224 points
[i
].Y
= points
[i
- 1].Y
+ fill
->PointData
.pointsR
[i
].Y
;
3229 for (i
= 0; i
< fill
->Count
; i
++)
3231 points
[i
].X
= fill
->PointData
.points
[i
].X
;
3232 points
[i
].Y
= fill
->PointData
.points
[i
].Y
;
3236 stat
= GdipFillClosedCurve2(real_metafile
->playback_graphics
, brush
,
3237 points
, fill
->Count
, fill
->Tension
, mode
);
3244 stat
= GdipFillClosedCurve2(real_metafile
->playback_graphics
, brush
,
3245 (const GpPointF
*)fill
->PointData
.pointsF
, fill
->Count
, fill
->Tension
, mode
);
3247 GdipDeleteBrush((GpBrush
*)solidfill
);
3250 case EmfPlusRecordTypeFillEllipse
:
3252 EmfPlusFillEllipse
*fill
= (EmfPlusFillEllipse
*)header
;
3253 GpSolidFill
*solidfill
= NULL
;
3256 if (dataSize
<= FIELD_OFFSET(EmfPlusFillEllipse
, RectData
) - sizeof(EmfPlusRecordHeader
))
3257 return InvalidParameter
;
3258 dataSize
-= FIELD_OFFSET(EmfPlusFillEllipse
, RectData
) - sizeof(EmfPlusRecordHeader
);
3260 if (dataSize
!= (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3261 return InvalidParameter
;
3265 stat
= GdipCreateSolidFill(fill
->BrushId
, &solidfill
);
3268 brush
= (GpBrush
*)solidfill
;
3272 if (fill
->BrushId
>= EmfPlusObjectTableSize
||
3273 real_metafile
->objtable
[fill
->BrushId
].type
!= ObjectTypeBrush
)
3274 return InvalidParameter
;
3276 brush
= real_metafile
->objtable
[fill
->BrushId
].u
.brush
;
3280 stat
= GdipFillEllipseI(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rect
.X
,
3281 fill
->RectData
.rect
.Y
, fill
->RectData
.rect
.Width
, fill
->RectData
.rect
.Height
);
3283 stat
= GdipFillEllipse(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rectF
.X
,
3284 fill
->RectData
.rectF
.Y
, fill
->RectData
.rectF
.Width
, fill
->RectData
.rectF
.Height
);
3286 GdipDeleteBrush((GpBrush
*)solidfill
);
3289 case EmfPlusRecordTypeFillPie
:
3291 EmfPlusFillPie
*fill
= (EmfPlusFillPie
*)header
;
3292 GpSolidFill
*solidfill
= NULL
;
3295 if (dataSize
<= FIELD_OFFSET(EmfPlusFillPie
, RectData
) - sizeof(EmfPlusRecordHeader
))
3296 return InvalidParameter
;
3297 dataSize
-= FIELD_OFFSET(EmfPlusFillPie
, RectData
) - sizeof(EmfPlusRecordHeader
);
3299 if (dataSize
!= (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3300 return InvalidParameter
;
3302 if (flags
& 0x8000) /* S */
3304 stat
= GdipCreateSolidFill(fill
->BrushId
, &solidfill
);
3307 brush
= (GpBrush
*)solidfill
;
3311 if (fill
->BrushId
>= EmfPlusObjectTableSize
||
3312 real_metafile
->objtable
[fill
->BrushId
].type
!= ObjectTypeBrush
)
3313 return InvalidParameter
;
3315 brush
= real_metafile
->objtable
[fill
->BrushId
].u
.brush
;
3318 if (flags
& 0x4000) /* C */
3319 stat
= GdipFillPieI(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rect
.X
,
3320 fill
->RectData
.rect
.Y
, fill
->RectData
.rect
.Width
, fill
->RectData
.rect
.Height
,
3321 fill
->StartAngle
, fill
->SweepAngle
);
3323 stat
= GdipFillPie(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rectF
.X
,
3324 fill
->RectData
.rectF
.Y
, fill
->RectData
.rectF
.Width
, fill
->RectData
.rectF
.Height
,
3325 fill
->StartAngle
, fill
->SweepAngle
);
3327 GdipDeleteBrush((GpBrush
*)solidfill
);
3330 case EmfPlusRecordTypeDrawPath
:
3332 EmfPlusDrawPath
*draw
= (EmfPlusDrawPath
*)header
;
3333 BYTE path
= flags
& 0xff;
3335 if (dataSize
!= sizeof(draw
->PenId
))
3336 return InvalidParameter
;
3338 if (path
>= EmfPlusObjectTableSize
|| draw
->PenId
>= EmfPlusObjectTableSize
)
3339 return InvalidParameter
;
3341 if (real_metafile
->objtable
[path
].type
!= ObjectTypePath
||
3342 real_metafile
->objtable
[draw
->PenId
].type
!= ObjectTypePen
)
3343 return InvalidParameter
;
3345 return GdipDrawPath(real_metafile
->playback_graphics
, real_metafile
->objtable
[draw
->PenId
].u
.pen
,
3346 real_metafile
->objtable
[path
].u
.path
);
3348 case EmfPlusRecordTypeDrawArc
:
3350 EmfPlusDrawArc
*draw
= (EmfPlusDrawArc
*)header
;
3351 BYTE pen
= flags
& 0xff;
3353 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3354 return InvalidParameter
;
3356 if (dataSize
!= FIELD_OFFSET(EmfPlusDrawArc
, RectData
) - sizeof(EmfPlusRecordHeader
) +
3357 (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3358 return InvalidParameter
;
3360 if (flags
& 0x4000) /* C */
3361 return GdipDrawArcI(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3362 draw
->RectData
.rect
.X
, draw
->RectData
.rect
.Y
, draw
->RectData
.rect
.Width
,
3363 draw
->RectData
.rect
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3365 return GdipDrawArc(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3366 draw
->RectData
.rectF
.X
, draw
->RectData
.rectF
.Y
, draw
->RectData
.rectF
.Width
,
3367 draw
->RectData
.rectF
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3369 case EmfPlusRecordTypeDrawEllipse
:
3371 EmfPlusDrawEllipse
*draw
= (EmfPlusDrawEllipse
*)header
;
3372 BYTE pen
= flags
& 0xff;
3374 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3375 return InvalidParameter
;
3377 if (dataSize
!= (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3378 return InvalidParameter
;
3380 if (flags
& 0x4000) /* C */
3381 return GdipDrawEllipseI(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3382 draw
->RectData
.rect
.X
, draw
->RectData
.rect
.Y
, draw
->RectData
.rect
.Width
,
3383 draw
->RectData
.rect
.Height
);
3385 return GdipDrawEllipse(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3386 draw
->RectData
.rectF
.X
, draw
->RectData
.rectF
.Y
, draw
->RectData
.rectF
.Width
,
3387 draw
->RectData
.rectF
.Height
);
3389 case EmfPlusRecordTypeDrawPie
:
3391 EmfPlusDrawPie
*draw
= (EmfPlusDrawPie
*)header
;
3392 BYTE pen
= flags
& 0xff;
3394 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3395 return InvalidParameter
;
3397 if (dataSize
!= FIELD_OFFSET(EmfPlusDrawPie
, RectData
) - sizeof(EmfPlusRecordHeader
) +
3398 (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3399 return InvalidParameter
;
3401 if (flags
& 0x4000) /* C */
3402 return GdipDrawPieI(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3403 draw
->RectData
.rect
.X
, draw
->RectData
.rect
.Y
, draw
->RectData
.rect
.Width
,
3404 draw
->RectData
.rect
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3406 return GdipDrawPie(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3407 draw
->RectData
.rectF
.X
, draw
->RectData
.rectF
.Y
, draw
->RectData
.rectF
.Width
,
3408 draw
->RectData
.rectF
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3410 case EmfPlusRecordTypeDrawRects
:
3412 EmfPlusDrawRects
*draw
= (EmfPlusDrawRects
*)header
;
3413 BYTE pen
= flags
& 0xff;
3414 GpRectF
*rects
= NULL
;
3416 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3417 return InvalidParameter
;
3419 if (dataSize
<= FIELD_OFFSET(EmfPlusDrawRects
, RectData
) - sizeof(EmfPlusRecordHeader
))
3420 return InvalidParameter
;
3421 dataSize
-= FIELD_OFFSET(EmfPlusDrawRects
, RectData
) - sizeof(EmfPlusRecordHeader
);
3423 if (dataSize
!= draw
->Count
* (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3424 return InvalidParameter
;
3430 rects
= GdipAlloc(draw
->Count
* sizeof(*rects
));
3434 for (i
= 0; i
< draw
->Count
; i
++)
3436 rects
[i
].X
= draw
->RectData
.rect
[i
].X
;
3437 rects
[i
].Y
= draw
->RectData
.rect
[i
].Y
;
3438 rects
[i
].Width
= draw
->RectData
.rect
[i
].Width
;
3439 rects
[i
].Height
= draw
->RectData
.rect
[i
].Height
;
3443 stat
= GdipDrawRectangles(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3444 rects
? rects
: (GpRectF
*)draw
->RectData
.rectF
, draw
->Count
);
3448 case EmfPlusRecordTypeDrawDriverString
:
3451 DWORD expected_size
;
3454 GpSolidFill
*solidfill
= NULL
;
3455 void* alignedmem
= NULL
;
3456 GpMatrix
*matrix
= NULL
;
3457 BYTE font
= flags
& 0xff;
3458 EmfPlusDrawDriverString
*draw
= (EmfPlusDrawDriverString
*)header
;
3460 if (font
>= EmfPlusObjectTableSize
||
3461 real_metafile
->objtable
[font
].type
!= ObjectTypeFont
)
3462 return InvalidParameter
;
3464 expected_size
= FIELD_OFFSET(EmfPlusDrawDriverString
, VariableData
) -
3465 sizeof(EmfPlusRecordHeader
);
3466 if (dataSize
< expected_size
|| draw
->GlyphCount
<= 0)
3467 return InvalidParameter
;
3469 expected_size
+= draw
->GlyphCount
* (sizeof(*text
) + sizeof(*positions
));
3470 if (draw
->MatrixPresent
)
3471 expected_size
+= sizeof(*matrix
);
3473 /* Pad expected size to DWORD alignment. */
3474 expected_size
= (expected_size
+ 3) & ~3;
3476 if (dataSize
!= expected_size
)
3477 return InvalidParameter
;
3481 stat
= GdipCreateSolidFill(draw
->brush
.Color
, (GpSolidFill
**)&solidfill
);
3484 return InvalidParameter
;
3486 brush
= (GpBrush
*)solidfill
;
3490 if (draw
->brush
.BrushId
>= EmfPlusObjectTableSize
||
3491 real_metafile
->objtable
[draw
->brush
.BrushId
].type
!= ObjectTypeBrush
)
3492 return InvalidParameter
;
3494 brush
= real_metafile
->objtable
[draw
->brush
.BrushId
].u
.brush
;
3497 text
= (UINT16
*)&draw
->VariableData
[0];
3499 /* If GlyphCount is odd, all subsequent fields will be 2-byte
3500 aligned rather than 4-byte aligned, which may lead to access
3501 issues. Handle this case by making our own copy of positions. */
3502 if (draw
->GlyphCount
% 2)
3504 SIZE_T alloc_size
= draw
->GlyphCount
* sizeof(*positions
);
3506 if (draw
->MatrixPresent
)
3507 alloc_size
+= sizeof(*matrix
);
3509 positions
= alignedmem
= heap_alloc(alloc_size
);
3512 GdipDeleteBrush((GpBrush
*)solidfill
);
3516 memcpy(positions
, &text
[draw
->GlyphCount
], alloc_size
);
3519 positions
= (PointF
*)&text
[draw
->GlyphCount
];
3521 if (draw
->MatrixPresent
)
3522 matrix
= (GpMatrix
*)&positions
[draw
->GlyphCount
];
3524 stat
= GdipDrawDriverString(real_metafile
->playback_graphics
, text
, draw
->GlyphCount
,
3525 real_metafile
->objtable
[font
].u
.font
, brush
, positions
,
3526 draw
->DriverStringOptionsFlags
, matrix
);
3528 GdipDeleteBrush((GpBrush
*)solidfill
);
3529 heap_free(alignedmem
);
3533 case EmfPlusRecordTypeFillRegion
:
3535 EmfPlusFillRegion
* const fill
= (EmfPlusFillRegion
*)header
;
3536 GpSolidFill
*solidfill
= NULL
;
3538 BYTE region
= flags
& 0xff;
3540 if (dataSize
!= sizeof(EmfPlusFillRegion
) - sizeof(EmfPlusRecordHeader
))
3541 return InvalidParameter
;
3543 if (region
>= EmfPlusObjectTableSize
||
3544 real_metafile
->objtable
[region
].type
!= ObjectTypeRegion
)
3545 return InvalidParameter
;
3549 stat
= GdipCreateSolidFill(fill
->data
.Color
, &solidfill
);
3552 brush
= (GpBrush
*)solidfill
;
3556 if (fill
->data
.BrushId
>= EmfPlusObjectTableSize
||
3557 real_metafile
->objtable
[fill
->data
.BrushId
].type
!= ObjectTypeBrush
)
3558 return InvalidParameter
;
3560 brush
= real_metafile
->objtable
[fill
->data
.BrushId
].u
.brush
;
3563 stat
= GdipFillRegion(real_metafile
->playback_graphics
, brush
,
3564 real_metafile
->objtable
[region
].u
.region
);
3565 GdipDeleteBrush((GpBrush
*)solidfill
);
3570 FIXME("Not implemented for record type %x\n", recordType
);
3571 return NotImplemented
;
3578 struct enum_metafile_data
3580 EnumerateMetafileProc callback
;
3581 void *callback_data
;
3582 GpMetafile
*metafile
;
3585 static int CALLBACK
enum_metafile_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
3586 int nObj
, LPARAM lpData
)
3589 struct enum_metafile_data
*data
= (struct enum_metafile_data
*)lpData
;
3592 data
->metafile
->handle_table
= lpHTable
;
3593 data
->metafile
->handle_count
= nObj
;
3595 /* First check for an EMF+ record. */
3596 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
3598 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
3600 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
3604 while (offset
+ sizeof(EmfPlusRecordHeader
) <= comment
->cbData
)
3606 const EmfPlusRecordHeader
*record
= (const EmfPlusRecordHeader
*)&comment
->Data
[offset
];
3608 if (record
->DataSize
)
3609 pStr
= (const BYTE
*)(record
+1);
3613 ret
= data
->callback(record
->Type
, record
->Flags
, record
->DataSize
,
3614 pStr
, data
->callback_data
);
3619 offset
+= record
->Size
;
3626 if (lpEMFR
->nSize
!= 8)
3627 pStr
= (const BYTE
*)lpEMFR
->dParm
;
3631 return data
->callback(lpEMFR
->iType
, 0, lpEMFR
->nSize
-8,
3632 pStr
, data
->callback_data
);
3635 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestPoints(GpGraphics
*graphics
,
3636 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*destPoints
, INT count
,
3637 GDIPCONST GpRectF
*srcRect
, Unit srcUnit
, EnumerateMetafileProc callback
,
3638 VOID
*callbackData
, GDIPCONST GpImageAttributes
*imageAttributes
)
3640 struct enum_metafile_data data
;
3642 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
; /* whoever made this const was joking */
3643 GraphicsContainer state
;
3647 TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics
, metafile
,
3648 destPoints
, count
, srcRect
, srcUnit
, callback
, callbackData
,
3651 if (!graphics
|| !metafile
|| !destPoints
|| count
!= 3 || !srcRect
)
3652 return InvalidParameter
;
3654 if (!metafile
->hemf
)
3655 return InvalidParameter
;
3657 if (metafile
->playback_graphics
)
3660 TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect
), srcUnit
,
3661 debugstr_pointf(&destPoints
[0]), debugstr_pointf(&destPoints
[1]),
3662 debugstr_pointf(&destPoints
[2]));
3664 data
.callback
= callback
;
3665 data
.callback_data
= callbackData
;
3666 data
.metafile
= real_metafile
;
3668 real_metafile
->playback_graphics
= graphics
;
3669 real_metafile
->playback_dc
= NULL
;
3670 real_metafile
->src_rect
= *srcRect
;
3672 memcpy(real_metafile
->playback_points
, destPoints
, sizeof(PointF
) * 3);
3673 stat
= GdipTransformPoints(graphics
, CoordinateSpaceDevice
, CoordinateSpaceWorld
, real_metafile
->playback_points
, 3);
3676 stat
= GdipBeginContainer2(graphics
, &state
);
3680 stat
= GdipSetPageScale(graphics
, 1.0);
3683 stat
= GdipSetPageUnit(graphics
, UnitPixel
);
3686 stat
= GdipResetWorldTransform(graphics
);
3689 stat
= GdipCreateRegion(&real_metafile
->base_clip
);
3692 stat
= GdipGetClip(graphics
, real_metafile
->base_clip
);
3695 stat
= GdipCreateRegion(&real_metafile
->clip
);
3698 stat
= GdipCreatePath(FillModeAlternate
, &dst_path
);
3702 GpPointF clip_points
[4];
3704 clip_points
[0] = real_metafile
->playback_points
[0];
3705 clip_points
[1] = real_metafile
->playback_points
[1];
3706 clip_points
[2].X
= real_metafile
->playback_points
[1].X
+ real_metafile
->playback_points
[2].X
3707 - real_metafile
->playback_points
[0].X
;
3708 clip_points
[2].Y
= real_metafile
->playback_points
[1].Y
+ real_metafile
->playback_points
[2].Y
3709 - real_metafile
->playback_points
[0].Y
;
3710 clip_points
[3] = real_metafile
->playback_points
[2];
3712 stat
= GdipAddPathPolygon(dst_path
, clip_points
, 4);
3715 stat
= GdipCombineRegionPath(real_metafile
->base_clip
, dst_path
, CombineModeIntersect
);
3717 GdipDeletePath(dst_path
);
3721 stat
= GdipCreateMatrix(&real_metafile
->world_transform
);
3725 real_metafile
->page_unit
= UnitDisplay
;
3726 real_metafile
->page_scale
= 1.0;
3727 stat
= METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
3732 stat
= METAFILE_PlaybackUpdateClip(real_metafile
);
3737 stat
= METAFILE_PlaybackGetDC(real_metafile
);
3739 dst_bounds
.left
= real_metafile
->playback_points
[0].X
;
3740 dst_bounds
.right
= real_metafile
->playback_points
[1].X
;
3741 dst_bounds
.top
= real_metafile
->playback_points
[0].Y
;
3742 dst_bounds
.bottom
= real_metafile
->playback_points
[2].Y
;
3746 EnumEnhMetaFile(real_metafile
->playback_dc
, metafile
->hemf
, enum_metafile_proc
,
3747 &data
, &dst_bounds
);
3749 METAFILE_PlaybackReleaseDC(real_metafile
);
3751 GdipDeleteMatrix(real_metafile
->world_transform
);
3752 real_metafile
->world_transform
= NULL
;
3754 GdipDeleteRegion(real_metafile
->base_clip
);
3755 real_metafile
->base_clip
= NULL
;
3757 GdipDeleteRegion(real_metafile
->clip
);
3758 real_metafile
->clip
= NULL
;
3760 while (list_head(&real_metafile
->containers
))
3762 container
* cont
= LIST_ENTRY(list_head(&real_metafile
->containers
), container
, entry
);
3763 list_remove(&cont
->entry
);
3764 GdipDeleteRegion(cont
->clip
);
3768 GdipEndContainer(graphics
, state
);
3771 real_metafile
->playback_graphics
= NULL
;
3776 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRect(GpGraphics
*graphics
,
3777 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRectF
*dest
,
3778 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3782 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
3784 points
[0].X
= points
[2].X
= dest
->X
;
3785 points
[0].Y
= points
[1].Y
= dest
->Y
;
3786 points
[1].X
= dest
->X
+ dest
->Width
;
3787 points
[2].Y
= dest
->Y
+ dest
->Height
;
3789 return GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, points
, 3,
3790 &metafile
->bounds
, metafile
->unit
, callback
, cb_data
, attrs
);
3793 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRectI(GpGraphics
*graphics
,
3794 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRect
*dest
,
3795 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3799 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
3803 destf
.Width
= dest
->Width
;
3804 destf
.Height
= dest
->Height
;
3806 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
3809 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPoint(GpGraphics
*graphics
,
3810 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*dest
,
3811 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3815 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
3819 destf
.Width
= units_to_pixels(metafile
->bounds
.Width
, metafile
->unit
, metafile
->image
.xres
);
3820 destf
.Height
= units_to_pixels(metafile
->bounds
.Height
, metafile
->unit
, metafile
->image
.yres
);
3822 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
3825 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPointI(GpGraphics
*graphics
,
3826 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPoint
*dest
,
3827 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3831 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
3836 return GdipEnumerateMetafileDestPoint(graphics
, metafile
, &ptf
, callback
, cb_data
, attrs
);
3839 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromMetafile(GpMetafile
* metafile
,
3840 MetafileHeader
* header
)
3844 TRACE("(%p, %p)\n", metafile
, header
);
3846 if(!metafile
|| !header
)
3847 return InvalidParameter
;
3851 status
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, header
);
3852 if (status
!= Ok
) return status
;
3856 memset(header
, 0, sizeof(*header
));
3857 header
->Version
= VERSION_MAGIC2
;
3860 header
->Type
= metafile
->metafile_type
;
3861 header
->DpiX
= metafile
->image
.xres
;
3862 header
->DpiY
= metafile
->image
.yres
;
3863 header
->Width
= gdip_round(metafile
->bounds
.Width
);
3864 header
->Height
= gdip_round(metafile
->bounds
.Height
);
3869 static int CALLBACK
get_emfplus_header_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
3870 int nObj
, LPARAM lpData
)
3872 EmfPlusHeader
*dst_header
= (EmfPlusHeader
*)lpData
;
3874 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
3876 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
3878 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
3880 const EmfPlusRecordHeader
*header
= (const EmfPlusRecordHeader
*)&comment
->Data
[4];
3882 if (4 + sizeof(EmfPlusHeader
) <= comment
->cbData
&&
3883 header
->Type
== EmfPlusRecordTypeHeader
)
3885 memcpy(dst_header
, header
, sizeof(*dst_header
));
3889 else if (lpEMFR
->iType
== EMR_HEADER
)
3895 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromEmf(HENHMETAFILE hemf
,
3896 MetafileHeader
*header
)
3898 ENHMETAHEADER3 emfheader
;
3899 EmfPlusHeader emfplusheader
;
3900 MetafileType metafile_type
;
3902 TRACE("(%p,%p)\n", hemf
, header
);
3904 if(!hemf
|| !header
)
3905 return InvalidParameter
;
3907 if (GetEnhMetaFileHeader(hemf
, sizeof(emfheader
), (ENHMETAHEADER
*)&emfheader
) == 0)
3908 return GenericError
;
3910 emfplusheader
.Header
.Type
= 0;
3912 EnumEnhMetaFile(NULL
, hemf
, get_emfplus_header_proc
, &emfplusheader
, NULL
);
3914 if (emfplusheader
.Header
.Type
== EmfPlusRecordTypeHeader
)
3916 if ((emfplusheader
.Header
.Flags
& 1) == 1)
3917 metafile_type
= MetafileTypeEmfPlusDual
;
3919 metafile_type
= MetafileTypeEmfPlusOnly
;
3922 metafile_type
= MetafileTypeEmf
;
3924 header
->Type
= metafile_type
;
3925 header
->Size
= emfheader
.nBytes
;
3926 header
->DpiX
= (REAL
)emfheader
.szlDevice
.cx
* 25.4 / emfheader
.szlMillimeters
.cx
;
3927 header
->DpiY
= (REAL
)emfheader
.szlDevice
.cy
* 25.4 / emfheader
.szlMillimeters
.cy
;
3928 header
->X
= gdip_round((REAL
)emfheader
.rclFrame
.left
/ 2540.0 * header
->DpiX
);
3929 header
->Y
= gdip_round((REAL
)emfheader
.rclFrame
.top
/ 2540.0 * header
->DpiY
);
3930 header
->Width
= gdip_round((REAL
)(emfheader
.rclFrame
.right
- emfheader
.rclFrame
.left
) / 2540.0 * header
->DpiX
);
3931 header
->Height
= gdip_round((REAL
)(emfheader
.rclFrame
.bottom
- emfheader
.rclFrame
.top
) / 2540.0 * header
->DpiY
);
3932 header
->u
.EmfHeader
= emfheader
;
3934 if (metafile_type
== MetafileTypeEmfPlusDual
|| metafile_type
== MetafileTypeEmfPlusOnly
)
3936 header
->Version
= emfplusheader
.Version
;
3937 header
->EmfPlusFlags
= emfplusheader
.EmfPlusFlags
;
3938 header
->EmfPlusHeaderSize
= emfplusheader
.Header
.Size
;
3939 header
->LogicalDpiX
= emfplusheader
.LogicalDpiX
;
3940 header
->LogicalDpiY
= emfplusheader
.LogicalDpiY
;
3944 header
->Version
= emfheader
.nVersion
;
3945 header
->EmfPlusFlags
= 0;
3946 header
->EmfPlusHeaderSize
= 0;
3947 header
->LogicalDpiX
= 0;
3948 header
->LogicalDpiY
= 0;
3954 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromWmf(HMETAFILE hwmf
,
3955 GDIPCONST WmfPlaceableFileHeader
*placeable
, MetafileHeader
*header
)
3958 GpMetafile
*metafile
;
3960 TRACE("(%p,%p,%p)\n", hwmf
, placeable
, header
);
3962 status
= GdipCreateMetafileFromWmf(hwmf
, FALSE
, placeable
, &metafile
);
3965 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
3966 GdipDisposeImage(&metafile
->image
);
3971 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR
*filename
,
3972 MetafileHeader
*header
)
3975 GpMetafile
*metafile
;
3977 TRACE("(%s,%p)\n", debugstr_w(filename
), header
);
3979 if (!filename
|| !header
)
3980 return InvalidParameter
;
3982 status
= GdipCreateMetafileFromFile(filename
, &metafile
);
3985 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
3986 GdipDisposeImage(&metafile
->image
);
3991 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromStream(IStream
*stream
,
3992 MetafileHeader
*header
)
3995 GpMetafile
*metafile
;
3997 TRACE("(%p,%p)\n", stream
, header
);
3999 if (!stream
|| !header
)
4000 return InvalidParameter
;
4002 status
= GdipCreateMetafileFromStream(stream
, &metafile
);
4005 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
4006 GdipDisposeImage(&metafile
->image
);
4011 GpStatus WINGDIPAPI
GdipCreateMetafileFromEmf(HENHMETAFILE hemf
, BOOL
delete,
4012 GpMetafile
**metafile
)
4015 MetafileHeader header
;
4017 TRACE("(%p,%i,%p)\n", hemf
, delete, metafile
);
4019 if(!hemf
|| !metafile
)
4020 return InvalidParameter
;
4022 stat
= GdipGetMetafileHeaderFromEmf(hemf
, &header
);
4026 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
4030 (*metafile
)->image
.type
= ImageTypeMetafile
;
4031 (*metafile
)->image
.format
= ImageFormatEMF
;
4032 (*metafile
)->image
.frame_count
= 1;
4033 (*metafile
)->image
.xres
= header
.DpiX
;
4034 (*metafile
)->image
.yres
= header
.DpiY
;
4035 (*metafile
)->bounds
.X
= (REAL
)header
.u
.EmfHeader
.rclFrame
.left
/ 2540.0 * header
.DpiX
;
4036 (*metafile
)->bounds
.Y
= (REAL
)header
.u
.EmfHeader
.rclFrame
.top
/ 2540.0 * header
.DpiY
;
4037 (*metafile
)->bounds
.Width
= (REAL
)(header
.u
.EmfHeader
.rclFrame
.right
- header
.u
.EmfHeader
.rclFrame
.left
)
4038 / 2540.0 * header
.DpiX
;
4039 (*metafile
)->bounds
.Height
= (REAL
)(header
.u
.EmfHeader
.rclFrame
.bottom
- header
.u
.EmfHeader
.rclFrame
.top
)
4040 / 2540.0 * header
.DpiY
;
4041 (*metafile
)->unit
= UnitPixel
;
4042 (*metafile
)->metafile_type
= header
.Type
;
4043 (*metafile
)->hemf
= hemf
;
4044 (*metafile
)->preserve_hemf
= !delete;
4045 list_init(&(*metafile
)->containers
);
4047 TRACE("<-- %p\n", *metafile
);
4052 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmf(HMETAFILE hwmf
, BOOL
delete,
4053 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
4058 GpStatus retval
= Ok
;
4060 TRACE("(%p, %d, %p, %p)\n", hwmf
, delete, placeable
, metafile
);
4062 if(!hwmf
|| !metafile
)
4063 return InvalidParameter
;
4066 read
= GetMetaFileBitsEx(hwmf
, 0, NULL
);
4068 return GenericError
;
4069 copy
= heap_alloc_zero(read
);
4070 GetMetaFileBitsEx(hwmf
, read
, copy
);
4072 hemf
= SetWinMetaFileBits(read
, copy
, NULL
, NULL
);
4075 /* FIXME: We should store and use hwmf instead of converting to hemf */
4076 retval
= GdipCreateMetafileFromEmf(hemf
, TRUE
, metafile
);
4082 (*metafile
)->image
.xres
= (REAL
)placeable
->Inch
;
4083 (*metafile
)->image
.yres
= (REAL
)placeable
->Inch
;
4084 (*metafile
)->bounds
.X
= ((REAL
)placeable
->BoundingBox
.Left
) / ((REAL
)placeable
->Inch
);
4085 (*metafile
)->bounds
.Y
= ((REAL
)placeable
->BoundingBox
.Top
) / ((REAL
)placeable
->Inch
);
4086 (*metafile
)->bounds
.Width
= (REAL
)(placeable
->BoundingBox
.Right
-
4087 placeable
->BoundingBox
.Left
);
4088 (*metafile
)->bounds
.Height
= (REAL
)(placeable
->BoundingBox
.Bottom
-
4089 placeable
->BoundingBox
.Top
);
4090 (*metafile
)->metafile_type
= MetafileTypeWmfPlaceable
;
4093 (*metafile
)->metafile_type
= MetafileTypeWmf
;
4094 (*metafile
)->image
.format
= ImageFormatWMF
;
4096 if (delete) DeleteMetaFile(hwmf
);
4099 DeleteEnhMetaFile(hemf
);
4103 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR
*file
,
4104 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
4109 TRACE("(%s, %p, %p)\n", debugstr_w(file
), placeable
, metafile
);
4111 hmf
= GetMetaFileW(file
);
4113 return GdipCreateMetafileFromWmf(hmf
, TRUE
, placeable
, metafile
);
4115 emf
= GetEnhMetaFileW(file
);
4117 return GdipCreateMetafileFromEmf(emf
, TRUE
, metafile
);
4119 return GenericError
;
4122 GpStatus WINGDIPAPI
GdipCreateMetafileFromFile(GDIPCONST WCHAR
*file
,
4123 GpMetafile
**metafile
)
4128 TRACE("(%p, %p)\n", file
, metafile
);
4130 if (!file
|| !metafile
) return InvalidParameter
;
4134 status
= GdipCreateStreamOnFile(file
, GENERIC_READ
, &stream
);
4137 status
= GdipCreateMetafileFromStream(stream
, metafile
);
4138 IStream_Release(stream
);
4143 GpStatus WINGDIPAPI
GdipCreateMetafileFromStream(IStream
*stream
,
4144 GpMetafile
**metafile
)
4148 TRACE("%p %p\n", stream
, metafile
);
4150 stat
= GdipLoadImageFromStream(stream
, (GpImage
**)metafile
);
4151 if (stat
!= Ok
) return stat
;
4153 if ((*metafile
)->image
.type
!= ImageTypeMetafile
)
4155 GdipDisposeImage(&(*metafile
)->image
);
4157 return GenericError
;
4163 GpStatus WINGDIPAPI
GdipGetMetafileDownLevelRasterizationLimit(GDIPCONST GpMetafile
*metafile
,
4166 TRACE("(%p,%p)\n", metafile
, limitDpi
);
4168 if (!metafile
|| !limitDpi
)
4169 return InvalidParameter
;
4171 if (!metafile
->record_dc
)
4174 *limitDpi
= metafile
->limit_dpi
;
4179 GpStatus WINGDIPAPI
GdipSetMetafileDownLevelRasterizationLimit(GpMetafile
*metafile
,
4182 TRACE("(%p,%u)\n", metafile
, limitDpi
);
4187 if (!metafile
|| limitDpi
< 10)
4188 return InvalidParameter
;
4190 if (!metafile
->record_dc
)
4193 metafile
->limit_dpi
= limitDpi
;
4198 GpStatus WINGDIPAPI
GdipConvertToEmfPlus(const GpGraphics
* ref
,
4199 GpMetafile
* metafile
, BOOL
* succ
, EmfType emfType
,
4200 const WCHAR
* description
, GpMetafile
** out_metafile
)
4204 TRACE("(%p,%p,%p,%u,%s,%p)\n", ref
, metafile
, succ
, emfType
,
4205 debugstr_w(description
), out_metafile
);
4207 if(!ref
|| !metafile
|| !out_metafile
|| emfType
< EmfTypeEmfOnly
|| emfType
> EmfTypeEmfPlusDual
)
4208 return InvalidParameter
;
4212 *out_metafile
= NULL
;
4215 FIXME("not implemented\n");
4217 return NotImplemented
;
4220 GpStatus WINGDIPAPI
GdipEmfToWmfBits(HENHMETAFILE hemf
, UINT cbData16
,
4221 LPBYTE pData16
, INT iMapMode
, INT eFlags
)
4223 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf
, cbData16
, pData16
, iMapMode
, eFlags
);
4224 return NotImplemented
;
4227 GpStatus WINGDIPAPI
GdipRecordMetafileFileName(GDIPCONST WCHAR
* fileName
,
4228 HDC hdc
, EmfType type
, GDIPCONST GpRectF
*pFrameRect
,
4229 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
,
4230 GpMetafile
**metafile
)
4232 FIXME("%s %p %d %s %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, debugstr_rectf(pFrameRect
),
4233 frameUnit
, debugstr_w(desc
), metafile
);
4235 return NotImplemented
;
4238 GpStatus WINGDIPAPI
GdipRecordMetafileFileNameI(GDIPCONST WCHAR
* fileName
, HDC hdc
, EmfType type
,
4239 GDIPCONST GpRect
*pFrameRect
, MetafileFrameUnit frameUnit
,
4240 GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
4242 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
4243 frameUnit
, debugstr_w(desc
), metafile
);
4245 return NotImplemented
;
4248 /*****************************************************************************
4249 * GdipConvertToEmfPlusToFile [GDIPLUS.@]
4252 GpStatus WINGDIPAPI
GdipConvertToEmfPlusToFile(const GpGraphics
* refGraphics
,
4253 GpMetafile
* metafile
, BOOL
* conversionSuccess
,
4254 const WCHAR
* filename
, EmfType emfType
,
4255 const WCHAR
* description
, GpMetafile
** out_metafile
)
4257 FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics
, metafile
, conversionSuccess
, filename
, emfType
, description
, out_metafile
);
4258 return NotImplemented
;
4261 static GpStatus
METAFILE_CreateCompressedImageStream(GpImage
*image
, IStream
**stream
, DWORD
*size
)
4270 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, stream
);
4271 if (FAILED(hr
)) return hresult_to_status(hr
);
4273 stat
= encode_image_png(image
, *stream
, NULL
);
4276 IStream_Release(*stream
);
4280 hr
= IStream_Stat(*stream
, &statstg
, 1);
4283 IStream_Release(*stream
);
4284 return hresult_to_status(hr
);
4286 *size
= statstg
.cbSize
.u
.LowPart
;
4289 hr
= IStream_Seek(*stream
, zero
, STREAM_SEEK_SET
, NULL
);
4292 IStream_Release(*stream
);
4293 return hresult_to_status(hr
);
4299 static GpStatus
METAFILE_FillEmfPlusBitmap(EmfPlusBitmap
*record
, IStream
*stream
, DWORD size
)
4306 record
->PixelFormat
= 0;
4307 record
->Type
= BitmapDataTypeCompressed
;
4309 hr
= IStream_Read(stream
, record
->BitmapData
, size
, NULL
);
4310 if (FAILED(hr
)) return hresult_to_status(hr
);
4314 static GpStatus
METAFILE_AddImageObject(GpMetafile
*metafile
, GpImage
*image
, DWORD
*id
)
4316 EmfPlusObject
*object_record
;
4322 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4325 if (image
->type
== ImageTypeBitmap
)
4330 stat
= METAFILE_CreateCompressedImageStream(image
, &stream
, &size
);
4331 if (stat
!= Ok
) return stat
;
4332 aligned_size
= (size
+ 3) & ~3;
4334 stat
= METAFILE_AllocateRecord(metafile
,
4335 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image
.ImageData
.bitmap
.BitmapData
[aligned_size
]),
4336 (void**)&object_record
);
4339 IStream_Release(stream
);
4342 memset(object_record
->ObjectData
.image
.ImageData
.bitmap
.BitmapData
+ size
, 0, aligned_size
- size
);
4344 *id
= METAFILE_AddObjectId(metafile
);
4345 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
4346 object_record
->Header
.Flags
= *id
| ObjectTypeImage
<< 8;
4347 object_record
->ObjectData
.image
.Version
= VERSION_MAGIC2
;
4348 object_record
->ObjectData
.image
.Type
= ImageDataTypeBitmap
;
4350 stat
= METAFILE_FillEmfPlusBitmap(&object_record
->ObjectData
.image
.ImageData
.bitmap
, stream
, size
);
4351 IStream_Release(stream
);
4352 if (stat
!= Ok
) METAFILE_RemoveLastRecord(metafile
, &object_record
->Header
);
4355 else if (image
->type
== ImageTypeMetafile
)
4357 HENHMETAFILE hemf
= ((GpMetafile
*)image
)->hemf
;
4358 EmfPlusMetafile
*metafile_record
;
4360 if (!hemf
) return InvalidParameter
;
4362 size
= GetEnhMetaFileBits(hemf
, 0, NULL
);
4363 if (!size
) return GenericError
;
4365 stat
= METAFILE_AllocateRecord(metafile
,
4366 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image
.ImageData
.metafile
.MetafileData
[size
]),
4367 (void**)&object_record
);
4368 if (stat
!= Ok
) return stat
;
4370 *id
= METAFILE_AddObjectId(metafile
);
4371 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
4372 object_record
->Header
.Flags
= *id
| ObjectTypeImage
<< 8;
4373 object_record
->ObjectData
.image
.Version
= VERSION_MAGIC2
;
4374 object_record
->ObjectData
.image
.Type
= ImageDataTypeMetafile
;
4375 metafile_record
= &object_record
->ObjectData
.image
.ImageData
.metafile
;
4376 metafile_record
->Type
= ((GpMetafile
*)image
)->metafile_type
;
4377 metafile_record
->MetafileDataSize
= size
;
4378 if (GetEnhMetaFileBits(hemf
, size
, metafile_record
->MetafileData
) != size
)
4380 METAFILE_RemoveLastRecord(metafile
, &object_record
->Header
);
4381 return GenericError
;
4387 FIXME("not supported image type (%d)\n", image
->type
);
4388 return NotImplemented
;
4392 static GpStatus
METAFILE_AddImageAttributesObject(GpMetafile
*metafile
, const GpImageAttributes
*attrs
, DWORD
*id
)
4394 EmfPlusObject
*object_record
;
4395 EmfPlusImageAttributes
*attrs_record
;
4400 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4406 stat
= METAFILE_AllocateRecord(metafile
,
4407 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image_attributes
) + sizeof(EmfPlusImageAttributes
),
4408 (void**)&object_record
);
4409 if (stat
!= Ok
) return stat
;
4411 *id
= METAFILE_AddObjectId(metafile
);
4412 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
4413 object_record
->Header
.Flags
= *id
| (ObjectTypeImageAttributes
<< 8);
4414 attrs_record
= &object_record
->ObjectData
.image_attributes
;
4415 attrs_record
->Version
= VERSION_MAGIC2
;
4416 attrs_record
->Reserved1
= 0;
4417 attrs_record
->WrapMode
= attrs
->wrap
;
4418 attrs_record
->ClampColor
= attrs
->outside_color
;
4419 attrs_record
->ObjectClamp
= attrs
->clamp
;
4420 attrs_record
->Reserved2
= 0;
4424 GpStatus
METAFILE_DrawImagePointsRect(GpMetafile
*metafile
, GpImage
*image
,
4425 GDIPCONST GpPointF
*points
, INT count
, REAL srcx
, REAL srcy
, REAL srcwidth
,
4426 REAL srcheight
, GpUnit srcUnit
, GDIPCONST GpImageAttributes
* imageAttributes
,
4427 DrawImageAbort callback
, VOID
*callbackData
)
4429 EmfPlusDrawImagePoints
*draw_image_record
;
4430 DWORD image_id
, attributes_id
;
4433 if (count
!= 3) return InvalidParameter
;
4435 if (metafile
->metafile_type
== MetafileTypeEmf
)
4437 FIXME("MetafileTypeEmf metafiles not supported\n");
4438 return NotImplemented
;
4441 FIXME("semi-stub\n");
4443 if (!imageAttributes
)
4445 stat
= METAFILE_AddImageObject(metafile
, image
, &image_id
);
4447 else if (image
->type
== ImageTypeBitmap
)
4449 INT width
= ((GpBitmap
*)image
)->width
;
4450 INT height
= ((GpBitmap
*)image
)->height
;
4451 GpGraphics
*graphics
;
4454 stat
= GdipCreateBitmapFromScan0(width
, height
,
4455 0, PixelFormat32bppARGB
, NULL
, &bitmap
);
4456 if (stat
!= Ok
) return stat
;
4458 stat
= GdipGetImageGraphicsContext((GpImage
*)bitmap
, &graphics
);
4461 GdipDisposeImage((GpImage
*)bitmap
);
4465 stat
= GdipDrawImageRectRectI(graphics
, image
, 0, 0, width
, height
,
4466 0, 0, width
, height
, UnitPixel
, imageAttributes
, NULL
, NULL
);
4467 GdipDeleteGraphics(graphics
);
4470 GdipDisposeImage((GpImage
*)bitmap
);
4474 stat
= METAFILE_AddImageObject(metafile
, (GpImage
*)bitmap
, &image_id
);
4475 GdipDisposeImage((GpImage
*)bitmap
);
4479 FIXME("imageAttributes not supported (image type %d)\n", image
->type
);
4480 return NotImplemented
;
4482 if (stat
!= Ok
) return stat
;
4484 stat
= METAFILE_AddImageAttributesObject(metafile
, imageAttributes
, &attributes_id
);
4485 if (stat
!= Ok
) return stat
;
4487 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusDrawImagePoints
), (void**)&draw_image_record
);
4488 if (stat
!= Ok
) return stat
;
4489 draw_image_record
->Header
.Type
= EmfPlusRecordTypeDrawImagePoints
;
4490 draw_image_record
->Header
.Flags
= image_id
;
4491 draw_image_record
->ImageAttributesID
= attributes_id
;
4492 draw_image_record
->SrcUnit
= UnitPixel
;
4493 draw_image_record
->SrcRect
.X
= units_to_pixels(srcx
, srcUnit
, metafile
->image
.xres
);
4494 draw_image_record
->SrcRect
.Y
= units_to_pixels(srcy
, srcUnit
, metafile
->image
.yres
);
4495 draw_image_record
->SrcRect
.Width
= units_to_pixels(srcwidth
, srcUnit
, metafile
->image
.xres
);
4496 draw_image_record
->SrcRect
.Height
= units_to_pixels(srcheight
, srcUnit
, metafile
->image
.yres
);
4497 draw_image_record
->count
= 3;
4498 memcpy(draw_image_record
->PointData
.pointsF
, points
, 3 * sizeof(*points
));
4499 METAFILE_WriteRecords(metafile
);
4503 GpStatus
METAFILE_AddSimpleProperty(GpMetafile
*metafile
, SHORT prop
, SHORT val
)
4505 EmfPlusRecordHeader
*record
;
4508 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4511 stat
= METAFILE_AllocateRecord(metafile
, sizeof(*record
), (void**)&record
);
4512 if (stat
!= Ok
) return stat
;
4514 record
->Type
= prop
;
4515 record
->Flags
= val
;
4517 METAFILE_WriteRecords(metafile
);
4521 static GpStatus
METAFILE_AddPathObject(GpMetafile
*metafile
, GpPath
*path
, DWORD
*id
)
4523 EmfPlusObject
*object_record
;
4528 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4531 size
= write_path_data(path
, NULL
);
4532 stat
= METAFILE_AllocateRecord(metafile
,
4533 FIELD_OFFSET(EmfPlusObject
, ObjectData
.path
) + size
,
4534 (void**)&object_record
);
4535 if (stat
!= Ok
) return stat
;
4537 *id
= METAFILE_AddObjectId(metafile
);
4538 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
4539 object_record
->Header
.Flags
= *id
| ObjectTypePath
<< 8;
4540 write_path_data(path
, &object_record
->ObjectData
.path
);
4544 static GpStatus
METAFILE_AddPenObject(GpMetafile
*metafile
, GpPen
*pen
, DWORD
*id
)
4546 DWORD i
, data_flags
, pen_data_size
, brush_size
;
4547 EmfPlusObject
*object_record
;
4548 EmfPlusPenData
*pen_data
;
4553 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4557 pen_data_size
= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
4559 GdipIsMatrixIdentity(&pen
->transform
, &result
);
4562 data_flags
|= PenDataTransform
;
4563 pen_data_size
+= sizeof(EmfPlusTransformMatrix
);
4565 if (pen
->startcap
!= LineCapFlat
)
4567 data_flags
|= PenDataStartCap
;
4568 pen_data_size
+= sizeof(DWORD
);
4570 if (pen
->endcap
!= LineCapFlat
)
4572 data_flags
|= PenDataEndCap
;
4573 pen_data_size
+= sizeof(DWORD
);
4575 if (pen
->join
!= LineJoinMiter
)
4577 data_flags
|= PenDataJoin
;
4578 pen_data_size
+= sizeof(DWORD
);
4580 if (pen
->miterlimit
!= 10.0)
4582 data_flags
|= PenDataMiterLimit
;
4583 pen_data_size
+= sizeof(REAL
);
4585 if (pen
->style
!= GP_DEFAULT_PENSTYLE
)
4587 data_flags
|= PenDataLineStyle
;
4588 pen_data_size
+= sizeof(DWORD
);
4590 if (pen
->dashcap
!= DashCapFlat
)
4592 data_flags
|= PenDataDashedLineCap
;
4593 pen_data_size
+= sizeof(DWORD
);
4595 data_flags
|= PenDataDashedLineOffset
;
4596 pen_data_size
+= sizeof(REAL
);
4599 data_flags
|= PenDataDashedLine
;
4600 pen_data_size
+= sizeof(DWORD
) + pen
->numdashes
*sizeof(REAL
);
4602 if (pen
->align
!= PenAlignmentCenter
)
4604 data_flags
|= PenDataNonCenter
;
4605 pen_data_size
+= sizeof(DWORD
);
4607 /* TODO: Add support for PenDataCompoundLine */
4608 if (pen
->customstart
)
4610 FIXME("ignoring custom start cup\n");
4614 FIXME("ignoring custom end cup\n");
4617 stat
= METAFILE_PrepareBrushData(pen
->brush
, &brush_size
);
4618 if (stat
!= Ok
) return stat
;
4620 stat
= METAFILE_AllocateRecord(metafile
,
4621 FIELD_OFFSET(EmfPlusObject
, ObjectData
.pen
.data
) + pen_data_size
+ brush_size
,
4622 (void**)&object_record
);
4623 if (stat
!= Ok
) return stat
;
4625 *id
= METAFILE_AddObjectId(metafile
);
4626 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
4627 object_record
->Header
.Flags
= *id
| ObjectTypePen
<< 8;
4628 object_record
->ObjectData
.pen
.Version
= VERSION_MAGIC2
;
4629 object_record
->ObjectData
.pen
.Type
= 0;
4631 pen_data
= (EmfPlusPenData
*)object_record
->ObjectData
.pen
.data
;
4632 pen_data
->PenDataFlags
= data_flags
;
4633 pen_data
->PenUnit
= pen
->unit
;
4634 pen_data
->PenWidth
= pen
->width
;
4637 if (data_flags
& PenDataTransform
)
4639 EmfPlusTransformMatrix
*m
= (EmfPlusTransformMatrix
*)(pen_data
->OptionalData
+ i
);
4640 memcpy(m
, &pen
->transform
, sizeof(*m
));
4641 i
+= sizeof(EmfPlusTransformMatrix
);
4643 if (data_flags
& PenDataStartCap
)
4645 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->startcap
;
4648 if (data_flags
& PenDataEndCap
)
4650 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->endcap
;
4653 if (data_flags
& PenDataJoin
)
4655 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->join
;
4658 if (data_flags
& PenDataMiterLimit
)
4660 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->miterlimit
;
4663 if (data_flags
& PenDataLineStyle
)
4665 switch (pen
->style
& PS_STYLE_MASK
)
4667 case PS_SOLID
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleSolid
; break;
4668 case PS_DASH
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDash
; break;
4669 case PS_DOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDot
; break;
4670 case PS_DASHDOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDashDot
; break;
4671 case PS_DASHDOTDOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDashDotDot
; break;
4672 default: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleCustom
; break;
4676 if (data_flags
& PenDataDashedLineCap
)
4678 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->dashcap
;
4681 if (data_flags
& PenDataDashedLineOffset
)
4683 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->offset
;
4686 if (data_flags
& PenDataDashedLine
)
4690 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->numdashes
;
4693 for (j
=0; j
<pen
->numdashes
; j
++)
4695 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->dashes
[j
];
4699 if (data_flags
& PenDataNonCenter
)
4701 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->align
;
4705 METAFILE_FillBrushData(pen
->brush
,
4706 (EmfPlusBrush
*)(object_record
->ObjectData
.pen
.data
+ pen_data_size
));
4710 GpStatus
METAFILE_DrawPath(GpMetafile
*metafile
, GpPen
*pen
, GpPath
*path
)
4712 EmfPlusDrawPath
*draw_path_record
;
4717 if (metafile
->metafile_type
== MetafileTypeEmf
)
4720 return NotImplemented
;
4723 stat
= METAFILE_AddPenObject(metafile
, pen
, &pen_id
);
4724 if (stat
!= Ok
) return stat
;
4726 stat
= METAFILE_AddPathObject(metafile
, path
, &path_id
);
4727 if (stat
!= Ok
) return stat
;
4729 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusDrawPath
), (void**)&draw_path_record
);
4730 if (stat
!= Ok
) return stat
;
4731 draw_path_record
->Header
.Type
= EmfPlusRecordTypeDrawPath
;
4732 draw_path_record
->Header
.Flags
= path_id
;
4733 draw_path_record
->PenId
= pen_id
;
4735 METAFILE_WriteRecords(metafile
);
4739 GpStatus
METAFILE_FillPath(GpMetafile
*metafile
, GpBrush
*brush
, GpPath
*path
)
4741 EmfPlusFillPath
*fill_path_record
;
4742 DWORD brush_id
= -1, path_id
;
4746 if (metafile
->metafile_type
== MetafileTypeEmf
)
4749 return NotImplemented
;
4752 inline_color
= brush
->bt
== BrushTypeSolidColor
;
4755 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
4756 if (stat
!= Ok
) return stat
;
4759 stat
= METAFILE_AddPathObject(metafile
, path
, &path_id
);
4760 if (stat
!= Ok
) return stat
;
4762 stat
= METAFILE_AllocateRecord(metafile
,
4763 sizeof(EmfPlusFillPath
), (void**)&fill_path_record
);
4764 if (stat
!= Ok
) return stat
;
4765 fill_path_record
->Header
.Type
= EmfPlusRecordTypeFillPath
;
4768 fill_path_record
->Header
.Flags
= 0x8000 | path_id
;
4769 fill_path_record
->data
.Color
= ((GpSolidFill
*)brush
)->color
;
4773 fill_path_record
->Header
.Flags
= path_id
;
4774 fill_path_record
->data
.BrushId
= brush_id
;
4777 METAFILE_WriteRecords(metafile
);
4781 static GpStatus
METAFILE_AddFontObject(GpMetafile
*metafile
, GDIPCONST GpFont
*font
, DWORD
*id
)
4783 EmfPlusObject
*object_record
;
4784 EmfPlusFont
*font_record
;
4791 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&&
4792 metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4795 /* The following cast is ugly, but GdipGetFontStyle does treat
4796 its first parameter as const. */
4797 stat
= GdipGetFontStyle((GpFont
*)font
, &style
);
4801 fn_len
= lstrlenW(font
->family
->FamilyName
);
4802 stat
= METAFILE_AllocateRecord(metafile
,
4803 FIELD_OFFSET(EmfPlusObject
, ObjectData
.font
.FamilyName
[(fn_len
+ 1) & ~1]),
4804 (void**)&object_record
);
4808 *id
= METAFILE_AddObjectId(metafile
);
4810 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
4811 object_record
->Header
.Flags
= *id
| ObjectTypeFont
<< 8;
4813 font_record
= &object_record
->ObjectData
.font
;
4814 font_record
->Version
= VERSION_MAGIC2
;
4815 font_record
->EmSize
= font
->emSize
;
4816 font_record
->SizeUnit
= font
->unit
;
4817 font_record
->FontStyleFlags
= style
;
4818 font_record
->Reserved
= 0;
4819 font_record
->Length
= fn_len
;
4821 memcpy(font_record
->FamilyName
, font
->family
->FamilyName
,
4822 fn_len
* sizeof(*font
->family
->FamilyName
));
4827 GpStatus
METAFILE_DrawDriverString(GpMetafile
*metafile
, GDIPCONST UINT16
*text
, INT length
,
4828 GDIPCONST GpFont
*font
, GDIPCONST GpStringFormat
*format
, GDIPCONST GpBrush
*brush
,
4829 GDIPCONST PointF
*positions
, INT flags
, GDIPCONST GpMatrix
*matrix
)
4835 EmfPlusDrawDriverString
*draw_string_record
;
4838 BOOL include_matrix
= FALSE
;
4841 return InvalidParameter
;
4843 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&&
4844 metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4846 FIXME("metafile type not supported: %i\n", metafile
->metafile_type
);
4847 return NotImplemented
;
4850 stat
= METAFILE_AddFontObject(metafile
, font
, &font_id
);
4854 inline_color
= (brush
->bt
== BrushTypeSolidColor
);
4857 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
4866 stat
= GdipIsMatrixIdentity(matrix
, &identity
);
4870 include_matrix
= !identity
;
4873 alloc_size
= FIELD_OFFSET(EmfPlusDrawDriverString
, VariableData
) +
4874 length
* (sizeof(*text
) + sizeof(*positions
));
4877 alloc_size
+= sizeof(*matrix
);
4879 /* Pad record to DWORD alignment. */
4880 alloc_size
= (alloc_size
+ 3) & ~3;
4882 stat
= METAFILE_AllocateRecord(metafile
, alloc_size
, (void**)&draw_string_record
);
4886 draw_string_record
->Header
.Type
= EmfPlusRecordTypeDrawDriverString
;
4887 draw_string_record
->Header
.Flags
= font_id
;
4888 draw_string_record
->DriverStringOptionsFlags
= flags
;
4889 draw_string_record
->MatrixPresent
= include_matrix
;
4890 draw_string_record
->GlyphCount
= length
;
4894 draw_string_record
->Header
.Flags
|= 0x8000;
4895 draw_string_record
->brush
.Color
= ((GpSolidFill
*)brush
)->color
;
4898 draw_string_record
->brush
.BrushId
= brush_id
;
4900 cursor
= &draw_string_record
->VariableData
[0];
4902 memcpy(cursor
, text
, length
* sizeof(*text
));
4903 cursor
+= length
* sizeof(*text
);
4905 if (flags
& DriverStringOptionsRealizedAdvance
)
4907 static BOOL fixme_written
= FALSE
;
4909 /* Native never writes DriverStringOptionsRealizedAdvance. Instead,
4910 in the case of RealizedAdvance, each glyph position is computed
4913 While native GDI+ is capable of playing back metafiles with this
4914 flag set, it is possible that some application might rely on
4915 metafiles produced from GDI+ not setting this flag. Ideally we
4916 would also compute the position of each glyph here, serialize those
4917 values, and not set DriverStringOptionsRealizedAdvance. */
4920 fixme_written
= TRUE
;
4921 FIXME("serializing RealizedAdvance flag and single GlyphPos with padding\n");
4924 *((PointF
*)cursor
) = *positions
;
4927 memcpy(cursor
, positions
, length
* sizeof(*positions
));
4931 cursor
+= length
* sizeof(*positions
);
4932 memcpy(cursor
, matrix
, sizeof(*matrix
));
4935 METAFILE_WriteRecords(metafile
);
4940 GpStatus
METAFILE_FillRegion(GpMetafile
* metafile
, GpBrush
* brush
, GpRegion
* region
)
4945 EmfPlusFillRegion
*fill_region_record
;
4948 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&&
4949 metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4951 FIXME("metafile type not supported: %i\n", metafile
->metafile_type
);
4952 return NotImplemented
;
4955 inline_color
= (brush
->bt
== BrushTypeSolidColor
);
4958 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
4963 stat
= METAFILE_AddRegionObject(metafile
, region
, ®ion_id
);
4967 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusFillRegion
),
4968 (void**)&fill_region_record
);
4972 fill_region_record
->Header
.Type
= EmfPlusRecordTypeFillRegion
;
4973 fill_region_record
->Header
.Flags
= region_id
;
4977 fill_region_record
->Header
.Flags
|= 0x8000;
4978 fill_region_record
->data
.Color
= ((GpSolidFill
*)brush
)->color
;
4981 fill_region_record
->data
.BrushId
= brush_id
;
4983 METAFILE_WriteRecords(metafile
);