2 * Copyright (C) 2011 Vincent Povirk for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define NONAMELESSUNION
39 #include "gdiplus_private.h"
40 #include "wine/debug.h"
41 #include "wine/list.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus
);
45 HRESULT WINAPI
WICCreateImagingFactory_Proxy(UINT
, IWICImagingFactory
**);
47 typedef ARGB EmfPlusARGB
;
49 typedef struct EmfPlusRecordHeader
55 } EmfPlusRecordHeader
;
57 typedef struct EmfPlusHeader
59 EmfPlusRecordHeader Header
;
66 typedef struct EmfPlusClear
68 EmfPlusRecordHeader Header
;
72 typedef struct EmfPlusFillRects
74 EmfPlusRecordHeader Header
;
79 typedef struct EmfPlusSetClipRect
81 EmfPlusRecordHeader Header
;
85 typedef struct EmfPlusSetPageTransform
87 EmfPlusRecordHeader Header
;
89 } EmfPlusSetPageTransform
;
91 typedef struct EmfPlusRect
99 typedef struct EmfPlusSetWorldTransform
101 EmfPlusRecordHeader Header
;
103 } EmfPlusSetWorldTransform
;
105 typedef struct EmfPlusScaleWorldTransform
107 EmfPlusRecordHeader Header
;
110 } EmfPlusScaleWorldTransform
;
112 typedef struct EmfPlusMultiplyWorldTransform
114 EmfPlusRecordHeader Header
;
116 } EmfPlusMultiplyWorldTransform
;
118 typedef struct EmfPlusRotateWorldTransform
120 EmfPlusRecordHeader Header
;
122 } EmfPlusRotateWorldTransform
;
124 typedef struct EmfPlusTranslateWorldTransform
126 EmfPlusRecordHeader Header
;
129 } EmfPlusTranslateWorldTransform
;
131 typedef struct EmfPlusBeginContainer
133 EmfPlusRecordHeader Header
;
137 } EmfPlusBeginContainer
;
139 typedef struct EmfPlusContainerRecord
141 EmfPlusRecordHeader Header
;
143 } EmfPlusContainerRecord
;
151 typedef struct container
155 enum container_type type
;
156 GraphicsContainer state
;
157 GpMatrix world_transform
;
165 PenDataTransform
= 0x0001,
166 PenDataStartCap
= 0x0002,
167 PenDataEndCap
= 0x0004,
168 PenDataJoin
= 0x0008,
169 PenDataMiterLimit
= 0x0010,
170 PenDataLineStyle
= 0x0020,
171 PenDataDashedLineCap
= 0x0040,
172 PenDataDashedLineOffset
= 0x0080,
173 PenDataDashedLine
= 0x0100,
174 PenDataNonCenter
= 0x0200,
175 PenDataCompoundLine
= 0x0400,
176 PenDataCustomStartCap
= 0x0800,
177 PenDataCustomEndCap
= 0x1000
180 typedef struct EmfPlusTransformMatrix
182 REAL TransformMatrix
[6];
183 } EmfPlusTransformMatrix
;
195 typedef struct EmfPlusDashedLineData
197 DWORD DashedLineDataSize
;
199 } EmfPlusDashedLineData
;
201 typedef struct EmfPlusCompoundLineData
203 DWORD CompoundLineDataSize
;
205 } EmfPlusCompoundLineData
;
207 typedef struct EmfPlusCustomStartCapData
209 DWORD CustomStartCapSize
;
211 } EmfPlusCustomStartCapData
;
213 typedef struct EmfPlusCustomEndCapData
215 DWORD CustomEndCapSize
;
217 } EmfPlusCustomEndCapData
;
219 typedef struct EmfPlusPenData
224 BYTE OptionalData
[1];
229 BrushDataPath
= 1 << 0,
230 BrushDataTransform
= 1 << 1,
231 BrushDataPresetColors
= 1 << 2,
232 BrushDataBlendFactorsH
= 1 << 3,
233 BrushDataBlendFactorsV
= 1 << 4,
234 BrushDataFocusScales
= 1 << 6,
235 BrushDataIsGammaCorrected
= 1 << 7,
236 BrushDataDoNotTransform
= 1 << 8,
239 typedef struct EmfPlusSolidBrushData
241 EmfPlusARGB SolidColor
;
242 } EmfPlusSolidBrushData
;
244 typedef struct EmfPlusHatchBrushData
247 EmfPlusARGB ForeColor
;
248 EmfPlusARGB BackColor
;
249 } EmfPlusHatchBrushData
;
251 typedef struct EmfPlusTextureBrushData
253 DWORD BrushDataFlags
;
255 BYTE OptionalData
[1];
256 } EmfPlusTextureBrushData
;
258 typedef struct EmfPlusRectF
266 typedef struct EmfPlusLinearGradientBrushData
268 DWORD BrushDataFlags
;
271 EmfPlusARGB StartColor
;
272 EmfPlusARGB EndColor
;
275 BYTE OptionalData
[1];
276 } EmfPlusLinearGradientBrushData
;
278 typedef struct EmfPlusBrush
283 EmfPlusSolidBrushData solid
;
284 EmfPlusHatchBrushData hatch
;
285 EmfPlusTextureBrushData texture
;
286 EmfPlusLinearGradientBrushData lineargradient
;
290 typedef struct EmfPlusPen
299 typedef struct EmfPlusPath
302 DWORD PathPointCount
;
303 DWORD PathPointFlags
;
305 /* PathPointTypes[] */
306 /* AlignmentPadding */
310 typedef struct EmfPlusRegionNodePath
312 DWORD RegionNodePathLength
;
313 EmfPlusPath RegionNodePath
;
314 } EmfPlusRegionNodePath
;
316 typedef struct EmfPlusRegion
319 DWORD RegionNodeCount
;
323 typedef struct EmfPlusPalette
325 DWORD PaletteStyleFlags
;
327 BYTE PaletteEntries
[1];
333 BitmapDataTypeCompressed
,
336 typedef struct EmfPlusBitmap
346 typedef struct EmfPlusMetafile
349 DWORD MetafileDataSize
;
350 BYTE MetafileData
[1];
353 typedef enum ImageDataType
355 ImageDataTypeUnknown
,
357 ImageDataTypeMetafile
,
360 typedef struct EmfPlusImage
366 EmfPlusBitmap bitmap
;
367 EmfPlusMetafile metafile
;
371 typedef struct EmfPlusImageAttributes
376 EmfPlusARGB ClampColor
;
379 } EmfPlusImageAttributes
;
381 typedef struct EmfPlusFont
386 DWORD FontStyleFlags
;
392 typedef struct EmfPlusObject
394 EmfPlusRecordHeader Header
;
400 EmfPlusRegion region
;
402 EmfPlusImageAttributes image_attributes
;
407 typedef struct EmfPlusPointR7
413 typedef struct EmfPlusPoint
419 typedef struct EmfPlusPointF
425 typedef struct EmfPlusDrawImage
427 EmfPlusRecordHeader Header
;
428 DWORD ImageAttributesID
;
430 EmfPlusRectF SrcRect
;
438 typedef struct EmfPlusDrawImagePoints
440 EmfPlusRecordHeader Header
;
441 DWORD ImageAttributesID
;
443 EmfPlusRectF SrcRect
;
447 EmfPlusPointR7 pointsR
[3];
448 EmfPlusPoint points
[3];
449 EmfPlusPointF pointsF
[3];
451 } EmfPlusDrawImagePoints
;
453 typedef struct EmfPlusDrawPath
455 EmfPlusRecordHeader Header
;
459 typedef struct EmfPlusDrawArc
461 EmfPlusRecordHeader Header
;
471 typedef struct EmfPlusDrawEllipse
473 EmfPlusRecordHeader Header
;
479 } EmfPlusDrawEllipse
;
481 typedef struct EmfPlusDrawPie
483 EmfPlusRecordHeader Header
;
493 typedef struct EmfPlusDrawRects
495 EmfPlusRecordHeader Header
;
500 EmfPlusRectF rectF
[1];
504 typedef struct EmfPlusFillPath
506 EmfPlusRecordHeader Header
;
514 typedef struct EmfPlusFillClosedCurve
516 EmfPlusRecordHeader Header
;
522 EmfPlusPointR7 pointsR
[1];
523 EmfPlusPoint points
[1];
524 EmfPlusPointF pointsF
[1];
526 } EmfPlusFillClosedCurve
;
528 typedef struct EmfPlusFillEllipse
530 EmfPlusRecordHeader Header
;
537 } EmfPlusFillEllipse
;
539 typedef struct EmfPlusFillPie
541 EmfPlusRecordHeader Header
;
552 typedef struct EmfPlusDrawDriverString
554 EmfPlusRecordHeader Header
;
560 DWORD DriverStringOptionsFlags
;
563 BYTE VariableData
[1];
564 } EmfPlusDrawDriverString
;
566 typedef struct EmfPlusFillRegion
568 EmfPlusRecordHeader Header
;
576 typedef struct EmfPlusOffsetClip
578 EmfPlusRecordHeader Header
;
583 typedef struct EmfPlusSetRenderingOrigin
585 EmfPlusRecordHeader Header
;
588 } EmfPlusSetRenderingOrigin
;
590 static void metafile_free_object_table_entry(GpMetafile
*metafile
, BYTE id
)
592 struct emfplus_object
*object
= &metafile
->objtable
[id
];
594 switch (object
->type
)
596 case ObjectTypeInvalid
:
598 case ObjectTypeBrush
:
599 GdipDeleteBrush(object
->u
.brush
);
602 GdipDeletePen(object
->u
.pen
);
605 GdipDeletePath(object
->u
.path
);
607 case ObjectTypeRegion
:
608 GdipDeleteRegion(object
->u
.region
);
610 case ObjectTypeImage
:
611 GdipDisposeImage(object
->u
.image
);
614 GdipDeleteFont(object
->u
.font
);
616 case ObjectTypeImageAttributes
:
617 GdipDisposeImageAttributes(object
->u
.image_attributes
);
620 FIXME("not implemented for object type %u.\n", object
->type
);
624 object
->type
= ObjectTypeInvalid
;
625 object
->u
.object
= NULL
;
628 void METAFILE_Free(GpMetafile
*metafile
)
632 heap_free(metafile
->comment_data
);
633 DeleteEnhMetaFile(CloseEnhMetaFile(metafile
->record_dc
));
634 if (!metafile
->preserve_hemf
)
635 DeleteEnhMetaFile(metafile
->hemf
);
636 if (metafile
->record_graphics
)
638 WARN("metafile closed while recording\n");
639 /* not sure what to do here; for now just prevent the graphics from functioning or using this object */
640 metafile
->record_graphics
->image
= NULL
;
641 metafile
->record_graphics
->busy
= TRUE
;
644 if (metafile
->record_stream
)
645 IStream_Release(metafile
->record_stream
);
647 for (i
= 0; i
< ARRAY_SIZE(metafile
->objtable
); i
++)
648 metafile_free_object_table_entry(metafile
, i
);
651 static DWORD
METAFILE_AddObjectId(GpMetafile
*metafile
)
653 return (metafile
->next_object_id
++) % EmfPlusObjectTableSize
;
656 static GpStatus
METAFILE_AllocateRecord(GpMetafile
*metafile
, EmfPlusRecordType record_type
,
657 DWORD size
, void **result
)
660 EmfPlusRecordHeader
*record
;
662 if (!metafile
->comment_data_size
)
664 DWORD data_size
= max(256, size
* 2 + 4);
665 metafile
->comment_data
= heap_alloc_zero(data_size
);
667 if (!metafile
->comment_data
)
670 memcpy(metafile
->comment_data
, "EMF+", 4);
672 metafile
->comment_data_size
= data_size
;
673 metafile
->comment_data_length
= 4;
676 size_needed
= size
+ metafile
->comment_data_length
;
678 if (size_needed
> metafile
->comment_data_size
)
680 DWORD data_size
= size_needed
* 2;
681 BYTE
*new_data
= heap_alloc_zero(data_size
);
686 memcpy(new_data
, metafile
->comment_data
, metafile
->comment_data_length
);
688 metafile
->comment_data_size
= data_size
;
689 heap_free(metafile
->comment_data
);
690 metafile
->comment_data
= new_data
;
693 *result
= metafile
->comment_data
+ metafile
->comment_data_length
;
694 metafile
->comment_data_length
+= size
;
696 record
= (EmfPlusRecordHeader
*)*result
;
697 record
->Type
= record_type
;
700 record
->DataSize
= size
- sizeof(EmfPlusRecordHeader
);
705 static void METAFILE_RemoveLastRecord(GpMetafile
*metafile
, EmfPlusRecordHeader
*record
)
707 assert(metafile
->comment_data
+ metafile
->comment_data_length
== (BYTE
*)record
+ record
->Size
);
708 metafile
->comment_data_length
-= record
->Size
;
711 static void METAFILE_WriteRecords(GpMetafile
*metafile
)
713 if (metafile
->comment_data_length
> 4)
715 GdiComment(metafile
->record_dc
, metafile
->comment_data_length
, metafile
->comment_data
);
716 metafile
->comment_data_length
= 4;
720 static GpStatus
METAFILE_WriteHeader(GpMetafile
*metafile
, HDC hdc
)
724 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
726 EmfPlusHeader
*header
;
728 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeHeader
, sizeof(EmfPlusHeader
), (void**)&header
);
732 if (metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
733 header
->Header
.Flags
= 1;
735 header
->Version
= VERSION_MAGIC2
;
737 if (GetDeviceCaps(hdc
, TECHNOLOGY
) == DT_RASDISPLAY
)
738 header
->EmfPlusFlags
= 1;
740 header
->EmfPlusFlags
= 0;
742 header
->LogicalDpiX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
743 header
->LogicalDpiY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
745 METAFILE_WriteRecords(metafile
);
751 static GpStatus
METAFILE_WriteEndOfFile(GpMetafile
*metafile
)
755 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
757 EmfPlusRecordHeader
*record
;
759 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeEndOfFile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
763 METAFILE_WriteRecords(metafile
);
769 GpStatus WINGDIPAPI
GdipRecordMetafile(HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
770 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
773 TRACE("(%p %d %s %d %p %p)\n", hdc
, type
, debugstr_rectf(frameRect
), frameUnit
, desc
, metafile
);
775 return GdipRecordMetafileFileName(NULL
, hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
778 /*****************************************************************************
779 * GdipRecordMetafileI [GDIPLUS.@]
781 GpStatus WINGDIPAPI
GdipRecordMetafileI(HDC hdc
, EmfType type
, GDIPCONST GpRect
*frameRect
,
782 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
784 GpRectF frameRectF
, *pFrameRectF
;
786 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
790 set_rect(&frameRectF
, frameRect
->X
, frameRect
->Y
, frameRect
->Width
, frameRect
->Height
);
791 pFrameRectF
= &frameRectF
;
796 return GdipRecordMetafile(hdc
, type
, pFrameRectF
, frameUnit
, desc
, metafile
);
799 GpStatus WINGDIPAPI
GdipRecordMetafileStreamI(IStream
*stream
, HDC hdc
, EmfType type
, GDIPCONST GpRect
*frameRect
,
800 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
802 GpRectF frameRectF
, *pFrameRectF
;
804 TRACE("(%p %p %d %p %d %p %p)\n", stream
, hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
808 set_rect(&frameRectF
, frameRect
->X
, frameRect
->Y
, frameRect
->Width
, frameRect
->Height
);
809 pFrameRectF
= &frameRectF
;
814 return GdipRecordMetafileStream(stream
, hdc
, type
, pFrameRectF
, frameUnit
, desc
, metafile
);
817 GpStatus WINGDIPAPI
GdipRecordMetafileStream(IStream
*stream
, HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
818 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
822 TRACE("(%p %p %d %s %d %p %p)\n", stream
, hdc
, type
, debugstr_rectf(frameRect
), frameUnit
, desc
, metafile
);
825 return InvalidParameter
;
827 stat
= GdipRecordMetafile(hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
831 (*metafile
)->record_stream
= stream
;
832 IStream_AddRef(stream
);
838 static void METAFILE_AdjustFrame(GpMetafile
* metafile
, const GpPointF
*points
,
843 if (!metafile
->auto_frame
|| !num_points
)
846 if (metafile
->auto_frame_max
.X
< metafile
->auto_frame_min
.X
)
847 metafile
->auto_frame_max
= metafile
->auto_frame_min
= points
[0];
849 for (i
=0; i
<num_points
; i
++)
851 if (points
[i
].X
< metafile
->auto_frame_min
.X
)
852 metafile
->auto_frame_min
.X
= points
[i
].X
;
853 if (points
[i
].X
> metafile
->auto_frame_max
.X
)
854 metafile
->auto_frame_max
.X
= points
[i
].X
;
855 if (points
[i
].Y
< metafile
->auto_frame_min
.Y
)
856 metafile
->auto_frame_min
.Y
= points
[i
].Y
;
857 if (points
[i
].Y
> metafile
->auto_frame_max
.Y
)
858 metafile
->auto_frame_max
.Y
= points
[i
].Y
;
862 GpStatus
METAFILE_GetGraphicsContext(GpMetafile
* metafile
, GpGraphics
**result
)
866 if (!metafile
->record_dc
|| metafile
->record_graphics
)
867 return InvalidParameter
;
869 stat
= graphics_from_image((GpImage
*)metafile
, &metafile
->record_graphics
);
873 *result
= metafile
->record_graphics
;
874 metafile
->record_graphics
->xres
= metafile
->logical_dpix
;
875 metafile
->record_graphics
->yres
= metafile
->logical_dpiy
;
876 metafile
->record_graphics
->printer_display
= metafile
->printer_display
;
882 GpStatus
METAFILE_GetDC(GpMetafile
* metafile
, HDC
*hdc
)
884 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
886 EmfPlusRecordHeader
*record
;
889 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeGetDC
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
893 METAFILE_WriteRecords(metafile
);
896 *hdc
= metafile
->record_dc
;
901 GpStatus
METAFILE_GraphicsClear(GpMetafile
* metafile
, ARGB color
)
903 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
905 EmfPlusClear
*record
;
908 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeClear
, sizeof(EmfPlusClear
), (void**)&record
);
912 record
->Color
= color
;
914 METAFILE_WriteRecords(metafile
);
920 static BOOL
is_integer_rect(const GpRectF
*rect
)
922 SHORT x
, y
, width
, height
;
926 height
= rect
->Height
;
927 if (rect
->X
!= (REAL
)x
|| rect
->Y
!= (REAL
)y
||
928 rect
->Width
!= (REAL
)width
|| rect
->Height
!= (REAL
)height
)
933 static GpStatus
METAFILE_PrepareBrushData(GDIPCONST GpBrush
*brush
, DWORD
*size
)
937 case BrushTypeSolidColor
:
938 *size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
) + sizeof(EmfPlusSolidBrushData
);
940 case BrushTypeHatchFill
:
941 *size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
) + sizeof(EmfPlusHatchBrushData
);
943 case BrushTypeLinearGradient
:
946 GpLineGradient
*gradient
= (GpLineGradient
*)brush
;
948 *size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
.lineargradient
.OptionalData
);
950 GdipIsMatrixIdentity(&gradient
->transform
, &ignore_xform
);
952 *size
+= sizeof(gradient
->transform
);
954 if (gradient
->pblendcount
> 1 && gradient
->pblendcolor
&& gradient
->pblendpos
)
955 *size
+= sizeof(DWORD
) + gradient
->pblendcount
*
956 (sizeof(*gradient
->pblendcolor
) + sizeof(*gradient
->pblendpos
));
957 else if (gradient
->blendcount
> 1 && gradient
->blendfac
&& gradient
->blendpos
)
958 *size
+= sizeof(DWORD
) + gradient
->blendcount
*
959 (sizeof(*gradient
->blendfac
) + sizeof(*gradient
->blendpos
));
964 FIXME("unsupported brush type: %d\n", brush
->bt
);
965 return NotImplemented
;
971 static void METAFILE_FillBrushData(GDIPCONST GpBrush
*brush
, EmfPlusBrush
*data
)
973 data
->Version
= VERSION_MAGIC2
;
974 data
->Type
= brush
->bt
;
978 case BrushTypeSolidColor
:
980 GpSolidFill
*solid
= (GpSolidFill
*)brush
;
981 data
->BrushData
.solid
.SolidColor
= solid
->color
;
984 case BrushTypeHatchFill
:
986 GpHatch
*hatch
= (GpHatch
*)brush
;
987 data
->BrushData
.hatch
.HatchStyle
= hatch
->hatchstyle
;
988 data
->BrushData
.hatch
.ForeColor
= hatch
->forecol
;
989 data
->BrushData
.hatch
.BackColor
= hatch
->backcol
;
992 case BrushTypeLinearGradient
:
996 GpLineGradient
*gradient
= (GpLineGradient
*)brush
;
998 data
->BrushData
.lineargradient
.BrushDataFlags
= 0;
999 data
->BrushData
.lineargradient
.WrapMode
= gradient
->wrap
;
1000 data
->BrushData
.lineargradient
.RectF
.X
= gradient
->rect
.X
;
1001 data
->BrushData
.lineargradient
.RectF
.Y
= gradient
->rect
.Y
;
1002 data
->BrushData
.lineargradient
.RectF
.Width
= gradient
->rect
.Width
;
1003 data
->BrushData
.lineargradient
.RectF
.Height
= gradient
->rect
.Height
;
1004 data
->BrushData
.lineargradient
.StartColor
= gradient
->startcolor
;
1005 data
->BrushData
.lineargradient
.EndColor
= gradient
->endcolor
;
1006 data
->BrushData
.lineargradient
.Reserved1
= gradient
->startcolor
;
1007 data
->BrushData
.lineargradient
.Reserved2
= gradient
->endcolor
;
1009 if (gradient
->gamma
)
1010 data
->BrushData
.lineargradient
.BrushDataFlags
|= BrushDataIsGammaCorrected
;
1012 cursor
= &data
->BrushData
.lineargradient
.OptionalData
[0];
1014 GdipIsMatrixIdentity(&gradient
->transform
, &ignore_xform
);
1017 data
->BrushData
.lineargradient
.BrushDataFlags
|= BrushDataTransform
;
1018 memcpy(cursor
, &gradient
->transform
, sizeof(gradient
->transform
));
1019 cursor
+= sizeof(gradient
->transform
);
1022 if (gradient
->pblendcount
> 1 && gradient
->pblendcolor
&& gradient
->pblendpos
)
1024 const DWORD count
= gradient
->pblendcount
;
1026 data
->BrushData
.lineargradient
.BrushDataFlags
|= BrushDataPresetColors
;
1028 memcpy(cursor
, &count
, sizeof(count
));
1029 cursor
+= sizeof(count
);
1031 memcpy(cursor
, gradient
->pblendpos
, count
* sizeof(*gradient
->pblendpos
));
1032 cursor
+= count
* sizeof(*gradient
->pblendpos
);
1034 memcpy(cursor
, gradient
->pblendcolor
, count
* sizeof(*gradient
->pblendcolor
));
1036 else if (gradient
->blendcount
> 1 && gradient
->blendfac
&& gradient
->blendpos
)
1038 const DWORD count
= gradient
->blendcount
;
1040 data
->BrushData
.lineargradient
.BrushDataFlags
|= BrushDataBlendFactorsH
;
1042 memcpy(cursor
, &count
, sizeof(count
));
1043 cursor
+= sizeof(count
);
1045 memcpy(cursor
, gradient
->blendpos
, count
* sizeof(*gradient
->blendpos
));
1046 cursor
+= count
* sizeof(*gradient
->blendpos
);
1048 memcpy(cursor
, gradient
->blendfac
, count
* sizeof(*gradient
->blendfac
));
1054 FIXME("unsupported brush type: %d\n", brush
->bt
);
1058 static GpStatus
METAFILE_AddBrushObject(GpMetafile
*metafile
, GDIPCONST GpBrush
*brush
, DWORD
*id
)
1060 EmfPlusObject
*object_record
;
1065 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
1068 stat
= METAFILE_PrepareBrushData(brush
, &size
);
1069 if (stat
!= Ok
) return stat
;
1071 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
1072 FIELD_OFFSET(EmfPlusObject
, ObjectData
) + size
, (void**)&object_record
);
1073 if (stat
!= Ok
) return stat
;
1075 *id
= METAFILE_AddObjectId(metafile
);
1076 object_record
->Header
.Flags
= *id
| ObjectTypeBrush
<< 8;
1077 METAFILE_FillBrushData(brush
, &object_record
->ObjectData
.brush
);
1081 GpStatus
METAFILE_FillRectangles(GpMetafile
* metafile
, GpBrush
* brush
,
1082 GDIPCONST GpRectF
* rects
, INT count
)
1084 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1086 EmfPlusFillRects
*record
;
1088 BOOL integer_rects
= TRUE
;
1093 if (brush
->bt
== BrushTypeSolidColor
)
1096 brushid
= ((GpSolidFill
*)brush
)->color
;
1100 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brushid
);
1105 for (i
=0; i
<count
; i
++)
1107 if (!is_integer_rect(&rects
[i
]))
1109 integer_rects
= FALSE
;
1117 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeFillRects
,
1118 sizeof(EmfPlusFillRects
) + count
* (integer_rects
? sizeof(EmfPlusRect
) : sizeof(GpRectF
)),
1123 record
->Header
.Flags
= flags
;
1124 record
->BrushID
= brushid
;
1125 record
->Count
= count
;
1129 EmfPlusRect
*record_rects
= (EmfPlusRect
*)(record
+1);
1130 for (i
=0; i
<count
; i
++)
1132 record_rects
[i
].X
= (SHORT
)rects
[i
].X
;
1133 record_rects
[i
].Y
= (SHORT
)rects
[i
].Y
;
1134 record_rects
[i
].Width
= (SHORT
)rects
[i
].Width
;
1135 record_rects
[i
].Height
= (SHORT
)rects
[i
].Height
;
1139 memcpy(record
+1, rects
, sizeof(GpRectF
) * count
);
1141 METAFILE_WriteRecords(metafile
);
1144 if (metafile
->auto_frame
)
1146 GpPointF corners
[4];
1149 for (i
=0; i
<count
; i
++)
1151 corners
[0].X
= rects
[i
].X
;
1152 corners
[0].Y
= rects
[i
].Y
;
1153 corners
[1].X
= rects
[i
].X
+ rects
[i
].Width
;
1154 corners
[1].Y
= rects
[i
].Y
;
1155 corners
[2].X
= rects
[i
].X
;
1156 corners
[2].Y
= rects
[i
].Y
+ rects
[i
].Height
;
1157 corners
[3].X
= rects
[i
].X
+ rects
[i
].Width
;
1158 corners
[3].Y
= rects
[i
].Y
+ rects
[i
].Height
;
1160 GdipTransformPoints(metafile
->record_graphics
, CoordinateSpaceDevice
,
1161 CoordinateSpaceWorld
, corners
, 4);
1163 METAFILE_AdjustFrame(metafile
, corners
, 4);
1170 GpStatus
METAFILE_SetClipRect(GpMetafile
* metafile
, REAL x
, REAL y
, REAL width
, REAL height
, CombineMode mode
)
1172 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1174 EmfPlusSetClipRect
*record
;
1177 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSetClipRect
,
1178 sizeof(EmfPlusSetClipRect
), (void **)&record
);
1182 record
->Header
.Flags
= (mode
& 0xf) << 8;
1183 record
->ClipRect
.X
= x
;
1184 record
->ClipRect
.Y
= y
;
1185 record
->ClipRect
.Width
= width
;
1186 record
->ClipRect
.Height
= height
;
1188 METAFILE_WriteRecords(metafile
);
1194 static GpStatus
METAFILE_AddRegionObject(GpMetafile
*metafile
, GpRegion
*region
, DWORD
*id
)
1196 EmfPlusObject
*object_record
;
1201 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
1204 size
= write_region_data(region
, NULL
);
1205 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
1206 FIELD_OFFSET(EmfPlusObject
, ObjectData
.region
) + size
, (void**)&object_record
);
1207 if (stat
!= Ok
) return stat
;
1209 *id
= METAFILE_AddObjectId(metafile
);
1210 object_record
->Header
.Flags
= *id
| ObjectTypeRegion
<< 8;
1211 write_region_data(region
, &object_record
->ObjectData
.region
);
1215 GpStatus
METAFILE_SetClipRegion(GpMetafile
* metafile
, GpRegion
* region
, CombineMode mode
)
1217 EmfPlusRecordHeader
*record
;
1221 if (metafile
->metafile_type
== MetafileTypeEmf
)
1224 return NotImplemented
;
1227 stat
= METAFILE_AddRegionObject(metafile
, region
, ®ion_id
);
1228 if (stat
!= Ok
) return stat
;
1230 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSetClipRegion
, sizeof(*record
), (void**)&record
);
1231 if (stat
!= Ok
) return stat
;
1233 record
->Flags
= region_id
| mode
<< 8;
1235 METAFILE_WriteRecords(metafile
);
1239 GpStatus
METAFILE_SetPageTransform(GpMetafile
* metafile
, GpUnit unit
, REAL scale
)
1241 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1243 EmfPlusSetPageTransform
*record
;
1246 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSetPageTransform
,
1247 sizeof(EmfPlusSetPageTransform
), (void **)&record
);
1251 record
->Header
.Flags
= unit
;
1252 record
->PageScale
= scale
;
1254 METAFILE_WriteRecords(metafile
);
1260 GpStatus
METAFILE_SetWorldTransform(GpMetafile
* metafile
, GDIPCONST GpMatrix
* transform
)
1262 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1264 EmfPlusSetWorldTransform
*record
;
1267 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSetWorldTransform
,
1268 sizeof(EmfPlusSetWorldTransform
), (void **)&record
);
1272 memcpy(record
->MatrixData
, transform
->matrix
, sizeof(record
->MatrixData
));
1274 METAFILE_WriteRecords(metafile
);
1280 GpStatus
METAFILE_ScaleWorldTransform(GpMetafile
* metafile
, REAL sx
, REAL sy
, MatrixOrder order
)
1282 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1284 EmfPlusScaleWorldTransform
*record
;
1287 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeScaleWorldTransform
,
1288 sizeof(EmfPlusScaleWorldTransform
), (void **)&record
);
1292 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1296 METAFILE_WriteRecords(metafile
);
1302 GpStatus
METAFILE_MultiplyWorldTransform(GpMetafile
* metafile
, GDIPCONST GpMatrix
* matrix
, MatrixOrder order
)
1304 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1306 EmfPlusMultiplyWorldTransform
*record
;
1309 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeMultiplyWorldTransform
,
1310 sizeof(EmfPlusMultiplyWorldTransform
), (void **)&record
);
1314 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1315 memcpy(record
->MatrixData
, matrix
->matrix
, sizeof(record
->MatrixData
));
1317 METAFILE_WriteRecords(metafile
);
1323 GpStatus
METAFILE_RotateWorldTransform(GpMetafile
* metafile
, REAL angle
, MatrixOrder order
)
1325 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1327 EmfPlusRotateWorldTransform
*record
;
1330 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeRotateWorldTransform
,
1331 sizeof(EmfPlusRotateWorldTransform
), (void **)&record
);
1335 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1336 record
->Angle
= angle
;
1338 METAFILE_WriteRecords(metafile
);
1344 GpStatus
METAFILE_TranslateWorldTransform(GpMetafile
* metafile
, REAL dx
, REAL dy
, MatrixOrder order
)
1346 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1348 EmfPlusTranslateWorldTransform
*record
;
1351 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeTranslateWorldTransform
,
1352 sizeof(EmfPlusTranslateWorldTransform
), (void **)&record
);
1356 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1360 METAFILE_WriteRecords(metafile
);
1366 GpStatus
METAFILE_ResetWorldTransform(GpMetafile
* metafile
)
1368 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1370 EmfPlusRecordHeader
*record
;
1373 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeResetWorldTransform
,
1374 sizeof(EmfPlusRecordHeader
), (void **)&record
);
1378 METAFILE_WriteRecords(metafile
);
1384 GpStatus
METAFILE_BeginContainer(GpMetafile
* metafile
, GDIPCONST GpRectF
*dstrect
,
1385 GDIPCONST GpRectF
*srcrect
, GpUnit unit
, DWORD StackIndex
)
1387 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1389 EmfPlusBeginContainer
*record
;
1392 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeBeginContainer
, sizeof(*record
), (void**)&record
);
1396 record
->Header
.Flags
= unit
& 0xff;
1397 record
->DestRect
= *dstrect
;
1398 record
->SrcRect
= *srcrect
;
1399 record
->StackIndex
= StackIndex
;
1401 METAFILE_WriteRecords(metafile
);
1407 GpStatus
METAFILE_BeginContainerNoParams(GpMetafile
* metafile
, DWORD StackIndex
)
1409 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1411 EmfPlusContainerRecord
*record
;
1414 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeBeginContainerNoParams
,
1415 sizeof(EmfPlusContainerRecord
), (void **)&record
);
1419 record
->StackIndex
= StackIndex
;
1421 METAFILE_WriteRecords(metafile
);
1427 GpStatus
METAFILE_EndContainer(GpMetafile
* metafile
, DWORD StackIndex
)
1429 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1431 EmfPlusContainerRecord
*record
;
1434 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeEndContainer
,
1435 sizeof(EmfPlusContainerRecord
), (void **)&record
);
1439 record
->StackIndex
= StackIndex
;
1441 METAFILE_WriteRecords(metafile
);
1447 GpStatus
METAFILE_SaveGraphics(GpMetafile
* metafile
, DWORD StackIndex
)
1449 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1451 EmfPlusContainerRecord
*record
;
1454 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSave
,
1455 sizeof(EmfPlusContainerRecord
), (void **)&record
);
1459 record
->StackIndex
= StackIndex
;
1461 METAFILE_WriteRecords(metafile
);
1467 GpStatus
METAFILE_RestoreGraphics(GpMetafile
* metafile
, DWORD StackIndex
)
1469 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1471 EmfPlusContainerRecord
*record
;
1474 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeRestore
,
1475 sizeof(EmfPlusContainerRecord
), (void **)&record
);
1479 record
->StackIndex
= StackIndex
;
1481 METAFILE_WriteRecords(metafile
);
1487 GpStatus
METAFILE_ReleaseDC(GpMetafile
* metafile
, HDC hdc
)
1489 if (hdc
!= metafile
->record_dc
)
1490 return InvalidParameter
;
1495 GpStatus
METAFILE_GraphicsDeleted(GpMetafile
* metafile
)
1499 stat
= METAFILE_WriteEndOfFile(metafile
);
1500 metafile
->record_graphics
= NULL
;
1502 metafile
->hemf
= CloseEnhMetaFile(metafile
->record_dc
);
1503 metafile
->record_dc
= NULL
;
1505 heap_free(metafile
->comment_data
);
1506 metafile
->comment_data
= NULL
;
1507 metafile
->comment_data_size
= 0;
1511 MetafileHeader header
;
1513 stat
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, &header
);
1514 if (stat
== Ok
&& metafile
->auto_frame
&&
1515 metafile
->auto_frame_max
.X
>= metafile
->auto_frame_min
.X
)
1517 RECTL bounds_rc
, gdi_bounds_rc
;
1518 REAL x_scale
= 2540.0 / header
.DpiX
;
1519 REAL y_scale
= 2540.0 / header
.DpiY
;
1523 gdi_bounds_rc
= header
.u
.EmfHeader
.rclBounds
;
1524 if (gdi_bounds_rc
.right
> gdi_bounds_rc
.left
&&
1525 gdi_bounds_rc
.bottom
> gdi_bounds_rc
.top
)
1527 GpPointF
*af_min
= &metafile
->auto_frame_min
;
1528 GpPointF
*af_max
= &metafile
->auto_frame_max
;
1530 af_min
->X
= fmin(af_min
->X
, gdi_bounds_rc
.left
);
1531 af_min
->Y
= fmin(af_min
->Y
, gdi_bounds_rc
.top
);
1532 af_max
->X
= fmax(af_max
->X
, gdi_bounds_rc
.right
);
1533 af_max
->Y
= fmax(af_max
->Y
, gdi_bounds_rc
.bottom
);
1536 bounds_rc
.left
= floorf(metafile
->auto_frame_min
.X
* x_scale
);
1537 bounds_rc
.top
= floorf(metafile
->auto_frame_min
.Y
* y_scale
);
1538 bounds_rc
.right
= ceilf(metafile
->auto_frame_max
.X
* x_scale
);
1539 bounds_rc
.bottom
= ceilf(metafile
->auto_frame_max
.Y
* y_scale
);
1541 buffer_size
= GetEnhMetaFileBits(metafile
->hemf
, 0, NULL
);
1542 buffer
= heap_alloc(buffer_size
);
1545 HENHMETAFILE new_hemf
;
1547 GetEnhMetaFileBits(metafile
->hemf
, buffer_size
, buffer
);
1549 ((ENHMETAHEADER
*)buffer
)->rclFrame
= bounds_rc
;
1551 new_hemf
= SetEnhMetaFileBits(buffer_size
, buffer
);
1555 DeleteEnhMetaFile(metafile
->hemf
);
1556 metafile
->hemf
= new_hemf
;
1567 stat
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, &header
);
1571 metafile
->bounds
.X
= header
.X
;
1572 metafile
->bounds
.Y
= header
.Y
;
1573 metafile
->bounds
.Width
= header
.Width
;
1574 metafile
->bounds
.Height
= header
.Height
;
1578 if (stat
== Ok
&& metafile
->record_stream
)
1583 buffer_size
= GetEnhMetaFileBits(metafile
->hemf
, 0, NULL
);
1585 buffer
= heap_alloc(buffer_size
);
1590 GetEnhMetaFileBits(metafile
->hemf
, buffer_size
, buffer
);
1592 hr
= IStream_Write(metafile
->record_stream
, buffer
, buffer_size
, NULL
);
1595 stat
= hresult_to_status(hr
);
1603 if (metafile
->record_stream
)
1605 IStream_Release(metafile
->record_stream
);
1606 metafile
->record_stream
= NULL
;
1612 GpStatus WINGDIPAPI
GdipGetHemfFromMetafile(GpMetafile
*metafile
, HENHMETAFILE
*hEmf
)
1614 TRACE("(%p,%p)\n", metafile
, hEmf
);
1616 if (!metafile
|| !hEmf
|| !metafile
->hemf
)
1617 return InvalidParameter
;
1619 *hEmf
= metafile
->hemf
;
1620 metafile
->hemf
= NULL
;
1625 static GpStatus
METAFILE_PlaybackGetDC(GpMetafile
*metafile
)
1629 stat
= GdipGetDC(metafile
->playback_graphics
, &metafile
->playback_dc
);
1634 static void METAFILE_PlaybackReleaseDC(GpMetafile
*metafile
)
1636 if (metafile
->playback_dc
)
1638 GdipReleaseDC(metafile
->playback_graphics
, metafile
->playback_dc
);
1639 metafile
->playback_dc
= NULL
;
1643 static GpStatus
METAFILE_PlaybackUpdateClip(GpMetafile
*metafile
)
1646 stat
= GdipCombineRegionRegion(metafile
->playback_graphics
->clip
, metafile
->base_clip
, CombineModeReplace
);
1648 stat
= GdipCombineRegionRegion(metafile
->playback_graphics
->clip
, metafile
->clip
, CombineModeIntersect
);
1652 static GpStatus
METAFILE_PlaybackUpdateWorldTransform(GpMetafile
*metafile
)
1654 GpMatrix
*real_transform
;
1657 stat
= GdipCreateMatrix3(&metafile
->src_rect
, metafile
->playback_points
, &real_transform
);
1661 REAL scale_x
= units_to_pixels(1.0, metafile
->page_unit
, metafile
->logical_dpix
, metafile
->printer_display
);
1662 REAL scale_y
= units_to_pixels(1.0, metafile
->page_unit
, metafile
->logical_dpiy
, metafile
->printer_display
);
1664 if (metafile
->page_unit
!= UnitDisplay
)
1666 scale_x
*= metafile
->page_scale
;
1667 scale_y
*= metafile
->page_scale
;
1670 stat
= GdipScaleMatrix(real_transform
, scale_x
, scale_y
, MatrixOrderPrepend
);
1673 stat
= GdipMultiplyMatrix(real_transform
, metafile
->world_transform
, MatrixOrderPrepend
);
1676 stat
= GdipSetWorldTransform(metafile
->playback_graphics
, real_transform
);
1678 GdipDeleteMatrix(real_transform
);
1684 static void metafile_set_object_table_entry(GpMetafile
*metafile
, BYTE id
, BYTE type
, void *object
)
1686 metafile_free_object_table_entry(metafile
, id
);
1687 metafile
->objtable
[id
].type
= type
;
1688 metafile
->objtable
[id
].u
.object
= object
;
1691 static GpStatus
metafile_deserialize_image(const BYTE
*record_data
, UINT data_size
, GpImage
**image
)
1693 EmfPlusImage
*data
= (EmfPlusImage
*)record_data
;
1698 if (data_size
< FIELD_OFFSET(EmfPlusImage
, ImageData
))
1699 return InvalidParameter
;
1700 data_size
-= FIELD_OFFSET(EmfPlusImage
, ImageData
);
1704 case ImageDataTypeBitmap
:
1706 EmfPlusBitmap
*bitmapdata
= &data
->ImageData
.bitmap
;
1708 if (data_size
<= FIELD_OFFSET(EmfPlusBitmap
, BitmapData
))
1709 return InvalidParameter
;
1710 data_size
-= FIELD_OFFSET(EmfPlusBitmap
, BitmapData
);
1712 switch (bitmapdata
->Type
)
1714 case BitmapDataTypePixel
:
1716 ColorPalette
*palette
;
1719 if (bitmapdata
->PixelFormat
& PixelFormatIndexed
)
1721 EmfPlusPalette
*palette_obj
= (EmfPlusPalette
*)bitmapdata
->BitmapData
;
1722 UINT palette_size
= FIELD_OFFSET(EmfPlusPalette
, PaletteEntries
);
1724 if (data_size
<= palette_size
)
1725 return InvalidParameter
;
1726 palette_size
+= palette_obj
->PaletteCount
* sizeof(EmfPlusARGB
);
1728 if (data_size
< palette_size
)
1729 return InvalidParameter
;
1730 data_size
-= palette_size
;
1732 palette
= (ColorPalette
*)bitmapdata
->BitmapData
;
1733 scan0
= (BYTE
*)bitmapdata
->BitmapData
+ palette_size
;
1738 scan0
= bitmapdata
->BitmapData
;
1741 if (data_size
< bitmapdata
->Height
* bitmapdata
->Stride
)
1742 return InvalidParameter
;
1744 status
= GdipCreateBitmapFromScan0(bitmapdata
->Width
, bitmapdata
->Height
, bitmapdata
->Stride
,
1745 bitmapdata
->PixelFormat
, scan0
, (GpBitmap
**)image
);
1746 if (status
== Ok
&& palette
)
1748 status
= GdipSetImagePalette(*image
, palette
);
1751 GdipDisposeImage(*image
);
1757 case BitmapDataTypeCompressed
:
1759 IWICImagingFactory
*factory
;
1763 if (WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION
, &factory
) != S_OK
)
1764 return GenericError
;
1766 hr
= IWICImagingFactory_CreateStream(factory
, &stream
);
1767 IWICImagingFactory_Release(factory
);
1769 return GenericError
;
1771 if (IWICStream_InitializeFromMemory(stream
, bitmapdata
->BitmapData
, data_size
) == S_OK
)
1772 status
= GdipCreateBitmapFromStream((IStream
*)stream
, (GpBitmap
**)image
);
1774 status
= GenericError
;
1776 IWICStream_Release(stream
);
1780 WARN("Invalid bitmap type %ld.\n", bitmapdata
->Type
);
1781 return InvalidParameter
;
1785 case ImageDataTypeMetafile
:
1787 EmfPlusMetafile
*metafiledata
= &data
->ImageData
.metafile
;
1789 if (data_size
<= FIELD_OFFSET(EmfPlusMetafile
, MetafileData
))
1790 return InvalidParameter
;
1791 data_size
-= FIELD_OFFSET(EmfPlusMetafile
, MetafileData
);
1793 switch (metafiledata
->Type
) {
1794 case MetafileTypeEmf
:
1795 case MetafileTypeEmfPlusOnly
:
1796 case MetafileTypeEmfPlusDual
:
1800 hemf
= SetEnhMetaFileBits(data_size
, metafiledata
->MetafileData
);
1803 return GenericError
;
1805 status
= GdipCreateMetafileFromEmf(hemf
, TRUE
, (GpMetafile
**)image
);
1808 DeleteEnhMetaFile(hemf
);
1813 FIXME("metafile type %ld not supported.\n", metafiledata
->Type
);
1814 return NotImplemented
;
1819 FIXME("image type %d not supported.\n", data
->Type
);
1820 return NotImplemented
;
1826 static GpStatus
metafile_deserialize_path(const BYTE
*record_data
, UINT data_size
, GpPath
**path
)
1828 EmfPlusPath
*data
= (EmfPlusPath
*)record_data
;
1836 if (data_size
<= FIELD_OFFSET(EmfPlusPath
, data
))
1837 return InvalidParameter
;
1838 data_size
-= FIELD_OFFSET(EmfPlusPath
, data
);
1840 if (data
->PathPointFlags
& 0x800) /* R */
1842 FIXME("RLE encoded path data is not supported.\n");
1843 return NotImplemented
;
1847 if (data
->PathPointFlags
& 0x4000) /* C */
1848 size
= sizeof(EmfPlusPoint
);
1850 size
= sizeof(EmfPlusPointF
);
1851 size
+= sizeof(BYTE
); /* EmfPlusPathPointType */
1852 size
*= data
->PathPointCount
;
1855 if (data_size
< size
)
1856 return InvalidParameter
;
1858 status
= GdipCreatePath(FillModeAlternate
, path
);
1862 (*path
)->pathdata
.Count
= data
->PathPointCount
;
1863 (*path
)->pathdata
.Points
= GdipAlloc(data
->PathPointCount
* sizeof(*(*path
)->pathdata
.Points
));
1864 (*path
)->pathdata
.Types
= GdipAlloc(data
->PathPointCount
* sizeof(*(*path
)->pathdata
.Types
));
1865 (*path
)->datalen
= (*path
)->pathdata
.Count
;
1867 if (!(*path
)->pathdata
.Points
|| !(*path
)->pathdata
.Types
)
1869 GdipDeletePath(*path
);
1873 if (data
->PathPointFlags
& 0x4000) /* C */
1875 EmfPlusPoint
*points
= (EmfPlusPoint
*)data
->data
;
1876 for (i
= 0; i
< data
->PathPointCount
; i
++)
1878 (*path
)->pathdata
.Points
[i
].X
= points
[i
].X
;
1879 (*path
)->pathdata
.Points
[i
].Y
= points
[i
].Y
;
1881 types
= (BYTE
*)(points
+ i
);
1885 EmfPlusPointF
*points
= (EmfPlusPointF
*)data
->data
;
1886 memcpy((*path
)->pathdata
.Points
, points
, sizeof(*points
) * data
->PathPointCount
);
1887 types
= (BYTE
*)(points
+ data
->PathPointCount
);
1890 memcpy((*path
)->pathdata
.Types
, types
, sizeof(*types
) * data
->PathPointCount
);
1895 static GpStatus
metafile_read_region_node(struct memory_buffer
*mbuf
, GpRegion
*region
, region_element
*node
, UINT
*count
)
1900 type
= buffer_read(mbuf
, sizeof(*type
));
1901 if (!type
) return Ok
;
1907 case CombineModeReplace
:
1908 case CombineModeIntersect
:
1909 case CombineModeUnion
:
1910 case CombineModeXor
:
1911 case CombineModeExclude
:
1912 case CombineModeComplement
:
1914 region_element
*left
, *right
;
1916 left
= heap_alloc_zero(sizeof(*left
));
1920 right
= heap_alloc_zero(sizeof(*right
));
1927 status
= metafile_read_region_node(mbuf
, region
, left
, count
);
1930 status
= metafile_read_region_node(mbuf
, region
, right
, count
);
1933 node
->elementdata
.combine
.left
= left
;
1934 node
->elementdata
.combine
.right
= right
;
1935 region
->num_children
+= 2;
1944 case RegionDataRect
:
1946 const EmfPlusRectF
*rect
;
1948 rect
= buffer_read(mbuf
, sizeof(*rect
));
1950 return InvalidParameter
;
1952 memcpy(&node
->elementdata
.rect
, rect
, sizeof(*rect
));
1956 case RegionDataPath
:
1958 const BYTE
*path_data
;
1959 const UINT
*data_size
;
1962 data_size
= buffer_read(mbuf
, FIELD_OFFSET(EmfPlusRegionNodePath
, RegionNodePath
));
1964 return InvalidParameter
;
1966 path_data
= buffer_read(mbuf
, *data_size
);
1968 return InvalidParameter
;
1970 status
= metafile_deserialize_path(path_data
, *data_size
, &path
);
1973 node
->elementdata
.path
= path
;
1978 case RegionDataEmptyRect
:
1979 case RegionDataInfiniteRect
:
1983 FIXME("element type %#lx is not supported\n", *type
);
1987 return InvalidParameter
;
1990 static GpStatus
metafile_deserialize_region(const BYTE
*record_data
, UINT data_size
, GpRegion
**region
)
1992 struct memory_buffer mbuf
;
1998 init_memory_buffer(&mbuf
, record_data
, data_size
);
2000 if (!buffer_read(&mbuf
, FIELD_OFFSET(EmfPlusRegion
, RegionNode
)))
2001 return InvalidParameter
;
2003 status
= GdipCreateRegion(region
);
2008 status
= metafile_read_region_node(&mbuf
, *region
, &(*region
)->node
, &count
);
2009 if (status
== Ok
&& !count
)
2010 status
= InvalidParameter
;
2014 GdipDeleteRegion(*region
);
2021 static GpStatus
metafile_deserialize_brush(const BYTE
*record_data
, UINT data_size
, GpBrush
**brush
)
2023 static const UINT header_size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
);
2024 EmfPlusBrush
*data
= (EmfPlusBrush
*)record_data
;
2025 EmfPlusTransformMatrix
*transform
= NULL
;
2032 if (data_size
< header_size
)
2033 return InvalidParameter
;
2037 case BrushTypeSolidColor
:
2038 if (data_size
!= header_size
+ sizeof(EmfPlusSolidBrushData
))
2039 return InvalidParameter
;
2041 status
= GdipCreateSolidFill(data
->BrushData
.solid
.SolidColor
, (GpSolidFill
**)brush
);
2043 case BrushTypeHatchFill
:
2044 if (data_size
!= header_size
+ sizeof(EmfPlusHatchBrushData
))
2045 return InvalidParameter
;
2047 status
= GdipCreateHatchBrush(data
->BrushData
.hatch
.HatchStyle
, data
->BrushData
.hatch
.ForeColor
,
2048 data
->BrushData
.hatch
.BackColor
, (GpHatch
**)brush
);
2050 case BrushTypeTextureFill
:
2054 offset
= header_size
+ FIELD_OFFSET(EmfPlusTextureBrushData
, OptionalData
);
2055 if (data_size
<= offset
)
2056 return InvalidParameter
;
2058 brushflags
= data
->BrushData
.texture
.BrushDataFlags
;
2059 if (brushflags
& BrushDataTransform
)
2061 if (data_size
<= offset
+ sizeof(EmfPlusTransformMatrix
))
2062 return InvalidParameter
;
2063 transform
= (EmfPlusTransformMatrix
*)(record_data
+ offset
);
2064 offset
+= sizeof(EmfPlusTransformMatrix
);
2067 status
= metafile_deserialize_image(record_data
+ offset
, data_size
- offset
, &image
);
2071 status
= GdipCreateTexture(image
, data
->BrushData
.texture
.WrapMode
, (GpTexture
**)brush
);
2072 if (status
== Ok
&& transform
&& !(brushflags
& BrushDataDoNotTransform
))
2073 GdipSetTextureTransform((GpTexture
*)*brush
, (const GpMatrix
*)transform
);
2075 GdipDisposeImage(image
);
2078 case BrushTypeLinearGradient
:
2080 GpLineGradient
*gradient
= NULL
;
2082 UINT position_count
= 0;
2084 offset
= header_size
+ FIELD_OFFSET(EmfPlusLinearGradientBrushData
, OptionalData
);
2085 if (data_size
< offset
)
2086 return InvalidParameter
;
2088 brushflags
= data
->BrushData
.lineargradient
.BrushDataFlags
;
2089 if ((brushflags
& BrushDataPresetColors
) && (brushflags
& (BrushDataBlendFactorsH
| BrushDataBlendFactorsV
)))
2090 return InvalidParameter
;
2092 if (brushflags
& BrushDataTransform
)
2094 if (data_size
< offset
+ sizeof(EmfPlusTransformMatrix
))
2095 return InvalidParameter
;
2096 transform
= (EmfPlusTransformMatrix
*)(record_data
+ offset
);
2097 offset
+= sizeof(EmfPlusTransformMatrix
);
2100 if (brushflags
& (BrushDataPresetColors
| BrushDataBlendFactorsH
| BrushDataBlendFactorsV
))
2102 if (data_size
<= offset
+ sizeof(DWORD
)) /* Number of factors/preset colors. */
2103 return InvalidParameter
;
2104 position_count
= *(DWORD
*)(record_data
+ offset
);
2105 offset
+= sizeof(DWORD
);
2108 if (brushflags
& BrushDataPresetColors
)
2110 if (data_size
!= offset
+ position_count
* (sizeof(float) + sizeof(EmfPlusARGB
)))
2111 return InvalidParameter
;
2113 else if (brushflags
& BrushDataBlendFactorsH
)
2115 if (data_size
!= offset
+ position_count
* 2 * sizeof(float))
2116 return InvalidParameter
;
2119 rect
.X
= data
->BrushData
.lineargradient
.RectF
.X
;
2120 rect
.Y
= data
->BrushData
.lineargradient
.RectF
.Y
;
2121 rect
.Width
= data
->BrushData
.lineargradient
.RectF
.Width
;
2122 rect
.Height
= data
->BrushData
.lineargradient
.RectF
.Height
;
2124 status
= GdipCreateLineBrushFromRect(&rect
, data
->BrushData
.lineargradient
.StartColor
,
2125 data
->BrushData
.lineargradient
.EndColor
, LinearGradientModeHorizontal
,
2126 data
->BrushData
.lineargradient
.WrapMode
, &gradient
);
2130 status
= GdipSetLineTransform(gradient
, (const GpMatrix
*)transform
);
2134 if (brushflags
& BrushDataPresetColors
)
2135 status
= GdipSetLinePresetBlend(gradient
, (ARGB
*)(record_data
+ offset
+
2136 position_count
* sizeof(REAL
)), (REAL
*)(record_data
+ offset
), position_count
);
2137 else if (brushflags
& BrushDataBlendFactorsH
)
2138 status
= GdipSetLineBlend(gradient
, (REAL
*)(record_data
+ offset
+ position_count
* sizeof(REAL
)),
2139 (REAL
*)(record_data
+ offset
), position_count
);
2141 if (brushflags
& BrushDataIsGammaCorrected
)
2142 FIXME("BrushDataIsGammaCorrected is not handled.\n");
2147 *brush
= (GpBrush
*)gradient
;
2149 GdipDeleteBrush((GpBrush
*)gradient
);
2154 FIXME("brush type %lu is not supported.\n", data
->Type
);
2155 return NotImplemented
;
2161 static GpStatus
metafile_get_pen_brush_data_offset(EmfPlusPen
*data
, UINT data_size
, DWORD
*ret
)
2163 EmfPlusPenData
*pendata
= (EmfPlusPenData
*)data
->data
;
2164 DWORD offset
= FIELD_OFFSET(EmfPlusPen
, data
);
2166 if (data_size
<= offset
)
2167 return InvalidParameter
;
2169 offset
+= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
2170 if (data_size
<= offset
)
2171 return InvalidParameter
;
2173 if (pendata
->PenDataFlags
& PenDataTransform
)
2174 offset
+= sizeof(EmfPlusTransformMatrix
);
2176 if (pendata
->PenDataFlags
& PenDataStartCap
)
2177 offset
+= sizeof(DWORD
);
2179 if (pendata
->PenDataFlags
& PenDataEndCap
)
2180 offset
+= sizeof(DWORD
);
2182 if (pendata
->PenDataFlags
& PenDataJoin
)
2183 offset
+= sizeof(DWORD
);
2185 if (pendata
->PenDataFlags
& PenDataMiterLimit
)
2186 offset
+= sizeof(REAL
);
2188 if (pendata
->PenDataFlags
& PenDataLineStyle
)
2189 offset
+= sizeof(DWORD
);
2191 if (pendata
->PenDataFlags
& PenDataDashedLineCap
)
2192 offset
+= sizeof(DWORD
);
2194 if (pendata
->PenDataFlags
& PenDataDashedLineOffset
)
2195 offset
+= sizeof(REAL
);
2197 if (pendata
->PenDataFlags
& PenDataDashedLine
)
2199 EmfPlusDashedLineData
*dashedline
= (EmfPlusDashedLineData
*)((BYTE
*)data
+ offset
);
2201 offset
+= FIELD_OFFSET(EmfPlusDashedLineData
, data
);
2202 if (data_size
<= offset
)
2203 return InvalidParameter
;
2205 offset
+= dashedline
->DashedLineDataSize
* sizeof(float);
2208 if (pendata
->PenDataFlags
& PenDataNonCenter
)
2209 offset
+= sizeof(DWORD
);
2211 if (pendata
->PenDataFlags
& PenDataCompoundLine
)
2213 EmfPlusCompoundLineData
*compoundline
= (EmfPlusCompoundLineData
*)((BYTE
*)data
+ offset
);
2215 offset
+= FIELD_OFFSET(EmfPlusCompoundLineData
, data
);
2216 if (data_size
<= offset
)
2217 return InvalidParameter
;
2219 offset
+= compoundline
->CompoundLineDataSize
* sizeof(float);
2222 if (pendata
->PenDataFlags
& PenDataCustomStartCap
)
2224 EmfPlusCustomStartCapData
*startcap
= (EmfPlusCustomStartCapData
*)((BYTE
*)data
+ offset
);
2226 offset
+= FIELD_OFFSET(EmfPlusCustomStartCapData
, data
);
2227 if (data_size
<= offset
)
2228 return InvalidParameter
;
2230 offset
+= startcap
->CustomStartCapSize
;
2233 if (pendata
->PenDataFlags
& PenDataCustomEndCap
)
2235 EmfPlusCustomEndCapData
*endcap
= (EmfPlusCustomEndCapData
*)((BYTE
*)data
+ offset
);
2237 offset
+= FIELD_OFFSET(EmfPlusCustomEndCapData
, data
);
2238 if (data_size
<= offset
)
2239 return InvalidParameter
;
2241 offset
+= endcap
->CustomEndCapSize
;
2248 static GpStatus
METAFILE_PlaybackObject(GpMetafile
*metafile
, UINT flags
, UINT data_size
, const BYTE
*record_data
)
2250 BYTE type
= (flags
>> 8) & 0xff;
2251 BYTE id
= flags
& 0xff;
2252 void *object
= NULL
;
2255 if (type
> ObjectTypeMax
|| id
>= EmfPlusObjectTableSize
)
2256 return InvalidParameter
;
2260 case ObjectTypeBrush
:
2261 status
= metafile_deserialize_brush(record_data
, data_size
, (GpBrush
**)&object
);
2265 EmfPlusPen
*data
= (EmfPlusPen
*)record_data
;
2266 EmfPlusPenData
*pendata
= (EmfPlusPenData
*)data
->data
;
2271 status
= metafile_get_pen_brush_data_offset(data
, data_size
, &offset
);
2275 status
= metafile_deserialize_brush(record_data
+ offset
, data_size
- offset
, &brush
);
2279 status
= GdipCreatePen2(brush
, pendata
->PenWidth
, pendata
->PenUnit
, &pen
);
2280 GdipDeleteBrush(brush
);
2284 offset
= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
2286 if (pendata
->PenDataFlags
& PenDataTransform
)
2288 FIXME("PenDataTransform is not supported.\n");
2289 offset
+= sizeof(EmfPlusTransformMatrix
);
2292 if (pendata
->PenDataFlags
& PenDataStartCap
)
2294 if ((status
= GdipSetPenStartCap(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2296 offset
+= sizeof(DWORD
);
2299 if (pendata
->PenDataFlags
& PenDataEndCap
)
2301 if ((status
= GdipSetPenEndCap(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2303 offset
+= sizeof(DWORD
);
2306 if (pendata
->PenDataFlags
& PenDataJoin
)
2308 if ((status
= GdipSetPenLineJoin(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2310 offset
+= sizeof(DWORD
);
2313 if (pendata
->PenDataFlags
& PenDataMiterLimit
)
2315 if ((status
= GdipSetPenMiterLimit(pen
, *(REAL
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2317 offset
+= sizeof(REAL
);
2320 if (pendata
->PenDataFlags
& PenDataLineStyle
)
2322 if ((status
= GdipSetPenDashStyle(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2324 offset
+= sizeof(DWORD
);
2327 if (pendata
->PenDataFlags
& PenDataDashedLineCap
)
2329 FIXME("PenDataDashedLineCap is not supported.\n");
2330 offset
+= sizeof(DWORD
);
2333 if (pendata
->PenDataFlags
& PenDataDashedLineOffset
)
2335 if ((status
= GdipSetPenDashOffset(pen
, *(REAL
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2337 offset
+= sizeof(REAL
);
2340 if (pendata
->PenDataFlags
& PenDataDashedLine
)
2342 EmfPlusDashedLineData
*dashedline
= (EmfPlusDashedLineData
*)((BYTE
*)pendata
+ offset
);
2343 FIXME("PenDataDashedLine is not supported.\n");
2344 offset
+= FIELD_OFFSET(EmfPlusDashedLineData
, data
) + dashedline
->DashedLineDataSize
* sizeof(float);
2347 if (pendata
->PenDataFlags
& PenDataNonCenter
)
2349 FIXME("PenDataNonCenter is not supported.\n");
2350 offset
+= sizeof(DWORD
);
2353 if (pendata
->PenDataFlags
& PenDataCompoundLine
)
2355 EmfPlusCompoundLineData
*compoundline
= (EmfPlusCompoundLineData
*)((BYTE
*)pendata
+ offset
);
2356 FIXME("PenDataCompoundLine is not supported.\n");
2357 offset
+= FIELD_OFFSET(EmfPlusCompoundLineData
, data
) + compoundline
->CompoundLineDataSize
* sizeof(float);
2360 if (pendata
->PenDataFlags
& PenDataCustomStartCap
)
2362 EmfPlusCustomStartCapData
*startcap
= (EmfPlusCustomStartCapData
*)((BYTE
*)pendata
+ offset
);
2363 FIXME("PenDataCustomStartCap is not supported.\n");
2364 offset
+= FIELD_OFFSET(EmfPlusCustomStartCapData
, data
) + startcap
->CustomStartCapSize
;
2367 if (pendata
->PenDataFlags
& PenDataCustomEndCap
)
2369 EmfPlusCustomEndCapData
*endcap
= (EmfPlusCustomEndCapData
*)((BYTE
*)pendata
+ offset
);
2370 FIXME("PenDataCustomEndCap is not supported.\n");
2371 offset
+= FIELD_OFFSET(EmfPlusCustomEndCapData
, data
) + endcap
->CustomEndCapSize
;
2381 case ObjectTypePath
:
2382 status
= metafile_deserialize_path(record_data
, data_size
, (GpPath
**)&object
);
2384 case ObjectTypeRegion
:
2385 status
= metafile_deserialize_region(record_data
, data_size
, (GpRegion
**)&object
);
2387 case ObjectTypeImage
:
2388 status
= metafile_deserialize_image(record_data
, data_size
, (GpImage
**)&object
);
2390 case ObjectTypeFont
:
2392 EmfPlusFont
*data
= (EmfPlusFont
*)record_data
;
2393 GpFontFamily
*family
;
2396 if (data_size
<= FIELD_OFFSET(EmfPlusFont
, FamilyName
))
2397 return InvalidParameter
;
2398 data_size
-= FIELD_OFFSET(EmfPlusFont
, FamilyName
);
2400 if (data_size
< data
->Length
* sizeof(WCHAR
))
2401 return InvalidParameter
;
2403 if (!(familyname
= GdipAlloc((data
->Length
+ 1) * sizeof(*familyname
))))
2406 memcpy(familyname
, data
->FamilyName
, data
->Length
* sizeof(*familyname
));
2407 familyname
[data
->Length
] = 0;
2409 status
= GdipCreateFontFamilyFromName(familyname
, NULL
, &family
);
2410 GdipFree(familyname
);
2412 /* If a font family cannot be created from family name, native
2413 falls back to a sans serif font. */
2415 status
= GdipGetGenericFontFamilySansSerif(&family
);
2419 status
= GdipCreateFont(family
, data
->EmSize
, data
->FontStyleFlags
, data
->SizeUnit
, (GpFont
**)&object
);
2420 GdipDeleteFontFamily(family
);
2423 case ObjectTypeImageAttributes
:
2425 EmfPlusImageAttributes
*data
= (EmfPlusImageAttributes
*)record_data
;
2426 GpImageAttributes
*attributes
= NULL
;
2428 if (data_size
!= sizeof(*data
))
2429 return InvalidParameter
;
2431 if ((status
= GdipCreateImageAttributes(&attributes
)) != Ok
)
2434 status
= GdipSetImageAttributesWrapMode(attributes
, data
->WrapMode
, *(DWORD
*)&data
->ClampColor
,
2435 !!data
->ObjectClamp
);
2437 object
= attributes
;
2439 GdipDisposeImageAttributes(attributes
);
2443 FIXME("not implemented for object type %d.\n", type
);
2444 return NotImplemented
;
2448 metafile_set_object_table_entry(metafile
, id
, type
, object
);
2453 static GpStatus
metafile_set_clip_region(GpMetafile
*metafile
, GpRegion
*region
, CombineMode mode
)
2455 GpMatrix world_to_device
;
2457 get_graphics_transform(metafile
->playback_graphics
, CoordinateSpaceDevice
, CoordinateSpaceWorld
, &world_to_device
);
2459 GdipTransformRegion(region
, &world_to_device
);
2460 GdipCombineRegionRegion(metafile
->clip
, region
, mode
);
2462 return METAFILE_PlaybackUpdateClip(metafile
);
2465 GpStatus WINGDIPAPI
GdipPlayMetafileRecord(GDIPCONST GpMetafile
*metafile
,
2466 EmfPlusRecordType recordType
, UINT flags
, UINT dataSize
, GDIPCONST BYTE
*data
)
2469 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
;
2471 TRACE("(%p,%x,%x,%d,%p)\n", metafile
, recordType
, flags
, dataSize
, data
);
2473 if (!metafile
|| (dataSize
&& !data
) || !metafile
->playback_graphics
)
2474 return InvalidParameter
;
2476 if (recordType
>= 1 && recordType
<= 0x7a)
2478 /* regular EMF record */
2479 if (metafile
->playback_dc
)
2481 ENHMETARECORD
*record
= heap_alloc_zero(dataSize
+ 8);
2485 record
->iType
= recordType
;
2486 record
->nSize
= dataSize
+ 8;
2487 memcpy(record
->dParm
, data
, dataSize
);
2489 if (record
->iType
== EMR_BITBLT
|| record
->iType
== EMR_STRETCHBLT
)
2490 SetStretchBltMode(metafile
->playback_dc
, STRETCH_HALFTONE
);
2492 if(PlayEnhMetaFileRecord(metafile
->playback_dc
, metafile
->handle_table
,
2493 record
, metafile
->handle_count
) == 0)
2494 ERR("PlayEnhMetaFileRecord failed\n");
2504 EmfPlusRecordHeader
*header
= (EmfPlusRecordHeader
*)(data
)-1;
2506 METAFILE_PlaybackReleaseDC((GpMetafile
*)metafile
);
2510 case EmfPlusRecordTypeHeader
:
2511 case EmfPlusRecordTypeEndOfFile
:
2513 case EmfPlusRecordTypeGetDC
:
2514 METAFILE_PlaybackGetDC((GpMetafile
*)metafile
);
2516 case EmfPlusRecordTypeClear
:
2518 EmfPlusClear
*record
= (EmfPlusClear
*)header
;
2520 if (dataSize
!= sizeof(record
->Color
))
2521 return InvalidParameter
;
2523 return GdipGraphicsClear(metafile
->playback_graphics
, record
->Color
);
2525 case EmfPlusRecordTypeFillRects
:
2527 EmfPlusFillRects
*record
= (EmfPlusFillRects
*)header
;
2528 GpBrush
*brush
, *temp_brush
=NULL
;
2529 GpRectF
*rects
, *temp_rects
=NULL
;
2531 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
))
2532 return InvalidParameter
;
2536 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(EmfPlusRect
) * record
->Count
)
2537 return InvalidParameter
;
2541 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(GpRectF
) * record
->Count
)
2542 return InvalidParameter
;
2547 stat
= GdipCreateSolidFill(record
->BrushID
, (GpSolidFill
**)&temp_brush
);
2552 if (record
->BrushID
>= EmfPlusObjectTableSize
||
2553 real_metafile
->objtable
[record
->BrushID
].type
!= ObjectTypeBrush
)
2554 return InvalidParameter
;
2556 brush
= real_metafile
->objtable
[record
->BrushID
].u
.brush
;
2564 EmfPlusRect
*int_rects
= (EmfPlusRect
*)(record
+1);
2567 rects
= temp_rects
= heap_alloc_zero(sizeof(GpRectF
) * record
->Count
);
2570 for (i
=0; i
<record
->Count
; i
++)
2572 rects
[i
].X
= int_rects
[i
].X
;
2573 rects
[i
].Y
= int_rects
[i
].Y
;
2574 rects
[i
].Width
= int_rects
[i
].Width
;
2575 rects
[i
].Height
= int_rects
[i
].Height
;
2582 rects
= (GpRectF
*)(record
+1);
2587 stat
= GdipFillRectangles(metafile
->playback_graphics
, brush
, rects
, record
->Count
);
2590 GdipDeleteBrush(temp_brush
);
2591 heap_free(temp_rects
);
2595 case EmfPlusRecordTypeSetClipRect
:
2597 EmfPlusSetClipRect
*record
= (EmfPlusSetClipRect
*)header
;
2598 CombineMode mode
= (CombineMode
)((flags
>> 8) & 0xf);
2601 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(*record
))
2602 return InvalidParameter
;
2604 stat
= GdipCreateRegionRect(&record
->ClipRect
, ®ion
);
2608 stat
= metafile_set_clip_region(real_metafile
, region
, mode
);
2609 GdipDeleteRegion(region
);
2614 case EmfPlusRecordTypeSetClipRegion
:
2616 CombineMode mode
= (flags
>> 8) & 0xf;
2617 BYTE regionid
= flags
& 0xff;
2621 return InvalidParameter
;
2623 if (regionid
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[regionid
].type
!= ObjectTypeRegion
)
2624 return InvalidParameter
;
2626 stat
= GdipCloneRegion(real_metafile
->objtable
[regionid
].u
.region
, ®ion
);
2629 stat
= metafile_set_clip_region(real_metafile
, region
, mode
);
2630 GdipDeleteRegion(region
);
2635 case EmfPlusRecordTypeSetClipPath
:
2637 CombineMode mode
= (flags
>> 8) & 0xf;
2638 BYTE pathid
= flags
& 0xff;
2642 return InvalidParameter
;
2644 if (pathid
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pathid
].type
!= ObjectTypePath
)
2645 return InvalidParameter
;
2647 stat
= GdipCreateRegionPath(real_metafile
->objtable
[pathid
].u
.path
, ®ion
);
2650 stat
= metafile_set_clip_region(real_metafile
, region
, mode
);
2651 GdipDeleteRegion(region
);
2656 case EmfPlusRecordTypeSetPageTransform
:
2658 EmfPlusSetPageTransform
*record
= (EmfPlusSetPageTransform
*)header
;
2659 GpUnit unit
= (GpUnit
)flags
;
2661 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetPageTransform
))
2662 return InvalidParameter
;
2664 real_metafile
->page_unit
= unit
;
2665 real_metafile
->page_scale
= record
->PageScale
;
2667 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2669 case EmfPlusRecordTypeSetWorldTransform
:
2671 EmfPlusSetWorldTransform
*record
= (EmfPlusSetWorldTransform
*)header
;
2673 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetWorldTransform
))
2674 return InvalidParameter
;
2676 memcpy(real_metafile
->world_transform
->matrix
, record
->MatrixData
, sizeof(record
->MatrixData
));
2678 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2680 case EmfPlusRecordTypeScaleWorldTransform
:
2682 EmfPlusScaleWorldTransform
*record
= (EmfPlusScaleWorldTransform
*)header
;
2683 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2685 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusScaleWorldTransform
))
2686 return InvalidParameter
;
2688 GdipScaleMatrix(real_metafile
->world_transform
, record
->Sx
, record
->Sy
, order
);
2690 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2692 case EmfPlusRecordTypeMultiplyWorldTransform
:
2694 EmfPlusMultiplyWorldTransform
*record
= (EmfPlusMultiplyWorldTransform
*)header
;
2695 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2698 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusMultiplyWorldTransform
))
2699 return InvalidParameter
;
2701 memcpy(matrix
.matrix
, record
->MatrixData
, sizeof(matrix
.matrix
));
2703 GdipMultiplyMatrix(real_metafile
->world_transform
, &matrix
, order
);
2705 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2707 case EmfPlusRecordTypeRotateWorldTransform
:
2709 EmfPlusRotateWorldTransform
*record
= (EmfPlusRotateWorldTransform
*)header
;
2710 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2712 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusRotateWorldTransform
))
2713 return InvalidParameter
;
2715 GdipRotateMatrix(real_metafile
->world_transform
, record
->Angle
, order
);
2717 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2719 case EmfPlusRecordTypeTranslateWorldTransform
:
2721 EmfPlusTranslateWorldTransform
*record
= (EmfPlusTranslateWorldTransform
*)header
;
2722 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2724 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusTranslateWorldTransform
))
2725 return InvalidParameter
;
2727 GdipTranslateMatrix(real_metafile
->world_transform
, record
->dx
, record
->dy
, order
);
2729 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2731 case EmfPlusRecordTypeResetWorldTransform
:
2733 GdipSetMatrixElements(real_metafile
->world_transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
2735 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2737 case EmfPlusRecordTypeBeginContainer
:
2739 EmfPlusBeginContainer
*record
= (EmfPlusBeginContainer
*)header
;
2742 REAL scale_x
, scale_y
;
2743 GpRectF scaled_srcrect
;
2746 cont
= heap_alloc_zero(sizeof(*cont
));
2750 stat
= GdipCloneRegion(metafile
->clip
, &cont
->clip
);
2757 stat
= GdipBeginContainer2(metafile
->playback_graphics
, &cont
->state
);
2761 GdipDeleteRegion(cont
->clip
);
2766 cont
->id
= record
->StackIndex
;
2767 cont
->type
= BEGIN_CONTAINER
;
2768 cont
->world_transform
= *metafile
->world_transform
;
2769 cont
->page_unit
= metafile
->page_unit
;
2770 cont
->page_scale
= metafile
->page_scale
;
2771 list_add_head(&real_metafile
->containers
, &cont
->entry
);
2773 unit
= record
->Header
.Flags
& 0xff;
2775 scale_x
= units_to_pixels(1.0, unit
, metafile
->image
.xres
, metafile
->printer_display
);
2776 scale_y
= units_to_pixels(1.0, unit
, metafile
->image
.yres
, metafile
->printer_display
);
2778 scaled_srcrect
.X
= scale_x
* record
->SrcRect
.X
;
2779 scaled_srcrect
.Y
= scale_y
* record
->SrcRect
.Y
;
2780 scaled_srcrect
.Width
= scale_x
* record
->SrcRect
.Width
;
2781 scaled_srcrect
.Height
= scale_y
* record
->SrcRect
.Height
;
2783 transform
.matrix
[0] = record
->DestRect
.Width
/ scaled_srcrect
.Width
;
2784 transform
.matrix
[1] = 0.0;
2785 transform
.matrix
[2] = 0.0;
2786 transform
.matrix
[3] = record
->DestRect
.Height
/ scaled_srcrect
.Height
;
2787 transform
.matrix
[4] = record
->DestRect
.X
- scaled_srcrect
.X
;
2788 transform
.matrix
[5] = record
->DestRect
.Y
- scaled_srcrect
.Y
;
2790 GdipMultiplyMatrix(real_metafile
->world_transform
, &transform
, MatrixOrderPrepend
);
2792 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2794 case EmfPlusRecordTypeBeginContainerNoParams
:
2795 case EmfPlusRecordTypeSave
:
2797 EmfPlusContainerRecord
*record
= (EmfPlusContainerRecord
*)header
;
2800 cont
= heap_alloc_zero(sizeof(*cont
));
2804 stat
= GdipCloneRegion(metafile
->clip
, &cont
->clip
);
2811 if (recordType
== EmfPlusRecordTypeBeginContainerNoParams
)
2812 stat
= GdipBeginContainer2(metafile
->playback_graphics
, &cont
->state
);
2814 stat
= GdipSaveGraphics(metafile
->playback_graphics
, &cont
->state
);
2818 GdipDeleteRegion(cont
->clip
);
2823 cont
->id
= record
->StackIndex
;
2824 if (recordType
== EmfPlusRecordTypeBeginContainerNoParams
)
2825 cont
->type
= BEGIN_CONTAINER
;
2827 cont
->type
= SAVE_GRAPHICS
;
2828 cont
->world_transform
= *metafile
->world_transform
;
2829 cont
->page_unit
= metafile
->page_unit
;
2830 cont
->page_scale
= metafile
->page_scale
;
2831 list_add_head(&real_metafile
->containers
, &cont
->entry
);
2835 case EmfPlusRecordTypeEndContainer
:
2836 case EmfPlusRecordTypeRestore
:
2838 EmfPlusContainerRecord
*record
= (EmfPlusContainerRecord
*)header
;
2840 enum container_type type
;
2843 if (recordType
== EmfPlusRecordTypeEndContainer
)
2844 type
= BEGIN_CONTAINER
;
2846 type
= SAVE_GRAPHICS
;
2848 LIST_FOR_EACH_ENTRY(cont
, &real_metafile
->containers
, container
, entry
)
2850 if (cont
->id
== record
->StackIndex
&& cont
->type
== type
)
2861 /* pop any newer items on the stack */
2862 while ((cont2
= LIST_ENTRY(list_head(&real_metafile
->containers
), container
, entry
)) != cont
)
2864 list_remove(&cont2
->entry
);
2865 GdipDeleteRegion(cont2
->clip
);
2869 if (type
== BEGIN_CONTAINER
)
2870 GdipEndContainer(real_metafile
->playback_graphics
, cont
->state
);
2872 GdipRestoreGraphics(real_metafile
->playback_graphics
, cont
->state
);
2874 *real_metafile
->world_transform
= cont
->world_transform
;
2875 real_metafile
->page_unit
= cont
->page_unit
;
2876 real_metafile
->page_scale
= cont
->page_scale
;
2877 GdipCombineRegionRegion(real_metafile
->clip
, cont
->clip
, CombineModeReplace
);
2879 list_remove(&cont
->entry
);
2880 GdipDeleteRegion(cont
->clip
);
2886 case EmfPlusRecordTypeSetPixelOffsetMode
:
2888 return GdipSetPixelOffsetMode(real_metafile
->playback_graphics
, flags
& 0xff);
2890 case EmfPlusRecordTypeSetCompositingQuality
:
2892 return GdipSetCompositingQuality(real_metafile
->playback_graphics
, flags
& 0xff);
2894 case EmfPlusRecordTypeSetInterpolationMode
:
2896 return GdipSetInterpolationMode(real_metafile
->playback_graphics
, flags
& 0xff);
2898 case EmfPlusRecordTypeSetTextRenderingHint
:
2900 return GdipSetTextRenderingHint(real_metafile
->playback_graphics
, flags
& 0xff);
2902 case EmfPlusRecordTypeSetAntiAliasMode
:
2904 return GdipSetSmoothingMode(real_metafile
->playback_graphics
, (flags
>> 1) & 0xff);
2906 case EmfPlusRecordTypeSetCompositingMode
:
2908 return GdipSetCompositingMode(real_metafile
->playback_graphics
, flags
& 0xff);
2910 case EmfPlusRecordTypeObject
:
2912 return METAFILE_PlaybackObject(real_metafile
, flags
, dataSize
, data
);
2914 case EmfPlusRecordTypeDrawImage
:
2916 EmfPlusDrawImage
*draw
= (EmfPlusDrawImage
*)header
;
2917 BYTE image
= flags
& 0xff;
2920 if (image
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[image
].type
!= ObjectTypeImage
)
2921 return InvalidParameter
;
2923 if (dataSize
!= FIELD_OFFSET(EmfPlusDrawImage
, RectData
) - sizeof(EmfPlusRecordHeader
) +
2924 (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
2925 return InvalidParameter
;
2927 if (draw
->ImageAttributesID
>= EmfPlusObjectTableSize
||
2928 real_metafile
->objtable
[draw
->ImageAttributesID
].type
!= ObjectTypeImageAttributes
)
2929 return InvalidParameter
;
2931 if (flags
& 0x4000) /* C */
2933 points
[0].X
= draw
->RectData
.rect
.X
;
2934 points
[0].Y
= draw
->RectData
.rect
.Y
;
2935 points
[1].X
= points
[0].X
+ draw
->RectData
.rect
.Width
;
2936 points
[1].Y
= points
[0].Y
;
2937 points
[2].X
= points
[1].X
;
2938 points
[2].Y
= points
[1].Y
+ draw
->RectData
.rect
.Height
;
2942 points
[0].X
= draw
->RectData
.rectF
.X
;
2943 points
[0].Y
= draw
->RectData
.rectF
.Y
;
2944 points
[1].X
= points
[0].X
+ draw
->RectData
.rectF
.Width
;
2945 points
[1].Y
= points
[0].Y
;
2946 points
[2].X
= points
[1].X
;
2947 points
[2].Y
= points
[1].Y
+ draw
->RectData
.rectF
.Height
;
2950 return GdipDrawImagePointsRect(real_metafile
->playback_graphics
, real_metafile
->objtable
[image
].u
.image
,
2951 points
, 3, draw
->SrcRect
.X
, draw
->SrcRect
.Y
, draw
->SrcRect
.Width
, draw
->SrcRect
.Height
, draw
->SrcUnit
,
2952 real_metafile
->objtable
[draw
->ImageAttributesID
].u
.image_attributes
, NULL
, NULL
);
2954 case EmfPlusRecordTypeDrawImagePoints
:
2956 EmfPlusDrawImagePoints
*draw
= (EmfPlusDrawImagePoints
*)header
;
2957 static const UINT fixed_part_size
= FIELD_OFFSET(EmfPlusDrawImagePoints
, PointData
) -
2958 FIELD_OFFSET(EmfPlusDrawImagePoints
, ImageAttributesID
);
2959 BYTE image
= flags
& 0xff;
2964 if (image
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[image
].type
!= ObjectTypeImage
)
2965 return InvalidParameter
;
2967 if (dataSize
<= fixed_part_size
)
2968 return InvalidParameter
;
2969 dataSize
-= fixed_part_size
;
2971 if (draw
->ImageAttributesID
>= EmfPlusObjectTableSize
||
2972 real_metafile
->objtable
[draw
->ImageAttributesID
].type
!= ObjectTypeImageAttributes
)
2973 return InvalidParameter
;
2975 if (draw
->count
!= 3)
2976 return InvalidParameter
;
2978 if ((flags
>> 13) & 1) /* E */
2979 FIXME("image effects are not supported.\n");
2981 if ((flags
>> 11) & 1) /* P */
2982 size
= sizeof(EmfPlusPointR7
) * draw
->count
;
2983 else if ((flags
>> 14) & 1) /* C */
2984 size
= sizeof(EmfPlusPoint
) * draw
->count
;
2986 size
= sizeof(EmfPlusPointF
) * draw
->count
;
2988 if (dataSize
!= size
)
2989 return InvalidParameter
;
2991 if ((flags
>> 11) & 1) /* P */
2993 points
[0].X
= draw
->PointData
.pointsR
[0].X
;
2994 points
[0].Y
= draw
->PointData
.pointsR
[0].Y
;
2995 for (i
= 1; i
< 3; i
++)
2997 points
[i
].X
= points
[i
-1].X
+ draw
->PointData
.pointsR
[i
].X
;
2998 points
[i
].Y
= points
[i
-1].Y
+ draw
->PointData
.pointsR
[i
].Y
;
3001 else if ((flags
>> 14) & 1) /* C */
3003 for (i
= 0; i
< 3; i
++)
3005 points
[i
].X
= draw
->PointData
.points
[i
].X
;
3006 points
[i
].Y
= draw
->PointData
.points
[i
].Y
;
3010 memcpy(points
, draw
->PointData
.pointsF
, sizeof(points
));
3012 return GdipDrawImagePointsRect(real_metafile
->playback_graphics
, real_metafile
->objtable
[image
].u
.image
,
3013 points
, 3, draw
->SrcRect
.X
, draw
->SrcRect
.Y
, draw
->SrcRect
.Width
, draw
->SrcRect
.Height
, draw
->SrcUnit
,
3014 real_metafile
->objtable
[draw
->ImageAttributesID
].u
.image_attributes
, NULL
, NULL
);
3016 case EmfPlusRecordTypeFillPath
:
3018 EmfPlusFillPath
*fill
= (EmfPlusFillPath
*)header
;
3019 GpSolidFill
*solidfill
= NULL
;
3020 BYTE path
= flags
& 0xff;
3023 if (path
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[path
].type
!= ObjectTypePath
)
3024 return InvalidParameter
;
3026 if (dataSize
!= sizeof(fill
->data
.BrushId
))
3027 return InvalidParameter
;
3031 stat
= GdipCreateSolidFill(fill
->data
.Color
, &solidfill
);
3034 brush
= (GpBrush
*)solidfill
;
3038 if (fill
->data
.BrushId
>= EmfPlusObjectTableSize
||
3039 real_metafile
->objtable
[fill
->data
.BrushId
].type
!= ObjectTypeBrush
)
3040 return InvalidParameter
;
3042 brush
= real_metafile
->objtable
[fill
->data
.BrushId
].u
.brush
;
3045 stat
= GdipFillPath(real_metafile
->playback_graphics
, brush
, real_metafile
->objtable
[path
].u
.path
);
3046 GdipDeleteBrush((GpBrush
*)solidfill
);
3049 case EmfPlusRecordTypeFillClosedCurve
:
3051 static const UINT fixed_part_size
= FIELD_OFFSET(EmfPlusFillClosedCurve
, PointData
) -
3052 sizeof(EmfPlusRecordHeader
);
3053 EmfPlusFillClosedCurve
*fill
= (EmfPlusFillClosedCurve
*)header
;
3054 GpSolidFill
*solidfill
= NULL
;
3059 if (dataSize
<= fixed_part_size
)
3060 return InvalidParameter
;
3062 if (fill
->Count
== 0)
3063 return InvalidParameter
;
3065 if (flags
& 0x800) /* P */
3066 size
= (fixed_part_size
+ sizeof(EmfPlusPointR7
) * fill
->Count
+ 3) & ~3;
3067 else if (flags
& 0x4000) /* C */
3068 size
= fixed_part_size
+ sizeof(EmfPlusPoint
) * fill
->Count
;
3070 size
= fixed_part_size
+ sizeof(EmfPlusPointF
) * fill
->Count
;
3072 if (dataSize
!= size
)
3073 return InvalidParameter
;
3075 mode
= flags
& 0x200 ? FillModeWinding
: FillModeAlternate
; /* W */
3077 if (flags
& 0x8000) /* S */
3079 stat
= GdipCreateSolidFill(fill
->BrushId
, &solidfill
);
3082 brush
= (GpBrush
*)solidfill
;
3086 if (fill
->BrushId
>= EmfPlusObjectTableSize
||
3087 real_metafile
->objtable
[fill
->BrushId
].type
!= ObjectTypeBrush
)
3088 return InvalidParameter
;
3090 brush
= real_metafile
->objtable
[fill
->BrushId
].u
.brush
;
3093 if (flags
& (0x800 | 0x4000))
3095 GpPointF
*points
= GdipAlloc(fill
->Count
* sizeof(*points
));
3098 if (flags
& 0x800) /* P */
3100 for (i
= 1; i
< fill
->Count
; i
++)
3102 points
[i
].X
= points
[i
- 1].X
+ fill
->PointData
.pointsR
[i
].X
;
3103 points
[i
].Y
= points
[i
- 1].Y
+ fill
->PointData
.pointsR
[i
].Y
;
3108 for (i
= 0; i
< fill
->Count
; i
++)
3110 points
[i
].X
= fill
->PointData
.points
[i
].X
;
3111 points
[i
].Y
= fill
->PointData
.points
[i
].Y
;
3115 stat
= GdipFillClosedCurve2(real_metafile
->playback_graphics
, brush
,
3116 points
, fill
->Count
, fill
->Tension
, mode
);
3123 stat
= GdipFillClosedCurve2(real_metafile
->playback_graphics
, brush
,
3124 (const GpPointF
*)fill
->PointData
.pointsF
, fill
->Count
, fill
->Tension
, mode
);
3126 GdipDeleteBrush((GpBrush
*)solidfill
);
3129 case EmfPlusRecordTypeFillEllipse
:
3131 EmfPlusFillEllipse
*fill
= (EmfPlusFillEllipse
*)header
;
3132 GpSolidFill
*solidfill
= NULL
;
3135 if (dataSize
<= FIELD_OFFSET(EmfPlusFillEllipse
, RectData
) - sizeof(EmfPlusRecordHeader
))
3136 return InvalidParameter
;
3137 dataSize
-= FIELD_OFFSET(EmfPlusFillEllipse
, RectData
) - sizeof(EmfPlusRecordHeader
);
3139 if (dataSize
!= (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3140 return InvalidParameter
;
3144 stat
= GdipCreateSolidFill(fill
->BrushId
, &solidfill
);
3147 brush
= (GpBrush
*)solidfill
;
3151 if (fill
->BrushId
>= EmfPlusObjectTableSize
||
3152 real_metafile
->objtable
[fill
->BrushId
].type
!= ObjectTypeBrush
)
3153 return InvalidParameter
;
3155 brush
= real_metafile
->objtable
[fill
->BrushId
].u
.brush
;
3159 stat
= GdipFillEllipseI(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rect
.X
,
3160 fill
->RectData
.rect
.Y
, fill
->RectData
.rect
.Width
, fill
->RectData
.rect
.Height
);
3162 stat
= GdipFillEllipse(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rectF
.X
,
3163 fill
->RectData
.rectF
.Y
, fill
->RectData
.rectF
.Width
, fill
->RectData
.rectF
.Height
);
3165 GdipDeleteBrush((GpBrush
*)solidfill
);
3168 case EmfPlusRecordTypeFillPie
:
3170 EmfPlusFillPie
*fill
= (EmfPlusFillPie
*)header
;
3171 GpSolidFill
*solidfill
= NULL
;
3174 if (dataSize
<= FIELD_OFFSET(EmfPlusFillPie
, RectData
) - sizeof(EmfPlusRecordHeader
))
3175 return InvalidParameter
;
3176 dataSize
-= FIELD_OFFSET(EmfPlusFillPie
, RectData
) - sizeof(EmfPlusRecordHeader
);
3178 if (dataSize
!= (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3179 return InvalidParameter
;
3181 if (flags
& 0x8000) /* S */
3183 stat
= GdipCreateSolidFill(fill
->BrushId
, &solidfill
);
3186 brush
= (GpBrush
*)solidfill
;
3190 if (fill
->BrushId
>= EmfPlusObjectTableSize
||
3191 real_metafile
->objtable
[fill
->BrushId
].type
!= ObjectTypeBrush
)
3192 return InvalidParameter
;
3194 brush
= real_metafile
->objtable
[fill
->BrushId
].u
.brush
;
3197 if (flags
& 0x4000) /* C */
3198 stat
= GdipFillPieI(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rect
.X
,
3199 fill
->RectData
.rect
.Y
, fill
->RectData
.rect
.Width
, fill
->RectData
.rect
.Height
,
3200 fill
->StartAngle
, fill
->SweepAngle
);
3202 stat
= GdipFillPie(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rectF
.X
,
3203 fill
->RectData
.rectF
.Y
, fill
->RectData
.rectF
.Width
, fill
->RectData
.rectF
.Height
,
3204 fill
->StartAngle
, fill
->SweepAngle
);
3206 GdipDeleteBrush((GpBrush
*)solidfill
);
3209 case EmfPlusRecordTypeDrawPath
:
3211 EmfPlusDrawPath
*draw
= (EmfPlusDrawPath
*)header
;
3212 BYTE path
= flags
& 0xff;
3214 if (dataSize
!= sizeof(draw
->PenId
))
3215 return InvalidParameter
;
3217 if (path
>= EmfPlusObjectTableSize
|| draw
->PenId
>= EmfPlusObjectTableSize
)
3218 return InvalidParameter
;
3220 if (real_metafile
->objtable
[path
].type
!= ObjectTypePath
||
3221 real_metafile
->objtable
[draw
->PenId
].type
!= ObjectTypePen
)
3222 return InvalidParameter
;
3224 return GdipDrawPath(real_metafile
->playback_graphics
, real_metafile
->objtable
[draw
->PenId
].u
.pen
,
3225 real_metafile
->objtable
[path
].u
.path
);
3227 case EmfPlusRecordTypeDrawArc
:
3229 EmfPlusDrawArc
*draw
= (EmfPlusDrawArc
*)header
;
3230 BYTE pen
= flags
& 0xff;
3232 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3233 return InvalidParameter
;
3235 if (dataSize
!= FIELD_OFFSET(EmfPlusDrawArc
, RectData
) - sizeof(EmfPlusRecordHeader
) +
3236 (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3237 return InvalidParameter
;
3239 if (flags
& 0x4000) /* C */
3240 return GdipDrawArcI(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3241 draw
->RectData
.rect
.X
, draw
->RectData
.rect
.Y
, draw
->RectData
.rect
.Width
,
3242 draw
->RectData
.rect
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3244 return GdipDrawArc(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3245 draw
->RectData
.rectF
.X
, draw
->RectData
.rectF
.Y
, draw
->RectData
.rectF
.Width
,
3246 draw
->RectData
.rectF
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3248 case EmfPlusRecordTypeDrawEllipse
:
3250 EmfPlusDrawEllipse
*draw
= (EmfPlusDrawEllipse
*)header
;
3251 BYTE pen
= flags
& 0xff;
3253 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3254 return InvalidParameter
;
3256 if (dataSize
!= (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3257 return InvalidParameter
;
3259 if (flags
& 0x4000) /* C */
3260 return GdipDrawEllipseI(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3261 draw
->RectData
.rect
.X
, draw
->RectData
.rect
.Y
, draw
->RectData
.rect
.Width
,
3262 draw
->RectData
.rect
.Height
);
3264 return GdipDrawEllipse(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3265 draw
->RectData
.rectF
.X
, draw
->RectData
.rectF
.Y
, draw
->RectData
.rectF
.Width
,
3266 draw
->RectData
.rectF
.Height
);
3268 case EmfPlusRecordTypeDrawPie
:
3270 EmfPlusDrawPie
*draw
= (EmfPlusDrawPie
*)header
;
3271 BYTE pen
= flags
& 0xff;
3273 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3274 return InvalidParameter
;
3276 if (dataSize
!= FIELD_OFFSET(EmfPlusDrawPie
, RectData
) - sizeof(EmfPlusRecordHeader
) +
3277 (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3278 return InvalidParameter
;
3280 if (flags
& 0x4000) /* C */
3281 return GdipDrawPieI(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3282 draw
->RectData
.rect
.X
, draw
->RectData
.rect
.Y
, draw
->RectData
.rect
.Width
,
3283 draw
->RectData
.rect
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3285 return GdipDrawPie(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3286 draw
->RectData
.rectF
.X
, draw
->RectData
.rectF
.Y
, draw
->RectData
.rectF
.Width
,
3287 draw
->RectData
.rectF
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3289 case EmfPlusRecordTypeDrawRects
:
3291 EmfPlusDrawRects
*draw
= (EmfPlusDrawRects
*)header
;
3292 BYTE pen
= flags
& 0xff;
3293 GpRectF
*rects
= NULL
;
3295 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3296 return InvalidParameter
;
3298 if (dataSize
<= FIELD_OFFSET(EmfPlusDrawRects
, RectData
) - sizeof(EmfPlusRecordHeader
))
3299 return InvalidParameter
;
3300 dataSize
-= FIELD_OFFSET(EmfPlusDrawRects
, RectData
) - sizeof(EmfPlusRecordHeader
);
3302 if (dataSize
!= draw
->Count
* (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3303 return InvalidParameter
;
3309 rects
= GdipAlloc(draw
->Count
* sizeof(*rects
));
3313 for (i
= 0; i
< draw
->Count
; i
++)
3315 rects
[i
].X
= draw
->RectData
.rect
[i
].X
;
3316 rects
[i
].Y
= draw
->RectData
.rect
[i
].Y
;
3317 rects
[i
].Width
= draw
->RectData
.rect
[i
].Width
;
3318 rects
[i
].Height
= draw
->RectData
.rect
[i
].Height
;
3322 stat
= GdipDrawRectangles(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3323 rects
? rects
: (GpRectF
*)draw
->RectData
.rectF
, draw
->Count
);
3327 case EmfPlusRecordTypeDrawDriverString
:
3330 DWORD expected_size
;
3333 GpSolidFill
*solidfill
= NULL
;
3334 void* alignedmem
= NULL
;
3335 GpMatrix
*matrix
= NULL
;
3336 BYTE font
= flags
& 0xff;
3337 EmfPlusDrawDriverString
*draw
= (EmfPlusDrawDriverString
*)header
;
3339 if (font
>= EmfPlusObjectTableSize
||
3340 real_metafile
->objtable
[font
].type
!= ObjectTypeFont
)
3341 return InvalidParameter
;
3343 expected_size
= FIELD_OFFSET(EmfPlusDrawDriverString
, VariableData
) -
3344 sizeof(EmfPlusRecordHeader
);
3345 if (dataSize
< expected_size
|| draw
->GlyphCount
<= 0)
3346 return InvalidParameter
;
3348 expected_size
+= draw
->GlyphCount
* (sizeof(*text
) + sizeof(*positions
));
3349 if (draw
->MatrixPresent
)
3350 expected_size
+= sizeof(*matrix
);
3352 /* Pad expected size to DWORD alignment. */
3353 expected_size
= (expected_size
+ 3) & ~3;
3355 if (dataSize
!= expected_size
)
3356 return InvalidParameter
;
3360 stat
= GdipCreateSolidFill(draw
->brush
.Color
, &solidfill
);
3363 return InvalidParameter
;
3365 brush
= (GpBrush
*)solidfill
;
3369 if (draw
->brush
.BrushId
>= EmfPlusObjectTableSize
||
3370 real_metafile
->objtable
[draw
->brush
.BrushId
].type
!= ObjectTypeBrush
)
3371 return InvalidParameter
;
3373 brush
= real_metafile
->objtable
[draw
->brush
.BrushId
].u
.brush
;
3376 text
= (UINT16
*)&draw
->VariableData
[0];
3378 /* If GlyphCount is odd, all subsequent fields will be 2-byte
3379 aligned rather than 4-byte aligned, which may lead to access
3380 issues. Handle this case by making our own copy of positions. */
3381 if (draw
->GlyphCount
% 2)
3383 SIZE_T alloc_size
= draw
->GlyphCount
* sizeof(*positions
);
3385 if (draw
->MatrixPresent
)
3386 alloc_size
+= sizeof(*matrix
);
3388 positions
= alignedmem
= heap_alloc(alloc_size
);
3391 GdipDeleteBrush((GpBrush
*)solidfill
);
3395 memcpy(positions
, &text
[draw
->GlyphCount
], alloc_size
);
3398 positions
= (PointF
*)&text
[draw
->GlyphCount
];
3400 if (draw
->MatrixPresent
)
3401 matrix
= (GpMatrix
*)&positions
[draw
->GlyphCount
];
3403 stat
= GdipDrawDriverString(real_metafile
->playback_graphics
, text
, draw
->GlyphCount
,
3404 real_metafile
->objtable
[font
].u
.font
, brush
, positions
,
3405 draw
->DriverStringOptionsFlags
, matrix
);
3407 GdipDeleteBrush((GpBrush
*)solidfill
);
3408 heap_free(alignedmem
);
3412 case EmfPlusRecordTypeFillRegion
:
3414 EmfPlusFillRegion
* const fill
= (EmfPlusFillRegion
*)header
;
3415 GpSolidFill
*solidfill
= NULL
;
3417 BYTE region
= flags
& 0xff;
3419 if (dataSize
!= sizeof(EmfPlusFillRegion
) - sizeof(EmfPlusRecordHeader
))
3420 return InvalidParameter
;
3422 if (region
>= EmfPlusObjectTableSize
||
3423 real_metafile
->objtable
[region
].type
!= ObjectTypeRegion
)
3424 return InvalidParameter
;
3428 stat
= GdipCreateSolidFill(fill
->data
.Color
, &solidfill
);
3431 brush
= (GpBrush
*)solidfill
;
3435 if (fill
->data
.BrushId
>= EmfPlusObjectTableSize
||
3436 real_metafile
->objtable
[fill
->data
.BrushId
].type
!= ObjectTypeBrush
)
3437 return InvalidParameter
;
3439 brush
= real_metafile
->objtable
[fill
->data
.BrushId
].u
.brush
;
3442 stat
= GdipFillRegion(real_metafile
->playback_graphics
, brush
,
3443 real_metafile
->objtable
[region
].u
.region
);
3444 GdipDeleteBrush((GpBrush
*)solidfill
);
3449 FIXME("Not implemented for record type %x\n", recordType
);
3450 return NotImplemented
;
3457 struct enum_metafile_data
3459 EnumerateMetafileProc callback
;
3460 void *callback_data
;
3461 GpMetafile
*metafile
;
3464 static int CALLBACK
enum_metafile_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
3465 int nObj
, LPARAM lpData
)
3468 struct enum_metafile_data
*data
= (struct enum_metafile_data
*)lpData
;
3471 data
->metafile
->handle_table
= lpHTable
;
3472 data
->metafile
->handle_count
= nObj
;
3474 /* First check for an EMF+ record. */
3475 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
3477 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
3479 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
3483 while (offset
+ sizeof(EmfPlusRecordHeader
) <= comment
->cbData
)
3485 const EmfPlusRecordHeader
*record
= (const EmfPlusRecordHeader
*)&comment
->Data
[offset
];
3487 if (record
->DataSize
)
3488 pStr
= (const BYTE
*)(record
+1);
3492 ret
= data
->callback(record
->Type
, record
->Flags
, record
->DataSize
,
3493 pStr
, data
->callback_data
);
3498 offset
+= record
->Size
;
3505 if (lpEMFR
->nSize
!= 8)
3506 pStr
= (const BYTE
*)lpEMFR
->dParm
;
3510 return data
->callback(lpEMFR
->iType
, 0, lpEMFR
->nSize
-8,
3511 pStr
, data
->callback_data
);
3514 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestPoints(GpGraphics
*graphics
,
3515 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*destPoints
, INT count
,
3516 GDIPCONST GpRectF
*srcRect
, Unit srcUnit
, EnumerateMetafileProc callback
,
3517 VOID
*callbackData
, GDIPCONST GpImageAttributes
*imageAttributes
)
3519 struct enum_metafile_data data
;
3521 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
; /* whoever made this const was joking */
3522 GraphicsContainer state
;
3526 TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics
, metafile
,
3527 destPoints
, count
, srcRect
, srcUnit
, callback
, callbackData
,
3530 if (!graphics
|| !metafile
|| !destPoints
|| count
!= 3 || !srcRect
)
3531 return InvalidParameter
;
3533 if (!metafile
->hemf
)
3534 return InvalidParameter
;
3536 if (metafile
->playback_graphics
)
3539 TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect
), srcUnit
,
3540 debugstr_pointf(&destPoints
[0]), debugstr_pointf(&destPoints
[1]),
3541 debugstr_pointf(&destPoints
[2]));
3543 data
.callback
= callback
;
3544 data
.callback_data
= callbackData
;
3545 data
.metafile
= real_metafile
;
3547 real_metafile
->playback_graphics
= graphics
;
3548 real_metafile
->playback_dc
= NULL
;
3549 real_metafile
->src_rect
= *srcRect
;
3551 memcpy(real_metafile
->playback_points
, destPoints
, sizeof(PointF
) * 3);
3552 stat
= GdipTransformPoints(graphics
, CoordinateSpaceDevice
, CoordinateSpaceWorld
, real_metafile
->playback_points
, 3);
3555 stat
= GdipBeginContainer2(graphics
, &state
);
3559 stat
= GdipSetPageScale(graphics
, 1.0);
3562 stat
= GdipSetPageUnit(graphics
, UnitPixel
);
3565 stat
= GdipResetWorldTransform(graphics
);
3568 stat
= GdipCreateRegion(&real_metafile
->base_clip
);
3571 stat
= GdipGetClip(graphics
, real_metafile
->base_clip
);
3574 stat
= GdipCreateRegion(&real_metafile
->clip
);
3577 stat
= GdipCreatePath(FillModeAlternate
, &dst_path
);
3581 GpPointF clip_points
[4];
3583 clip_points
[0] = real_metafile
->playback_points
[0];
3584 clip_points
[1] = real_metafile
->playback_points
[1];
3585 clip_points
[2].X
= real_metafile
->playback_points
[1].X
+ real_metafile
->playback_points
[2].X
3586 - real_metafile
->playback_points
[0].X
;
3587 clip_points
[2].Y
= real_metafile
->playback_points
[1].Y
+ real_metafile
->playback_points
[2].Y
3588 - real_metafile
->playback_points
[0].Y
;
3589 clip_points
[3] = real_metafile
->playback_points
[2];
3591 stat
= GdipAddPathPolygon(dst_path
, clip_points
, 4);
3594 stat
= GdipCombineRegionPath(real_metafile
->base_clip
, dst_path
, CombineModeIntersect
);
3596 GdipDeletePath(dst_path
);
3600 stat
= GdipCreateMatrix(&real_metafile
->world_transform
);
3604 real_metafile
->page_unit
= UnitDisplay
;
3605 real_metafile
->page_scale
= 1.0;
3606 stat
= METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
3611 stat
= METAFILE_PlaybackUpdateClip(real_metafile
);
3616 stat
= METAFILE_PlaybackGetDC(real_metafile
);
3618 dst_bounds
.left
= real_metafile
->playback_points
[0].X
;
3619 dst_bounds
.right
= real_metafile
->playback_points
[1].X
;
3620 dst_bounds
.top
= real_metafile
->playback_points
[0].Y
;
3621 dst_bounds
.bottom
= real_metafile
->playback_points
[2].Y
;
3625 EnumEnhMetaFile(real_metafile
->playback_dc
, metafile
->hemf
, enum_metafile_proc
,
3626 &data
, &dst_bounds
);
3628 METAFILE_PlaybackReleaseDC(real_metafile
);
3630 GdipDeleteMatrix(real_metafile
->world_transform
);
3631 real_metafile
->world_transform
= NULL
;
3633 GdipDeleteRegion(real_metafile
->base_clip
);
3634 real_metafile
->base_clip
= NULL
;
3636 GdipDeleteRegion(real_metafile
->clip
);
3637 real_metafile
->clip
= NULL
;
3639 while (list_head(&real_metafile
->containers
))
3641 container
* cont
= LIST_ENTRY(list_head(&real_metafile
->containers
), container
, entry
);
3642 list_remove(&cont
->entry
);
3643 GdipDeleteRegion(cont
->clip
);
3647 GdipEndContainer(graphics
, state
);
3650 real_metafile
->playback_graphics
= NULL
;
3655 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestRect( GpGraphics
*graphics
,
3656 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRectF
*dest
,
3657 GDIPCONST GpRectF
*src
, Unit srcUnit
, EnumerateMetafileProc callback
,
3658 VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3662 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
3664 points
[0].X
= points
[2].X
= dest
->X
;
3665 points
[0].Y
= points
[1].Y
= dest
->Y
;
3666 points
[1].X
= dest
->X
+ dest
->Width
;
3667 points
[2].Y
= dest
->Y
+ dest
->Height
;
3669 return GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, points
, 3,
3670 src
, srcUnit
, callback
, cb_data
, attrs
);
3672 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestRectI( GpGraphics
* graphics
,
3673 GDIPCONST GpMetafile
*metafile
, GDIPCONST Rect
*destRect
,
3674 GDIPCONST Rect
*srcRect
, Unit srcUnit
, EnumerateMetafileProc callback
,
3675 VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3677 GpRectF destRectF
, srcRectF
;
3679 destRectF
.X
= destRect
->X
;
3680 destRectF
.Y
= destRect
->Y
;
3681 destRectF
.Width
= destRect
->Width
;
3682 destRectF
.Height
= destRect
->Height
;
3684 srcRectF
.X
= srcRect
->X
;
3685 srcRectF
.Y
= srcRect
->Y
;
3686 srcRectF
.Width
= srcRect
->Width
;
3687 srcRectF
.Height
= srcRect
->Height
;
3689 return GdipEnumerateMetafileSrcRectDestRect( graphics
, metafile
, &destRectF
, &srcRectF
, srcUnit
, callback
, cb_data
, attrs
);
3692 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRect(GpGraphics
*graphics
,
3693 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRectF
*dest
,
3694 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3698 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
3700 points
[0].X
= points
[2].X
= dest
->X
;
3701 points
[0].Y
= points
[1].Y
= dest
->Y
;
3702 points
[1].X
= dest
->X
+ dest
->Width
;
3703 points
[2].Y
= dest
->Y
+ dest
->Height
;
3705 return GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, points
, 3,
3706 &metafile
->bounds
, metafile
->unit
, callback
, cb_data
, attrs
);
3709 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRectI(GpGraphics
*graphics
,
3710 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRect
*dest
,
3711 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3715 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
3719 destf
.Width
= dest
->Width
;
3720 destf
.Height
= dest
->Height
;
3722 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
3725 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPoint(GpGraphics
*graphics
,
3726 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*dest
,
3727 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3731 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
3735 destf
.Width
= units_to_pixels(metafile
->bounds
.Width
, metafile
->unit
,
3736 metafile
->image
.xres
, metafile
->printer_display
);
3737 destf
.Height
= units_to_pixels(metafile
->bounds
.Height
, metafile
->unit
,
3738 metafile
->image
.yres
, metafile
->printer_display
);
3740 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
3743 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPointI(GpGraphics
*graphics
,
3744 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPoint
*dest
,
3745 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3749 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
3754 return GdipEnumerateMetafileDestPoint(graphics
, metafile
, &ptf
, callback
, cb_data
, attrs
);
3757 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromMetafile(GpMetafile
* metafile
,
3758 MetafileHeader
* header
)
3762 TRACE("(%p, %p)\n", metafile
, header
);
3764 if(!metafile
|| !header
)
3765 return InvalidParameter
;
3769 status
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, header
);
3770 if (status
!= Ok
) return status
;
3774 memset(header
, 0, sizeof(*header
));
3775 header
->Version
= VERSION_MAGIC2
;
3778 header
->Type
= metafile
->metafile_type
;
3779 header
->DpiX
= metafile
->image
.xres
;
3780 header
->DpiY
= metafile
->image
.yres
;
3781 header
->Width
= gdip_round(metafile
->bounds
.Width
);
3782 header
->Height
= gdip_round(metafile
->bounds
.Height
);
3787 static int CALLBACK
get_emfplus_header_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
3788 int nObj
, LPARAM lpData
)
3790 EmfPlusHeader
*dst_header
= (EmfPlusHeader
*)lpData
;
3792 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
3794 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
3796 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
3798 const EmfPlusRecordHeader
*header
= (const EmfPlusRecordHeader
*)&comment
->Data
[4];
3800 if (4 + sizeof(EmfPlusHeader
) <= comment
->cbData
&&
3801 header
->Type
== EmfPlusRecordTypeHeader
)
3803 memcpy(dst_header
, header
, sizeof(*dst_header
));
3807 else if (lpEMFR
->iType
== EMR_HEADER
)
3813 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromEmf(HENHMETAFILE hemf
,
3814 MetafileHeader
*header
)
3816 ENHMETAHEADER3 emfheader
;
3817 EmfPlusHeader emfplusheader
;
3818 MetafileType metafile_type
;
3820 TRACE("(%p,%p)\n", hemf
, header
);
3822 if(!hemf
|| !header
)
3823 return InvalidParameter
;
3825 if (GetEnhMetaFileHeader(hemf
, sizeof(emfheader
), (ENHMETAHEADER
*)&emfheader
) == 0)
3826 return GenericError
;
3828 emfplusheader
.Header
.Type
= 0;
3830 EnumEnhMetaFile(NULL
, hemf
, get_emfplus_header_proc
, &emfplusheader
, NULL
);
3832 if (emfplusheader
.Header
.Type
== EmfPlusRecordTypeHeader
)
3834 if ((emfplusheader
.Header
.Flags
& 1) == 1)
3835 metafile_type
= MetafileTypeEmfPlusDual
;
3837 metafile_type
= MetafileTypeEmfPlusOnly
;
3840 metafile_type
= MetafileTypeEmf
;
3842 header
->Type
= metafile_type
;
3843 header
->Size
= emfheader
.nBytes
;
3844 header
->DpiX
= (REAL
)emfheader
.szlDevice
.cx
* 25.4 / emfheader
.szlMillimeters
.cx
;
3845 header
->DpiY
= (REAL
)emfheader
.szlDevice
.cy
* 25.4 / emfheader
.szlMillimeters
.cy
;
3846 header
->X
= gdip_round((REAL
)emfheader
.rclFrame
.left
/ 2540.0 * header
->DpiX
);
3847 header
->Y
= gdip_round((REAL
)emfheader
.rclFrame
.top
/ 2540.0 * header
->DpiY
);
3848 header
->Width
= gdip_round((REAL
)(emfheader
.rclFrame
.right
- emfheader
.rclFrame
.left
) / 2540.0 * header
->DpiX
);
3849 header
->Height
= gdip_round((REAL
)(emfheader
.rclFrame
.bottom
- emfheader
.rclFrame
.top
) / 2540.0 * header
->DpiY
);
3850 header
->u
.EmfHeader
= emfheader
;
3852 if (metafile_type
== MetafileTypeEmfPlusDual
|| metafile_type
== MetafileTypeEmfPlusOnly
)
3854 header
->Version
= emfplusheader
.Version
;
3855 header
->EmfPlusFlags
= emfplusheader
.EmfPlusFlags
;
3856 header
->EmfPlusHeaderSize
= emfplusheader
.Header
.Size
;
3857 header
->LogicalDpiX
= emfplusheader
.LogicalDpiX
;
3858 header
->LogicalDpiY
= emfplusheader
.LogicalDpiY
;
3862 header
->Version
= emfheader
.nVersion
;
3863 header
->EmfPlusFlags
= 0;
3864 header
->EmfPlusHeaderSize
= 0;
3865 header
->LogicalDpiX
= 0;
3866 header
->LogicalDpiY
= 0;
3872 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromWmf(HMETAFILE hwmf
,
3873 GDIPCONST WmfPlaceableFileHeader
*placeable
, MetafileHeader
*header
)
3876 GpMetafile
*metafile
;
3878 TRACE("(%p,%p,%p)\n", hwmf
, placeable
, header
);
3880 status
= GdipCreateMetafileFromWmf(hwmf
, FALSE
, placeable
, &metafile
);
3883 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
3884 GdipDisposeImage(&metafile
->image
);
3889 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR
*filename
,
3890 MetafileHeader
*header
)
3893 GpMetafile
*metafile
;
3895 TRACE("(%s,%p)\n", debugstr_w(filename
), header
);
3897 if (!filename
|| !header
)
3898 return InvalidParameter
;
3900 status
= GdipCreateMetafileFromFile(filename
, &metafile
);
3903 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
3904 GdipDisposeImage(&metafile
->image
);
3909 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromStream(IStream
*stream
,
3910 MetafileHeader
*header
)
3913 GpMetafile
*metafile
;
3915 TRACE("(%p,%p)\n", stream
, header
);
3917 if (!stream
|| !header
)
3918 return InvalidParameter
;
3920 status
= GdipCreateMetafileFromStream(stream
, &metafile
);
3923 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
3924 GdipDisposeImage(&metafile
->image
);
3929 GpStatus WINGDIPAPI
GdipCreateMetafileFromEmf(HENHMETAFILE hemf
, BOOL
delete,
3930 GpMetafile
**metafile
)
3933 MetafileHeader header
;
3935 TRACE("(%p,%i,%p)\n", hemf
, delete, metafile
);
3937 if(!hemf
|| !metafile
)
3938 return InvalidParameter
;
3940 stat
= GdipGetMetafileHeaderFromEmf(hemf
, &header
);
3944 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
3948 (*metafile
)->image
.type
= ImageTypeMetafile
;
3949 (*metafile
)->image
.format
= ImageFormatEMF
;
3950 (*metafile
)->image
.frame_count
= 1;
3951 (*metafile
)->image
.xres
= header
.DpiX
;
3952 (*metafile
)->image
.yres
= header
.DpiY
;
3953 (*metafile
)->bounds
.X
= (REAL
)header
.u
.EmfHeader
.rclFrame
.left
/ 2540.0 * header
.DpiX
;
3954 (*metafile
)->bounds
.Y
= (REAL
)header
.u
.EmfHeader
.rclFrame
.top
/ 2540.0 * header
.DpiY
;
3955 (*metafile
)->bounds
.Width
= (REAL
)(header
.u
.EmfHeader
.rclFrame
.right
- header
.u
.EmfHeader
.rclFrame
.left
)
3956 / 2540.0 * header
.DpiX
;
3957 (*metafile
)->bounds
.Height
= (REAL
)(header
.u
.EmfHeader
.rclFrame
.bottom
- header
.u
.EmfHeader
.rclFrame
.top
)
3958 / 2540.0 * header
.DpiY
;
3959 (*metafile
)->unit
= UnitPixel
;
3960 (*metafile
)->metafile_type
= header
.Type
;
3961 (*metafile
)->hemf
= hemf
;
3962 (*metafile
)->preserve_hemf
= !delete;
3963 /* If the 31th bit of EmfPlusFlags was set, metafile was recorded with a DC for a video display.
3964 * If clear, metafile was recorded with a DC for a printer */
3965 (*metafile
)->printer_display
= !(header
.EmfPlusFlags
& (1u << 31));
3966 (*metafile
)->logical_dpix
= header
.LogicalDpiX
;
3967 (*metafile
)->logical_dpiy
= header
.LogicalDpiY
;
3968 list_init(&(*metafile
)->containers
);
3970 TRACE("<-- %p\n", *metafile
);
3975 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmf(HMETAFILE hwmf
, BOOL
delete,
3976 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
3981 GpStatus retval
= Ok
;
3983 TRACE("(%p, %d, %p, %p)\n", hwmf
, delete, placeable
, metafile
);
3985 if(!hwmf
|| !metafile
)
3986 return InvalidParameter
;
3989 read
= GetMetaFileBitsEx(hwmf
, 0, NULL
);
3991 return GenericError
;
3992 copy
= heap_alloc_zero(read
);
3993 GetMetaFileBitsEx(hwmf
, read
, copy
);
3995 hemf
= SetWinMetaFileBits(read
, copy
, NULL
, NULL
);
3998 /* FIXME: We should store and use hwmf instead of converting to hemf */
3999 retval
= GdipCreateMetafileFromEmf(hemf
, TRUE
, metafile
);
4005 (*metafile
)->image
.xres
= (REAL
)placeable
->Inch
;
4006 (*metafile
)->image
.yres
= (REAL
)placeable
->Inch
;
4007 (*metafile
)->bounds
.X
= ((REAL
)placeable
->BoundingBox
.Left
) / ((REAL
)placeable
->Inch
);
4008 (*metafile
)->bounds
.Y
= ((REAL
)placeable
->BoundingBox
.Top
) / ((REAL
)placeable
->Inch
);
4009 (*metafile
)->bounds
.Width
= (REAL
)(placeable
->BoundingBox
.Right
-
4010 placeable
->BoundingBox
.Left
);
4011 (*metafile
)->bounds
.Height
= (REAL
)(placeable
->BoundingBox
.Bottom
-
4012 placeable
->BoundingBox
.Top
);
4013 (*metafile
)->metafile_type
= MetafileTypeWmfPlaceable
;
4016 (*metafile
)->metafile_type
= MetafileTypeWmf
;
4017 (*metafile
)->image
.format
= ImageFormatWMF
;
4019 if (delete) DeleteMetaFile(hwmf
);
4022 DeleteEnhMetaFile(hemf
);
4026 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR
*file
,
4027 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
4032 TRACE("(%s, %p, %p)\n", debugstr_w(file
), placeable
, metafile
);
4034 hmf
= GetMetaFileW(file
);
4036 return GdipCreateMetafileFromWmf(hmf
, TRUE
, placeable
, metafile
);
4038 emf
= GetEnhMetaFileW(file
);
4040 return GdipCreateMetafileFromEmf(emf
, TRUE
, metafile
);
4042 return GenericError
;
4045 GpStatus WINGDIPAPI
GdipCreateMetafileFromFile(GDIPCONST WCHAR
*file
,
4046 GpMetafile
**metafile
)
4051 TRACE("(%p, %p)\n", file
, metafile
);
4053 if (!file
|| !metafile
) return InvalidParameter
;
4057 status
= GdipCreateStreamOnFile(file
, GENERIC_READ
, &stream
);
4060 status
= GdipCreateMetafileFromStream(stream
, metafile
);
4061 IStream_Release(stream
);
4066 GpStatus WINGDIPAPI
GdipCreateMetafileFromStream(IStream
*stream
,
4067 GpMetafile
**metafile
)
4071 TRACE("%p %p\n", stream
, metafile
);
4073 stat
= GdipLoadImageFromStream(stream
, (GpImage
**)metafile
);
4074 if (stat
!= Ok
) return stat
;
4076 if ((*metafile
)->image
.type
!= ImageTypeMetafile
)
4078 GdipDisposeImage(&(*metafile
)->image
);
4080 return GenericError
;
4086 GpStatus WINGDIPAPI
GdipGetMetafileDownLevelRasterizationLimit(GDIPCONST GpMetafile
*metafile
,
4089 TRACE("(%p,%p)\n", metafile
, limitDpi
);
4091 if (!metafile
|| !limitDpi
)
4092 return InvalidParameter
;
4094 if (!metafile
->record_dc
)
4097 *limitDpi
= metafile
->limit_dpi
;
4102 GpStatus WINGDIPAPI
GdipSetMetafileDownLevelRasterizationLimit(GpMetafile
*metafile
,
4105 TRACE("(%p,%u)\n", metafile
, limitDpi
);
4110 if (!metafile
|| limitDpi
< 10)
4111 return InvalidParameter
;
4113 if (!metafile
->record_dc
)
4116 metafile
->limit_dpi
= limitDpi
;
4121 GpStatus WINGDIPAPI
GdipConvertToEmfPlus(const GpGraphics
* ref
,
4122 GpMetafile
* metafile
, BOOL
* succ
, EmfType emfType
,
4123 const WCHAR
* description
, GpMetafile
** out_metafile
)
4127 TRACE("(%p,%p,%p,%u,%s,%p)\n", ref
, metafile
, succ
, emfType
,
4128 debugstr_w(description
), out_metafile
);
4130 if(!ref
|| !metafile
|| !out_metafile
|| emfType
< EmfTypeEmfOnly
|| emfType
> EmfTypeEmfPlusDual
)
4131 return InvalidParameter
;
4135 *out_metafile
= NULL
;
4138 FIXME("not implemented\n");
4140 return NotImplemented
;
4143 GpStatus WINGDIPAPI
GdipEmfToWmfBits(HENHMETAFILE hemf
, UINT cbData16
,
4144 LPBYTE pData16
, INT iMapMode
, INT eFlags
)
4146 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf
, cbData16
, pData16
, iMapMode
, eFlags
);
4147 return NotImplemented
;
4150 GpStatus WINGDIPAPI
GdipRecordMetafileFileName(GDIPCONST WCHAR
* fileName
,
4151 HDC hdc
, EmfType type
, GDIPCONST GpRectF
*pFrameRect
,
4152 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
,
4153 GpMetafile
**metafile
)
4157 REAL framerect_factor_x
, framerect_factor_y
;
4161 TRACE("%s %p %d %s %d %s %p\n", debugstr_w(fileName
), hdc
, type
, debugstr_rectf(pFrameRect
),
4162 frameUnit
, debugstr_w(desc
), metafile
);
4164 if (!hdc
|| type
< EmfTypeEmfOnly
|| type
> EmfTypeEmfPlusDual
|| !metafile
)
4165 return InvalidParameter
;
4167 dpix
= (REAL
)GetDeviceCaps(hdc
, HORZRES
) / GetDeviceCaps(hdc
, HORZSIZE
) * 25.4;
4168 dpiy
= (REAL
)GetDeviceCaps(hdc
, VERTRES
) / GetDeviceCaps(hdc
, VERTSIZE
) * 25.4;
4174 case MetafileFrameUnitPixel
:
4175 framerect_factor_x
= 2540.0 / dpix
;
4176 framerect_factor_y
= 2540.0 / dpiy
;
4178 case MetafileFrameUnitPoint
:
4179 framerect_factor_x
= framerect_factor_y
= 2540.0 / 72.0;
4181 case MetafileFrameUnitInch
:
4182 framerect_factor_x
= framerect_factor_y
= 2540.0;
4184 case MetafileFrameUnitDocument
:
4185 framerect_factor_x
= framerect_factor_y
= 2540.0 / 300.0;
4187 case MetafileFrameUnitMillimeter
:
4188 framerect_factor_x
= framerect_factor_y
= 100.0;
4190 case MetafileFrameUnitGdi
:
4191 framerect_factor_x
= framerect_factor_y
= 1.0;
4194 return InvalidParameter
;
4197 rc
.left
= framerect_factor_x
* pFrameRect
->X
;
4198 rc
.top
= framerect_factor_y
* pFrameRect
->Y
;
4199 rc
.right
= rc
.left
+ framerect_factor_x
* pFrameRect
->Width
;
4200 rc
.bottom
= rc
.top
+ framerect_factor_y
* pFrameRect
->Height
;
4207 record_dc
= CreateEnhMetaFileW(hdc
, fileName
, lprc
, desc
);
4210 return GenericError
;
4212 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
4215 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
4219 (*metafile
)->image
.type
= ImageTypeMetafile
;
4220 (*metafile
)->image
.flags
= ImageFlagsNone
;
4221 (*metafile
)->image
.palette
= NULL
;
4222 (*metafile
)->image
.xres
= dpix
;
4223 (*metafile
)->image
.yres
= dpiy
;
4224 (*metafile
)->bounds
.X
= (*metafile
)->bounds
.Y
= 0.0;
4225 (*metafile
)->bounds
.Width
= (*metafile
)->bounds
.Height
= 1.0;
4226 (*metafile
)->unit
= UnitPixel
;
4227 (*metafile
)->metafile_type
= type
;
4228 (*metafile
)->record_dc
= record_dc
;
4229 (*metafile
)->comment_data
= NULL
;
4230 (*metafile
)->comment_data_size
= 0;
4231 (*metafile
)->comment_data_length
= 0;
4232 (*metafile
)->limit_dpi
= 96;
4233 (*metafile
)->hemf
= NULL
;
4234 (*metafile
)->printer_display
= (GetDeviceCaps(record_dc
, TECHNOLOGY
) == DT_RASPRINTER
);
4235 (*metafile
)->logical_dpix
= (REAL
)GetDeviceCaps(record_dc
, LOGPIXELSX
);
4236 (*metafile
)->logical_dpiy
= (REAL
)GetDeviceCaps(record_dc
, LOGPIXELSY
);
4237 list_init(&(*metafile
)->containers
);
4241 (*metafile
)->auto_frame
= TRUE
;
4242 (*metafile
)->auto_frame_min
.X
= 0;
4243 (*metafile
)->auto_frame_min
.Y
= 0;
4244 (*metafile
)->auto_frame_max
.X
= -1;
4245 (*metafile
)->auto_frame_max
.Y
= -1;
4248 stat
= METAFILE_WriteHeader(*metafile
, hdc
);
4252 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
4253 heap_free(*metafile
);
4261 GpStatus WINGDIPAPI
GdipRecordMetafileFileNameI(GDIPCONST WCHAR
* fileName
, HDC hdc
, EmfType type
,
4262 GDIPCONST GpRect
*pFrameRect
, MetafileFrameUnit frameUnit
,
4263 GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
4265 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
4266 frameUnit
, debugstr_w(desc
), metafile
);
4268 return NotImplemented
;
4271 /*****************************************************************************
4272 * GdipConvertToEmfPlusToFile [GDIPLUS.@]
4275 GpStatus WINGDIPAPI
GdipConvertToEmfPlusToFile(const GpGraphics
* refGraphics
,
4276 GpMetafile
* metafile
, BOOL
* conversionSuccess
,
4277 const WCHAR
* filename
, EmfType emfType
,
4278 const WCHAR
* description
, GpMetafile
** out_metafile
)
4280 FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics
, metafile
, conversionSuccess
, filename
, emfType
, description
, out_metafile
);
4281 return NotImplemented
;
4284 static GpStatus
METAFILE_CreateCompressedImageStream(GpImage
*image
, IStream
**stream
, DWORD
*size
)
4293 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, stream
);
4294 if (FAILED(hr
)) return hresult_to_status(hr
);
4296 stat
= encode_image_png(image
, *stream
, NULL
);
4299 IStream_Release(*stream
);
4303 hr
= IStream_Stat(*stream
, &statstg
, 1);
4306 IStream_Release(*stream
);
4307 return hresult_to_status(hr
);
4309 *size
= statstg
.cbSize
.u
.LowPart
;
4312 hr
= IStream_Seek(*stream
, zero
, STREAM_SEEK_SET
, NULL
);
4315 IStream_Release(*stream
);
4316 return hresult_to_status(hr
);
4322 static GpStatus
METAFILE_FillEmfPlusBitmap(EmfPlusBitmap
*record
, IStream
*stream
, DWORD size
)
4329 record
->PixelFormat
= 0;
4330 record
->Type
= BitmapDataTypeCompressed
;
4332 hr
= IStream_Read(stream
, record
->BitmapData
, size
, NULL
);
4333 if (FAILED(hr
)) return hresult_to_status(hr
);
4337 static GpStatus
METAFILE_AddImageObject(GpMetafile
*metafile
, GpImage
*image
, DWORD
*id
)
4339 EmfPlusObject
*object_record
;
4345 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4348 if (image
->type
== ImageTypeBitmap
)
4353 stat
= METAFILE_CreateCompressedImageStream(image
, &stream
, &size
);
4354 if (stat
!= Ok
) return stat
;
4355 aligned_size
= (size
+ 3) & ~3;
4357 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
4358 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image
.ImageData
.bitmap
.BitmapData
[aligned_size
]),
4359 (void**)&object_record
);
4362 IStream_Release(stream
);
4365 memset(object_record
->ObjectData
.image
.ImageData
.bitmap
.BitmapData
+ size
, 0, aligned_size
- size
);
4367 *id
= METAFILE_AddObjectId(metafile
);
4368 object_record
->Header
.Flags
= *id
| ObjectTypeImage
<< 8;
4369 object_record
->ObjectData
.image
.Version
= VERSION_MAGIC2
;
4370 object_record
->ObjectData
.image
.Type
= ImageDataTypeBitmap
;
4372 stat
= METAFILE_FillEmfPlusBitmap(&object_record
->ObjectData
.image
.ImageData
.bitmap
, stream
, size
);
4373 IStream_Release(stream
);
4374 if (stat
!= Ok
) METAFILE_RemoveLastRecord(metafile
, &object_record
->Header
);
4377 else if (image
->type
== ImageTypeMetafile
)
4379 HENHMETAFILE hemf
= ((GpMetafile
*)image
)->hemf
;
4380 EmfPlusMetafile
*metafile_record
;
4382 if (!hemf
) return InvalidParameter
;
4384 size
= GetEnhMetaFileBits(hemf
, 0, NULL
);
4385 if (!size
) return GenericError
;
4387 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
4388 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image
.ImageData
.metafile
.MetafileData
[size
]),
4389 (void**)&object_record
);
4390 if (stat
!= Ok
) return stat
;
4392 *id
= METAFILE_AddObjectId(metafile
);
4393 object_record
->Header
.Flags
= *id
| ObjectTypeImage
<< 8;
4394 object_record
->ObjectData
.image
.Version
= VERSION_MAGIC2
;
4395 object_record
->ObjectData
.image
.Type
= ImageDataTypeMetafile
;
4396 metafile_record
= &object_record
->ObjectData
.image
.ImageData
.metafile
;
4397 metafile_record
->Type
= ((GpMetafile
*)image
)->metafile_type
;
4398 metafile_record
->MetafileDataSize
= size
;
4399 if (GetEnhMetaFileBits(hemf
, size
, metafile_record
->MetafileData
) != size
)
4401 METAFILE_RemoveLastRecord(metafile
, &object_record
->Header
);
4402 return GenericError
;
4408 FIXME("not supported image type (%d)\n", image
->type
);
4409 return NotImplemented
;
4413 static GpStatus
METAFILE_AddImageAttributesObject(GpMetafile
*metafile
, const GpImageAttributes
*attrs
, DWORD
*id
)
4415 EmfPlusObject
*object_record
;
4416 EmfPlusImageAttributes
*attrs_record
;
4421 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4427 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
4428 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image_attributes
) + sizeof(EmfPlusImageAttributes
),
4429 (void**)&object_record
);
4430 if (stat
!= Ok
) return stat
;
4432 *id
= METAFILE_AddObjectId(metafile
);
4433 object_record
->Header
.Flags
= *id
| (ObjectTypeImageAttributes
<< 8);
4434 attrs_record
= &object_record
->ObjectData
.image_attributes
;
4435 attrs_record
->Version
= VERSION_MAGIC2
;
4436 attrs_record
->Reserved1
= 0;
4437 attrs_record
->WrapMode
= attrs
->wrap
;
4438 attrs_record
->ClampColor
= attrs
->outside_color
;
4439 attrs_record
->ObjectClamp
= attrs
->clamp
;
4440 attrs_record
->Reserved2
= 0;
4444 GpStatus
METAFILE_DrawImagePointsRect(GpMetafile
*metafile
, GpImage
*image
,
4445 GDIPCONST GpPointF
*points
, INT count
, REAL srcx
, REAL srcy
, REAL srcwidth
,
4446 REAL srcheight
, GpUnit srcUnit
, GDIPCONST GpImageAttributes
* imageAttributes
,
4447 DrawImageAbort callback
, VOID
*callbackData
)
4449 EmfPlusDrawImagePoints
*draw_image_record
;
4450 DWORD image_id
, attributes_id
;
4453 if (count
!= 3) return InvalidParameter
;
4455 if (metafile
->metafile_type
== MetafileTypeEmf
)
4457 FIXME("MetafileTypeEmf metafiles not supported\n");
4458 return NotImplemented
;
4461 FIXME("semi-stub\n");
4463 if (!imageAttributes
)
4465 stat
= METAFILE_AddImageObject(metafile
, image
, &image_id
);
4467 else if (image
->type
== ImageTypeBitmap
)
4469 INT width
= ((GpBitmap
*)image
)->width
;
4470 INT height
= ((GpBitmap
*)image
)->height
;
4471 GpGraphics
*graphics
;
4474 stat
= GdipCreateBitmapFromScan0(width
, height
,
4475 0, PixelFormat32bppARGB
, NULL
, &bitmap
);
4476 if (stat
!= Ok
) return stat
;
4478 stat
= GdipGetImageGraphicsContext((GpImage
*)bitmap
, &graphics
);
4481 GdipDisposeImage((GpImage
*)bitmap
);
4485 stat
= GdipDrawImageRectRectI(graphics
, image
, 0, 0, width
, height
,
4486 0, 0, width
, height
, UnitPixel
, imageAttributes
, NULL
, NULL
);
4487 GdipDeleteGraphics(graphics
);
4490 GdipDisposeImage((GpImage
*)bitmap
);
4494 stat
= METAFILE_AddImageObject(metafile
, (GpImage
*)bitmap
, &image_id
);
4495 GdipDisposeImage((GpImage
*)bitmap
);
4499 FIXME("imageAttributes not supported (image type %d)\n", image
->type
);
4500 return NotImplemented
;
4502 if (stat
!= Ok
) return stat
;
4504 stat
= METAFILE_AddImageAttributesObject(metafile
, imageAttributes
, &attributes_id
);
4505 if (stat
!= Ok
) return stat
;
4507 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeDrawImagePoints
,
4508 sizeof(EmfPlusDrawImagePoints
), (void **)&draw_image_record
);
4509 if (stat
!= Ok
) return stat
;
4511 draw_image_record
->Header
.Flags
= image_id
;
4512 draw_image_record
->ImageAttributesID
= attributes_id
;
4513 draw_image_record
->SrcUnit
= UnitPixel
;
4514 draw_image_record
->SrcRect
.X
= units_to_pixels(srcx
, srcUnit
, metafile
->image
.xres
, metafile
->printer_display
);
4515 draw_image_record
->SrcRect
.Y
= units_to_pixels(srcy
, srcUnit
, metafile
->image
.yres
, metafile
->printer_display
);
4516 draw_image_record
->SrcRect
.Width
= units_to_pixels(srcwidth
, srcUnit
, metafile
->image
.xres
, metafile
->printer_display
);
4517 draw_image_record
->SrcRect
.Height
= units_to_pixels(srcheight
, srcUnit
, metafile
->image
.yres
, metafile
->printer_display
);
4518 draw_image_record
->count
= 3;
4519 memcpy(draw_image_record
->PointData
.pointsF
, points
, 3 * sizeof(*points
));
4520 METAFILE_WriteRecords(metafile
);
4524 GpStatus
METAFILE_AddSimpleProperty(GpMetafile
*metafile
, SHORT prop
, SHORT val
)
4526 EmfPlusRecordHeader
*record
;
4529 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4532 stat
= METAFILE_AllocateRecord(metafile
, prop
, sizeof(*record
), (void**)&record
);
4533 if (stat
!= Ok
) return stat
;
4535 record
->Flags
= val
;
4537 METAFILE_WriteRecords(metafile
);
4541 static GpStatus
METAFILE_AddPathObject(GpMetafile
*metafile
, GpPath
*path
, DWORD
*id
)
4543 EmfPlusObject
*object_record
;
4548 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4551 size
= write_path_data(path
, NULL
);
4552 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
4553 FIELD_OFFSET(EmfPlusObject
, ObjectData
.path
) + size
,
4554 (void**)&object_record
);
4555 if (stat
!= Ok
) return stat
;
4557 *id
= METAFILE_AddObjectId(metafile
);
4558 object_record
->Header
.Flags
= *id
| ObjectTypePath
<< 8;
4559 write_path_data(path
, &object_record
->ObjectData
.path
);
4563 static GpStatus
METAFILE_AddPenObject(GpMetafile
*metafile
, GpPen
*pen
, DWORD
*id
)
4565 DWORD i
, data_flags
, pen_data_size
, brush_size
;
4566 EmfPlusObject
*object_record
;
4567 EmfPlusPenData
*pen_data
;
4572 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4576 pen_data_size
= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
4578 GdipIsMatrixIdentity(&pen
->transform
, &result
);
4581 data_flags
|= PenDataTransform
;
4582 pen_data_size
+= sizeof(EmfPlusTransformMatrix
);
4584 if (pen
->startcap
!= LineCapFlat
)
4586 data_flags
|= PenDataStartCap
;
4587 pen_data_size
+= sizeof(DWORD
);
4589 if (pen
->endcap
!= LineCapFlat
)
4591 data_flags
|= PenDataEndCap
;
4592 pen_data_size
+= sizeof(DWORD
);
4594 if (pen
->join
!= LineJoinMiter
)
4596 data_flags
|= PenDataJoin
;
4597 pen_data_size
+= sizeof(DWORD
);
4599 if (pen
->miterlimit
!= 10.0)
4601 data_flags
|= PenDataMiterLimit
;
4602 pen_data_size
+= sizeof(REAL
);
4604 if (pen
->style
!= GP_DEFAULT_PENSTYLE
)
4606 data_flags
|= PenDataLineStyle
;
4607 pen_data_size
+= sizeof(DWORD
);
4609 if (pen
->dashcap
!= DashCapFlat
)
4611 data_flags
|= PenDataDashedLineCap
;
4612 pen_data_size
+= sizeof(DWORD
);
4614 data_flags
|= PenDataDashedLineOffset
;
4615 pen_data_size
+= sizeof(REAL
);
4618 data_flags
|= PenDataDashedLine
;
4619 pen_data_size
+= sizeof(DWORD
) + pen
->numdashes
*sizeof(REAL
);
4621 if (pen
->align
!= PenAlignmentCenter
)
4623 data_flags
|= PenDataNonCenter
;
4624 pen_data_size
+= sizeof(DWORD
);
4626 /* TODO: Add support for PenDataCompoundLine */
4627 if (pen
->customstart
)
4629 FIXME("ignoring custom start cup\n");
4633 FIXME("ignoring custom end cup\n");
4636 stat
= METAFILE_PrepareBrushData(pen
->brush
, &brush_size
);
4637 if (stat
!= Ok
) return stat
;
4639 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
4640 FIELD_OFFSET(EmfPlusObject
, ObjectData
.pen
.data
) + pen_data_size
+ brush_size
,
4641 (void**)&object_record
);
4642 if (stat
!= Ok
) return stat
;
4644 *id
= METAFILE_AddObjectId(metafile
);
4645 object_record
->Header
.Flags
= *id
| ObjectTypePen
<< 8;
4646 object_record
->ObjectData
.pen
.Version
= VERSION_MAGIC2
;
4647 object_record
->ObjectData
.pen
.Type
= 0;
4649 pen_data
= (EmfPlusPenData
*)object_record
->ObjectData
.pen
.data
;
4650 pen_data
->PenDataFlags
= data_flags
;
4651 pen_data
->PenUnit
= pen
->unit
;
4652 pen_data
->PenWidth
= pen
->width
;
4655 if (data_flags
& PenDataTransform
)
4657 EmfPlusTransformMatrix
*m
= (EmfPlusTransformMatrix
*)(pen_data
->OptionalData
+ i
);
4658 memcpy(m
, &pen
->transform
, sizeof(*m
));
4659 i
+= sizeof(EmfPlusTransformMatrix
);
4661 if (data_flags
& PenDataStartCap
)
4663 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->startcap
;
4666 if (data_flags
& PenDataEndCap
)
4668 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->endcap
;
4671 if (data_flags
& PenDataJoin
)
4673 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->join
;
4676 if (data_flags
& PenDataMiterLimit
)
4678 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->miterlimit
;
4681 if (data_flags
& PenDataLineStyle
)
4683 switch (pen
->style
& PS_STYLE_MASK
)
4685 case PS_SOLID
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleSolid
; break;
4686 case PS_DASH
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDash
; break;
4687 case PS_DOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDot
; break;
4688 case PS_DASHDOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDashDot
; break;
4689 case PS_DASHDOTDOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDashDotDot
; break;
4690 default: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleCustom
; break;
4694 if (data_flags
& PenDataDashedLineCap
)
4696 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->dashcap
;
4699 if (data_flags
& PenDataDashedLineOffset
)
4701 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->offset
;
4704 if (data_flags
& PenDataDashedLine
)
4708 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->numdashes
;
4711 for (j
=0; j
<pen
->numdashes
; j
++)
4713 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->dashes
[j
];
4717 if (data_flags
& PenDataNonCenter
)
4719 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->align
;
4723 METAFILE_FillBrushData(pen
->brush
,
4724 (EmfPlusBrush
*)(object_record
->ObjectData
.pen
.data
+ pen_data_size
));
4728 GpStatus
METAFILE_DrawPath(GpMetafile
*metafile
, GpPen
*pen
, GpPath
*path
)
4730 EmfPlusDrawPath
*draw_path_record
;
4735 if (metafile
->metafile_type
== MetafileTypeEmf
)
4738 return NotImplemented
;
4741 stat
= METAFILE_AddPenObject(metafile
, pen
, &pen_id
);
4742 if (stat
!= Ok
) return stat
;
4744 stat
= METAFILE_AddPathObject(metafile
, path
, &path_id
);
4745 if (stat
!= Ok
) return stat
;
4747 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeDrawPath
,
4748 sizeof(EmfPlusDrawPath
), (void **)&draw_path_record
);
4749 if (stat
!= Ok
) return stat
;
4750 draw_path_record
->Header
.Type
= EmfPlusRecordTypeDrawPath
;
4751 draw_path_record
->Header
.Flags
= path_id
;
4752 draw_path_record
->PenId
= pen_id
;
4754 METAFILE_WriteRecords(metafile
);
4758 GpStatus
METAFILE_DrawEllipse(GpMetafile
*metafile
, GpPen
*pen
, GpRectF
*rect
)
4760 EmfPlusDrawEllipse
*record
;
4764 if (metafile
->metafile_type
== MetafileTypeEmf
)
4767 return NotImplemented
;
4770 stat
= METAFILE_AddPenObject(metafile
, pen
, &pen_id
);
4771 if (stat
!= Ok
) return stat
;
4773 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeDrawEllipse
,
4774 sizeof(EmfPlusDrawEllipse
), (void **)&record
);
4775 if (stat
!= Ok
) return stat
;
4776 record
->Header
.Type
= EmfPlusRecordTypeDrawEllipse
;
4777 record
->Header
.Flags
= pen_id
;
4778 if (is_integer_rect(rect
))
4780 record
->Header
.Flags
|= 0x4000;
4781 record
->RectData
.rect
.X
= (SHORT
)rect
->X
;
4782 record
->RectData
.rect
.Y
= (SHORT
)rect
->Y
;
4783 record
->RectData
.rect
.Width
= (SHORT
)rect
->Width
;
4784 record
->RectData
.rect
.Height
= (SHORT
)rect
->Height
;
4787 memcpy(&record
->RectData
.rectF
, rect
, sizeof(*rect
));
4789 METAFILE_WriteRecords(metafile
);
4793 GpStatus
METAFILE_FillPath(GpMetafile
*metafile
, GpBrush
*brush
, GpPath
*path
)
4795 EmfPlusFillPath
*fill_path_record
;
4796 DWORD brush_id
= -1, path_id
;
4800 if (metafile
->metafile_type
== MetafileTypeEmf
)
4803 return NotImplemented
;
4806 inline_color
= brush
->bt
== BrushTypeSolidColor
;
4809 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
4810 if (stat
!= Ok
) return stat
;
4813 stat
= METAFILE_AddPathObject(metafile
, path
, &path_id
);
4814 if (stat
!= Ok
) return stat
;
4816 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeFillPath
,
4817 sizeof(EmfPlusFillPath
), (void**)&fill_path_record
);
4818 if (stat
!= Ok
) return stat
;
4821 fill_path_record
->Header
.Flags
= 0x8000 | path_id
;
4822 fill_path_record
->data
.Color
= ((GpSolidFill
*)brush
)->color
;
4826 fill_path_record
->Header
.Flags
= path_id
;
4827 fill_path_record
->data
.BrushId
= brush_id
;
4830 METAFILE_WriteRecords(metafile
);
4834 GpStatus
METAFILE_FillEllipse(GpMetafile
*metafile
, GpBrush
*brush
, GpRectF
*rect
)
4836 EmfPlusFillEllipse
*record
;
4837 DWORD brush_id
= -1;
4841 if (metafile
->metafile_type
== MetafileTypeEmf
)
4844 return NotImplemented
;
4847 inline_color
= brush
->bt
== BrushTypeSolidColor
;
4850 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
4851 if (stat
!= Ok
) return stat
;
4854 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeFillEllipse
, sizeof(EmfPlusFillEllipse
), (void **)&record
);
4855 if (stat
!= Ok
) return stat
;
4858 record
->Header
.Flags
= 0x8000;
4859 record
->BrushId
= ((GpSolidFill
*)brush
)->color
;
4862 record
->BrushId
= brush_id
;
4864 if (is_integer_rect(rect
))
4866 record
->Header
.Flags
|= 0x4000;
4867 record
->RectData
.rect
.X
= (SHORT
)rect
->X
;
4868 record
->RectData
.rect
.Y
= (SHORT
)rect
->Y
;
4869 record
->RectData
.rect
.Width
= (SHORT
)rect
->Width
;
4870 record
->RectData
.rect
.Height
= (SHORT
)rect
->Height
;
4873 memcpy(&record
->RectData
.rectF
, rect
, sizeof(*rect
));
4875 METAFILE_WriteRecords(metafile
);
4879 GpStatus
METAFILE_FillPie(GpMetafile
*metafile
, GpBrush
*brush
, const GpRectF
*rect
,
4880 REAL startAngle
, REAL sweepAngle
)
4882 BOOL is_int_rect
, inline_color
;
4883 EmfPlusFillPie
*record
;
4884 DWORD brush_id
= -1;
4887 if (metafile
->metafile_type
== MetafileTypeEmf
)
4890 return NotImplemented
;
4893 inline_color
= brush
->bt
== BrushTypeSolidColor
;
4896 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
4897 if (stat
!= Ok
) return stat
;
4900 is_int_rect
= is_integer_rect(rect
);
4902 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeFillPie
,
4903 FIELD_OFFSET(EmfPlusFillPie
, RectData
) + is_int_rect
? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
),
4905 if (stat
!= Ok
) return stat
;
4908 record
->Header
.Flags
= 0x8000;
4909 record
->BrushId
= ((GpSolidFill
*)brush
)->color
;
4912 record
->BrushId
= brush_id
;
4914 record
->StartAngle
= startAngle
;
4915 record
->SweepAngle
= sweepAngle
;
4919 record
->Header
.Flags
|= 0x4000;
4920 record
->RectData
.rect
.X
= (SHORT
)rect
->X
;
4921 record
->RectData
.rect
.Y
= (SHORT
)rect
->Y
;
4922 record
->RectData
.rect
.Width
= (SHORT
)rect
->Width
;
4923 record
->RectData
.rect
.Height
= (SHORT
)rect
->Height
;
4926 memcpy(&record
->RectData
.rectF
, rect
, sizeof(*rect
));
4928 METAFILE_WriteRecords(metafile
);
4932 static GpStatus
METAFILE_AddFontObject(GpMetafile
*metafile
, GDIPCONST GpFont
*font
, DWORD
*id
)
4934 EmfPlusObject
*object_record
;
4935 EmfPlusFont
*font_record
;
4942 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&&
4943 metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4946 /* The following cast is ugly, but GdipGetFontStyle does treat
4947 its first parameter as const. */
4948 stat
= GdipGetFontStyle((GpFont
*)font
, &style
);
4952 fn_len
= lstrlenW(font
->family
->FamilyName
);
4953 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeObject
,
4954 FIELD_OFFSET(EmfPlusObject
, ObjectData
.font
.FamilyName
[(fn_len
+ 1) & ~1]),
4955 (void**)&object_record
);
4959 *id
= METAFILE_AddObjectId(metafile
);
4961 object_record
->Header
.Flags
= *id
| ObjectTypeFont
<< 8;
4963 font_record
= &object_record
->ObjectData
.font
;
4964 font_record
->Version
= VERSION_MAGIC2
;
4965 font_record
->EmSize
= font
->emSize
;
4966 font_record
->SizeUnit
= font
->unit
;
4967 font_record
->FontStyleFlags
= style
;
4968 font_record
->Reserved
= 0;
4969 font_record
->Length
= fn_len
;
4971 memcpy(font_record
->FamilyName
, font
->family
->FamilyName
,
4972 fn_len
* sizeof(*font
->family
->FamilyName
));
4977 GpStatus
METAFILE_DrawDriverString(GpMetafile
*metafile
, GDIPCONST UINT16
*text
, INT length
,
4978 GDIPCONST GpFont
*font
, GDIPCONST GpStringFormat
*format
, GDIPCONST GpBrush
*brush
,
4979 GDIPCONST PointF
*positions
, INT flags
, GDIPCONST GpMatrix
*matrix
)
4985 EmfPlusDrawDriverString
*draw_string_record
;
4988 BOOL include_matrix
= FALSE
;
4991 return InvalidParameter
;
4993 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&&
4994 metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4996 FIXME("metafile type not supported: %i\n", metafile
->metafile_type
);
4997 return NotImplemented
;
5000 stat
= METAFILE_AddFontObject(metafile
, font
, &font_id
);
5004 inline_color
= (brush
->bt
== BrushTypeSolidColor
);
5007 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
5016 stat
= GdipIsMatrixIdentity(matrix
, &identity
);
5020 include_matrix
= !identity
;
5023 alloc_size
= FIELD_OFFSET(EmfPlusDrawDriverString
, VariableData
) +
5024 length
* (sizeof(*text
) + sizeof(*positions
));
5027 alloc_size
+= sizeof(*matrix
);
5029 /* Pad record to DWORD alignment. */
5030 alloc_size
= (alloc_size
+ 3) & ~3;
5032 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeDrawDriverString
, alloc_size
, (void**)&draw_string_record
);
5036 draw_string_record
->Header
.Flags
= font_id
;
5037 draw_string_record
->DriverStringOptionsFlags
= flags
;
5038 draw_string_record
->MatrixPresent
= include_matrix
;
5039 draw_string_record
->GlyphCount
= length
;
5043 draw_string_record
->Header
.Flags
|= 0x8000;
5044 draw_string_record
->brush
.Color
= ((GpSolidFill
*)brush
)->color
;
5047 draw_string_record
->brush
.BrushId
= brush_id
;
5049 cursor
= &draw_string_record
->VariableData
[0];
5051 memcpy(cursor
, text
, length
* sizeof(*text
));
5052 cursor
+= length
* sizeof(*text
);
5054 if (flags
& DriverStringOptionsRealizedAdvance
)
5056 static BOOL fixme_written
= FALSE
;
5058 /* Native never writes DriverStringOptionsRealizedAdvance. Instead,
5059 in the case of RealizedAdvance, each glyph position is computed
5062 While native GDI+ is capable of playing back metafiles with this
5063 flag set, it is possible that some application might rely on
5064 metafiles produced from GDI+ not setting this flag. Ideally we
5065 would also compute the position of each glyph here, serialize those
5066 values, and not set DriverStringOptionsRealizedAdvance. */
5069 fixme_written
= TRUE
;
5070 FIXME("serializing RealizedAdvance flag and single GlyphPos with padding\n");
5073 *((PointF
*)cursor
) = *positions
;
5076 memcpy(cursor
, positions
, length
* sizeof(*positions
));
5080 cursor
+= length
* sizeof(*positions
);
5081 memcpy(cursor
, matrix
, sizeof(*matrix
));
5084 METAFILE_WriteRecords(metafile
);
5089 GpStatus
METAFILE_FillRegion(GpMetafile
* metafile
, GpBrush
* brush
, GpRegion
* region
)
5094 EmfPlusFillRegion
*fill_region_record
;
5097 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&&
5098 metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
5100 FIXME("metafile type not supported: %i\n", metafile
->metafile_type
);
5101 return NotImplemented
;
5104 inline_color
= (brush
->bt
== BrushTypeSolidColor
);
5107 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
5112 stat
= METAFILE_AddRegionObject(metafile
, region
, ®ion_id
);
5116 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeFillRegion
, sizeof(EmfPlusFillRegion
),
5117 (void**)&fill_region_record
);
5121 fill_region_record
->Header
.Flags
= region_id
;
5125 fill_region_record
->Header
.Flags
|= 0x8000;
5126 fill_region_record
->data
.Color
= ((GpSolidFill
*)brush
)->color
;
5129 fill_region_record
->data
.BrushId
= brush_id
;
5131 METAFILE_WriteRecords(metafile
);
5136 GpStatus
METAFILE_DrawRectangles(GpMetafile
*metafile
, GpPen
*pen
, const GpRectF
*rects
, INT count
)
5138 EmfPlusDrawRects
*record
;
5140 BOOL integer_rects
= TRUE
;
5144 if (metafile
->metafile_type
== MetafileTypeEmf
)
5147 return NotImplemented
;
5150 stat
= METAFILE_AddPenObject(metafile
, pen
, &pen_id
);
5151 if (stat
!= Ok
) return stat
;
5153 for (i
= 0; i
< count
; i
++)
5155 if (!is_integer_rect(&rects
[i
]))
5157 integer_rects
= FALSE
;
5162 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeDrawRects
, FIELD_OFFSET(EmfPlusDrawRects
, RectData
) +
5163 count
* (integer_rects
? sizeof(record
->RectData
.rect
) : sizeof(record
->RectData
.rectF
)),
5168 record
->Header
.Flags
= pen_id
;
5170 record
->Header
.Flags
|= 0x4000;
5171 record
->Count
= count
;
5175 for (i
= 0; i
< count
; i
++)
5177 record
->RectData
.rect
[i
].X
= (SHORT
)rects
[i
].X
;
5178 record
->RectData
.rect
[i
].Y
= (SHORT
)rects
[i
].Y
;
5179 record
->RectData
.rect
[i
].Width
= (SHORT
)rects
[i
].Width
;
5180 record
->RectData
.rect
[i
].Height
= (SHORT
)rects
[i
].Height
;
5184 memcpy(record
->RectData
.rectF
, rects
, sizeof(*rects
) * count
);
5186 METAFILE_WriteRecords(metafile
);
5191 GpStatus
METAFILE_DrawArc(GpMetafile
*metafile
, GpPen
*pen
, const GpRectF
*rect
, REAL startAngle
, REAL sweepAngle
)
5193 EmfPlusDrawArc
*record
;
5198 if (metafile
->metafile_type
== MetafileTypeEmf
)
5201 return NotImplemented
;
5204 stat
= METAFILE_AddPenObject(metafile
, pen
, &pen_id
);
5205 if (stat
!= Ok
) return stat
;
5207 integer_rect
= is_integer_rect(rect
);
5209 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeDrawArc
, FIELD_OFFSET(EmfPlusDrawArc
, RectData
) +
5210 integer_rect
? sizeof(record
->RectData
.rect
) : sizeof(record
->RectData
.rectF
),
5215 record
->Header
.Flags
= pen_id
;
5217 record
->Header
.Flags
|= 0x4000;
5218 record
->StartAngle
= startAngle
;
5219 record
->SweepAngle
= sweepAngle
;
5223 record
->RectData
.rect
.X
= (SHORT
)rect
->X
;
5224 record
->RectData
.rect
.Y
= (SHORT
)rect
->Y
;
5225 record
->RectData
.rect
.Width
= (SHORT
)rect
->Width
;
5226 record
->RectData
.rect
.Height
= (SHORT
)rect
->Height
;
5229 memcpy(&record
->RectData
.rectF
, rect
, sizeof(*rect
));
5231 METAFILE_WriteRecords(metafile
);
5236 GpStatus
METAFILE_OffsetClip(GpMetafile
*metafile
, REAL dx
, REAL dy
)
5238 EmfPlusOffsetClip
*record
;
5241 if (metafile
->metafile_type
== MetafileTypeEmf
)
5244 return NotImplemented
;
5247 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeOffsetClip
,
5248 sizeof(*record
), (void **)&record
);
5255 METAFILE_WriteRecords(metafile
);
5260 GpStatus
METAFILE_ResetClip(GpMetafile
*metafile
)
5262 EmfPlusRecordHeader
*record
;
5265 if (metafile
->metafile_type
== MetafileTypeEmf
)
5268 return NotImplemented
;
5271 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeResetClip
,
5272 sizeof(*record
), (void **)&record
);
5276 METAFILE_WriteRecords(metafile
);
5281 GpStatus
METAFILE_SetClipPath(GpMetafile
*metafile
, GpPath
*path
, CombineMode mode
)
5283 EmfPlusRecordHeader
*record
;
5287 if (metafile
->metafile_type
== MetafileTypeEmf
)
5290 return NotImplemented
;
5293 stat
= METAFILE_AddPathObject(metafile
, path
, &path_id
);
5294 if (stat
!= Ok
) return stat
;
5296 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSetClipPath
,
5297 sizeof(*record
), (void **)&record
);
5301 record
->Flags
= ((mode
& 0xf) << 8) | path_id
;
5303 METAFILE_WriteRecords(metafile
);
5308 GpStatus
METAFILE_SetRenderingOrigin(GpMetafile
*metafile
, INT x
, INT y
)
5310 EmfPlusSetRenderingOrigin
*record
;
5313 if (metafile
->metafile_type
== MetafileTypeEmf
)
5316 return NotImplemented
;
5319 stat
= METAFILE_AllocateRecord(metafile
, EmfPlusRecordTypeSetRenderingOrigin
,
5320 sizeof(*record
), (void **)&record
);
5327 METAFILE_WriteRecords(metafile
);