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
37 #include "gdiplus_private.h"
38 #include "wine/debug.h"
39 #include "wine/list.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus
);
43 HRESULT WINAPI
WICCreateImagingFactory_Proxy(UINT
, IWICImagingFactory
**);
45 typedef ARGB EmfPlusARGB
;
47 typedef struct EmfPlusPointF
53 typedef struct EmfPlusRecordHeader
59 } EmfPlusRecordHeader
;
61 typedef struct EmfPlusHeader
63 EmfPlusRecordHeader Header
;
70 typedef struct EmfPlusClear
72 EmfPlusRecordHeader Header
;
76 typedef struct EmfPlusFillRects
78 EmfPlusRecordHeader Header
;
83 typedef struct EmfPlusSetClipRect
85 EmfPlusRecordHeader Header
;
89 typedef struct EmfPlusSetPageTransform
91 EmfPlusRecordHeader Header
;
93 } EmfPlusSetPageTransform
;
95 typedef struct EmfPlusRect
103 typedef struct EmfPlusSetWorldTransform
105 EmfPlusRecordHeader Header
;
107 } EmfPlusSetWorldTransform
;
109 typedef struct EmfPlusScaleWorldTransform
111 EmfPlusRecordHeader Header
;
114 } EmfPlusScaleWorldTransform
;
116 typedef struct EmfPlusMultiplyWorldTransform
118 EmfPlusRecordHeader Header
;
120 } EmfPlusMultiplyWorldTransform
;
122 typedef struct EmfPlusRotateWorldTransform
124 EmfPlusRecordHeader Header
;
126 } EmfPlusRotateWorldTransform
;
128 typedef struct EmfPlusTranslateWorldTransform
130 EmfPlusRecordHeader Header
;
133 } EmfPlusTranslateWorldTransform
;
135 typedef struct EmfPlusBeginContainer
137 EmfPlusRecordHeader Header
;
141 } EmfPlusBeginContainer
;
143 typedef struct EmfPlusContainerRecord
145 EmfPlusRecordHeader Header
;
147 } EmfPlusContainerRecord
;
155 typedef struct container
159 enum container_type type
;
160 GraphicsContainer state
;
161 GpMatrix world_transform
;
169 PenDataTransform
= 0x0001,
170 PenDataStartCap
= 0x0002,
171 PenDataEndCap
= 0x0004,
172 PenDataJoin
= 0x0008,
173 PenDataMiterLimit
= 0x0010,
174 PenDataLineStyle
= 0x0020,
175 PenDataDashedLineCap
= 0x0040,
176 PenDataDashedLineOffset
= 0x0080,
177 PenDataDashedLine
= 0x0100,
178 PenDataNonCenter
= 0x0200,
179 PenDataCompoundLine
= 0x0400,
180 PenDataCustomStartCap
= 0x0800,
181 PenDataCustomEndCap
= 0x1000
184 enum CustomLineCapData
186 CustomLineCapDataFillPath
= 0x1,
187 CustomLineCapDataLinePath
= 0x2,
190 typedef struct EmfPlusTransformMatrix
192 REAL TransformMatrix
[6];
193 } EmfPlusTransformMatrix
;
205 typedef struct EmfPlusDashedLineData
207 DWORD DashedLineDataSize
;
209 } EmfPlusDashedLineData
;
211 typedef struct EmfPlusCompoundLineData
213 DWORD CompoundLineDataSize
;
215 } EmfPlusCompoundLineData
;
217 typedef struct EmfPlusCustomStartCapData
219 DWORD CustomStartCapSize
;
221 } EmfPlusCustomStartCapData
;
223 typedef struct EmfPlusCustomEndCapData
225 DWORD CustomEndCapSize
;
227 } EmfPlusCustomEndCapData
;
229 typedef struct EmfPlusPenData
234 BYTE OptionalData
[1];
239 BrushDataPath
= 1 << 0,
240 BrushDataTransform
= 1 << 1,
241 BrushDataPresetColors
= 1 << 2,
242 BrushDataBlendFactorsH
= 1 << 3,
243 BrushDataBlendFactorsV
= 1 << 4,
244 BrushDataFocusScales
= 1 << 6,
245 BrushDataIsGammaCorrected
= 1 << 7,
246 BrushDataDoNotTransform
= 1 << 8,
249 typedef struct EmfPlusSolidBrushData
251 EmfPlusARGB SolidColor
;
252 } EmfPlusSolidBrushData
;
254 typedef struct EmfPlusHatchBrushData
257 EmfPlusARGB ForeColor
;
258 EmfPlusARGB BackColor
;
259 } EmfPlusHatchBrushData
;
261 typedef struct EmfPlusTextureBrushData
263 DWORD BrushDataFlags
;
265 BYTE OptionalData
[1];
266 } EmfPlusTextureBrushData
;
268 typedef struct EmfPlusRectF
276 typedef struct EmfPlusLinearGradientBrushData
278 DWORD BrushDataFlags
;
281 EmfPlusARGB StartColor
;
282 EmfPlusARGB EndColor
;
285 BYTE OptionalData
[1];
286 } EmfPlusLinearGradientBrushData
;
288 typedef struct EmfPlusBrush
293 EmfPlusSolidBrushData solid
;
294 EmfPlusHatchBrushData hatch
;
295 EmfPlusTextureBrushData texture
;
296 EmfPlusLinearGradientBrushData lineargradient
;
300 typedef struct EmfPlusCustomLineCapArrowData
311 EmfPlusPointF FillHotSpot
;
312 EmfPlusPointF LineHotSpot
;
313 } EmfPlusCustomLineCapArrowData
;
315 typedef struct EmfPlusPath
318 DWORD PathPointCount
;
319 DWORD PathPointFlags
;
321 /* PathPointTypes[] */
322 /* AlignmentPadding */
326 typedef struct EmfPlusCustomLineCapDataFillPath
331 } EmfPlusCustomLineCapDataFillPath
;
333 typedef struct EmfPlusCustomLineCapDataLinePath
338 } EmfPlusCustomLineCapDataLinePath
;
340 typedef struct EmfPlusCustomLineCapData
342 DWORD CustomLineCapDataFlags
;
345 DWORD StrokeStartCap
;
348 REAL StrokeMiterLimit
;
350 EmfPlusPointF FillHotSpot
;
351 EmfPlusPointF LineHotSpot
;
352 /* EmfPlusCustomLineCapDataFillPath */
353 /* EmfPlusCustomLineCapDataLinePath */
354 BYTE OptionalData
[1];
355 } EmfPlusCustomLineCapData
;
357 typedef struct EmfPlusCustomLineCap
361 /* EmfPlusCustomLineCapArrowData */
362 /* EmfPlusCustomLineCapData */
363 BYTE CustomLineCapData
[1];
364 } EmfPlusCustomLineCap
;
366 typedef struct EmfPlusPen
375 typedef struct EmfPlusRegionNodePath
377 DWORD RegionNodePathLength
;
378 EmfPlusPath RegionNodePath
;
379 } EmfPlusRegionNodePath
;
381 typedef struct EmfPlusRegion
384 DWORD RegionNodeCount
;
388 typedef struct EmfPlusPalette
390 DWORD PaletteStyleFlags
;
392 BYTE PaletteEntries
[1];
398 BitmapDataTypeCompressed
,
401 typedef struct EmfPlusBitmap
411 typedef struct EmfPlusMetafile
414 DWORD MetafileDataSize
;
415 BYTE MetafileData
[1];
418 typedef enum ImageDataType
420 ImageDataTypeUnknown
,
422 ImageDataTypeMetafile
,
425 typedef struct EmfPlusImage
431 EmfPlusBitmap bitmap
;
432 EmfPlusMetafile metafile
;
436 typedef struct EmfPlusImageAttributes
441 EmfPlusARGB ClampColor
;
444 } EmfPlusImageAttributes
;
446 typedef struct EmfPlusFont
451 DWORD FontStyleFlags
;
457 typedef struct EmfPlusObject
459 EmfPlusRecordHeader Header
;
465 EmfPlusRegion region
;
467 EmfPlusImageAttributes image_attributes
;
472 typedef struct EmfPlusPointR7
478 typedef struct EmfPlusPoint
484 typedef struct EmfPlusDrawImage
486 EmfPlusRecordHeader Header
;
487 DWORD ImageAttributesID
;
489 EmfPlusRectF SrcRect
;
497 typedef struct EmfPlusDrawImagePoints
499 EmfPlusRecordHeader Header
;
500 DWORD ImageAttributesID
;
502 EmfPlusRectF SrcRect
;
506 EmfPlusPointR7 pointsR
[3];
507 EmfPlusPoint points
[3];
508 EmfPlusPointF pointsF
[3];
510 } EmfPlusDrawImagePoints
;
512 typedef struct EmfPlusDrawPath
514 EmfPlusRecordHeader Header
;
518 typedef struct EmfPlusDrawArc
520 EmfPlusRecordHeader Header
;
530 typedef struct EmfPlusDrawEllipse
532 EmfPlusRecordHeader Header
;
538 } EmfPlusDrawEllipse
;
540 typedef struct EmfPlusDrawPie
542 EmfPlusRecordHeader Header
;
552 typedef struct EmfPlusDrawRects
554 EmfPlusRecordHeader Header
;
559 EmfPlusRectF rectF
[1];
563 typedef struct EmfPlusFillPath
565 EmfPlusRecordHeader Header
;
573 typedef struct EmfPlusFillClosedCurve
575 EmfPlusRecordHeader Header
;
581 EmfPlusPointR7 pointsR
[1];
582 EmfPlusPoint points
[1];
583 EmfPlusPointF pointsF
[1];
585 } EmfPlusFillClosedCurve
;
587 typedef struct EmfPlusFillEllipse
589 EmfPlusRecordHeader Header
;
596 } EmfPlusFillEllipse
;
598 typedef struct EmfPlusFillPie
600 EmfPlusRecordHeader Header
;
611 typedef struct EmfPlusDrawDriverString
613 EmfPlusRecordHeader Header
;
619 DWORD DriverStringOptionsFlags
;
622 BYTE VariableData
[1];
623 } EmfPlusDrawDriverString
;
625 typedef struct EmfPlusFillRegion
627 EmfPlusRecordHeader Header
;
635 typedef struct EmfPlusOffsetClip
637 EmfPlusRecordHeader Header
;
642 typedef struct EmfPlusSetRenderingOrigin
644 EmfPlusRecordHeader Header
;
647 } EmfPlusSetRenderingOrigin
;
649 static void metafile_free_object_table_entry(GpMetafile
*metafile
, BYTE id
)
651 struct emfplus_object
*object
= &metafile
->objtable
[id
];
653 switch (object
->type
)
655 case ObjectTypeInvalid
:
657 case ObjectTypeBrush
:
658 GdipDeleteBrush(object
->u
.brush
);
661 GdipDeletePen(object
->u
.pen
);
664 GdipDeletePath(object
->u
.path
);
666 case ObjectTypeRegion
:
667 GdipDeleteRegion(object
->u
.region
);
669 case ObjectTypeImage
:
670 GdipDisposeImage(object
->u
.image
);
673 GdipDeleteFont(object
->u
.font
);
675 case ObjectTypeImageAttributes
:
676 GdipDisposeImageAttributes(object
->u
.image_attributes
);
679 FIXME("not implemented for object type %u.\n", object
->type
);
683 object
->type
= ObjectTypeInvalid
;
684 object
->u
.object
= NULL
;
687 void METAFILE_Free(GpMetafile
*metafile
)
691 free(metafile
->comment_data
);
692 DeleteEnhMetaFile(CloseEnhMetaFile(metafile
->record_dc
));
693 if (!metafile
->preserve_hemf
)
694 DeleteEnhMetaFile(metafile
->hemf
);
695 if (metafile
->record_graphics
)
697 WARN("metafile closed while recording\n");
698 /* not sure what to do here; for now just prevent the graphics from functioning or using this object */
699 metafile
->record_graphics
->image
= NULL
;
700 metafile
->record_graphics
->busy
= TRUE
;
703 if (metafile
->record_stream
)
704 IStream_Release(metafile
->record_stream
);
706 for (i
= 0; i
< ARRAY_SIZE(metafile
->objtable
); i
++)
707 metafile_free_object_table_entry(metafile
, i
);
710 static DWORD
METAFILE_AddObjectId(GpMetafile
*metafile
)
712 return (metafile
->next_object_id
++) % EmfPlusObjectTableSize
;
715 static GpStatus
METAFILE_AllocateRecord(GpMetafile
*metafile
, EmfPlusRecordType record_type
,
716 DWORD size
, void **result
)
719 EmfPlusRecordHeader
*record
;
721 if (!metafile
->comment_data_size
)
723 DWORD data_size
= max(256, size
* 2 + 4);
724 metafile
->comment_data
= calloc(1, data_size
);
726 if (!metafile
->comment_data
)
729 memcpy(metafile
->comment_data
, "EMF+", 4);
731 metafile
->comment_data_size
= data_size
;
732 metafile
->comment_data_length
= 4;
735 size_needed
= size
+ metafile
->comment_data_length
;
737 if (size_needed
> metafile
->comment_data_size
)
739 DWORD data_size
= size_needed
* 2;
740 BYTE
*new_data
= calloc(1, data_size
);
745 memcpy(new_data
, metafile
->comment_data
, metafile
->comment_data_length
);
747 metafile
->comment_data_size
= data_size
;
748 free(metafile
->comment_data
);
749 metafile
->comment_data
= new_data
;
752 *result
= metafile
->comment_data
+ metafile
->comment_data_length
;
753 metafile
->comment_data_length
+= size
;
755 record
= (EmfPlusRecordHeader
*)*result
;
756 record
->Type
= record_type
;
759 record
->DataSize
= size
- sizeof(EmfPlusRecordHeader
);
764 static void METAFILE_RemoveLastRecord(GpMetafile
*metafile
, EmfPlusRecordHeader
*record
)
766 assert(metafile
->comment_data
+ metafile
->comment_data_length
== (BYTE
*)record
+ record
->Size
);
767 metafile
->comment_data_length
-= record
->Size
;
770 static void METAFILE_WriteRecords(GpMetafile
*metafile
)
772 if (metafile
->comment_data_length
> 4)
774 GdiComment(metafile
->record_dc
, metafile
->comment_data_length
, metafile
->comment_data
);
775 metafile
->comment_data_length
= 4;
779 static GpStatus
METAFILE_WriteHeader(GpMetafile
*metafile
, HDC hdc
)
783 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
785 EmfPlusHeader
*header
;
787 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeHeader
, sizeof(EmfPlusHeader
), (void**)&header
);
791 if (metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
792 header
->Header
.Flags
= 1;
794 header
->Version
= VERSION_MAGIC2
;
796 if (GetDeviceCaps(hdc
, TECHNOLOGY
) == DT_RASDISPLAY
)
797 header
->EmfPlusFlags
= 1;
799 header
->EmfPlusFlags
= 0;
801 header
->LogicalDpiX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
802 header
->LogicalDpiY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
804 METAFILE_WriteRecords(metafile
);
810 static GpStatus
METAFILE_WriteEndOfFile(GpMetafile
*metafile
)
814 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
816 EmfPlusRecordHeader
*record
;
818 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeEndOfFile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
822 METAFILE_WriteRecords(metafile
);
828 GpStatus WINGDIPAPI
GdipRecordMetafile(HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
829 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
832 TRACE("(%p %d %s %d %p %p)\n", hdc
, type
, debugstr_rectf(frameRect
), frameUnit
, desc
, metafile
);
834 return GdipRecordMetafileFileName(NULL
, hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
837 /*****************************************************************************
838 * GdipRecordMetafileI [GDIPLUS.@]
840 GpStatus WINGDIPAPI
GdipRecordMetafileI(HDC hdc
, EmfType type
, GDIPCONST GpRect
*frameRect
,
841 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
843 GpRectF frameRectF
, *pFrameRectF
;
845 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
849 set_rect(&frameRectF
, frameRect
->X
, frameRect
->Y
, frameRect
->Width
, frameRect
->Height
);
850 pFrameRectF
= &frameRectF
;
855 return GdipRecordMetafile(hdc
, type
, pFrameRectF
, frameUnit
, desc
, metafile
);
858 GpStatus WINGDIPAPI
GdipRecordMetafileStreamI(IStream
*stream
, HDC hdc
, EmfType type
, GDIPCONST GpRect
*frameRect
,
859 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
861 GpRectF frameRectF
, *pFrameRectF
;
863 TRACE("(%p %p %d %p %d %p %p)\n", stream
, hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
867 set_rect(&frameRectF
, frameRect
->X
, frameRect
->Y
, frameRect
->Width
, frameRect
->Height
);
868 pFrameRectF
= &frameRectF
;
873 return GdipRecordMetafileStream(stream
, hdc
, type
, pFrameRectF
, frameUnit
, desc
, metafile
);
876 GpStatus WINGDIPAPI
GdipRecordMetafileStream(IStream
*stream
, HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
877 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
881 TRACE("(%p %p %d %s %d %p %p)\n", stream
, hdc
, type
, debugstr_rectf(frameRect
), frameUnit
, desc
, metafile
);
884 return InvalidParameter
;
886 stat
= GdipRecordMetafile(hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
890 (*metafile
)->record_stream
= stream
;
891 IStream_AddRef(stream
);
897 static void METAFILE_AdjustFrame(GpMetafile
* metafile
, const GpPointF
*points
,
902 if (!metafile
->auto_frame
|| !num_points
)
905 if (metafile
->auto_frame_max
.X
< metafile
->auto_frame_min
.X
)
906 metafile
->auto_frame_max
= metafile
->auto_frame_min
= points
[0];
908 for (i
=0; i
<num_points
; i
++)
910 if (points
[i
].X
< metafile
->auto_frame_min
.X
)
911 metafile
->auto_frame_min
.X
= points
[i
].X
;
912 if (points
[i
].X
> metafile
->auto_frame_max
.X
)
913 metafile
->auto_frame_max
.X
= points
[i
].X
;
914 if (points
[i
].Y
< metafile
->auto_frame_min
.Y
)
915 metafile
->auto_frame_min
.Y
= points
[i
].Y
;
916 if (points
[i
].Y
> metafile
->auto_frame_max
.Y
)
917 metafile
->auto_frame_max
.Y
= points
[i
].Y
;
921 GpStatus
METAFILE_GetGraphicsContext(GpMetafile
* metafile
, GpGraphics
**result
)
925 if (!metafile
->record_dc
|| metafile
->record_graphics
)
926 return InvalidParameter
;
928 stat
= graphics_from_image((GpImage
*)metafile
, &metafile
->record_graphics
);
932 *result
= metafile
->record_graphics
;
933 metafile
->record_graphics
->xres
= metafile
->logical_dpix
;
934 metafile
->record_graphics
->yres
= metafile
->logical_dpiy
;
935 metafile
->record_graphics
->printer_display
= metafile
->printer_display
;
941 GpStatus
METAFILE_GetDC(GpMetafile
* metafile
, HDC
*hdc
)
943 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
945 EmfPlusRecordHeader
*record
;
948 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeGetDC
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
952 METAFILE_WriteRecords(metafile
);
955 *hdc
= metafile
->record_dc
;
960 GpStatus
METAFILE_GraphicsClear(GpMetafile
* metafile
, ARGB color
)
962 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
964 EmfPlusClear
*record
;
967 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeClear
, sizeof(EmfPlusClear
), (void**)&record
);
971 record
->Color
= color
;
973 METAFILE_WriteRecords(metafile
);
979 static BOOL
is_integer_rect(const GpRectF
*rect
)
981 SHORT x
, y
, width
, height
;
985 height
= rect
->Height
;
986 if (rect
->X
!= (REAL
)x
|| rect
->Y
!= (REAL
)y
||
987 rect
->Width
!= (REAL
)width
|| rect
->Height
!= (REAL
)height
)
992 static GpStatus
METAFILE_PrepareBrushData(GDIPCONST GpBrush
*brush
, DWORD
*size
)
996 case BrushTypeSolidColor
:
997 *size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
) + sizeof(EmfPlusSolidBrushData
);
999 case BrushTypeHatchFill
:
1000 *size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
) + sizeof(EmfPlusHatchBrushData
);
1002 case BrushTypeLinearGradient
:
1005 GpLineGradient
*gradient
= (GpLineGradient
*)brush
;
1007 *size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
.lineargradient
.OptionalData
);
1009 GdipIsMatrixIdentity(&gradient
->transform
, &ignore_xform
);
1011 *size
+= sizeof(gradient
->transform
);
1013 if (gradient
->pblendcount
> 1 && gradient
->pblendcolor
&& gradient
->pblendpos
)
1014 *size
+= sizeof(DWORD
) + gradient
->pblendcount
*
1015 (sizeof(*gradient
->pblendcolor
) + sizeof(*gradient
->pblendpos
));
1016 else if (gradient
->blendcount
> 1 && gradient
->blendfac
&& gradient
->blendpos
)
1017 *size
+= sizeof(DWORD
) + gradient
->blendcount
*
1018 (sizeof(*gradient
->blendfac
) + sizeof(*gradient
->blendpos
));
1023 FIXME("unsupported brush type: %d\n", brush
->bt
);
1024 return NotImplemented
;
1030 static void METAFILE_FillBrushData(GDIPCONST GpBrush
*brush
, EmfPlusBrush
*data
)
1032 data
->Version
= VERSION_MAGIC2
;
1033 data
->Type
= brush
->bt
;
1037 case BrushTypeSolidColor
:
1039 GpSolidFill
*solid
= (GpSolidFill
*)brush
;
1040 data
->BrushData
.solid
.SolidColor
= solid
->color
;
1043 case BrushTypeHatchFill
:
1045 GpHatch
*hatch
= (GpHatch
*)brush
;
1046 data
->BrushData
.hatch
.HatchStyle
= hatch
->hatchstyle
;
1047 data
->BrushData
.hatch
.ForeColor
= hatch
->forecol
;
1048 data
->BrushData
.hatch
.BackColor
= hatch
->backcol
;
1051 case BrushTypeLinearGradient
:
1055 GpLineGradient
*gradient
= (GpLineGradient
*)brush
;
1057 data
->BrushData
.lineargradient
.BrushDataFlags
= 0;
1058 data
->BrushData
.lineargradient
.WrapMode
= gradient
->wrap
;
1059 data
->BrushData
.lineargradient
.RectF
.X
= gradient
->rect
.X
;
1060 data
->BrushData
.lineargradient
.RectF
.Y
= gradient
->rect
.Y
;
1061 data
->BrushData
.lineargradient
.RectF
.Width
= gradient
->rect
.Width
;
1062 data
->BrushData
.lineargradient
.RectF
.Height
= gradient
->rect
.Height
;
1063 data
->BrushData
.lineargradient
.StartColor
= gradient
->startcolor
;
1064 data
->BrushData
.lineargradient
.EndColor
= gradient
->endcolor
;
1065 data
->BrushData
.lineargradient
.Reserved1
= gradient
->startcolor
;
1066 data
->BrushData
.lineargradient
.Reserved2
= gradient
->endcolor
;
1068 if (gradient
->gamma
)
1069 data
->BrushData
.lineargradient
.BrushDataFlags
|= BrushDataIsGammaCorrected
;
1071 cursor
= &data
->BrushData
.lineargradient
.OptionalData
[0];
1073 GdipIsMatrixIdentity(&gradient
->transform
, &ignore_xform
);
1076 data
->BrushData
.lineargradient
.BrushDataFlags
|= BrushDataTransform
;
1077 memcpy(cursor
, &gradient
->transform
, sizeof(gradient
->transform
));
1078 cursor
+= sizeof(gradient
->transform
);
1081 if (gradient
->pblendcount
> 1 && gradient
->pblendcolor
&& gradient
->pblendpos
)
1083 const DWORD count
= gradient
->pblendcount
;
1085 data
->BrushData
.lineargradient
.BrushDataFlags
|= BrushDataPresetColors
;
1087 memcpy(cursor
, &count
, sizeof(count
));
1088 cursor
+= sizeof(count
);
1090 memcpy(cursor
, gradient
->pblendpos
, count
* sizeof(*gradient
->pblendpos
));
1091 cursor
+= count
* sizeof(*gradient
->pblendpos
);
1093 memcpy(cursor
, gradient
->pblendcolor
, count
* sizeof(*gradient
->pblendcolor
));
1095 else if (gradient
->blendcount
> 1 && gradient
->blendfac
&& gradient
->blendpos
)
1097 const DWORD count
= gradient
->blendcount
;
1099 data
->BrushData
.lineargradient
.BrushDataFlags
|= BrushDataBlendFactorsH
;
1101 memcpy(cursor
, &count
, sizeof(count
));
1102 cursor
+= sizeof(count
);
1104 memcpy(cursor
, gradient
->blendpos
, count
* sizeof(*gradient
->blendpos
));
1105 cursor
+= count
* sizeof(*gradient
->blendpos
);
1107 memcpy(cursor
, gradient
->blendfac
, count
* sizeof(*gradient
->blendfac
));
1113 FIXME("unsupported brush type: %d\n", brush
->bt
);
1117 static void METAFILE_PrepareCustomLineCapData(GDIPCONST GpCustomLineCap
*cap
, DWORD
*ret_cap_size
,
1118 DWORD
*ret_cap_data_size
, DWORD
*ret_path_size
)
1120 DWORD cap_size
, path_size
= 0;
1122 /* EmfPlusCustomStartCapData */
1123 cap_size
= FIELD_OFFSET(EmfPlusCustomStartCapData
, data
);
1124 /* -> EmfPlusCustomLineCap */
1125 cap_size
+= FIELD_OFFSET(EmfPlusCustomLineCap
, CustomLineCapData
);
1126 /* -> EmfPlusCustomLineCapArrowData */
1127 if (cap
->type
== CustomLineCapTypeAdjustableArrow
)
1128 cap_size
+= sizeof(EmfPlusCustomLineCapArrowData
);
1129 /* -> EmfPlusCustomLineCapData */
1132 /* -> EmfPlusCustomLineCapOptionalData */
1133 cap_size
+= FIELD_OFFSET(EmfPlusCustomLineCapData
, OptionalData
);
1135 /* -> EmfPlusCustomLineCapDataFillPath */
1136 cap_size
+= FIELD_OFFSET(EmfPlusCustomLineCapDataFillPath
, FillPath
);
1138 /* -> EmfPlusCustomLineCapDataLinePath */
1139 cap_size
+= FIELD_OFFSET(EmfPlusCustomLineCapDataLinePath
, LinePath
);
1141 /* -> EmfPlusPath in EmfPlusCustomLineCapDataFillPath and EmfPlusCustomLineCapDataLinePath */
1142 path_size
= FIELD_OFFSET(EmfPlusPath
, data
);
1143 path_size
+= sizeof(PointF
) * cap
->pathdata
.Count
;
1144 path_size
+= sizeof(BYTE
) * cap
->pathdata
.Count
;
1145 path_size
= (path_size
+ 3) & ~3;
1147 cap_size
+= path_size
;
1150 *ret_cap_size
= cap_size
;
1151 *ret_cap_data_size
= cap_size
- FIELD_OFFSET(EmfPlusCustomStartCapData
, data
);
1152 *ret_path_size
= path_size
;
1155 static void METAFILE_FillCustomLineCapData(GDIPCONST GpCustomLineCap
*cap
, BYTE
*ptr
,
1156 REAL line_miter_limit
, DWORD data_size
, DWORD path_size
)
1158 EmfPlusCustomStartCapData
*cap_data
;
1159 EmfPlusCustomLineCap
*line_cap
;
1162 cap_data
= (EmfPlusCustomStartCapData
*)ptr
;
1163 cap_data
->CustomStartCapSize
= data_size
;
1164 i
= FIELD_OFFSET(EmfPlusCustomStartCapData
, data
);
1166 line_cap
= (EmfPlusCustomLineCap
*)(ptr
+ i
);
1167 line_cap
->Version
= VERSION_MAGIC2
;
1168 line_cap
->Type
= cap
->type
;
1169 i
+= FIELD_OFFSET(EmfPlusCustomLineCap
, CustomLineCapData
);
1171 if (cap
->type
== CustomLineCapTypeAdjustableArrow
)
1173 EmfPlusCustomLineCapArrowData
*arrow_data
;
1174 GpAdjustableArrowCap
*arrow_cap
;
1176 arrow_data
= (EmfPlusCustomLineCapArrowData
*)(ptr
+ i
);
1177 arrow_cap
= (GpAdjustableArrowCap
*)cap
;
1178 arrow_data
->Width
= arrow_cap
->width
;
1179 arrow_data
->Height
= arrow_cap
->height
;
1180 arrow_data
->MiddleInset
= arrow_cap
->middle_inset
;
1181 arrow_data
->FillState
= arrow_cap
->cap
.fill
;
1182 arrow_data
->LineStartCap
= arrow_cap
->cap
.strokeStartCap
;
1183 arrow_data
->LineEndCap
= arrow_cap
->cap
.strokeEndCap
;
1184 arrow_data
->LineJoin
= arrow_cap
->cap
.join
;
1185 arrow_data
->LineMiterLimit
= line_miter_limit
;
1186 arrow_data
->WidthScale
= arrow_cap
->cap
.scale
;
1187 arrow_data
->FillHotSpot
.X
= 0;
1188 arrow_data
->FillHotSpot
.Y
= 0;
1189 arrow_data
->LineHotSpot
.X
= 0;
1190 arrow_data
->LineHotSpot
.Y
= 0;
1194 EmfPlusCustomLineCapData
*line_cap_data
= (EmfPlusCustomLineCapData
*)(ptr
+ i
);
1198 line_cap_data
->CustomLineCapDataFlags
= CustomLineCapDataFillPath
;
1200 line_cap_data
->CustomLineCapDataFlags
= CustomLineCapDataLinePath
;
1201 line_cap_data
->BaseCap
= cap
->basecap
;
1202 line_cap_data
->BaseInset
= cap
->inset
;
1203 line_cap_data
->StrokeStartCap
= cap
->strokeStartCap
;
1204 line_cap_data
->StrokeEndCap
= cap
->strokeEndCap
;
1205 line_cap_data
->StrokeJoin
= cap
->join
;
1206 line_cap_data
->StrokeMiterLimit
= line_miter_limit
;
1207 line_cap_data
->WidthScale
= cap
->scale
;
1208 line_cap_data
->FillHotSpot
.X
= 0;
1209 line_cap_data
->FillHotSpot
.Y
= 0;
1210 line_cap_data
->LineHotSpot
.X
= 0;
1211 line_cap_data
->LineHotSpot
.Y
= 0;
1212 i
+= FIELD_OFFSET(EmfPlusCustomLineCapData
, OptionalData
);
1216 EmfPlusCustomLineCapDataFillPath
*fill_path
= (EmfPlusCustomLineCapDataFillPath
*)(ptr
+ i
);
1217 fill_path
->FillPathLength
= path_size
;
1218 i
+= FIELD_OFFSET(EmfPlusCustomLineCapDataFillPath
, FillPath
);
1222 EmfPlusCustomLineCapDataLinePath
*line_path
= (EmfPlusCustomLineCapDataLinePath
*)(ptr
+ i
);
1223 line_path
->LinePathLength
= path_size
;
1224 i
+= FIELD_OFFSET(EmfPlusCustomLineCapDataLinePath
, LinePath
);
1227 path
= (EmfPlusPath
*)(ptr
+ i
);
1228 path
->Version
= VERSION_MAGIC2
;
1229 path
->PathPointCount
= cap
->pathdata
.Count
;
1230 path
->PathPointFlags
= 0;
1231 i
+= FIELD_OFFSET(EmfPlusPath
, data
);
1232 memcpy(ptr
+ i
, cap
->pathdata
.Points
, cap
->pathdata
.Count
* sizeof(PointF
));
1233 i
+= cap
->pathdata
.Count
* sizeof(PointF
);
1234 memcpy(ptr
+ i
, cap
->pathdata
.Types
, cap
->pathdata
.Count
* sizeof(BYTE
));
1238 static GpStatus
METAFILE_AddBrushObject(GpMetafile
*metafile
, GDIPCONST GpBrush
*brush
, DWORD
*id
)
1240 EmfPlusObject
*object_record
;
1245 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
1248 stat
= METAFILE_PrepareBrushData(brush
, &size
);
1249 if (stat
!= Ok
) return stat
;
1251 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
1252 FIELD_OFFSET(EmfPlusObject
, ObjectData
) + size
, (void**)&object_record
);
1253 if (stat
!= Ok
) return stat
;
1255 *id
= METAFILE_AddObjectId(metafile
);
1256 object_record
->Header
.Flags
= *id
| ObjectTypeBrush
<< 8;
1257 METAFILE_FillBrushData(brush
, &object_record
->ObjectData
.brush
);
1261 GpStatus
METAFILE_FillRectangles(GpMetafile
* metafile
, GpBrush
* brush
,
1262 GDIPCONST GpRectF
* rects
, INT count
)
1264 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1266 EmfPlusFillRects
*record
;
1268 BOOL integer_rects
= TRUE
;
1273 if (brush
->bt
== BrushTypeSolidColor
)
1276 brushid
= ((GpSolidFill
*)brush
)->color
;
1280 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brushid
);
1285 for (i
=0; i
<count
; i
++)
1287 if (!is_integer_rect(&rects
[i
]))
1289 integer_rects
= FALSE
;
1297 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeFillRects
,
1298 sizeof(EmfPlusFillRects
) + count
* (integer_rects
? sizeof(EmfPlusRect
) : sizeof(GpRectF
)),
1303 record
->Header
.Flags
= flags
;
1304 record
->BrushID
= brushid
;
1305 record
->Count
= count
;
1309 EmfPlusRect
*record_rects
= (EmfPlusRect
*)(record
+1);
1310 for (i
=0; i
<count
; i
++)
1312 record_rects
[i
].X
= (SHORT
)rects
[i
].X
;
1313 record_rects
[i
].Y
= (SHORT
)rects
[i
].Y
;
1314 record_rects
[i
].Width
= (SHORT
)rects
[i
].Width
;
1315 record_rects
[i
].Height
= (SHORT
)rects
[i
].Height
;
1319 memcpy(record
+1, rects
, sizeof(GpRectF
) * count
);
1321 METAFILE_WriteRecords(metafile
);
1324 if (metafile
->auto_frame
)
1326 GpPointF corners
[4];
1329 for (i
=0; i
<count
; i
++)
1331 corners
[0].X
= rects
[i
].X
;
1332 corners
[0].Y
= rects
[i
].Y
;
1333 corners
[1].X
= rects
[i
].X
+ rects
[i
].Width
;
1334 corners
[1].Y
= rects
[i
].Y
;
1335 corners
[2].X
= rects
[i
].X
;
1336 corners
[2].Y
= rects
[i
].Y
+ rects
[i
].Height
;
1337 corners
[3].X
= rects
[i
].X
+ rects
[i
].Width
;
1338 corners
[3].Y
= rects
[i
].Y
+ rects
[i
].Height
;
1340 GdipTransformPoints(metafile
->record_graphics
, CoordinateSpaceDevice
,
1341 CoordinateSpaceWorld
, corners
, 4);
1343 METAFILE_AdjustFrame(metafile
, corners
, 4);
1350 GpStatus
METAFILE_SetClipRect(GpMetafile
* metafile
, REAL x
, REAL y
, REAL width
, REAL height
, CombineMode mode
)
1352 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1354 EmfPlusSetClipRect
*record
;
1357 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSetClipRect
,
1358 sizeof(EmfPlusSetClipRect
), (void **)&record
);
1362 record
->Header
.Flags
= (mode
& 0xf) << 8;
1363 record
->ClipRect
.X
= x
;
1364 record
->ClipRect
.Y
= y
;
1365 record
->ClipRect
.Width
= width
;
1366 record
->ClipRect
.Height
= height
;
1368 METAFILE_WriteRecords(metafile
);
1374 static GpStatus
METAFILE_AddRegionObject(GpMetafile
*metafile
, GpRegion
*region
, DWORD
*id
)
1376 EmfPlusObject
*object_record
;
1381 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
1384 size
= write_region_data(region
, NULL
);
1385 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
1386 FIELD_OFFSET(EmfPlusObject
, ObjectData
.region
) + size
, (void**)&object_record
);
1387 if (stat
!= Ok
) return stat
;
1389 *id
= METAFILE_AddObjectId(metafile
);
1390 object_record
->Header
.Flags
= *id
| ObjectTypeRegion
<< 8;
1391 write_region_data(region
, &object_record
->ObjectData
.region
);
1395 GpStatus
METAFILE_SetClipRegion(GpMetafile
* metafile
, GpRegion
* region
, CombineMode mode
)
1397 EmfPlusRecordHeader
*record
;
1401 if (metafile
->metafile_type
== MetafileTypeEmf
)
1404 return NotImplemented
;
1407 stat
= METAFILE_AddRegionObject(metafile
, region
, ®ion_id
);
1408 if (stat
!= Ok
) return stat
;
1410 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSetClipRegion
, sizeof(*record
), (void**)&record
);
1411 if (stat
!= Ok
) return stat
;
1413 record
->Flags
= region_id
| mode
<< 8;
1415 METAFILE_WriteRecords(metafile
);
1419 GpStatus
METAFILE_SetPageTransform(GpMetafile
* metafile
, GpUnit unit
, REAL scale
)
1421 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1423 EmfPlusSetPageTransform
*record
;
1426 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSetPageTransform
,
1427 sizeof(EmfPlusSetPageTransform
), (void **)&record
);
1431 record
->Header
.Flags
= unit
;
1432 record
->PageScale
= scale
;
1434 METAFILE_WriteRecords(metafile
);
1440 GpStatus
METAFILE_SetWorldTransform(GpMetafile
* metafile
, GDIPCONST GpMatrix
* transform
)
1442 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1444 EmfPlusSetWorldTransform
*record
;
1447 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSetWorldTransform
,
1448 sizeof(EmfPlusSetWorldTransform
), (void **)&record
);
1452 memcpy(record
->MatrixData
, transform
->matrix
, sizeof(record
->MatrixData
));
1454 METAFILE_WriteRecords(metafile
);
1460 GpStatus
METAFILE_ScaleWorldTransform(GpMetafile
* metafile
, REAL sx
, REAL sy
, MatrixOrder order
)
1462 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1464 EmfPlusScaleWorldTransform
*record
;
1467 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeScaleWorldTransform
,
1468 sizeof(EmfPlusScaleWorldTransform
), (void **)&record
);
1472 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1476 METAFILE_WriteRecords(metafile
);
1482 GpStatus
METAFILE_MultiplyWorldTransform(GpMetafile
* metafile
, GDIPCONST GpMatrix
* matrix
, MatrixOrder order
)
1484 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1486 EmfPlusMultiplyWorldTransform
*record
;
1489 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeMultiplyWorldTransform
,
1490 sizeof(EmfPlusMultiplyWorldTransform
), (void **)&record
);
1494 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1495 memcpy(record
->MatrixData
, matrix
->matrix
, sizeof(record
->MatrixData
));
1497 METAFILE_WriteRecords(metafile
);
1503 GpStatus
METAFILE_RotateWorldTransform(GpMetafile
* metafile
, REAL angle
, MatrixOrder order
)
1505 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1507 EmfPlusRotateWorldTransform
*record
;
1510 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeRotateWorldTransform
,
1511 sizeof(EmfPlusRotateWorldTransform
), (void **)&record
);
1515 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1516 record
->Angle
= angle
;
1518 METAFILE_WriteRecords(metafile
);
1524 GpStatus
METAFILE_TranslateWorldTransform(GpMetafile
* metafile
, REAL dx
, REAL dy
, MatrixOrder order
)
1526 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1528 EmfPlusTranslateWorldTransform
*record
;
1531 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeTranslateWorldTransform
,
1532 sizeof(EmfPlusTranslateWorldTransform
), (void **)&record
);
1536 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1540 METAFILE_WriteRecords(metafile
);
1546 GpStatus
METAFILE_ResetWorldTransform(GpMetafile
* metafile
)
1548 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1550 EmfPlusRecordHeader
*record
;
1553 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeResetWorldTransform
,
1554 sizeof(EmfPlusRecordHeader
), (void **)&record
);
1558 METAFILE_WriteRecords(metafile
);
1564 GpStatus
METAFILE_BeginContainer(GpMetafile
* metafile
, GDIPCONST GpRectF
*dstrect
,
1565 GDIPCONST GpRectF
*srcrect
, GpUnit unit
, DWORD StackIndex
)
1567 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1569 EmfPlusBeginContainer
*record
;
1572 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeBeginContainer
, sizeof(*record
), (void**)&record
);
1576 record
->Header
.Flags
= unit
& 0xff;
1577 record
->DestRect
= *dstrect
;
1578 record
->SrcRect
= *srcrect
;
1579 record
->StackIndex
= StackIndex
;
1581 METAFILE_WriteRecords(metafile
);
1587 GpStatus
METAFILE_BeginContainerNoParams(GpMetafile
* metafile
, DWORD StackIndex
)
1589 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1591 EmfPlusContainerRecord
*record
;
1594 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeBeginContainerNoParams
,
1595 sizeof(EmfPlusContainerRecord
), (void **)&record
);
1599 record
->StackIndex
= StackIndex
;
1601 METAFILE_WriteRecords(metafile
);
1607 GpStatus
METAFILE_EndContainer(GpMetafile
* metafile
, DWORD StackIndex
)
1609 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1611 EmfPlusContainerRecord
*record
;
1614 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeEndContainer
,
1615 sizeof(EmfPlusContainerRecord
), (void **)&record
);
1619 record
->StackIndex
= StackIndex
;
1621 METAFILE_WriteRecords(metafile
);
1627 GpStatus
METAFILE_SaveGraphics(GpMetafile
* metafile
, DWORD StackIndex
)
1629 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1631 EmfPlusContainerRecord
*record
;
1634 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSave
,
1635 sizeof(EmfPlusContainerRecord
), (void **)&record
);
1639 record
->StackIndex
= StackIndex
;
1641 METAFILE_WriteRecords(metafile
);
1647 GpStatus
METAFILE_RestoreGraphics(GpMetafile
* metafile
, DWORD StackIndex
)
1649 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1651 EmfPlusContainerRecord
*record
;
1654 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeRestore
,
1655 sizeof(EmfPlusContainerRecord
), (void **)&record
);
1659 record
->StackIndex
= StackIndex
;
1661 METAFILE_WriteRecords(metafile
);
1667 GpStatus
METAFILE_ReleaseDC(GpMetafile
* metafile
, HDC hdc
)
1669 if (hdc
!= metafile
->record_dc
)
1670 return InvalidParameter
;
1675 GpStatus
METAFILE_GraphicsDeleted(GpMetafile
* metafile
)
1679 stat
= METAFILE_WriteEndOfFile(metafile
);
1680 metafile
->record_graphics
= NULL
;
1682 metafile
->hemf
= CloseEnhMetaFile(metafile
->record_dc
);
1683 metafile
->record_dc
= NULL
;
1685 free(metafile
->comment_data
);
1686 metafile
->comment_data
= NULL
;
1687 metafile
->comment_data_size
= 0;
1691 MetafileHeader header
;
1693 stat
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, &header
);
1694 if (stat
== Ok
&& metafile
->auto_frame
&&
1695 metafile
->auto_frame_max
.X
>= metafile
->auto_frame_min
.X
)
1697 RECTL bounds_rc
, gdi_bounds_rc
;
1698 REAL x_scale
= 2540.0 / header
.DpiX
;
1699 REAL y_scale
= 2540.0 / header
.DpiY
;
1703 gdi_bounds_rc
= header
.EmfHeader
.rclBounds
;
1704 if (gdi_bounds_rc
.right
> gdi_bounds_rc
.left
&&
1705 gdi_bounds_rc
.bottom
> gdi_bounds_rc
.top
)
1707 GpPointF
*af_min
= &metafile
->auto_frame_min
;
1708 GpPointF
*af_max
= &metafile
->auto_frame_max
;
1710 af_min
->X
= fmin(af_min
->X
, gdi_bounds_rc
.left
);
1711 af_min
->Y
= fmin(af_min
->Y
, gdi_bounds_rc
.top
);
1712 af_max
->X
= fmax(af_max
->X
, gdi_bounds_rc
.right
);
1713 af_max
->Y
= fmax(af_max
->Y
, gdi_bounds_rc
.bottom
);
1716 bounds_rc
.left
= floorf(metafile
->auto_frame_min
.X
* x_scale
);
1717 bounds_rc
.top
= floorf(metafile
->auto_frame_min
.Y
* y_scale
);
1718 bounds_rc
.right
= ceilf(metafile
->auto_frame_max
.X
* x_scale
);
1719 bounds_rc
.bottom
= ceilf(metafile
->auto_frame_max
.Y
* y_scale
);
1721 buffer_size
= GetEnhMetaFileBits(metafile
->hemf
, 0, NULL
);
1722 buffer
= malloc(buffer_size
);
1725 HENHMETAFILE new_hemf
;
1727 GetEnhMetaFileBits(metafile
->hemf
, buffer_size
, buffer
);
1729 ((ENHMETAHEADER
*)buffer
)->rclFrame
= bounds_rc
;
1731 new_hemf
= SetEnhMetaFileBits(buffer_size
, buffer
);
1735 DeleteEnhMetaFile(metafile
->hemf
);
1736 metafile
->hemf
= new_hemf
;
1747 stat
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, &header
);
1751 metafile
->bounds
.X
= header
.X
;
1752 metafile
->bounds
.Y
= header
.Y
;
1753 metafile
->bounds
.Width
= header
.Width
;
1754 metafile
->bounds
.Height
= header
.Height
;
1758 if (stat
== Ok
&& metafile
->record_stream
)
1763 buffer_size
= GetEnhMetaFileBits(metafile
->hemf
, 0, NULL
);
1765 buffer
= malloc(buffer_size
);
1770 GetEnhMetaFileBits(metafile
->hemf
, buffer_size
, buffer
);
1772 hr
= IStream_Write(metafile
->record_stream
, buffer
, buffer_size
, NULL
);
1775 stat
= hresult_to_status(hr
);
1783 if (metafile
->record_stream
)
1785 IStream_Release(metafile
->record_stream
);
1786 metafile
->record_stream
= NULL
;
1792 GpStatus WINGDIPAPI
GdipGetHemfFromMetafile(GpMetafile
*metafile
, HENHMETAFILE
*hEmf
)
1794 TRACE("(%p,%p)\n", metafile
, hEmf
);
1796 if (!metafile
|| !hEmf
|| !metafile
->hemf
)
1797 return InvalidParameter
;
1799 *hEmf
= metafile
->hemf
;
1800 metafile
->hemf
= NULL
;
1805 static GpStatus
METAFILE_PlaybackGetDC(GpMetafile
*metafile
)
1809 stat
= GdipGetDC(metafile
->playback_graphics
, &metafile
->playback_dc
);
1814 static void METAFILE_PlaybackReleaseDC(GpMetafile
*metafile
)
1816 if (metafile
->playback_dc
)
1818 GdipReleaseDC(metafile
->playback_graphics
, metafile
->playback_dc
);
1819 metafile
->playback_dc
= NULL
;
1823 static GpStatus
METAFILE_PlaybackUpdateClip(GpMetafile
*metafile
)
1826 stat
= GdipCombineRegionRegion(metafile
->playback_graphics
->clip
, metafile
->base_clip
, CombineModeReplace
);
1828 stat
= GdipCombineRegionRegion(metafile
->playback_graphics
->clip
, metafile
->clip
, CombineModeIntersect
);
1832 static GpStatus
METAFILE_PlaybackUpdateWorldTransform(GpMetafile
*metafile
)
1834 GpMatrix
*real_transform
;
1837 stat
= GdipCreateMatrix3(&metafile
->src_rect
, metafile
->playback_points
, &real_transform
);
1841 REAL scale_x
= units_to_pixels(1.0, metafile
->page_unit
, metafile
->logical_dpix
, metafile
->printer_display
);
1842 REAL scale_y
= units_to_pixels(1.0, metafile
->page_unit
, metafile
->logical_dpiy
, metafile
->printer_display
);
1844 if (metafile
->page_unit
!= UnitDisplay
)
1846 scale_x
*= metafile
->page_scale
;
1847 scale_y
*= metafile
->page_scale
;
1850 stat
= GdipScaleMatrix(real_transform
, scale_x
, scale_y
, MatrixOrderPrepend
);
1853 stat
= GdipMultiplyMatrix(real_transform
, metafile
->world_transform
, MatrixOrderPrepend
);
1856 stat
= GdipSetWorldTransform(metafile
->playback_graphics
, real_transform
);
1858 GdipDeleteMatrix(real_transform
);
1864 static void metafile_set_object_table_entry(GpMetafile
*metafile
, BYTE id
, BYTE type
, void *object
)
1866 metafile_free_object_table_entry(metafile
, id
);
1867 metafile
->objtable
[id
].type
= type
;
1868 metafile
->objtable
[id
].u
.object
= object
;
1871 static GpStatus
metafile_deserialize_image(const BYTE
*record_data
, UINT data_size
, GpImage
**image
)
1873 EmfPlusImage
*data
= (EmfPlusImage
*)record_data
;
1878 if (data_size
< FIELD_OFFSET(EmfPlusImage
, ImageData
))
1879 return InvalidParameter
;
1880 data_size
-= FIELD_OFFSET(EmfPlusImage
, ImageData
);
1884 case ImageDataTypeBitmap
:
1886 EmfPlusBitmap
*bitmapdata
= &data
->ImageData
.bitmap
;
1888 if (data_size
<= FIELD_OFFSET(EmfPlusBitmap
, BitmapData
))
1889 return InvalidParameter
;
1890 data_size
-= FIELD_OFFSET(EmfPlusBitmap
, BitmapData
);
1892 switch (bitmapdata
->Type
)
1894 case BitmapDataTypePixel
:
1896 ColorPalette
*palette
;
1899 if (bitmapdata
->PixelFormat
& PixelFormatIndexed
)
1901 EmfPlusPalette
*palette_obj
= (EmfPlusPalette
*)bitmapdata
->BitmapData
;
1902 UINT palette_size
= FIELD_OFFSET(EmfPlusPalette
, PaletteEntries
);
1904 if (data_size
<= palette_size
)
1905 return InvalidParameter
;
1906 palette_size
+= palette_obj
->PaletteCount
* sizeof(EmfPlusARGB
);
1908 if (data_size
< palette_size
)
1909 return InvalidParameter
;
1910 data_size
-= palette_size
;
1912 palette
= (ColorPalette
*)bitmapdata
->BitmapData
;
1913 scan0
= (BYTE
*)bitmapdata
->BitmapData
+ palette_size
;
1918 scan0
= bitmapdata
->BitmapData
;
1921 if (data_size
< bitmapdata
->Height
* bitmapdata
->Stride
)
1922 return InvalidParameter
;
1924 status
= GdipCreateBitmapFromScan0(bitmapdata
->Width
, bitmapdata
->Height
, bitmapdata
->Stride
,
1925 bitmapdata
->PixelFormat
, scan0
, (GpBitmap
**)image
);
1926 if (status
== Ok
&& palette
)
1928 status
= GdipSetImagePalette(*image
, palette
);
1931 GdipDisposeImage(*image
);
1937 case BitmapDataTypeCompressed
:
1939 IWICImagingFactory
*factory
;
1943 if (WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION
, &factory
) != S_OK
)
1944 return GenericError
;
1946 hr
= IWICImagingFactory_CreateStream(factory
, &stream
);
1947 IWICImagingFactory_Release(factory
);
1949 return GenericError
;
1951 if (IWICStream_InitializeFromMemory(stream
, bitmapdata
->BitmapData
, data_size
) == S_OK
)
1952 status
= GdipCreateBitmapFromStream((IStream
*)stream
, (GpBitmap
**)image
);
1954 status
= GenericError
;
1956 IWICStream_Release(stream
);
1960 WARN("Invalid bitmap type %ld.\n", bitmapdata
->Type
);
1961 return InvalidParameter
;
1965 case ImageDataTypeMetafile
:
1967 EmfPlusMetafile
*metafiledata
= &data
->ImageData
.metafile
;
1969 if (data_size
<= FIELD_OFFSET(EmfPlusMetafile
, MetafileData
))
1970 return InvalidParameter
;
1971 data_size
-= FIELD_OFFSET(EmfPlusMetafile
, MetafileData
);
1973 switch (metafiledata
->Type
) {
1974 case MetafileTypeEmf
:
1975 case MetafileTypeEmfPlusOnly
:
1976 case MetafileTypeEmfPlusDual
:
1980 hemf
= SetEnhMetaFileBits(data_size
, metafiledata
->MetafileData
);
1983 return GenericError
;
1985 status
= GdipCreateMetafileFromEmf(hemf
, TRUE
, (GpMetafile
**)image
);
1988 DeleteEnhMetaFile(hemf
);
1993 FIXME("metafile type %ld not supported.\n", metafiledata
->Type
);
1994 return NotImplemented
;
1999 FIXME("image type %d not supported.\n", data
->Type
);
2000 return NotImplemented
;
2006 static GpStatus
metafile_deserialize_path(const BYTE
*record_data
, UINT data_size
, GpPath
**path
)
2008 EmfPlusPath
*data
= (EmfPlusPath
*)record_data
;
2015 if (data_size
<= FIELD_OFFSET(EmfPlusPath
, data
))
2016 return InvalidParameter
;
2017 data_size
-= FIELD_OFFSET(EmfPlusPath
, data
);
2019 if (data
->PathPointFlags
& 0x800) /* R */
2021 FIXME("RLE encoded path data is not supported.\n");
2022 return NotImplemented
;
2026 if (data
->PathPointFlags
& 0x4000) /* C */
2027 size
= sizeof(EmfPlusPoint
);
2029 size
= sizeof(EmfPlusPointF
);
2030 size
+= sizeof(BYTE
); /* EmfPlusPathPointType */
2031 size
*= data
->PathPointCount
;
2034 if (data_size
< size
)
2035 return InvalidParameter
;
2037 if (data
->PathPointCount
)
2039 if (data
->PathPointFlags
& 0x4000) /* C */
2041 EmfPlusPoint
*points
= (EmfPlusPoint
*)data
->data
;
2042 GpPointF
*temp
= malloc(sizeof(GpPointF
) * data
->PathPointCount
);
2044 for (i
= 0; i
< data
->PathPointCount
; i
++)
2046 temp
[i
].X
= points
[i
].X
;
2047 temp
[i
].Y
= points
[i
].Y
;
2050 types
= (BYTE
*)(points
+ i
);
2051 GdipCreatePath2(temp
, types
, data
->PathPointCount
, FillModeAlternate
, path
);
2056 EmfPlusPointF
*points
= (EmfPlusPointF
*)data
->data
;
2057 types
= (BYTE
*)(points
+ data
->PathPointCount
);
2058 return GdipCreatePath2((GpPointF
*)points
, types
, data
->PathPointCount
, FillModeAlternate
, path
);
2063 return GdipCreatePath(FillModeAlternate
, path
);
2069 static GpStatus
metafile_read_region_node(struct memory_buffer
*mbuf
, GpRegion
*region
, region_element
*node
, UINT
*count
)
2074 type
= buffer_read(mbuf
, sizeof(*type
));
2075 if (!type
) return Ok
;
2081 case CombineModeReplace
:
2082 case CombineModeIntersect
:
2083 case CombineModeUnion
:
2084 case CombineModeXor
:
2085 case CombineModeExclude
:
2086 case CombineModeComplement
:
2088 region_element
*left
, *right
;
2090 left
= calloc(1, sizeof(*left
));
2094 right
= calloc(1, sizeof(*right
));
2101 status
= metafile_read_region_node(mbuf
, region
, left
, count
);
2104 status
= metafile_read_region_node(mbuf
, region
, right
, count
);
2107 node
->elementdata
.combine
.left
= left
;
2108 node
->elementdata
.combine
.right
= right
;
2109 region
->num_children
+= 2;
2118 case RegionDataRect
:
2120 const EmfPlusRectF
*rect
;
2122 rect
= buffer_read(mbuf
, sizeof(*rect
));
2124 return InvalidParameter
;
2126 memcpy(&node
->elementdata
.rect
, rect
, sizeof(*rect
));
2130 case RegionDataPath
:
2132 const BYTE
*path_data
;
2133 const UINT
*data_size
;
2136 data_size
= buffer_read(mbuf
, FIELD_OFFSET(EmfPlusRegionNodePath
, RegionNodePath
));
2138 return InvalidParameter
;
2140 path_data
= buffer_read(mbuf
, *data_size
);
2142 return InvalidParameter
;
2144 status
= metafile_deserialize_path(path_data
, *data_size
, &path
);
2147 node
->elementdata
.path
= path
;
2152 case RegionDataEmptyRect
:
2153 case RegionDataInfiniteRect
:
2157 FIXME("element type %#lx is not supported\n", *type
);
2161 return InvalidParameter
;
2164 static GpStatus
metafile_deserialize_region(const BYTE
*record_data
, UINT data_size
, GpRegion
**region
)
2166 struct memory_buffer mbuf
;
2172 init_memory_buffer(&mbuf
, record_data
, data_size
);
2174 if (!buffer_read(&mbuf
, FIELD_OFFSET(EmfPlusRegion
, RegionNode
)))
2175 return InvalidParameter
;
2177 status
= GdipCreateRegion(region
);
2182 status
= metafile_read_region_node(&mbuf
, *region
, &(*region
)->node
, &count
);
2183 if (status
== Ok
&& !count
)
2184 status
= InvalidParameter
;
2188 GdipDeleteRegion(*region
);
2195 static GpStatus
metafile_deserialize_brush(const BYTE
*record_data
, UINT data_size
, GpBrush
**brush
)
2197 static const UINT header_size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
);
2198 EmfPlusBrush
*data
= (EmfPlusBrush
*)record_data
;
2199 EmfPlusTransformMatrix
*transform
= NULL
;
2206 if (data_size
< header_size
)
2207 return InvalidParameter
;
2211 case BrushTypeSolidColor
:
2212 if (data_size
!= header_size
+ sizeof(EmfPlusSolidBrushData
))
2213 return InvalidParameter
;
2215 status
= GdipCreateSolidFill(data
->BrushData
.solid
.SolidColor
, (GpSolidFill
**)brush
);
2217 case BrushTypeHatchFill
:
2218 if (data_size
!= header_size
+ sizeof(EmfPlusHatchBrushData
))
2219 return InvalidParameter
;
2221 status
= GdipCreateHatchBrush(data
->BrushData
.hatch
.HatchStyle
, data
->BrushData
.hatch
.ForeColor
,
2222 data
->BrushData
.hatch
.BackColor
, (GpHatch
**)brush
);
2224 case BrushTypeTextureFill
:
2228 offset
= header_size
+ FIELD_OFFSET(EmfPlusTextureBrushData
, OptionalData
);
2229 if (data_size
<= offset
)
2230 return InvalidParameter
;
2232 brushflags
= data
->BrushData
.texture
.BrushDataFlags
;
2233 if (brushflags
& BrushDataTransform
)
2235 if (data_size
<= offset
+ sizeof(EmfPlusTransformMatrix
))
2236 return InvalidParameter
;
2237 transform
= (EmfPlusTransformMatrix
*)(record_data
+ offset
);
2238 offset
+= sizeof(EmfPlusTransformMatrix
);
2241 status
= metafile_deserialize_image(record_data
+ offset
, data_size
- offset
, &image
);
2245 status
= GdipCreateTexture(image
, data
->BrushData
.texture
.WrapMode
, (GpTexture
**)brush
);
2246 if (status
== Ok
&& transform
&& !(brushflags
& BrushDataDoNotTransform
))
2247 GdipSetTextureTransform((GpTexture
*)*brush
, (const GpMatrix
*)transform
);
2249 GdipDisposeImage(image
);
2252 case BrushTypeLinearGradient
:
2254 GpLineGradient
*gradient
= NULL
;
2256 UINT position_count
= 0;
2258 offset
= header_size
+ FIELD_OFFSET(EmfPlusLinearGradientBrushData
, OptionalData
);
2259 if (data_size
< offset
)
2260 return InvalidParameter
;
2262 brushflags
= data
->BrushData
.lineargradient
.BrushDataFlags
;
2263 if ((brushflags
& BrushDataPresetColors
) && (brushflags
& (BrushDataBlendFactorsH
| BrushDataBlendFactorsV
)))
2264 return InvalidParameter
;
2266 if (brushflags
& BrushDataTransform
)
2268 if (data_size
< offset
+ sizeof(EmfPlusTransformMatrix
))
2269 return InvalidParameter
;
2270 transform
= (EmfPlusTransformMatrix
*)(record_data
+ offset
);
2271 offset
+= sizeof(EmfPlusTransformMatrix
);
2274 if (brushflags
& (BrushDataPresetColors
| BrushDataBlendFactorsH
| BrushDataBlendFactorsV
))
2276 if (data_size
<= offset
+ sizeof(DWORD
)) /* Number of factors/preset colors. */
2277 return InvalidParameter
;
2278 position_count
= *(DWORD
*)(record_data
+ offset
);
2279 offset
+= sizeof(DWORD
);
2282 if (brushflags
& BrushDataPresetColors
)
2284 if (data_size
!= offset
+ position_count
* (sizeof(float) + sizeof(EmfPlusARGB
)))
2285 return InvalidParameter
;
2287 else if (brushflags
& BrushDataBlendFactorsH
)
2289 if (data_size
!= offset
+ position_count
* 2 * sizeof(float))
2290 return InvalidParameter
;
2293 rect
.X
= data
->BrushData
.lineargradient
.RectF
.X
;
2294 rect
.Y
= data
->BrushData
.lineargradient
.RectF
.Y
;
2295 rect
.Width
= data
->BrushData
.lineargradient
.RectF
.Width
;
2296 rect
.Height
= data
->BrushData
.lineargradient
.RectF
.Height
;
2298 status
= GdipCreateLineBrushFromRect(&rect
, data
->BrushData
.lineargradient
.StartColor
,
2299 data
->BrushData
.lineargradient
.EndColor
, LinearGradientModeHorizontal
,
2300 data
->BrushData
.lineargradient
.WrapMode
, &gradient
);
2304 status
= GdipSetLineTransform(gradient
, (const GpMatrix
*)transform
);
2308 if (brushflags
& BrushDataPresetColors
)
2309 status
= GdipSetLinePresetBlend(gradient
, (ARGB
*)(record_data
+ offset
+
2310 position_count
* sizeof(REAL
)), (REAL
*)(record_data
+ offset
), position_count
);
2311 else if (brushflags
& BrushDataBlendFactorsH
)
2312 status
= GdipSetLineBlend(gradient
, (REAL
*)(record_data
+ offset
+ position_count
* sizeof(REAL
)),
2313 (REAL
*)(record_data
+ offset
), position_count
);
2315 if (brushflags
& BrushDataIsGammaCorrected
)
2316 FIXME("BrushDataIsGammaCorrected is not handled.\n");
2321 *brush
= (GpBrush
*)gradient
;
2323 GdipDeleteBrush((GpBrush
*)gradient
);
2328 FIXME("brush type %lu is not supported.\n", data
->Type
);
2329 return NotImplemented
;
2335 static GpStatus
metafile_deserialize_custom_line_cap(const BYTE
*record_data
, UINT data_size
, GpCustomLineCap
**cap
)
2337 EmfPlusCustomStartCapData
*custom_cap_data
= (EmfPlusCustomStartCapData
*)record_data
;
2338 EmfPlusCustomLineCap
*line_cap
;
2344 if (data_size
< FIELD_OFFSET(EmfPlusCustomStartCapData
, data
))
2345 return InvalidParameter
;
2346 if (data_size
< FIELD_OFFSET(EmfPlusCustomStartCapData
, data
) + custom_cap_data
->CustomStartCapSize
)
2347 return InvalidParameter
;
2348 offset
= FIELD_OFFSET(EmfPlusCustomStartCapData
, data
);
2349 line_cap
= (EmfPlusCustomLineCap
*)(record_data
+ offset
);
2351 if (data_size
< offset
+ FIELD_OFFSET(EmfPlusCustomLineCap
, CustomLineCapData
))
2352 return InvalidParameter
;
2353 offset
+= FIELD_OFFSET(EmfPlusCustomLineCap
, CustomLineCapData
);
2355 if (line_cap
->Type
== CustomLineCapTypeAdjustableArrow
)
2357 EmfPlusCustomLineCapArrowData
*arrow_data
;
2358 GpAdjustableArrowCap
*arrow_cap
;
2360 arrow_data
= (EmfPlusCustomLineCapArrowData
*)(record_data
+ offset
);
2362 if (data_size
< offset
+ sizeof(EmfPlusCustomLineCapArrowData
))
2363 return InvalidParameter
;
2365 if ((status
= GdipCreateAdjustableArrowCap(arrow_data
->Height
, arrow_data
->Width
,
2366 arrow_data
->FillState
, &arrow_cap
)))
2369 if ((status
= GdipSetAdjustableArrowCapMiddleInset(arrow_cap
, arrow_data
->MiddleInset
)))
2370 goto arrow_cap_failed
;
2371 if ((status
= GdipSetCustomLineCapStrokeCaps((GpCustomLineCap
*)arrow_cap
, arrow_data
->LineStartCap
, arrow_data
->LineEndCap
)))
2372 goto arrow_cap_failed
;
2373 if ((status
= GdipSetCustomLineCapStrokeJoin((GpCustomLineCap
*)arrow_cap
, arrow_data
->LineJoin
)))
2374 goto arrow_cap_failed
;
2375 if ((status
= GdipSetCustomLineCapWidthScale((GpCustomLineCap
*)arrow_cap
, arrow_data
->WidthScale
)))
2376 goto arrow_cap_failed
;
2378 *cap
= (GpCustomLineCap
*)arrow_cap
;
2382 GdipDeleteCustomLineCap((GpCustomLineCap
*)arrow_cap
);
2387 GpPath
*path
, *fill_path
= NULL
, *stroke_path
= NULL
;
2388 EmfPlusCustomLineCapData
*line_cap_data
;
2389 GpCustomLineCap
*line_cap
= NULL
;
2392 line_cap_data
= (EmfPlusCustomLineCapData
*)(record_data
+ offset
);
2394 if (data_size
< offset
+ FIELD_OFFSET(EmfPlusCustomLineCapData
, OptionalData
))
2395 return InvalidParameter
;
2396 offset
+= FIELD_OFFSET(EmfPlusCustomLineCapData
, OptionalData
);
2398 if (line_cap_data
->CustomLineCapDataFlags
== CustomLineCapDataFillPath
)
2400 EmfPlusCustomLineCapDataFillPath
*fill_path
= (EmfPlusCustomLineCapDataFillPath
*)(record_data
+ offset
);
2402 if (data_size
< offset
+ FIELD_OFFSET(EmfPlusCustomLineCapDataFillPath
, FillPath
))
2403 return InvalidParameter
;
2404 if (data_size
< offset
+ fill_path
->FillPathLength
)
2405 return InvalidParameter
;
2407 offset
+= FIELD_OFFSET(EmfPlusCustomLineCapDataFillPath
, FillPath
);
2411 EmfPlusCustomLineCapDataLinePath
*line_path
= (EmfPlusCustomLineCapDataLinePath
*)(record_data
+ offset
);
2413 if (data_size
< offset
+ FIELD_OFFSET(EmfPlusCustomLineCapDataLinePath
, LinePath
))
2414 return InvalidParameter
;
2415 if (data_size
< offset
+ line_path
->LinePathLength
)
2416 return InvalidParameter
;
2418 offset
+= FIELD_OFFSET(EmfPlusCustomLineCapDataLinePath
, LinePath
);
2421 if ((status
= metafile_deserialize_path(record_data
+ offset
, data_size
- offset
, &path
)))
2424 if (line_cap_data
->CustomLineCapDataFlags
== CustomLineCapDataFillPath
)
2429 if ((status
= GdipCreateCustomLineCap(fill_path
, stroke_path
, line_cap_data
->BaseCap
,
2430 line_cap_data
->BaseInset
, &line_cap
)))
2431 goto default_cap_failed
;
2432 if ((status
= GdipSetCustomLineCapStrokeCaps(line_cap
, line_cap_data
->StrokeStartCap
, line_cap_data
->StrokeEndCap
)))
2433 goto default_cap_failed
;
2434 if ((status
= GdipSetCustomLineCapStrokeJoin(line_cap
, line_cap_data
->StrokeJoin
)))
2435 goto default_cap_failed
;
2436 if ((status
= GdipSetCustomLineCapWidthScale(line_cap
, line_cap_data
->WidthScale
)))
2437 goto default_cap_failed
;
2439 GdipDeletePath(path
);
2445 GdipDeleteCustomLineCap(line_cap
);
2446 GdipDeletePath(path
);
2451 static GpStatus
metafile_get_pen_brush_data_offset(EmfPlusPen
*data
, UINT data_size
, DWORD
*ret
)
2453 EmfPlusPenData
*pendata
= (EmfPlusPenData
*)data
->data
;
2454 DWORD offset
= FIELD_OFFSET(EmfPlusPen
, data
);
2456 if (data_size
<= offset
)
2457 return InvalidParameter
;
2459 offset
+= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
2460 if (data_size
<= offset
)
2461 return InvalidParameter
;
2463 if (pendata
->PenDataFlags
& PenDataTransform
)
2464 offset
+= sizeof(EmfPlusTransformMatrix
);
2466 if (pendata
->PenDataFlags
& PenDataStartCap
)
2467 offset
+= sizeof(DWORD
);
2469 if (pendata
->PenDataFlags
& PenDataEndCap
)
2470 offset
+= sizeof(DWORD
);
2472 if (pendata
->PenDataFlags
& PenDataJoin
)
2473 offset
+= sizeof(DWORD
);
2475 if (pendata
->PenDataFlags
& PenDataMiterLimit
)
2476 offset
+= sizeof(REAL
);
2478 if (pendata
->PenDataFlags
& PenDataLineStyle
)
2479 offset
+= sizeof(DWORD
);
2481 if (pendata
->PenDataFlags
& PenDataDashedLineCap
)
2482 offset
+= sizeof(DWORD
);
2484 if (pendata
->PenDataFlags
& PenDataDashedLineOffset
)
2485 offset
+= sizeof(REAL
);
2487 if (pendata
->PenDataFlags
& PenDataDashedLine
)
2489 EmfPlusDashedLineData
*dashedline
= (EmfPlusDashedLineData
*)((BYTE
*)data
+ offset
);
2491 offset
+= FIELD_OFFSET(EmfPlusDashedLineData
, data
);
2492 if (data_size
<= offset
)
2493 return InvalidParameter
;
2495 offset
+= dashedline
->DashedLineDataSize
* sizeof(float);
2498 if (pendata
->PenDataFlags
& PenDataNonCenter
)
2499 offset
+= sizeof(DWORD
);
2501 if (pendata
->PenDataFlags
& PenDataCompoundLine
)
2503 EmfPlusCompoundLineData
*compoundline
= (EmfPlusCompoundLineData
*)((BYTE
*)data
+ offset
);
2505 offset
+= FIELD_OFFSET(EmfPlusCompoundLineData
, data
);
2506 if (data_size
<= offset
)
2507 return InvalidParameter
;
2509 offset
+= compoundline
->CompoundLineDataSize
* sizeof(float);
2512 if (pendata
->PenDataFlags
& PenDataCustomStartCap
)
2514 EmfPlusCustomStartCapData
*startcap
= (EmfPlusCustomStartCapData
*)((BYTE
*)data
+ offset
);
2516 offset
+= FIELD_OFFSET(EmfPlusCustomStartCapData
, data
);
2517 if (data_size
<= offset
)
2518 return InvalidParameter
;
2520 offset
+= startcap
->CustomStartCapSize
;
2523 if (pendata
->PenDataFlags
& PenDataCustomEndCap
)
2525 EmfPlusCustomEndCapData
*endcap
= (EmfPlusCustomEndCapData
*)((BYTE
*)data
+ offset
);
2527 offset
+= FIELD_OFFSET(EmfPlusCustomEndCapData
, data
);
2528 if (data_size
<= offset
)
2529 return InvalidParameter
;
2531 offset
+= endcap
->CustomEndCapSize
;
2538 static GpStatus
METAFILE_PlaybackObject(GpMetafile
*metafile
, UINT flags
, UINT data_size
, const BYTE
*record_data
)
2540 BYTE type
= (flags
>> 8) & 0xff;
2541 BYTE id
= flags
& 0xff;
2542 void *object
= NULL
;
2545 if (type
> ObjectTypeMax
|| id
>= EmfPlusObjectTableSize
)
2546 return InvalidParameter
;
2550 case ObjectTypeBrush
:
2551 status
= metafile_deserialize_brush(record_data
, data_size
, (GpBrush
**)&object
);
2555 EmfPlusPen
*data
= (EmfPlusPen
*)record_data
;
2556 EmfPlusPenData
*pendata
= (EmfPlusPenData
*)data
->data
;
2557 GpCustomLineCap
*custom_line_cap
;
2562 status
= metafile_get_pen_brush_data_offset(data
, data_size
, &offset
);
2566 status
= metafile_deserialize_brush(record_data
+ offset
, data_size
- offset
, &brush
);
2570 status
= GdipCreatePen2(brush
, pendata
->PenWidth
, pendata
->PenUnit
, &pen
);
2571 GdipDeleteBrush(brush
);
2575 offset
= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
2577 if (pendata
->PenDataFlags
& PenDataTransform
)
2579 FIXME("PenDataTransform is not supported.\n");
2580 offset
+= sizeof(EmfPlusTransformMatrix
);
2583 if (pendata
->PenDataFlags
& PenDataStartCap
)
2585 if ((status
= GdipSetPenStartCap(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2587 offset
+= sizeof(DWORD
);
2590 if (pendata
->PenDataFlags
& PenDataEndCap
)
2592 if ((status
= GdipSetPenEndCap(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2594 offset
+= sizeof(DWORD
);
2597 if (pendata
->PenDataFlags
& PenDataJoin
)
2599 if ((status
= GdipSetPenLineJoin(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2601 offset
+= sizeof(DWORD
);
2604 if (pendata
->PenDataFlags
& PenDataMiterLimit
)
2606 if ((status
= GdipSetPenMiterLimit(pen
, *(REAL
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2608 offset
+= sizeof(REAL
);
2611 if (pendata
->PenDataFlags
& PenDataLineStyle
)
2613 if ((status
= GdipSetPenDashStyle(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2615 offset
+= sizeof(DWORD
);
2618 if (pendata
->PenDataFlags
& PenDataDashedLineCap
)
2620 FIXME("PenDataDashedLineCap is not supported.\n");
2621 offset
+= sizeof(DWORD
);
2624 if (pendata
->PenDataFlags
& PenDataDashedLineOffset
)
2626 if ((status
= GdipSetPenDashOffset(pen
, *(REAL
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2628 offset
+= sizeof(REAL
);
2631 if (pendata
->PenDataFlags
& PenDataDashedLine
)
2633 EmfPlusDashedLineData
*dashedline
= (EmfPlusDashedLineData
*)((BYTE
*)pendata
+ offset
);
2634 FIXME("PenDataDashedLine is not supported.\n");
2635 offset
+= FIELD_OFFSET(EmfPlusDashedLineData
, data
) + dashedline
->DashedLineDataSize
* sizeof(float);
2638 if (pendata
->PenDataFlags
& PenDataNonCenter
)
2640 FIXME("PenDataNonCenter is not supported.\n");
2641 offset
+= sizeof(DWORD
);
2644 if (pendata
->PenDataFlags
& PenDataCompoundLine
)
2646 EmfPlusCompoundLineData
*compoundline
= (EmfPlusCompoundLineData
*)((BYTE
*)pendata
+ offset
);
2647 FIXME("PenDataCompoundLine is not supported.\n");
2648 offset
+= FIELD_OFFSET(EmfPlusCompoundLineData
, data
) + compoundline
->CompoundLineDataSize
* sizeof(float);
2651 if (pendata
->PenDataFlags
& PenDataCustomStartCap
)
2653 EmfPlusCustomStartCapData
*startcap
= (EmfPlusCustomStartCapData
*)((BYTE
*)pendata
+ offset
);
2654 if ((status
= metafile_deserialize_custom_line_cap((BYTE
*)startcap
, data_size
, &custom_line_cap
)) != Ok
)
2656 status
= GdipSetPenCustomStartCap(pen
, custom_line_cap
);
2657 GdipDeleteCustomLineCap(custom_line_cap
);
2660 offset
+= FIELD_OFFSET(EmfPlusCustomStartCapData
, data
) + startcap
->CustomStartCapSize
;
2663 if (pendata
->PenDataFlags
& PenDataCustomEndCap
)
2665 EmfPlusCustomEndCapData
*endcap
= (EmfPlusCustomEndCapData
*)((BYTE
*)pendata
+ offset
);
2666 if ((status
= metafile_deserialize_custom_line_cap((BYTE
*)endcap
, data_size
, &custom_line_cap
)) != Ok
)
2668 status
= GdipSetPenCustomEndCap(pen
, custom_line_cap
);
2669 GdipDeleteCustomLineCap(custom_line_cap
);
2672 offset
+= FIELD_OFFSET(EmfPlusCustomEndCapData
, data
) + endcap
->CustomEndCapSize
;
2682 case ObjectTypePath
:
2683 status
= metafile_deserialize_path(record_data
, data_size
, (GpPath
**)&object
);
2685 case ObjectTypeRegion
:
2686 status
= metafile_deserialize_region(record_data
, data_size
, (GpRegion
**)&object
);
2688 case ObjectTypeImage
:
2689 status
= metafile_deserialize_image(record_data
, data_size
, (GpImage
**)&object
);
2691 case ObjectTypeFont
:
2693 EmfPlusFont
*data
= (EmfPlusFont
*)record_data
;
2694 GpFontFamily
*family
;
2697 if (data_size
<= FIELD_OFFSET(EmfPlusFont
, FamilyName
))
2698 return InvalidParameter
;
2699 data_size
-= FIELD_OFFSET(EmfPlusFont
, FamilyName
);
2701 if (data_size
< data
->Length
* sizeof(WCHAR
))
2702 return InvalidParameter
;
2704 if (!(familyname
= malloc((data
->Length
+ 1) * sizeof(*familyname
))))
2707 memcpy(familyname
, data
->FamilyName
, data
->Length
* sizeof(*familyname
));
2708 familyname
[data
->Length
] = 0;
2710 status
= GdipCreateFontFamilyFromName(familyname
, NULL
, &family
);
2713 /* If a font family cannot be created from family name, native
2714 falls back to a sans serif font. */
2716 status
= GdipGetGenericFontFamilySansSerif(&family
);
2720 status
= GdipCreateFont(family
, data
->EmSize
, data
->FontStyleFlags
, data
->SizeUnit
, (GpFont
**)&object
);
2721 GdipDeleteFontFamily(family
);
2724 case ObjectTypeImageAttributes
:
2726 EmfPlusImageAttributes
*data
= (EmfPlusImageAttributes
*)record_data
;
2727 GpImageAttributes
*attributes
= NULL
;
2729 if (data_size
!= sizeof(*data
))
2730 return InvalidParameter
;
2732 if ((status
= GdipCreateImageAttributes(&attributes
)) != Ok
)
2735 status
= GdipSetImageAttributesWrapMode(attributes
, data
->WrapMode
, *(DWORD
*)&data
->ClampColor
,
2736 !!data
->ObjectClamp
);
2738 object
= attributes
;
2740 GdipDisposeImageAttributes(attributes
);
2744 FIXME("not implemented for object type %d.\n", type
);
2745 return NotImplemented
;
2749 metafile_set_object_table_entry(metafile
, id
, type
, object
);
2754 static GpStatus
metafile_set_clip_region(GpMetafile
*metafile
, GpRegion
*region
, CombineMode mode
)
2756 GpMatrix world_to_device
;
2758 get_graphics_transform(metafile
->playback_graphics
, CoordinateSpaceDevice
, CoordinateSpaceWorld
, &world_to_device
);
2760 GdipTransformRegion(region
, &world_to_device
);
2761 GdipCombineRegionRegion(metafile
->clip
, region
, mode
);
2763 return METAFILE_PlaybackUpdateClip(metafile
);
2766 GpStatus WINGDIPAPI
GdipPlayMetafileRecord(GDIPCONST GpMetafile
*metafile
,
2767 EmfPlusRecordType recordType
, UINT flags
, UINT dataSize
, GDIPCONST BYTE
*data
)
2770 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
;
2772 TRACE("(%p,%x,%x,%d,%p)\n", metafile
, recordType
, flags
, dataSize
, data
);
2774 if (!metafile
|| (dataSize
&& !data
) || !metafile
->playback_graphics
)
2775 return InvalidParameter
;
2777 if (recordType
>= 1 && recordType
<= 0x7a)
2779 /* regular EMF record */
2780 if (metafile
->playback_dc
)
2782 ENHMETARECORD
*record
= calloc(1, dataSize
+ 8);
2786 record
->iType
= recordType
;
2787 record
->nSize
= dataSize
+ 8;
2788 memcpy(record
->dParm
, data
, dataSize
);
2790 if (record
->iType
== EMR_BITBLT
|| record
->iType
== EMR_STRETCHBLT
)
2791 SetStretchBltMode(metafile
->playback_dc
, STRETCH_HALFTONE
);
2793 if(PlayEnhMetaFileRecord(metafile
->playback_dc
, metafile
->handle_table
,
2794 record
, metafile
->handle_count
) == 0)
2795 ERR("PlayEnhMetaFileRecord failed\n");
2805 EmfPlusRecordHeader
*header
= (EmfPlusRecordHeader
*)(data
)-1;
2807 METAFILE_PlaybackReleaseDC((GpMetafile
*)metafile
);
2811 case EmfPlusRecordTypeHeader
:
2812 case EmfPlusRecordTypeEndOfFile
:
2814 case EmfPlusRecordTypeGetDC
:
2815 METAFILE_PlaybackGetDC((GpMetafile
*)metafile
);
2817 case EmfPlusRecordTypeClear
:
2819 EmfPlusClear
*record
= (EmfPlusClear
*)header
;
2821 if (dataSize
!= sizeof(record
->Color
))
2822 return InvalidParameter
;
2824 return GdipGraphicsClear(metafile
->playback_graphics
, record
->Color
);
2826 case EmfPlusRecordTypeFillRects
:
2828 EmfPlusFillRects
*record
= (EmfPlusFillRects
*)header
;
2829 GpBrush
*brush
, *temp_brush
=NULL
;
2830 GpRectF
*rects
, *temp_rects
=NULL
;
2832 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
))
2833 return InvalidParameter
;
2837 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(EmfPlusRect
) * record
->Count
)
2838 return InvalidParameter
;
2842 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(GpRectF
) * record
->Count
)
2843 return InvalidParameter
;
2848 stat
= GdipCreateSolidFill(record
->BrushID
, (GpSolidFill
**)&temp_brush
);
2853 if (record
->BrushID
>= EmfPlusObjectTableSize
||
2854 real_metafile
->objtable
[record
->BrushID
].type
!= ObjectTypeBrush
)
2855 return InvalidParameter
;
2857 brush
= real_metafile
->objtable
[record
->BrushID
].u
.brush
;
2865 EmfPlusRect
*int_rects
= (EmfPlusRect
*)(record
+1);
2868 rects
= temp_rects
= calloc(record
->Count
, sizeof(GpRectF
));
2871 for (i
=0; i
<record
->Count
; i
++)
2873 rects
[i
].X
= int_rects
[i
].X
;
2874 rects
[i
].Y
= int_rects
[i
].Y
;
2875 rects
[i
].Width
= int_rects
[i
].Width
;
2876 rects
[i
].Height
= int_rects
[i
].Height
;
2883 rects
= (GpRectF
*)(record
+1);
2888 stat
= GdipFillRectangles(metafile
->playback_graphics
, brush
, rects
, record
->Count
);
2891 GdipDeleteBrush(temp_brush
);
2896 case EmfPlusRecordTypeSetClipRect
:
2898 EmfPlusSetClipRect
*record
= (EmfPlusSetClipRect
*)header
;
2899 CombineMode mode
= (CombineMode
)((flags
>> 8) & 0xf);
2902 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(*record
))
2903 return InvalidParameter
;
2905 stat
= GdipCreateRegionRect(&record
->ClipRect
, ®ion
);
2909 stat
= metafile_set_clip_region(real_metafile
, region
, mode
);
2910 GdipDeleteRegion(region
);
2915 case EmfPlusRecordTypeSetClipRegion
:
2917 CombineMode mode
= (flags
>> 8) & 0xf;
2918 BYTE regionid
= flags
& 0xff;
2922 return InvalidParameter
;
2924 if (regionid
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[regionid
].type
!= ObjectTypeRegion
)
2925 return InvalidParameter
;
2927 stat
= GdipCloneRegion(real_metafile
->objtable
[regionid
].u
.region
, ®ion
);
2930 stat
= metafile_set_clip_region(real_metafile
, region
, mode
);
2931 GdipDeleteRegion(region
);
2936 case EmfPlusRecordTypeSetClipPath
:
2938 CombineMode mode
= (flags
>> 8) & 0xf;
2939 BYTE pathid
= flags
& 0xff;
2943 return InvalidParameter
;
2945 if (pathid
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pathid
].type
!= ObjectTypePath
)
2946 return InvalidParameter
;
2948 stat
= GdipCreateRegionPath(real_metafile
->objtable
[pathid
].u
.path
, ®ion
);
2951 stat
= metafile_set_clip_region(real_metafile
, region
, mode
);
2952 GdipDeleteRegion(region
);
2957 case EmfPlusRecordTypeSetPageTransform
:
2959 EmfPlusSetPageTransform
*record
= (EmfPlusSetPageTransform
*)header
;
2960 GpUnit unit
= (GpUnit
)flags
;
2962 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetPageTransform
))
2963 return InvalidParameter
;
2965 real_metafile
->page_unit
= unit
;
2966 real_metafile
->page_scale
= record
->PageScale
;
2968 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2970 case EmfPlusRecordTypeSetWorldTransform
:
2972 EmfPlusSetWorldTransform
*record
= (EmfPlusSetWorldTransform
*)header
;
2974 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetWorldTransform
))
2975 return InvalidParameter
;
2977 memcpy(real_metafile
->world_transform
->matrix
, record
->MatrixData
, sizeof(record
->MatrixData
));
2979 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2981 case EmfPlusRecordTypeScaleWorldTransform
:
2983 EmfPlusScaleWorldTransform
*record
= (EmfPlusScaleWorldTransform
*)header
;
2984 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2986 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusScaleWorldTransform
))
2987 return InvalidParameter
;
2989 GdipScaleMatrix(real_metafile
->world_transform
, record
->Sx
, record
->Sy
, order
);
2991 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2993 case EmfPlusRecordTypeMultiplyWorldTransform
:
2995 EmfPlusMultiplyWorldTransform
*record
= (EmfPlusMultiplyWorldTransform
*)header
;
2996 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2999 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusMultiplyWorldTransform
))
3000 return InvalidParameter
;
3002 memcpy(matrix
.matrix
, record
->MatrixData
, sizeof(matrix
.matrix
));
3004 GdipMultiplyMatrix(real_metafile
->world_transform
, &matrix
, order
);
3006 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
3008 case EmfPlusRecordTypeRotateWorldTransform
:
3010 EmfPlusRotateWorldTransform
*record
= (EmfPlusRotateWorldTransform
*)header
;
3011 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
3013 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusRotateWorldTransform
))
3014 return InvalidParameter
;
3016 GdipRotateMatrix(real_metafile
->world_transform
, record
->Angle
, order
);
3018 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
3020 case EmfPlusRecordTypeTranslateWorldTransform
:
3022 EmfPlusTranslateWorldTransform
*record
= (EmfPlusTranslateWorldTransform
*)header
;
3023 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
3025 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusTranslateWorldTransform
))
3026 return InvalidParameter
;
3028 GdipTranslateMatrix(real_metafile
->world_transform
, record
->dx
, record
->dy
, order
);
3030 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
3032 case EmfPlusRecordTypeResetWorldTransform
:
3034 GdipSetMatrixElements(real_metafile
->world_transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
3036 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
3038 case EmfPlusRecordTypeBeginContainer
:
3040 EmfPlusBeginContainer
*record
= (EmfPlusBeginContainer
*)header
;
3043 REAL scale_x
, scale_y
;
3044 GpRectF scaled_srcrect
;
3047 cont
= calloc(1, sizeof(*cont
));
3051 stat
= GdipCloneRegion(metafile
->clip
, &cont
->clip
);
3058 stat
= GdipBeginContainer2(metafile
->playback_graphics
, &cont
->state
);
3062 GdipDeleteRegion(cont
->clip
);
3067 cont
->id
= record
->StackIndex
;
3068 cont
->type
= BEGIN_CONTAINER
;
3069 cont
->world_transform
= *metafile
->world_transform
;
3070 cont
->page_unit
= metafile
->page_unit
;
3071 cont
->page_scale
= metafile
->page_scale
;
3072 list_add_head(&real_metafile
->containers
, &cont
->entry
);
3074 unit
= record
->Header
.Flags
& 0xff;
3076 scale_x
= units_to_pixels(1.0, unit
, metafile
->image
.xres
, metafile
->printer_display
);
3077 scale_y
= units_to_pixels(1.0, unit
, metafile
->image
.yres
, metafile
->printer_display
);
3079 scaled_srcrect
.X
= scale_x
* record
->SrcRect
.X
;
3080 scaled_srcrect
.Y
= scale_y
* record
->SrcRect
.Y
;
3081 scaled_srcrect
.Width
= scale_x
* record
->SrcRect
.Width
;
3082 scaled_srcrect
.Height
= scale_y
* record
->SrcRect
.Height
;
3084 transform
.matrix
[0] = record
->DestRect
.Width
/ scaled_srcrect
.Width
;
3085 transform
.matrix
[1] = 0.0;
3086 transform
.matrix
[2] = 0.0;
3087 transform
.matrix
[3] = record
->DestRect
.Height
/ scaled_srcrect
.Height
;
3088 transform
.matrix
[4] = record
->DestRect
.X
- scaled_srcrect
.X
;
3089 transform
.matrix
[5] = record
->DestRect
.Y
- scaled_srcrect
.Y
;
3091 GdipMultiplyMatrix(real_metafile
->world_transform
, &transform
, MatrixOrderPrepend
);
3093 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
3095 case EmfPlusRecordTypeBeginContainerNoParams
:
3096 case EmfPlusRecordTypeSave
:
3098 EmfPlusContainerRecord
*record
= (EmfPlusContainerRecord
*)header
;
3101 cont
= calloc(1, sizeof(*cont
));
3105 stat
= GdipCloneRegion(metafile
->clip
, &cont
->clip
);
3112 if (recordType
== EmfPlusRecordTypeBeginContainerNoParams
)
3113 stat
= GdipBeginContainer2(metafile
->playback_graphics
, &cont
->state
);
3115 stat
= GdipSaveGraphics(metafile
->playback_graphics
, &cont
->state
);
3119 GdipDeleteRegion(cont
->clip
);
3124 cont
->id
= record
->StackIndex
;
3125 if (recordType
== EmfPlusRecordTypeBeginContainerNoParams
)
3126 cont
->type
= BEGIN_CONTAINER
;
3128 cont
->type
= SAVE_GRAPHICS
;
3129 cont
->world_transform
= *metafile
->world_transform
;
3130 cont
->page_unit
= metafile
->page_unit
;
3131 cont
->page_scale
= metafile
->page_scale
;
3132 list_add_head(&real_metafile
->containers
, &cont
->entry
);
3136 case EmfPlusRecordTypeEndContainer
:
3137 case EmfPlusRecordTypeRestore
:
3139 EmfPlusContainerRecord
*record
= (EmfPlusContainerRecord
*)header
;
3141 enum container_type type
;
3144 if (recordType
== EmfPlusRecordTypeEndContainer
)
3145 type
= BEGIN_CONTAINER
;
3147 type
= SAVE_GRAPHICS
;
3149 LIST_FOR_EACH_ENTRY(cont
, &real_metafile
->containers
, container
, entry
)
3151 if (cont
->id
== record
->StackIndex
&& cont
->type
== type
)
3162 /* pop any newer items on the stack */
3163 while ((cont2
= LIST_ENTRY(list_head(&real_metafile
->containers
), container
, entry
)) != cont
)
3165 list_remove(&cont2
->entry
);
3166 GdipDeleteRegion(cont2
->clip
);
3170 if (type
== BEGIN_CONTAINER
)
3171 GdipEndContainer(real_metafile
->playback_graphics
, cont
->state
);
3173 GdipRestoreGraphics(real_metafile
->playback_graphics
, cont
->state
);
3175 *real_metafile
->world_transform
= cont
->world_transform
;
3176 real_metafile
->page_unit
= cont
->page_unit
;
3177 real_metafile
->page_scale
= cont
->page_scale
;
3178 GdipCombineRegionRegion(real_metafile
->clip
, cont
->clip
, CombineModeReplace
);
3180 list_remove(&cont
->entry
);
3181 GdipDeleteRegion(cont
->clip
);
3187 case EmfPlusRecordTypeSetPixelOffsetMode
:
3189 return GdipSetPixelOffsetMode(real_metafile
->playback_graphics
, flags
& 0xff);
3191 case EmfPlusRecordTypeSetCompositingQuality
:
3193 return GdipSetCompositingQuality(real_metafile
->playback_graphics
, flags
& 0xff);
3195 case EmfPlusRecordTypeSetInterpolationMode
:
3197 return GdipSetInterpolationMode(real_metafile
->playback_graphics
, flags
& 0xff);
3199 case EmfPlusRecordTypeSetTextRenderingHint
:
3201 return GdipSetTextRenderingHint(real_metafile
->playback_graphics
, flags
& 0xff);
3203 case EmfPlusRecordTypeSetAntiAliasMode
:
3205 return GdipSetSmoothingMode(real_metafile
->playback_graphics
, (flags
>> 1) & 0xff);
3207 case EmfPlusRecordTypeSetCompositingMode
:
3209 return GdipSetCompositingMode(real_metafile
->playback_graphics
, flags
& 0xff);
3211 case EmfPlusRecordTypeObject
:
3213 return METAFILE_PlaybackObject(real_metafile
, flags
, dataSize
, data
);
3215 case EmfPlusRecordTypeDrawImage
:
3217 EmfPlusDrawImage
*draw
= (EmfPlusDrawImage
*)header
;
3218 BYTE image
= flags
& 0xff;
3221 if (image
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[image
].type
!= ObjectTypeImage
)
3222 return InvalidParameter
;
3224 if (dataSize
!= FIELD_OFFSET(EmfPlusDrawImage
, RectData
) - sizeof(EmfPlusRecordHeader
) +
3225 (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3226 return InvalidParameter
;
3228 if (draw
->ImageAttributesID
>= EmfPlusObjectTableSize
||
3229 real_metafile
->objtable
[draw
->ImageAttributesID
].type
!= ObjectTypeImageAttributes
)
3230 return InvalidParameter
;
3232 if (flags
& 0x4000) /* C */
3234 points
[0].X
= draw
->RectData
.rect
.X
;
3235 points
[0].Y
= draw
->RectData
.rect
.Y
;
3236 points
[1].X
= points
[0].X
+ draw
->RectData
.rect
.Width
;
3237 points
[1].Y
= points
[0].Y
;
3238 points
[2].X
= points
[1].X
;
3239 points
[2].Y
= points
[1].Y
+ draw
->RectData
.rect
.Height
;
3243 points
[0].X
= draw
->RectData
.rectF
.X
;
3244 points
[0].Y
= draw
->RectData
.rectF
.Y
;
3245 points
[1].X
= points
[0].X
+ draw
->RectData
.rectF
.Width
;
3246 points
[1].Y
= points
[0].Y
;
3247 points
[2].X
= points
[1].X
;
3248 points
[2].Y
= points
[1].Y
+ draw
->RectData
.rectF
.Height
;
3251 return GdipDrawImagePointsRect(real_metafile
->playback_graphics
, real_metafile
->objtable
[image
].u
.image
,
3252 points
, 3, draw
->SrcRect
.X
, draw
->SrcRect
.Y
, draw
->SrcRect
.Width
, draw
->SrcRect
.Height
, draw
->SrcUnit
,
3253 real_metafile
->objtable
[draw
->ImageAttributesID
].u
.image_attributes
, NULL
, NULL
);
3255 case EmfPlusRecordTypeDrawImagePoints
:
3257 EmfPlusDrawImagePoints
*draw
= (EmfPlusDrawImagePoints
*)header
;
3258 static const UINT fixed_part_size
= FIELD_OFFSET(EmfPlusDrawImagePoints
, PointData
) -
3259 FIELD_OFFSET(EmfPlusDrawImagePoints
, ImageAttributesID
);
3260 BYTE image
= flags
& 0xff;
3265 if (image
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[image
].type
!= ObjectTypeImage
)
3266 return InvalidParameter
;
3268 if (dataSize
<= fixed_part_size
)
3269 return InvalidParameter
;
3270 dataSize
-= fixed_part_size
;
3272 if (draw
->ImageAttributesID
>= EmfPlusObjectTableSize
||
3273 real_metafile
->objtable
[draw
->ImageAttributesID
].type
!= ObjectTypeImageAttributes
)
3274 return InvalidParameter
;
3276 if (draw
->count
!= 3)
3277 return InvalidParameter
;
3279 if ((flags
>> 13) & 1) /* E */
3280 FIXME("image effects are not supported.\n");
3282 if ((flags
>> 11) & 1) /* P */
3283 size
= sizeof(EmfPlusPointR7
) * draw
->count
;
3284 else if ((flags
>> 14) & 1) /* C */
3285 size
= sizeof(EmfPlusPoint
) * draw
->count
;
3287 size
= sizeof(EmfPlusPointF
) * draw
->count
;
3289 if (dataSize
!= size
)
3290 return InvalidParameter
;
3292 if ((flags
>> 11) & 1) /* P */
3294 points
[0].X
= draw
->PointData
.pointsR
[0].X
;
3295 points
[0].Y
= draw
->PointData
.pointsR
[0].Y
;
3296 for (i
= 1; i
< 3; i
++)
3298 points
[i
].X
= points
[i
-1].X
+ draw
->PointData
.pointsR
[i
].X
;
3299 points
[i
].Y
= points
[i
-1].Y
+ draw
->PointData
.pointsR
[i
].Y
;
3302 else if ((flags
>> 14) & 1) /* C */
3304 for (i
= 0; i
< 3; i
++)
3306 points
[i
].X
= draw
->PointData
.points
[i
].X
;
3307 points
[i
].Y
= draw
->PointData
.points
[i
].Y
;
3311 memcpy(points
, draw
->PointData
.pointsF
, sizeof(points
));
3313 return GdipDrawImagePointsRect(real_metafile
->playback_graphics
, real_metafile
->objtable
[image
].u
.image
,
3314 points
, 3, draw
->SrcRect
.X
, draw
->SrcRect
.Y
, draw
->SrcRect
.Width
, draw
->SrcRect
.Height
, draw
->SrcUnit
,
3315 real_metafile
->objtable
[draw
->ImageAttributesID
].u
.image_attributes
, NULL
, NULL
);
3317 case EmfPlusRecordTypeFillPath
:
3319 EmfPlusFillPath
*fill
= (EmfPlusFillPath
*)header
;
3320 GpSolidFill
*solidfill
= NULL
;
3321 BYTE path
= flags
& 0xff;
3324 if (path
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[path
].type
!= ObjectTypePath
)
3325 return InvalidParameter
;
3327 if (dataSize
!= sizeof(fill
->data
.BrushId
))
3328 return InvalidParameter
;
3332 stat
= GdipCreateSolidFill(fill
->data
.Color
, &solidfill
);
3335 brush
= (GpBrush
*)solidfill
;
3339 if (fill
->data
.BrushId
>= EmfPlusObjectTableSize
||
3340 real_metafile
->objtable
[fill
->data
.BrushId
].type
!= ObjectTypeBrush
)
3341 return InvalidParameter
;
3343 brush
= real_metafile
->objtable
[fill
->data
.BrushId
].u
.brush
;
3346 stat
= GdipFillPath(real_metafile
->playback_graphics
, brush
, real_metafile
->objtable
[path
].u
.path
);
3347 GdipDeleteBrush((GpBrush
*)solidfill
);
3350 case EmfPlusRecordTypeFillClosedCurve
:
3352 static const UINT fixed_part_size
= FIELD_OFFSET(EmfPlusFillClosedCurve
, PointData
) -
3353 sizeof(EmfPlusRecordHeader
);
3354 EmfPlusFillClosedCurve
*fill
= (EmfPlusFillClosedCurve
*)header
;
3355 GpSolidFill
*solidfill
= NULL
;
3360 if (dataSize
<= fixed_part_size
)
3361 return InvalidParameter
;
3363 if (fill
->Count
== 0)
3364 return InvalidParameter
;
3366 if (flags
& 0x800) /* P */
3367 size
= (fixed_part_size
+ sizeof(EmfPlusPointR7
) * fill
->Count
+ 3) & ~3;
3368 else if (flags
& 0x4000) /* C */
3369 size
= fixed_part_size
+ sizeof(EmfPlusPoint
) * fill
->Count
;
3371 size
= fixed_part_size
+ sizeof(EmfPlusPointF
) * fill
->Count
;
3373 if (dataSize
!= size
)
3374 return InvalidParameter
;
3376 mode
= flags
& 0x200 ? FillModeWinding
: FillModeAlternate
; /* W */
3378 if (flags
& 0x8000) /* S */
3380 stat
= GdipCreateSolidFill(fill
->BrushId
, &solidfill
);
3383 brush
= (GpBrush
*)solidfill
;
3387 if (fill
->BrushId
>= EmfPlusObjectTableSize
||
3388 real_metafile
->objtable
[fill
->BrushId
].type
!= ObjectTypeBrush
)
3389 return InvalidParameter
;
3391 brush
= real_metafile
->objtable
[fill
->BrushId
].u
.brush
;
3394 if (flags
& (0x800 | 0x4000))
3396 GpPointF
*points
= malloc(fill
->Count
* sizeof(*points
));
3399 if (flags
& 0x800) /* P */
3403 for (i
= 1; i
< fill
->Count
; i
++)
3405 points
[i
].X
= points
[i
- 1].X
+ fill
->PointData
.pointsR
[i
].X
;
3406 points
[i
].Y
= points
[i
- 1].Y
+ fill
->PointData
.pointsR
[i
].Y
;
3411 for (i
= 0; i
< fill
->Count
; i
++)
3413 points
[i
].X
= fill
->PointData
.points
[i
].X
;
3414 points
[i
].Y
= fill
->PointData
.points
[i
].Y
;
3418 stat
= GdipFillClosedCurve2(real_metafile
->playback_graphics
, brush
,
3419 points
, fill
->Count
, fill
->Tension
, mode
);
3426 stat
= GdipFillClosedCurve2(real_metafile
->playback_graphics
, brush
,
3427 (const GpPointF
*)fill
->PointData
.pointsF
, fill
->Count
, fill
->Tension
, mode
);
3429 GdipDeleteBrush((GpBrush
*)solidfill
);
3432 case EmfPlusRecordTypeFillEllipse
:
3434 EmfPlusFillEllipse
*fill
= (EmfPlusFillEllipse
*)header
;
3435 GpSolidFill
*solidfill
= NULL
;
3438 if (dataSize
<= FIELD_OFFSET(EmfPlusFillEllipse
, RectData
) - sizeof(EmfPlusRecordHeader
))
3439 return InvalidParameter
;
3440 dataSize
-= FIELD_OFFSET(EmfPlusFillEllipse
, RectData
) - sizeof(EmfPlusRecordHeader
);
3442 if (dataSize
!= (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3443 return InvalidParameter
;
3447 stat
= GdipCreateSolidFill(fill
->BrushId
, &solidfill
);
3450 brush
= (GpBrush
*)solidfill
;
3454 if (fill
->BrushId
>= EmfPlusObjectTableSize
||
3455 real_metafile
->objtable
[fill
->BrushId
].type
!= ObjectTypeBrush
)
3456 return InvalidParameter
;
3458 brush
= real_metafile
->objtable
[fill
->BrushId
].u
.brush
;
3462 stat
= GdipFillEllipseI(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rect
.X
,
3463 fill
->RectData
.rect
.Y
, fill
->RectData
.rect
.Width
, fill
->RectData
.rect
.Height
);
3465 stat
= GdipFillEllipse(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rectF
.X
,
3466 fill
->RectData
.rectF
.Y
, fill
->RectData
.rectF
.Width
, fill
->RectData
.rectF
.Height
);
3468 GdipDeleteBrush((GpBrush
*)solidfill
);
3471 case EmfPlusRecordTypeFillPie
:
3473 EmfPlusFillPie
*fill
= (EmfPlusFillPie
*)header
;
3474 GpSolidFill
*solidfill
= NULL
;
3477 if (dataSize
<= FIELD_OFFSET(EmfPlusFillPie
, RectData
) - sizeof(EmfPlusRecordHeader
))
3478 return InvalidParameter
;
3479 dataSize
-= FIELD_OFFSET(EmfPlusFillPie
, RectData
) - sizeof(EmfPlusRecordHeader
);
3481 if (dataSize
!= (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3482 return InvalidParameter
;
3484 if (flags
& 0x8000) /* S */
3486 stat
= GdipCreateSolidFill(fill
->BrushId
, &solidfill
);
3489 brush
= (GpBrush
*)solidfill
;
3493 if (fill
->BrushId
>= EmfPlusObjectTableSize
||
3494 real_metafile
->objtable
[fill
->BrushId
].type
!= ObjectTypeBrush
)
3495 return InvalidParameter
;
3497 brush
= real_metafile
->objtable
[fill
->BrushId
].u
.brush
;
3500 if (flags
& 0x4000) /* C */
3501 stat
= GdipFillPieI(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rect
.X
,
3502 fill
->RectData
.rect
.Y
, fill
->RectData
.rect
.Width
, fill
->RectData
.rect
.Height
,
3503 fill
->StartAngle
, fill
->SweepAngle
);
3505 stat
= GdipFillPie(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rectF
.X
,
3506 fill
->RectData
.rectF
.Y
, fill
->RectData
.rectF
.Width
, fill
->RectData
.rectF
.Height
,
3507 fill
->StartAngle
, fill
->SweepAngle
);
3509 GdipDeleteBrush((GpBrush
*)solidfill
);
3512 case EmfPlusRecordTypeDrawPath
:
3514 EmfPlusDrawPath
*draw
= (EmfPlusDrawPath
*)header
;
3515 BYTE path
= flags
& 0xff;
3517 if (dataSize
!= sizeof(draw
->PenId
))
3518 return InvalidParameter
;
3520 if (path
>= EmfPlusObjectTableSize
|| draw
->PenId
>= EmfPlusObjectTableSize
)
3521 return InvalidParameter
;
3523 if (real_metafile
->objtable
[path
].type
!= ObjectTypePath
||
3524 real_metafile
->objtable
[draw
->PenId
].type
!= ObjectTypePen
)
3525 return InvalidParameter
;
3527 return GdipDrawPath(real_metafile
->playback_graphics
, real_metafile
->objtable
[draw
->PenId
].u
.pen
,
3528 real_metafile
->objtable
[path
].u
.path
);
3530 case EmfPlusRecordTypeDrawArc
:
3532 EmfPlusDrawArc
*draw
= (EmfPlusDrawArc
*)header
;
3533 BYTE pen
= flags
& 0xff;
3535 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3536 return InvalidParameter
;
3538 if (dataSize
!= FIELD_OFFSET(EmfPlusDrawArc
, RectData
) - sizeof(EmfPlusRecordHeader
) +
3539 (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3540 return InvalidParameter
;
3542 if (flags
& 0x4000) /* C */
3543 return GdipDrawArcI(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3544 draw
->RectData
.rect
.X
, draw
->RectData
.rect
.Y
, draw
->RectData
.rect
.Width
,
3545 draw
->RectData
.rect
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3547 return GdipDrawArc(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3548 draw
->RectData
.rectF
.X
, draw
->RectData
.rectF
.Y
, draw
->RectData
.rectF
.Width
,
3549 draw
->RectData
.rectF
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3551 case EmfPlusRecordTypeDrawEllipse
:
3553 EmfPlusDrawEllipse
*draw
= (EmfPlusDrawEllipse
*)header
;
3554 BYTE pen
= flags
& 0xff;
3556 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3557 return InvalidParameter
;
3559 if (dataSize
!= (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3560 return InvalidParameter
;
3562 if (flags
& 0x4000) /* C */
3563 return GdipDrawEllipseI(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3564 draw
->RectData
.rect
.X
, draw
->RectData
.rect
.Y
, draw
->RectData
.rect
.Width
,
3565 draw
->RectData
.rect
.Height
);
3567 return GdipDrawEllipse(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3568 draw
->RectData
.rectF
.X
, draw
->RectData
.rectF
.Y
, draw
->RectData
.rectF
.Width
,
3569 draw
->RectData
.rectF
.Height
);
3571 case EmfPlusRecordTypeDrawPie
:
3573 EmfPlusDrawPie
*draw
= (EmfPlusDrawPie
*)header
;
3574 BYTE pen
= flags
& 0xff;
3576 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3577 return InvalidParameter
;
3579 if (dataSize
!= FIELD_OFFSET(EmfPlusDrawPie
, RectData
) - sizeof(EmfPlusRecordHeader
) +
3580 (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3581 return InvalidParameter
;
3583 if (flags
& 0x4000) /* C */
3584 return GdipDrawPieI(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3585 draw
->RectData
.rect
.X
, draw
->RectData
.rect
.Y
, draw
->RectData
.rect
.Width
,
3586 draw
->RectData
.rect
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3588 return GdipDrawPie(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3589 draw
->RectData
.rectF
.X
, draw
->RectData
.rectF
.Y
, draw
->RectData
.rectF
.Width
,
3590 draw
->RectData
.rectF
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3592 case EmfPlusRecordTypeDrawRects
:
3594 EmfPlusDrawRects
*draw
= (EmfPlusDrawRects
*)header
;
3595 BYTE pen
= flags
& 0xff;
3596 GpRectF
*rects
= NULL
;
3598 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3599 return InvalidParameter
;
3601 if (dataSize
<= FIELD_OFFSET(EmfPlusDrawRects
, RectData
) - sizeof(EmfPlusRecordHeader
))
3602 return InvalidParameter
;
3603 dataSize
-= FIELD_OFFSET(EmfPlusDrawRects
, RectData
) - sizeof(EmfPlusRecordHeader
);
3605 if (dataSize
!= draw
->Count
* (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3606 return InvalidParameter
;
3612 rects
= malloc(draw
->Count
* sizeof(*rects
));
3616 for (i
= 0; i
< draw
->Count
; i
++)
3618 rects
[i
].X
= draw
->RectData
.rect
[i
].X
;
3619 rects
[i
].Y
= draw
->RectData
.rect
[i
].Y
;
3620 rects
[i
].Width
= draw
->RectData
.rect
[i
].Width
;
3621 rects
[i
].Height
= draw
->RectData
.rect
[i
].Height
;
3625 stat
= GdipDrawRectangles(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3626 rects
? rects
: (GpRectF
*)draw
->RectData
.rectF
, draw
->Count
);
3630 case EmfPlusRecordTypeDrawDriverString
:
3633 DWORD expected_size
;
3636 GpSolidFill
*solidfill
= NULL
;
3637 void* alignedmem
= NULL
;
3638 GpMatrix
*matrix
= NULL
;
3639 BYTE font
= flags
& 0xff;
3640 EmfPlusDrawDriverString
*draw
= (EmfPlusDrawDriverString
*)header
;
3642 if (font
>= EmfPlusObjectTableSize
||
3643 real_metafile
->objtable
[font
].type
!= ObjectTypeFont
)
3644 return InvalidParameter
;
3646 expected_size
= FIELD_OFFSET(EmfPlusDrawDriverString
, VariableData
) -
3647 sizeof(EmfPlusRecordHeader
);
3648 if (dataSize
< expected_size
|| draw
->GlyphCount
<= 0)
3649 return InvalidParameter
;
3651 expected_size
+= draw
->GlyphCount
* (sizeof(*text
) + sizeof(*positions
));
3652 if (draw
->MatrixPresent
)
3653 expected_size
+= sizeof(*matrix
);
3655 /* Pad expected size to DWORD alignment. */
3656 expected_size
= (expected_size
+ 3) & ~3;
3658 if (dataSize
!= expected_size
)
3659 return InvalidParameter
;
3663 stat
= GdipCreateSolidFill(draw
->brush
.Color
, &solidfill
);
3666 return InvalidParameter
;
3668 brush
= (GpBrush
*)solidfill
;
3672 if (draw
->brush
.BrushId
>= EmfPlusObjectTableSize
||
3673 real_metafile
->objtable
[draw
->brush
.BrushId
].type
!= ObjectTypeBrush
)
3674 return InvalidParameter
;
3676 brush
= real_metafile
->objtable
[draw
->brush
.BrushId
].u
.brush
;
3679 text
= (UINT16
*)&draw
->VariableData
[0];
3681 /* If GlyphCount is odd, all subsequent fields will be 2-byte
3682 aligned rather than 4-byte aligned, which may lead to access
3683 issues. Handle this case by making our own copy of positions. */
3684 if (draw
->GlyphCount
% 2)
3686 SIZE_T alloc_size
= draw
->GlyphCount
* sizeof(*positions
);
3688 if (draw
->MatrixPresent
)
3689 alloc_size
+= sizeof(*matrix
);
3691 positions
= alignedmem
= malloc(alloc_size
);
3694 GdipDeleteBrush((GpBrush
*)solidfill
);
3698 memcpy(positions
, &text
[draw
->GlyphCount
], alloc_size
);
3701 positions
= (PointF
*)&text
[draw
->GlyphCount
];
3703 if (draw
->MatrixPresent
)
3704 matrix
= (GpMatrix
*)&positions
[draw
->GlyphCount
];
3706 stat
= GdipDrawDriverString(real_metafile
->playback_graphics
, text
, draw
->GlyphCount
,
3707 real_metafile
->objtable
[font
].u
.font
, brush
, positions
,
3708 draw
->DriverStringOptionsFlags
, matrix
);
3710 GdipDeleteBrush((GpBrush
*)solidfill
);
3715 case EmfPlusRecordTypeFillRegion
:
3717 EmfPlusFillRegion
* const fill
= (EmfPlusFillRegion
*)header
;
3718 GpSolidFill
*solidfill
= NULL
;
3720 BYTE region
= flags
& 0xff;
3722 if (dataSize
!= sizeof(EmfPlusFillRegion
) - sizeof(EmfPlusRecordHeader
))
3723 return InvalidParameter
;
3725 if (region
>= EmfPlusObjectTableSize
||
3726 real_metafile
->objtable
[region
].type
!= ObjectTypeRegion
)
3727 return InvalidParameter
;
3731 stat
= GdipCreateSolidFill(fill
->data
.Color
, &solidfill
);
3734 brush
= (GpBrush
*)solidfill
;
3738 if (fill
->data
.BrushId
>= EmfPlusObjectTableSize
||
3739 real_metafile
->objtable
[fill
->data
.BrushId
].type
!= ObjectTypeBrush
)
3740 return InvalidParameter
;
3742 brush
= real_metafile
->objtable
[fill
->data
.BrushId
].u
.brush
;
3745 stat
= GdipFillRegion(real_metafile
->playback_graphics
, brush
,
3746 real_metafile
->objtable
[region
].u
.region
);
3747 GdipDeleteBrush((GpBrush
*)solidfill
);
3752 FIXME("Not implemented for record type %x\n", recordType
);
3753 return NotImplemented
;
3760 struct enum_metafile_data
3762 EnumerateMetafileProc callback
;
3763 void *callback_data
;
3764 GpMetafile
*metafile
;
3767 static int CALLBACK
enum_metafile_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
3768 int nObj
, LPARAM lpData
)
3771 struct enum_metafile_data
*data
= (struct enum_metafile_data
*)lpData
;
3774 data
->metafile
->handle_table
= lpHTable
;
3775 data
->metafile
->handle_count
= nObj
;
3777 /* First check for an EMF+ record. */
3778 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
3780 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
3782 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
3786 while (offset
+ sizeof(EmfPlusRecordHeader
) <= comment
->cbData
)
3788 const EmfPlusRecordHeader
*record
= (const EmfPlusRecordHeader
*)&comment
->Data
[offset
];
3790 if (record
->DataSize
)
3791 pStr
= (const BYTE
*)(record
+1);
3795 ret
= data
->callback(record
->Type
, record
->Flags
, record
->DataSize
,
3796 pStr
, data
->callback_data
);
3801 offset
+= record
->Size
;
3808 if (lpEMFR
->nSize
!= 8)
3809 pStr
= (const BYTE
*)lpEMFR
->dParm
;
3813 return data
->callback(lpEMFR
->iType
, 0, lpEMFR
->nSize
-8,
3814 pStr
, data
->callback_data
);
3817 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestPoints(GpGraphics
*graphics
,
3818 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*destPoints
, INT count
,
3819 GDIPCONST GpRectF
*srcRect
, Unit srcUnit
, EnumerateMetafileProc callback
,
3820 VOID
*callbackData
, GDIPCONST GpImageAttributes
*imageAttributes
)
3822 struct enum_metafile_data data
;
3824 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
; /* whoever made this const was joking */
3825 GraphicsContainer state
;
3829 TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics
, metafile
,
3830 destPoints
, count
, srcRect
, srcUnit
, callback
, callbackData
,
3833 if (!graphics
|| !metafile
|| !destPoints
|| count
!= 3 || !srcRect
)
3834 return InvalidParameter
;
3836 if (!metafile
->hemf
)
3837 return InvalidParameter
;
3839 if (metafile
->playback_graphics
)
3842 TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect
), srcUnit
,
3843 debugstr_pointf(&destPoints
[0]), debugstr_pointf(&destPoints
[1]),
3844 debugstr_pointf(&destPoints
[2]));
3846 data
.callback
= callback
;
3847 data
.callback_data
= callbackData
;
3848 data
.metafile
= real_metafile
;
3850 real_metafile
->playback_graphics
= graphics
;
3851 real_metafile
->playback_dc
= NULL
;
3852 real_metafile
->src_rect
= *srcRect
;
3854 memcpy(real_metafile
->playback_points
, destPoints
, sizeof(PointF
) * 3);
3855 stat
= GdipTransformPoints(graphics
, CoordinateSpaceDevice
, CoordinateSpaceWorld
, real_metafile
->playback_points
, 3);
3858 stat
= GdipBeginContainer2(graphics
, &state
);
3862 stat
= GdipSetPageScale(graphics
, 1.0);
3865 stat
= GdipSetPageUnit(graphics
, UnitPixel
);
3868 stat
= GdipResetWorldTransform(graphics
);
3871 stat
= GdipCreateRegion(&real_metafile
->base_clip
);
3874 stat
= GdipGetClip(graphics
, real_metafile
->base_clip
);
3877 stat
= GdipCreateRegion(&real_metafile
->clip
);
3880 stat
= GdipCreatePath(FillModeAlternate
, &dst_path
);
3884 GpPointF clip_points
[4];
3886 clip_points
[0] = real_metafile
->playback_points
[0];
3887 clip_points
[1] = real_metafile
->playback_points
[1];
3888 clip_points
[2].X
= real_metafile
->playback_points
[1].X
+ real_metafile
->playback_points
[2].X
3889 - real_metafile
->playback_points
[0].X
;
3890 clip_points
[2].Y
= real_metafile
->playback_points
[1].Y
+ real_metafile
->playback_points
[2].Y
3891 - real_metafile
->playback_points
[0].Y
;
3892 clip_points
[3] = real_metafile
->playback_points
[2];
3894 stat
= GdipAddPathPolygon(dst_path
, clip_points
, 4);
3897 stat
= GdipCombineRegionPath(real_metafile
->base_clip
, dst_path
, CombineModeIntersect
);
3899 GdipDeletePath(dst_path
);
3903 stat
= GdipCreateMatrix(&real_metafile
->world_transform
);
3907 real_metafile
->page_unit
= UnitDisplay
;
3908 real_metafile
->page_scale
= 1.0;
3909 stat
= METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
3914 stat
= METAFILE_PlaybackUpdateClip(real_metafile
);
3919 stat
= METAFILE_PlaybackGetDC(real_metafile
);
3921 dst_bounds
.left
= real_metafile
->playback_points
[0].X
;
3922 dst_bounds
.right
= real_metafile
->playback_points
[1].X
;
3923 dst_bounds
.top
= real_metafile
->playback_points
[0].Y
;
3924 dst_bounds
.bottom
= real_metafile
->playback_points
[2].Y
;
3928 EnumEnhMetaFile(real_metafile
->playback_dc
, metafile
->hemf
, enum_metafile_proc
,
3929 &data
, &dst_bounds
);
3931 METAFILE_PlaybackReleaseDC(real_metafile
);
3933 GdipDeleteMatrix(real_metafile
->world_transform
);
3934 real_metafile
->world_transform
= NULL
;
3936 GdipDeleteRegion(real_metafile
->base_clip
);
3937 real_metafile
->base_clip
= NULL
;
3939 GdipDeleteRegion(real_metafile
->clip
);
3940 real_metafile
->clip
= NULL
;
3942 while (list_head(&real_metafile
->containers
))
3944 container
* cont
= LIST_ENTRY(list_head(&real_metafile
->containers
), container
, entry
);
3945 list_remove(&cont
->entry
);
3946 GdipDeleteRegion(cont
->clip
);
3950 GdipEndContainer(graphics
, state
);
3953 real_metafile
->playback_graphics
= NULL
;
3958 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestRect( GpGraphics
*graphics
,
3959 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRectF
*dest
,
3960 GDIPCONST GpRectF
*src
, Unit srcUnit
, EnumerateMetafileProc callback
,
3961 VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3965 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
3967 points
[0].X
= points
[2].X
= dest
->X
;
3968 points
[0].Y
= points
[1].Y
= dest
->Y
;
3969 points
[1].X
= dest
->X
+ dest
->Width
;
3970 points
[2].Y
= dest
->Y
+ dest
->Height
;
3972 return GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, points
, 3,
3973 src
, srcUnit
, callback
, cb_data
, attrs
);
3975 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestRectI( GpGraphics
* graphics
,
3976 GDIPCONST GpMetafile
*metafile
, GDIPCONST Rect
*destRect
,
3977 GDIPCONST Rect
*srcRect
, Unit srcUnit
, EnumerateMetafileProc callback
,
3978 VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3980 GpRectF destRectF
, srcRectF
;
3982 destRectF
.X
= destRect
->X
;
3983 destRectF
.Y
= destRect
->Y
;
3984 destRectF
.Width
= destRect
->Width
;
3985 destRectF
.Height
= destRect
->Height
;
3987 srcRectF
.X
= srcRect
->X
;
3988 srcRectF
.Y
= srcRect
->Y
;
3989 srcRectF
.Width
= srcRect
->Width
;
3990 srcRectF
.Height
= srcRect
->Height
;
3992 return GdipEnumerateMetafileSrcRectDestRect( graphics
, metafile
, &destRectF
, &srcRectF
, srcUnit
, callback
, cb_data
, attrs
);
3995 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRect(GpGraphics
*graphics
,
3996 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRectF
*dest
,
3997 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
4001 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
4003 points
[0].X
= points
[2].X
= dest
->X
;
4004 points
[0].Y
= points
[1].Y
= dest
->Y
;
4005 points
[1].X
= dest
->X
+ dest
->Width
;
4006 points
[2].Y
= dest
->Y
+ dest
->Height
;
4008 return GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, points
, 3,
4009 &metafile
->bounds
, metafile
->unit
, callback
, cb_data
, attrs
);
4012 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRectI(GpGraphics
*graphics
,
4013 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRect
*dest
,
4014 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
4018 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
4022 destf
.Width
= dest
->Width
;
4023 destf
.Height
= dest
->Height
;
4025 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
4028 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPoint(GpGraphics
*graphics
,
4029 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*dest
,
4030 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
4034 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
4038 destf
.Width
= units_to_pixels(metafile
->bounds
.Width
, metafile
->unit
,
4039 metafile
->image
.xres
, metafile
->printer_display
);
4040 destf
.Height
= units_to_pixels(metafile
->bounds
.Height
, metafile
->unit
,
4041 metafile
->image
.yres
, metafile
->printer_display
);
4043 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
4046 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPointI(GpGraphics
*graphics
,
4047 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPoint
*dest
,
4048 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
4052 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
4057 return GdipEnumerateMetafileDestPoint(graphics
, metafile
, &ptf
, callback
, cb_data
, attrs
);
4060 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromMetafile(GpMetafile
* metafile
,
4061 MetafileHeader
* header
)
4065 TRACE("(%p, %p)\n", metafile
, header
);
4067 if(!metafile
|| !header
)
4068 return InvalidParameter
;
4072 status
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, header
);
4073 if (status
!= Ok
) return status
;
4077 memset(header
, 0, sizeof(*header
));
4078 header
->Version
= VERSION_MAGIC2
;
4081 header
->Type
= metafile
->metafile_type
;
4082 header
->DpiX
= metafile
->image
.xres
;
4083 header
->DpiY
= metafile
->image
.yres
;
4084 header
->Width
= gdip_round(metafile
->bounds
.Width
);
4085 header
->Height
= gdip_round(metafile
->bounds
.Height
);
4090 static int CALLBACK
get_emfplus_header_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
4091 int nObj
, LPARAM lpData
)
4093 EmfPlusHeader
*dst_header
= (EmfPlusHeader
*)lpData
;
4095 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
4097 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
4099 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
4101 const EmfPlusRecordHeader
*header
= (const EmfPlusRecordHeader
*)&comment
->Data
[4];
4103 if (4 + sizeof(EmfPlusHeader
) <= comment
->cbData
&&
4104 header
->Type
== EmfPlusRecordTypeHeader
)
4106 memcpy(dst_header
, header
, sizeof(*dst_header
));
4110 else if (lpEMFR
->iType
== EMR_HEADER
)
4116 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromEmf(HENHMETAFILE hemf
,
4117 MetafileHeader
*header
)
4119 ENHMETAHEADER3 emfheader
;
4120 EmfPlusHeader emfplusheader
;
4121 MetafileType metafile_type
;
4123 TRACE("(%p,%p)\n", hemf
, header
);
4125 if(!hemf
|| !header
)
4126 return InvalidParameter
;
4128 if (GetEnhMetaFileHeader(hemf
, sizeof(emfheader
), (ENHMETAHEADER
*)&emfheader
) == 0)
4129 return GenericError
;
4131 emfplusheader
.Header
.Type
= 0;
4133 EnumEnhMetaFile(NULL
, hemf
, get_emfplus_header_proc
, &emfplusheader
, NULL
);
4135 if (emfplusheader
.Header
.Type
== EmfPlusRecordTypeHeader
)
4137 if ((emfplusheader
.Header
.Flags
& 1) == 1)
4138 metafile_type
= MetafileTypeEmfPlusDual
;
4140 metafile_type
= MetafileTypeEmfPlusOnly
;
4143 metafile_type
= MetafileTypeEmf
;
4145 header
->Type
= metafile_type
;
4146 header
->Size
= emfheader
.nBytes
;
4147 header
->DpiX
= (REAL
)emfheader
.szlDevice
.cx
* 25.4 / emfheader
.szlMillimeters
.cx
;
4148 header
->DpiY
= (REAL
)emfheader
.szlDevice
.cy
* 25.4 / emfheader
.szlMillimeters
.cy
;
4149 header
->X
= gdip_round((REAL
)emfheader
.rclFrame
.left
/ 2540.0 * header
->DpiX
);
4150 header
->Y
= gdip_round((REAL
)emfheader
.rclFrame
.top
/ 2540.0 * header
->DpiY
);
4151 header
->Width
= gdip_round((REAL
)(emfheader
.rclFrame
.right
- emfheader
.rclFrame
.left
) / 2540.0 * header
->DpiX
);
4152 header
->Height
= gdip_round((REAL
)(emfheader
.rclFrame
.bottom
- emfheader
.rclFrame
.top
) / 2540.0 * header
->DpiY
);
4153 header
->EmfHeader
= emfheader
;
4155 if (metafile_type
== MetafileTypeEmfPlusDual
|| metafile_type
== MetafileTypeEmfPlusOnly
)
4157 header
->Version
= emfplusheader
.Version
;
4158 header
->EmfPlusFlags
= emfplusheader
.EmfPlusFlags
;
4159 header
->EmfPlusHeaderSize
= emfplusheader
.Header
.Size
;
4160 header
->LogicalDpiX
= emfplusheader
.LogicalDpiX
;
4161 header
->LogicalDpiY
= emfplusheader
.LogicalDpiY
;
4165 header
->Version
= emfheader
.nVersion
;
4166 header
->EmfPlusFlags
= 0;
4167 header
->EmfPlusHeaderSize
= 0;
4168 header
->LogicalDpiX
= 0;
4169 header
->LogicalDpiY
= 0;
4175 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromWmf(HMETAFILE hwmf
,
4176 GDIPCONST WmfPlaceableFileHeader
*placeable
, MetafileHeader
*header
)
4179 GpMetafile
*metafile
;
4181 TRACE("(%p,%p,%p)\n", hwmf
, placeable
, header
);
4183 status
= GdipCreateMetafileFromWmf(hwmf
, FALSE
, placeable
, &metafile
);
4186 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
4187 GdipDisposeImage(&metafile
->image
);
4192 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR
*filename
,
4193 MetafileHeader
*header
)
4196 GpMetafile
*metafile
;
4198 TRACE("(%s,%p)\n", debugstr_w(filename
), header
);
4200 if (!filename
|| !header
)
4201 return InvalidParameter
;
4203 status
= GdipCreateMetafileFromFile(filename
, &metafile
);
4206 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
4207 GdipDisposeImage(&metafile
->image
);
4212 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromStream(IStream
*stream
,
4213 MetafileHeader
*header
)
4216 GpMetafile
*metafile
;
4218 TRACE("(%p,%p)\n", stream
, header
);
4220 if (!stream
|| !header
)
4221 return InvalidParameter
;
4223 status
= GdipCreateMetafileFromStream(stream
, &metafile
);
4226 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
4227 GdipDisposeImage(&metafile
->image
);
4232 GpStatus WINGDIPAPI
GdipCreateMetafileFromEmf(HENHMETAFILE hemf
, BOOL
delete,
4233 GpMetafile
**metafile
)
4236 MetafileHeader header
;
4238 TRACE("(%p,%i,%p)\n", hemf
, delete, metafile
);
4240 if(!hemf
|| !metafile
)
4241 return InvalidParameter
;
4243 stat
= GdipGetMetafileHeaderFromEmf(hemf
, &header
);
4247 *metafile
= calloc(1, sizeof(GpMetafile
));
4251 (*metafile
)->image
.type
= ImageTypeMetafile
;
4252 (*metafile
)->image
.format
= ImageFormatEMF
;
4253 (*metafile
)->image
.frame_count
= 1;
4254 (*metafile
)->image
.xres
= header
.DpiX
;
4255 (*metafile
)->image
.yres
= header
.DpiY
;
4256 (*metafile
)->bounds
.X
= (REAL
)header
.EmfHeader
.rclFrame
.left
/ 2540.0 * header
.DpiX
;
4257 (*metafile
)->bounds
.Y
= (REAL
)header
.EmfHeader
.rclFrame
.top
/ 2540.0 * header
.DpiY
;
4258 (*metafile
)->bounds
.Width
= (REAL
)(header
.EmfHeader
.rclFrame
.right
- header
.EmfHeader
.rclFrame
.left
)
4259 / 2540.0 * header
.DpiX
;
4260 (*metafile
)->bounds
.Height
= (REAL
)(header
.EmfHeader
.rclFrame
.bottom
- header
.EmfHeader
.rclFrame
.top
)
4261 / 2540.0 * header
.DpiY
;
4262 (*metafile
)->unit
= UnitPixel
;
4263 (*metafile
)->metafile_type
= header
.Type
;
4264 (*metafile
)->hemf
= hemf
;
4265 (*metafile
)->preserve_hemf
= !delete;
4266 /* If the 31th bit of EmfPlusFlags was set, metafile was recorded with a DC for a video display.
4267 * If clear, metafile was recorded with a DC for a printer */
4268 (*metafile
)->printer_display
= !(header
.EmfPlusFlags
& (1u << 31));
4269 (*metafile
)->logical_dpix
= header
.LogicalDpiX
;
4270 (*metafile
)->logical_dpiy
= header
.LogicalDpiY
;
4271 list_init(&(*metafile
)->containers
);
4273 TRACE("<-- %p\n", *metafile
);
4278 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmf(HMETAFILE hwmf
, BOOL
delete,
4279 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
4284 GpStatus retval
= Ok
;
4286 TRACE("(%p, %d, %p, %p)\n", hwmf
, delete, placeable
, metafile
);
4288 if(!hwmf
|| !metafile
)
4289 return InvalidParameter
;
4292 read
= GetMetaFileBitsEx(hwmf
, 0, NULL
);
4294 return GenericError
;
4295 copy
= malloc(read
);
4296 GetMetaFileBitsEx(hwmf
, read
, copy
);
4298 hemf
= SetWinMetaFileBits(read
, copy
, NULL
, NULL
);
4301 /* FIXME: We should store and use hwmf instead of converting to hemf */
4302 retval
= GdipCreateMetafileFromEmf(hemf
, TRUE
, metafile
);
4308 (*metafile
)->image
.xres
= (REAL
)placeable
->Inch
;
4309 (*metafile
)->image
.yres
= (REAL
)placeable
->Inch
;
4310 (*metafile
)->bounds
.X
= ((REAL
)placeable
->BoundingBox
.Left
) / ((REAL
)placeable
->Inch
);
4311 (*metafile
)->bounds
.Y
= ((REAL
)placeable
->BoundingBox
.Top
) / ((REAL
)placeable
->Inch
);
4312 (*metafile
)->bounds
.Width
= (REAL
)(placeable
->BoundingBox
.Right
-
4313 placeable
->BoundingBox
.Left
);
4314 (*metafile
)->bounds
.Height
= (REAL
)(placeable
->BoundingBox
.Bottom
-
4315 placeable
->BoundingBox
.Top
);
4316 (*metafile
)->metafile_type
= MetafileTypeWmfPlaceable
;
4319 (*metafile
)->metafile_type
= MetafileTypeWmf
;
4320 (*metafile
)->image
.format
= ImageFormatWMF
;
4322 if (delete) DeleteMetaFile(hwmf
);
4325 DeleteEnhMetaFile(hemf
);
4329 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR
*file
,
4330 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
4335 TRACE("(%s, %p, %p)\n", debugstr_w(file
), placeable
, metafile
);
4337 hmf
= GetMetaFileW(file
);
4339 return GdipCreateMetafileFromWmf(hmf
, TRUE
, placeable
, metafile
);
4341 emf
= GetEnhMetaFileW(file
);
4343 return GdipCreateMetafileFromEmf(emf
, TRUE
, metafile
);
4345 return GenericError
;
4348 GpStatus WINGDIPAPI
GdipCreateMetafileFromFile(GDIPCONST WCHAR
*file
,
4349 GpMetafile
**metafile
)
4354 TRACE("(%p, %p)\n", file
, metafile
);
4356 if (!file
|| !metafile
) return InvalidParameter
;
4360 status
= GdipCreateStreamOnFile(file
, GENERIC_READ
, &stream
);
4363 status
= GdipCreateMetafileFromStream(stream
, metafile
);
4364 IStream_Release(stream
);
4369 GpStatus WINGDIPAPI
GdipCreateMetafileFromStream(IStream
*stream
,
4370 GpMetafile
**metafile
)
4374 TRACE("%p %p\n", stream
, metafile
);
4376 stat
= GdipLoadImageFromStream(stream
, (GpImage
**)metafile
);
4377 if (stat
!= Ok
) return stat
;
4379 if ((*metafile
)->image
.type
!= ImageTypeMetafile
)
4381 GdipDisposeImage(&(*metafile
)->image
);
4383 return GenericError
;
4389 GpStatus WINGDIPAPI
GdipGetMetafileDownLevelRasterizationLimit(GDIPCONST GpMetafile
*metafile
,
4392 TRACE("(%p,%p)\n", metafile
, limitDpi
);
4394 if (!metafile
|| !limitDpi
)
4395 return InvalidParameter
;
4397 if (!metafile
->record_dc
)
4400 *limitDpi
= metafile
->limit_dpi
;
4405 GpStatus WINGDIPAPI
GdipSetMetafileDownLevelRasterizationLimit(GpMetafile
*metafile
,
4408 TRACE("(%p,%u)\n", metafile
, limitDpi
);
4413 if (!metafile
|| limitDpi
< 10)
4414 return InvalidParameter
;
4416 if (!metafile
->record_dc
)
4419 metafile
->limit_dpi
= limitDpi
;
4424 GpStatus WINGDIPAPI
GdipConvertToEmfPlus(const GpGraphics
* ref
,
4425 GpMetafile
* metafile
, BOOL
* succ
, EmfType emfType
,
4426 const WCHAR
* description
, GpMetafile
** out_metafile
)
4430 TRACE("(%p,%p,%p,%u,%s,%p)\n", ref
, metafile
, succ
, emfType
,
4431 debugstr_w(description
), out_metafile
);
4433 if(!ref
|| !metafile
|| !out_metafile
|| emfType
< EmfTypeEmfOnly
|| emfType
> EmfTypeEmfPlusDual
)
4434 return InvalidParameter
;
4438 *out_metafile
= NULL
;
4441 FIXME("not implemented\n");
4443 return NotImplemented
;
4446 GpStatus WINGDIPAPI
GdipEmfToWmfBits(HENHMETAFILE hemf
, UINT cbData16
,
4447 LPBYTE pData16
, INT iMapMode
, INT eFlags
)
4449 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf
, cbData16
, pData16
, iMapMode
, eFlags
);
4450 return NotImplemented
;
4453 GpStatus WINGDIPAPI
GdipRecordMetafileFileName(GDIPCONST WCHAR
* fileName
,
4454 HDC hdc
, EmfType type
, GDIPCONST GpRectF
*pFrameRect
,
4455 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
,
4456 GpMetafile
**metafile
)
4460 REAL framerect_factor_x
, framerect_factor_y
;
4464 TRACE("%s %p %d %s %d %s %p\n", debugstr_w(fileName
), hdc
, type
, debugstr_rectf(pFrameRect
),
4465 frameUnit
, debugstr_w(desc
), metafile
);
4467 if (!hdc
|| type
< EmfTypeEmfOnly
|| type
> EmfTypeEmfPlusDual
|| !metafile
)
4468 return InvalidParameter
;
4470 dpix
= (REAL
)GetDeviceCaps(hdc
, HORZRES
) / GetDeviceCaps(hdc
, HORZSIZE
) * 25.4;
4471 dpiy
= (REAL
)GetDeviceCaps(hdc
, VERTRES
) / GetDeviceCaps(hdc
, VERTSIZE
) * 25.4;
4477 case MetafileFrameUnitPixel
:
4478 framerect_factor_x
= 2540.0 / dpix
;
4479 framerect_factor_y
= 2540.0 / dpiy
;
4481 case MetafileFrameUnitPoint
:
4482 framerect_factor_x
= framerect_factor_y
= 2540.0 / 72.0;
4484 case MetafileFrameUnitInch
:
4485 framerect_factor_x
= framerect_factor_y
= 2540.0;
4487 case MetafileFrameUnitDocument
:
4488 framerect_factor_x
= framerect_factor_y
= 2540.0 / 300.0;
4490 case MetafileFrameUnitMillimeter
:
4491 framerect_factor_x
= framerect_factor_y
= 100.0;
4493 case MetafileFrameUnitGdi
:
4494 framerect_factor_x
= framerect_factor_y
= 1.0;
4497 return InvalidParameter
;
4500 rc
.left
= framerect_factor_x
* pFrameRect
->X
;
4501 rc
.top
= framerect_factor_y
* pFrameRect
->Y
;
4502 rc
.right
= rc
.left
+ framerect_factor_x
* pFrameRect
->Width
;
4503 rc
.bottom
= rc
.top
+ framerect_factor_y
* pFrameRect
->Height
;
4510 record_dc
= CreateEnhMetaFileW(hdc
, fileName
, lprc
, desc
);
4513 return GenericError
;
4515 *metafile
= calloc(1, sizeof(GpMetafile
));
4518 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
4522 (*metafile
)->image
.type
= ImageTypeMetafile
;
4523 (*metafile
)->image
.flags
= ImageFlagsNone
;
4524 (*metafile
)->image
.palette
= NULL
;
4525 (*metafile
)->image
.xres
= dpix
;
4526 (*metafile
)->image
.yres
= dpiy
;
4527 (*metafile
)->bounds
.X
= (*metafile
)->bounds
.Y
= 0.0;
4528 (*metafile
)->bounds
.Width
= (*metafile
)->bounds
.Height
= 1.0;
4529 (*metafile
)->unit
= UnitPixel
;
4530 (*metafile
)->metafile_type
= (MetafileType
)type
;
4531 (*metafile
)->record_dc
= record_dc
;
4532 (*metafile
)->comment_data
= NULL
;
4533 (*metafile
)->comment_data_size
= 0;
4534 (*metafile
)->comment_data_length
= 0;
4535 (*metafile
)->limit_dpi
= 96;
4536 (*metafile
)->hemf
= NULL
;
4537 (*metafile
)->printer_display
= (GetDeviceCaps(record_dc
, TECHNOLOGY
) == DT_RASPRINTER
);
4538 (*metafile
)->logical_dpix
= (REAL
)GetDeviceCaps(record_dc
, LOGPIXELSX
);
4539 (*metafile
)->logical_dpiy
= (REAL
)GetDeviceCaps(record_dc
, LOGPIXELSY
);
4540 list_init(&(*metafile
)->containers
);
4544 (*metafile
)->auto_frame
= TRUE
;
4545 (*metafile
)->auto_frame_min
.X
= 0;
4546 (*metafile
)->auto_frame_min
.Y
= 0;
4547 (*metafile
)->auto_frame_max
.X
= -1;
4548 (*metafile
)->auto_frame_max
.Y
= -1;
4551 stat
= METAFILE_WriteHeader(*metafile
, hdc
);
4555 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
4564 GpStatus WINGDIPAPI
GdipRecordMetafileFileNameI(GDIPCONST WCHAR
* fileName
, HDC hdc
, EmfType type
,
4565 GDIPCONST GpRect
*pFrameRect
, MetafileFrameUnit frameUnit
,
4566 GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
4568 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
4569 frameUnit
, debugstr_w(desc
), metafile
);
4571 return NotImplemented
;
4574 /*****************************************************************************
4575 * GdipConvertToEmfPlusToFile [GDIPLUS.@]
4578 GpStatus WINGDIPAPI
GdipConvertToEmfPlusToFile(const GpGraphics
* refGraphics
,
4579 GpMetafile
* metafile
, BOOL
* conversionSuccess
,
4580 const WCHAR
* filename
, EmfType emfType
,
4581 const WCHAR
* description
, GpMetafile
** out_metafile
)
4583 FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics
, metafile
, conversionSuccess
, filename
, emfType
, description
, out_metafile
);
4584 return NotImplemented
;
4587 static GpStatus
METAFILE_CreateCompressedImageStream(GpImage
*image
, IStream
**stream
, DWORD
*size
)
4596 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, stream
);
4597 if (FAILED(hr
)) return hresult_to_status(hr
);
4599 stat
= encode_image_png(image
, *stream
, NULL
);
4602 IStream_Release(*stream
);
4606 hr
= IStream_Stat(*stream
, &statstg
, 1);
4609 IStream_Release(*stream
);
4610 return hresult_to_status(hr
);
4612 *size
= statstg
.cbSize
.u
.LowPart
;
4615 hr
= IStream_Seek(*stream
, zero
, STREAM_SEEK_SET
, NULL
);
4618 IStream_Release(*stream
);
4619 return hresult_to_status(hr
);
4625 static GpStatus
METAFILE_FillEmfPlusBitmap(EmfPlusBitmap
*record
, IStream
*stream
, DWORD size
)
4632 record
->PixelFormat
= 0;
4633 record
->Type
= BitmapDataTypeCompressed
;
4635 hr
= IStream_Read(stream
, record
->BitmapData
, size
, NULL
);
4636 if (FAILED(hr
)) return hresult_to_status(hr
);
4640 static GpStatus
METAFILE_AddImageObject(GpMetafile
*metafile
, GpImage
*image
, DWORD
*id
)
4642 EmfPlusObject
*object_record
;
4648 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4651 if (image
->type
== ImageTypeBitmap
)
4656 stat
= METAFILE_CreateCompressedImageStream(image
, &stream
, &size
);
4657 if (stat
!= Ok
) return stat
;
4658 aligned_size
= (size
+ 3) & ~3;
4660 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
4661 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image
.ImageData
.bitmap
.BitmapData
[aligned_size
]),
4662 (void**)&object_record
);
4665 IStream_Release(stream
);
4668 memset(object_record
->ObjectData
.image
.ImageData
.bitmap
.BitmapData
+ size
, 0, aligned_size
- size
);
4670 *id
= METAFILE_AddObjectId(metafile
);
4671 object_record
->Header
.Flags
= *id
| ObjectTypeImage
<< 8;
4672 object_record
->ObjectData
.image
.Version
= VERSION_MAGIC2
;
4673 object_record
->ObjectData
.image
.Type
= ImageDataTypeBitmap
;
4675 stat
= METAFILE_FillEmfPlusBitmap(&object_record
->ObjectData
.image
.ImageData
.bitmap
, stream
, size
);
4676 IStream_Release(stream
);
4677 if (stat
!= Ok
) METAFILE_RemoveLastRecord(metafile
, &object_record
->Header
);
4680 else if (image
->type
== ImageTypeMetafile
)
4682 HENHMETAFILE hemf
= ((GpMetafile
*)image
)->hemf
;
4683 EmfPlusMetafile
*metafile_record
;
4685 if (!hemf
) return InvalidParameter
;
4687 size
= GetEnhMetaFileBits(hemf
, 0, NULL
);
4688 if (!size
) return GenericError
;
4690 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
4691 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image
.ImageData
.metafile
.MetafileData
[size
]),
4692 (void**)&object_record
);
4693 if (stat
!= Ok
) return stat
;
4695 *id
= METAFILE_AddObjectId(metafile
);
4696 object_record
->Header
.Flags
= *id
| ObjectTypeImage
<< 8;
4697 object_record
->ObjectData
.image
.Version
= VERSION_MAGIC2
;
4698 object_record
->ObjectData
.image
.Type
= ImageDataTypeMetafile
;
4699 metafile_record
= &object_record
->ObjectData
.image
.ImageData
.metafile
;
4700 metafile_record
->Type
= ((GpMetafile
*)image
)->metafile_type
;
4701 metafile_record
->MetafileDataSize
= size
;
4702 if (GetEnhMetaFileBits(hemf
, size
, metafile_record
->MetafileData
) != size
)
4704 METAFILE_RemoveLastRecord(metafile
, &object_record
->Header
);
4705 return GenericError
;
4711 FIXME("not supported image type (%d)\n", image
->type
);
4712 return NotImplemented
;
4716 static GpStatus
METAFILE_AddImageAttributesObject(GpMetafile
*metafile
, const GpImageAttributes
*attrs
, DWORD
*id
)
4718 EmfPlusObject
*object_record
;
4719 EmfPlusImageAttributes
*attrs_record
;
4724 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4730 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
4731 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image_attributes
) + sizeof(EmfPlusImageAttributes
),
4732 (void**)&object_record
);
4733 if (stat
!= Ok
) return stat
;
4735 *id
= METAFILE_AddObjectId(metafile
);
4736 object_record
->Header
.Flags
= *id
| (ObjectTypeImageAttributes
<< 8);
4737 attrs_record
= &object_record
->ObjectData
.image_attributes
;
4738 attrs_record
->Version
= VERSION_MAGIC2
;
4739 attrs_record
->Reserved1
= 0;
4740 attrs_record
->WrapMode
= attrs
->wrap
;
4741 attrs_record
->ClampColor
= attrs
->outside_color
;
4742 attrs_record
->ObjectClamp
= attrs
->clamp
;
4743 attrs_record
->Reserved2
= 0;
4747 GpStatus
METAFILE_DrawImagePointsRect(GpMetafile
*metafile
, GpImage
*image
,
4748 GDIPCONST GpPointF
*points
, INT count
, REAL srcx
, REAL srcy
, REAL srcwidth
,
4749 REAL srcheight
, GpUnit srcUnit
, GDIPCONST GpImageAttributes
* imageAttributes
,
4750 DrawImageAbort callback
, VOID
*callbackData
)
4752 EmfPlusDrawImagePoints
*draw_image_record
;
4753 DWORD image_id
, attributes_id
;
4756 if (count
!= 3) return InvalidParameter
;
4758 if (metafile
->metafile_type
== MetafileTypeEmf
)
4760 FIXME("MetafileTypeEmf metafiles not supported\n");
4761 return NotImplemented
;
4764 FIXME("semi-stub\n");
4766 if (!imageAttributes
)
4768 stat
= METAFILE_AddImageObject(metafile
, image
, &image_id
);
4770 else if (image
->type
== ImageTypeBitmap
)
4772 INT width
= ((GpBitmap
*)image
)->width
;
4773 INT height
= ((GpBitmap
*)image
)->height
;
4774 GpGraphics
*graphics
;
4777 stat
= GdipCreateBitmapFromScan0(width
, height
,
4778 0, PixelFormat32bppARGB
, NULL
, &bitmap
);
4779 if (stat
!= Ok
) return stat
;
4781 stat
= GdipGetImageGraphicsContext((GpImage
*)bitmap
, &graphics
);
4784 GdipDisposeImage((GpImage
*)bitmap
);
4788 stat
= GdipDrawImageRectRectI(graphics
, image
, 0, 0, width
, height
,
4789 0, 0, width
, height
, UnitPixel
, imageAttributes
, NULL
, NULL
);
4790 GdipDeleteGraphics(graphics
);
4793 GdipDisposeImage((GpImage
*)bitmap
);
4797 stat
= METAFILE_AddImageObject(metafile
, (GpImage
*)bitmap
, &image_id
);
4798 GdipDisposeImage((GpImage
*)bitmap
);
4802 FIXME("imageAttributes not supported (image type %d)\n", image
->type
);
4803 return NotImplemented
;
4805 if (stat
!= Ok
) return stat
;
4807 stat
= METAFILE_AddImageAttributesObject(metafile
, imageAttributes
, &attributes_id
);
4808 if (stat
!= Ok
) return stat
;
4810 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeDrawImagePoints
,
4811 sizeof(EmfPlusDrawImagePoints
), (void **)&draw_image_record
);
4812 if (stat
!= Ok
) return stat
;
4814 draw_image_record
->Header
.Flags
= image_id
;
4815 draw_image_record
->ImageAttributesID
= attributes_id
;
4816 draw_image_record
->SrcUnit
= UnitPixel
;
4817 draw_image_record
->SrcRect
.X
= units_to_pixels(srcx
, srcUnit
, metafile
->image
.xres
, metafile
->printer_display
);
4818 draw_image_record
->SrcRect
.Y
= units_to_pixels(srcy
, srcUnit
, metafile
->image
.yres
, metafile
->printer_display
);
4819 draw_image_record
->SrcRect
.Width
= units_to_pixels(srcwidth
, srcUnit
, metafile
->image
.xres
, metafile
->printer_display
);
4820 draw_image_record
->SrcRect
.Height
= units_to_pixels(srcheight
, srcUnit
, metafile
->image
.yres
, metafile
->printer_display
);
4821 draw_image_record
->count
= 3;
4822 memcpy(draw_image_record
->PointData
.pointsF
, points
, 3 * sizeof(*points
));
4823 METAFILE_WriteRecords(metafile
);
4827 GpStatus
METAFILE_AddSimpleProperty(GpMetafile
*metafile
, SHORT prop
, SHORT val
)
4829 EmfPlusRecordHeader
*record
;
4832 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4835 stat
= METAFILE_AllocateRecord(metafile
, prop
, sizeof(*record
), (void**)&record
);
4836 if (stat
!= Ok
) return stat
;
4838 record
->Flags
= val
;
4840 METAFILE_WriteRecords(metafile
);
4844 static GpStatus
METAFILE_AddPathObject(GpMetafile
*metafile
, GpPath
*path
, DWORD
*id
)
4846 EmfPlusObject
*object_record
;
4851 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4854 size
= write_path_data(path
, NULL
);
4855 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
4856 FIELD_OFFSET(EmfPlusObject
, ObjectData
.path
) + size
,
4857 (void**)&object_record
);
4858 if (stat
!= Ok
) return stat
;
4860 *id
= METAFILE_AddObjectId(metafile
);
4861 object_record
->Header
.Flags
= *id
| ObjectTypePath
<< 8;
4862 write_path_data(path
, &object_record
->ObjectData
.path
);
4866 static GpStatus
METAFILE_AddPenObject(GpMetafile
*metafile
, GpPen
*pen
, DWORD
*id
)
4868 DWORD custom_start_cap_size
= 0, custom_start_cap_data_size
= 0, custom_start_cap_path_size
= 0;
4869 DWORD custom_end_cap_size
= 0, custom_end_cap_data_size
= 0, custom_end_cap_path_size
= 0;
4870 DWORD i
, data_flags
, pen_data_size
, brush_size
;
4871 EmfPlusObject
*object_record
;
4872 EmfPlusPenData
*pen_data
;
4877 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4881 pen_data_size
= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
4883 GdipIsMatrixIdentity(&pen
->transform
, &result
);
4886 data_flags
|= PenDataTransform
;
4887 pen_data_size
+= sizeof(EmfPlusTransformMatrix
);
4889 if (pen
->startcap
!= LineCapFlat
)
4891 data_flags
|= PenDataStartCap
;
4892 pen_data_size
+= sizeof(DWORD
);
4894 if (pen
->endcap
!= LineCapFlat
)
4896 data_flags
|= PenDataEndCap
;
4897 pen_data_size
+= sizeof(DWORD
);
4899 if (pen
->join
!= LineJoinMiter
)
4901 data_flags
|= PenDataJoin
;
4902 pen_data_size
+= sizeof(DWORD
);
4904 if (pen
->miterlimit
!= 10.0)
4906 data_flags
|= PenDataMiterLimit
;
4907 pen_data_size
+= sizeof(REAL
);
4909 if (pen
->style
!= GP_DEFAULT_PENSTYLE
)
4911 data_flags
|= PenDataLineStyle
;
4912 pen_data_size
+= sizeof(DWORD
);
4914 if (pen
->dashcap
!= DashCapFlat
)
4916 data_flags
|= PenDataDashedLineCap
;
4917 pen_data_size
+= sizeof(DWORD
);
4919 data_flags
|= PenDataDashedLineOffset
;
4920 pen_data_size
+= sizeof(REAL
);
4923 data_flags
|= PenDataDashedLine
;
4924 pen_data_size
+= sizeof(DWORD
) + pen
->numdashes
*sizeof(REAL
);
4926 if (pen
->align
!= PenAlignmentCenter
)
4928 data_flags
|= PenDataNonCenter
;
4929 pen_data_size
+= sizeof(DWORD
);
4931 /* TODO: Add support for PenDataCompoundLine */
4932 if (pen
->customstart
)
4934 data_flags
|= PenDataCustomStartCap
;
4935 METAFILE_PrepareCustomLineCapData(pen
->customstart
, &custom_start_cap_size
,
4936 &custom_start_cap_data_size
, &custom_start_cap_path_size
);
4937 pen_data_size
+= custom_start_cap_size
;
4941 data_flags
|= PenDataCustomEndCap
;
4942 METAFILE_PrepareCustomLineCapData(pen
->customend
, &custom_end_cap_size
,
4943 &custom_end_cap_data_size
, &custom_end_cap_path_size
);
4944 pen_data_size
+= custom_end_cap_size
;
4947 stat
= METAFILE_PrepareBrushData(pen
->brush
, &brush_size
);
4948 if (stat
!= Ok
) return stat
;
4950 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
4951 FIELD_OFFSET(EmfPlusObject
, ObjectData
.pen
.data
) + pen_data_size
+ brush_size
,
4952 (void**)&object_record
);
4953 if (stat
!= Ok
) return stat
;
4955 *id
= METAFILE_AddObjectId(metafile
);
4956 object_record
->Header
.Flags
= *id
| ObjectTypePen
<< 8;
4957 object_record
->ObjectData
.pen
.Version
= VERSION_MAGIC2
;
4958 object_record
->ObjectData
.pen
.Type
= 0;
4960 pen_data
= (EmfPlusPenData
*)object_record
->ObjectData
.pen
.data
;
4961 pen_data
->PenDataFlags
= data_flags
;
4962 pen_data
->PenUnit
= pen
->unit
;
4963 pen_data
->PenWidth
= pen
->width
;
4966 if (data_flags
& PenDataTransform
)
4968 EmfPlusTransformMatrix
*m
= (EmfPlusTransformMatrix
*)(pen_data
->OptionalData
+ i
);
4969 memcpy(m
, &pen
->transform
, sizeof(*m
));
4970 i
+= sizeof(EmfPlusTransformMatrix
);
4972 if (data_flags
& PenDataStartCap
)
4974 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->startcap
;
4977 if (data_flags
& PenDataEndCap
)
4979 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->endcap
;
4982 if (data_flags
& PenDataJoin
)
4984 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->join
;
4987 if (data_flags
& PenDataMiterLimit
)
4989 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->miterlimit
;
4992 if (data_flags
& PenDataLineStyle
)
4994 switch (pen
->style
& PS_STYLE_MASK
)
4996 case PS_SOLID
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleSolid
; break;
4997 case PS_DASH
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDash
; break;
4998 case PS_DOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDot
; break;
4999 case PS_DASHDOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDashDot
; break;
5000 case PS_DASHDOTDOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDashDotDot
; break;
5001 default: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleCustom
; break;
5005 if (data_flags
& PenDataDashedLineCap
)
5007 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->dashcap
;
5010 if (data_flags
& PenDataDashedLineOffset
)
5012 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->offset
;
5015 if (data_flags
& PenDataDashedLine
)
5019 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->numdashes
;
5022 for (j
=0; j
<pen
->numdashes
; j
++)
5024 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->dashes
[j
];
5028 if (data_flags
& PenDataNonCenter
)
5030 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->align
;
5033 if (data_flags
& PenDataCustomStartCap
)
5035 METAFILE_FillCustomLineCapData(pen
->customstart
, pen_data
->OptionalData
+ i
,
5036 pen
->miterlimit
, custom_start_cap_data_size
,
5037 custom_start_cap_path_size
);
5038 i
+= custom_start_cap_size
;
5040 if (data_flags
& PenDataCustomEndCap
)
5042 METAFILE_FillCustomLineCapData(pen
->customend
, pen_data
->OptionalData
+ i
,
5043 pen
->miterlimit
, custom_end_cap_data_size
,
5044 custom_end_cap_path_size
);
5045 i
+= custom_end_cap_size
;
5048 METAFILE_FillBrushData(pen
->brush
,
5049 (EmfPlusBrush
*)(object_record
->ObjectData
.pen
.data
+ pen_data_size
));
5053 GpStatus
METAFILE_DrawPath(GpMetafile
*metafile
, GpPen
*pen
, GpPath
*path
)
5055 EmfPlusDrawPath
*draw_path_record
;
5060 if (metafile
->metafile_type
== MetafileTypeEmf
)
5063 return NotImplemented
;
5066 stat
= METAFILE_AddPenObject(metafile
, pen
, &pen_id
);
5067 if (stat
!= Ok
) return stat
;
5069 stat
= METAFILE_AddPathObject(metafile
, path
, &path_id
);
5070 if (stat
!= Ok
) return stat
;
5072 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeDrawPath
,
5073 sizeof(EmfPlusDrawPath
), (void **)&draw_path_record
);
5074 if (stat
!= Ok
) return stat
;
5075 draw_path_record
->Header
.Type
= EmfPlusRecordTypeDrawPath
;
5076 draw_path_record
->Header
.Flags
= path_id
;
5077 draw_path_record
->PenId
= pen_id
;
5079 METAFILE_WriteRecords(metafile
);
5083 GpStatus
METAFILE_DrawEllipse(GpMetafile
*metafile
, GpPen
*pen
, GpRectF
*rect
)
5085 EmfPlusDrawEllipse
*record
;
5089 if (metafile
->metafile_type
== MetafileTypeEmf
)
5092 return NotImplemented
;
5095 stat
= METAFILE_AddPenObject(metafile
, pen
, &pen_id
);
5096 if (stat
!= Ok
) return stat
;
5098 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeDrawEllipse
,
5099 sizeof(EmfPlusDrawEllipse
), (void **)&record
);
5100 if (stat
!= Ok
) return stat
;
5101 record
->Header
.Type
= EmfPlusRecordTypeDrawEllipse
;
5102 record
->Header
.Flags
= pen_id
;
5103 if (is_integer_rect(rect
))
5105 record
->Header
.Flags
|= 0x4000;
5106 record
->RectData
.rect
.X
= (SHORT
)rect
->X
;
5107 record
->RectData
.rect
.Y
= (SHORT
)rect
->Y
;
5108 record
->RectData
.rect
.Width
= (SHORT
)rect
->Width
;
5109 record
->RectData
.rect
.Height
= (SHORT
)rect
->Height
;
5112 memcpy(&record
->RectData
.rectF
, rect
, sizeof(*rect
));
5114 METAFILE_WriteRecords(metafile
);
5118 GpStatus
METAFILE_FillPath(GpMetafile
*metafile
, GpBrush
*brush
, GpPath
*path
)
5120 EmfPlusFillPath
*fill_path_record
;
5121 DWORD brush_id
= -1, path_id
;
5125 if (metafile
->metafile_type
== MetafileTypeEmf
)
5128 return NotImplemented
;
5131 inline_color
= brush
->bt
== BrushTypeSolidColor
;
5134 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
5135 if (stat
!= Ok
) return stat
;
5138 stat
= METAFILE_AddPathObject(metafile
, path
, &path_id
);
5139 if (stat
!= Ok
) return stat
;
5141 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeFillPath
,
5142 sizeof(EmfPlusFillPath
), (void**)&fill_path_record
);
5143 if (stat
!= Ok
) return stat
;
5146 fill_path_record
->Header
.Flags
= 0x8000 | path_id
;
5147 fill_path_record
->data
.Color
= ((GpSolidFill
*)brush
)->color
;
5151 fill_path_record
->Header
.Flags
= path_id
;
5152 fill_path_record
->data
.BrushId
= brush_id
;
5155 METAFILE_WriteRecords(metafile
);
5159 GpStatus
METAFILE_FillEllipse(GpMetafile
*metafile
, GpBrush
*brush
, GpRectF
*rect
)
5161 EmfPlusFillEllipse
*record
;
5162 DWORD brush_id
= -1;
5166 if (metafile
->metafile_type
== MetafileTypeEmf
)
5169 return NotImplemented
;
5172 inline_color
= brush
->bt
== BrushTypeSolidColor
;
5175 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
5176 if (stat
!= Ok
) return stat
;
5179 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeFillEllipse
, sizeof(EmfPlusFillEllipse
), (void **)&record
);
5180 if (stat
!= Ok
) return stat
;
5183 record
->Header
.Flags
= 0x8000;
5184 record
->BrushId
= ((GpSolidFill
*)brush
)->color
;
5187 record
->BrushId
= brush_id
;
5189 if (is_integer_rect(rect
))
5191 record
->Header
.Flags
|= 0x4000;
5192 record
->RectData
.rect
.X
= (SHORT
)rect
->X
;
5193 record
->RectData
.rect
.Y
= (SHORT
)rect
->Y
;
5194 record
->RectData
.rect
.Width
= (SHORT
)rect
->Width
;
5195 record
->RectData
.rect
.Height
= (SHORT
)rect
->Height
;
5198 memcpy(&record
->RectData
.rectF
, rect
, sizeof(*rect
));
5200 METAFILE_WriteRecords(metafile
);
5204 GpStatus
METAFILE_FillPie(GpMetafile
*metafile
, GpBrush
*brush
, const GpRectF
*rect
,
5205 REAL startAngle
, REAL sweepAngle
)
5207 BOOL is_int_rect
, inline_color
;
5208 EmfPlusFillPie
*record
;
5209 DWORD brush_id
= -1;
5212 if (metafile
->metafile_type
== MetafileTypeEmf
)
5215 return NotImplemented
;
5218 inline_color
= brush
->bt
== BrushTypeSolidColor
;
5221 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
5222 if (stat
!= Ok
) return stat
;
5225 is_int_rect
= is_integer_rect(rect
);
5227 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeFillPie
,
5228 FIELD_OFFSET(EmfPlusFillPie
, RectData
) + is_int_rect
? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
),
5230 if (stat
!= Ok
) return stat
;
5233 record
->Header
.Flags
= 0x8000;
5234 record
->BrushId
= ((GpSolidFill
*)brush
)->color
;
5237 record
->BrushId
= brush_id
;
5239 record
->StartAngle
= startAngle
;
5240 record
->SweepAngle
= sweepAngle
;
5244 record
->Header
.Flags
|= 0x4000;
5245 record
->RectData
.rect
.X
= (SHORT
)rect
->X
;
5246 record
->RectData
.rect
.Y
= (SHORT
)rect
->Y
;
5247 record
->RectData
.rect
.Width
= (SHORT
)rect
->Width
;
5248 record
->RectData
.rect
.Height
= (SHORT
)rect
->Height
;
5251 memcpy(&record
->RectData
.rectF
, rect
, sizeof(*rect
));
5253 METAFILE_WriteRecords(metafile
);
5257 static GpStatus
METAFILE_AddFontObject(GpMetafile
*metafile
, GDIPCONST GpFont
*font
, DWORD
*id
)
5259 EmfPlusObject
*object_record
;
5260 EmfPlusFont
*font_record
;
5267 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&&
5268 metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
5271 /* The following cast is ugly, but GdipGetFontStyle does treat
5272 its first parameter as const. */
5273 stat
= GdipGetFontStyle((GpFont
*)font
, &style
);
5277 fn_len
= lstrlenW(font
->family
->FamilyName
);
5278 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
5279 FIELD_OFFSET(EmfPlusObject
, ObjectData
.font
.FamilyName
[(fn_len
+ 1) & ~1]),
5280 (void**)&object_record
);
5284 *id
= METAFILE_AddObjectId(metafile
);
5286 object_record
->Header
.Flags
= *id
| ObjectTypeFont
<< 8;
5288 font_record
= &object_record
->ObjectData
.font
;
5289 font_record
->Version
= VERSION_MAGIC2
;
5290 font_record
->EmSize
= font
->emSize
;
5291 font_record
->SizeUnit
= font
->unit
;
5292 font_record
->FontStyleFlags
= style
;
5293 font_record
->Reserved
= 0;
5294 font_record
->Length
= fn_len
;
5296 memcpy(font_record
->FamilyName
, font
->family
->FamilyName
,
5297 fn_len
* sizeof(*font
->family
->FamilyName
));
5302 GpStatus
METAFILE_DrawDriverString(GpMetafile
*metafile
, GDIPCONST UINT16
*text
, INT length
,
5303 GDIPCONST GpFont
*font
, GDIPCONST GpStringFormat
*format
, GDIPCONST GpBrush
*brush
,
5304 GDIPCONST PointF
*positions
, INT flags
, GDIPCONST GpMatrix
*matrix
)
5310 EmfPlusDrawDriverString
*draw_string_record
;
5313 BOOL include_matrix
= FALSE
;
5316 return InvalidParameter
;
5318 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&&
5319 metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
5321 FIXME("metafile type not supported: %i\n", metafile
->metafile_type
);
5322 return NotImplemented
;
5325 stat
= METAFILE_AddFontObject(metafile
, font
, &font_id
);
5329 inline_color
= (brush
->bt
== BrushTypeSolidColor
);
5332 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
5341 stat
= GdipIsMatrixIdentity(matrix
, &identity
);
5345 include_matrix
= !identity
;
5348 alloc_size
= FIELD_OFFSET(EmfPlusDrawDriverString
, VariableData
) +
5349 length
* (sizeof(*text
) + sizeof(*positions
));
5352 alloc_size
+= sizeof(*matrix
);
5354 /* Pad record to DWORD alignment. */
5355 alloc_size
= (alloc_size
+ 3) & ~3;
5357 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeDrawDriverString
, alloc_size
, (void**)&draw_string_record
);
5361 draw_string_record
->Header
.Flags
= font_id
;
5362 draw_string_record
->DriverStringOptionsFlags
= flags
;
5363 draw_string_record
->MatrixPresent
= include_matrix
;
5364 draw_string_record
->GlyphCount
= length
;
5368 draw_string_record
->Header
.Flags
|= 0x8000;
5369 draw_string_record
->brush
.Color
= ((GpSolidFill
*)brush
)->color
;
5372 draw_string_record
->brush
.BrushId
= brush_id
;
5374 cursor
= &draw_string_record
->VariableData
[0];
5376 memcpy(cursor
, text
, length
* sizeof(*text
));
5377 cursor
+= length
* sizeof(*text
);
5379 if (flags
& DriverStringOptionsRealizedAdvance
)
5381 static BOOL fixme_written
= FALSE
;
5383 /* Native never writes DriverStringOptionsRealizedAdvance. Instead,
5384 in the case of RealizedAdvance, each glyph position is computed
5387 While native GDI+ is capable of playing back metafiles with this
5388 flag set, it is possible that some application might rely on
5389 metafiles produced from GDI+ not setting this flag. Ideally we
5390 would also compute the position of each glyph here, serialize those
5391 values, and not set DriverStringOptionsRealizedAdvance. */
5394 fixme_written
= TRUE
;
5395 FIXME("serializing RealizedAdvance flag and single GlyphPos with padding\n");
5398 *((PointF
*)cursor
) = *positions
;
5401 memcpy(cursor
, positions
, length
* sizeof(*positions
));
5405 cursor
+= length
* sizeof(*positions
);
5406 memcpy(cursor
, matrix
, sizeof(*matrix
));
5409 METAFILE_WriteRecords(metafile
);
5414 GpStatus
METAFILE_FillRegion(GpMetafile
* metafile
, GpBrush
* brush
, GpRegion
* region
)
5419 EmfPlusFillRegion
*fill_region_record
;
5422 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&&
5423 metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
5425 FIXME("metafile type not supported: %i\n", metafile
->metafile_type
);
5426 return NotImplemented
;
5429 inline_color
= (brush
->bt
== BrushTypeSolidColor
);
5432 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
5437 stat
= METAFILE_AddRegionObject(metafile
, region
, ®ion_id
);
5441 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeFillRegion
, sizeof(EmfPlusFillRegion
),
5442 (void**)&fill_region_record
);
5446 fill_region_record
->Header
.Flags
= region_id
;
5450 fill_region_record
->Header
.Flags
|= 0x8000;
5451 fill_region_record
->data
.Color
= ((GpSolidFill
*)brush
)->color
;
5454 fill_region_record
->data
.BrushId
= brush_id
;
5456 METAFILE_WriteRecords(metafile
);
5461 GpStatus
METAFILE_DrawRectangles(GpMetafile
*metafile
, GpPen
*pen
, const GpRectF
*rects
, INT count
)
5463 EmfPlusDrawRects
*record
;
5465 BOOL integer_rects
= TRUE
;
5469 if (metafile
->metafile_type
== MetafileTypeEmf
)
5472 return NotImplemented
;
5475 stat
= METAFILE_AddPenObject(metafile
, pen
, &pen_id
);
5476 if (stat
!= Ok
) return stat
;
5478 for (i
= 0; i
< count
; i
++)
5480 if (!is_integer_rect(&rects
[i
]))
5482 integer_rects
= FALSE
;
5487 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeDrawRects
, FIELD_OFFSET(EmfPlusDrawRects
, RectData
) +
5488 count
* (integer_rects
? sizeof(record
->RectData
.rect
) : sizeof(record
->RectData
.rectF
)),
5493 record
->Header
.Flags
= pen_id
;
5495 record
->Header
.Flags
|= 0x4000;
5496 record
->Count
= count
;
5500 for (i
= 0; i
< count
; i
++)
5502 record
->RectData
.rect
[i
].X
= (SHORT
)rects
[i
].X
;
5503 record
->RectData
.rect
[i
].Y
= (SHORT
)rects
[i
].Y
;
5504 record
->RectData
.rect
[i
].Width
= (SHORT
)rects
[i
].Width
;
5505 record
->RectData
.rect
[i
].Height
= (SHORT
)rects
[i
].Height
;
5509 memcpy(record
->RectData
.rectF
, rects
, sizeof(*rects
) * count
);
5511 METAFILE_WriteRecords(metafile
);
5516 GpStatus
METAFILE_DrawArc(GpMetafile
*metafile
, GpPen
*pen
, const GpRectF
*rect
, REAL startAngle
, REAL sweepAngle
)
5518 EmfPlusDrawArc
*record
;
5523 if (metafile
->metafile_type
== MetafileTypeEmf
)
5526 return NotImplemented
;
5529 stat
= METAFILE_AddPenObject(metafile
, pen
, &pen_id
);
5530 if (stat
!= Ok
) return stat
;
5532 integer_rect
= is_integer_rect(rect
);
5534 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeDrawArc
, FIELD_OFFSET(EmfPlusDrawArc
, RectData
) +
5535 integer_rect
? sizeof(record
->RectData
.rect
) : sizeof(record
->RectData
.rectF
),
5540 record
->Header
.Flags
= pen_id
;
5542 record
->Header
.Flags
|= 0x4000;
5543 record
->StartAngle
= startAngle
;
5544 record
->SweepAngle
= sweepAngle
;
5548 record
->RectData
.rect
.X
= (SHORT
)rect
->X
;
5549 record
->RectData
.rect
.Y
= (SHORT
)rect
->Y
;
5550 record
->RectData
.rect
.Width
= (SHORT
)rect
->Width
;
5551 record
->RectData
.rect
.Height
= (SHORT
)rect
->Height
;
5554 memcpy(&record
->RectData
.rectF
, rect
, sizeof(*rect
));
5556 METAFILE_WriteRecords(metafile
);
5561 GpStatus
METAFILE_OffsetClip(GpMetafile
*metafile
, REAL dx
, REAL dy
)
5563 EmfPlusOffsetClip
*record
;
5566 if (metafile
->metafile_type
== MetafileTypeEmf
)
5569 return NotImplemented
;
5572 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeOffsetClip
,
5573 sizeof(*record
), (void **)&record
);
5580 METAFILE_WriteRecords(metafile
);
5585 GpStatus
METAFILE_ResetClip(GpMetafile
*metafile
)
5587 EmfPlusRecordHeader
*record
;
5590 if (metafile
->metafile_type
== MetafileTypeEmf
)
5593 return NotImplemented
;
5596 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeResetClip
,
5597 sizeof(*record
), (void **)&record
);
5601 METAFILE_WriteRecords(metafile
);
5606 GpStatus
METAFILE_SetClipPath(GpMetafile
*metafile
, GpPath
*path
, CombineMode mode
)
5608 EmfPlusRecordHeader
*record
;
5612 if (metafile
->metafile_type
== MetafileTypeEmf
)
5615 return NotImplemented
;
5618 stat
= METAFILE_AddPathObject(metafile
, path
, &path_id
);
5619 if (stat
!= Ok
) return stat
;
5621 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSetClipPath
,
5622 sizeof(*record
), (void **)&record
);
5626 record
->Flags
= ((mode
& 0xf) << 8) | path_id
;
5628 METAFILE_WriteRecords(metafile
);
5633 GpStatus
METAFILE_SetRenderingOrigin(GpMetafile
*metafile
, INT x
, INT y
)
5635 EmfPlusSetRenderingOrigin
*record
;
5638 if (metafile
->metafile_type
== MetafileTypeEmf
)
5641 return NotImplemented
;
5644 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSetRenderingOrigin
,
5645 sizeof(*record
), (void **)&record
);
5652 METAFILE_WriteRecords(metafile
);