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
28 #include "wine/unicode.h"
40 #include "gdiplus_private.h"
41 #include "wine/debug.h"
42 #include "wine/list.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus
);
46 HRESULT WINAPI
WICCreateImagingFactory_Proxy(UINT
, IWICImagingFactory
**);
48 typedef ARGB EmfPlusARGB
;
50 typedef struct EmfPlusRecordHeader
56 } EmfPlusRecordHeader
;
58 typedef struct EmfPlusHeader
60 EmfPlusRecordHeader Header
;
67 typedef struct EmfPlusClear
69 EmfPlusRecordHeader Header
;
73 typedef struct EmfPlusFillRects
75 EmfPlusRecordHeader Header
;
80 typedef struct EmfPlusSetClipRect
82 EmfPlusRecordHeader Header
;
86 typedef struct EmfPlusSetPageTransform
88 EmfPlusRecordHeader Header
;
90 } EmfPlusSetPageTransform
;
92 typedef struct EmfPlusRect
100 typedef struct EmfPlusSetWorldTransform
102 EmfPlusRecordHeader Header
;
104 } EmfPlusSetWorldTransform
;
106 typedef struct EmfPlusScaleWorldTransform
108 EmfPlusRecordHeader Header
;
111 } EmfPlusScaleWorldTransform
;
113 typedef struct EmfPlusMultiplyWorldTransform
115 EmfPlusRecordHeader Header
;
117 } EmfPlusMultiplyWorldTransform
;
119 typedef struct EmfPlusRotateWorldTransform
121 EmfPlusRecordHeader Header
;
123 } EmfPlusRotateWorldTransform
;
125 typedef struct EmfPlusTranslateWorldTransform
127 EmfPlusRecordHeader Header
;
130 } EmfPlusTranslateWorldTransform
;
132 typedef struct EmfPlusBeginContainer
134 EmfPlusRecordHeader Header
;
138 } EmfPlusBeginContainer
;
140 typedef struct EmfPlusContainerRecord
142 EmfPlusRecordHeader Header
;
144 } EmfPlusContainerRecord
;
152 typedef struct container
156 enum container_type type
;
157 GraphicsContainer state
;
158 GpMatrix world_transform
;
166 PenDataTransform
= 0x0001,
167 PenDataStartCap
= 0x0002,
168 PenDataEndCap
= 0x0004,
169 PenDataJoin
= 0x0008,
170 PenDataMiterLimit
= 0x0010,
171 PenDataLineStyle
= 0x0020,
172 PenDataDashedLineCap
= 0x0040,
173 PenDataDashedLineOffset
= 0x0080,
174 PenDataDashedLine
= 0x0100,
175 PenDataNonCenter
= 0x0200,
176 PenDataCompoundLine
= 0x0400,
177 PenDataCustomStartCap
= 0x0800,
178 PenDataCustomEndCap
= 0x1000
181 typedef struct EmfPlusTransformMatrix
183 REAL TransformMatrix
[6];
184 } EmfPlusTransformMatrix
;
196 typedef struct EmfPlusDashedLineData
198 DWORD DashedLineDataSize
;
200 } EmfPlusDashedLineData
;
202 typedef struct EmfPlusCompoundLineData
204 DWORD CompoundLineDataSize
;
206 } EmfPlusCompoundLineData
;
208 typedef struct EmfPlusCustomStartCapData
210 DWORD CustomStartCapSize
;
212 } EmfPlusCustomStartCapData
;
214 typedef struct EmfPlusCustomEndCapData
216 DWORD CustomEndCapSize
;
218 } EmfPlusCustomEndCapData
;
220 typedef struct EmfPlusPenData
225 BYTE OptionalData
[1];
230 BrushDataPath
= 1 << 0,
231 BrushDataTransform
= 1 << 1,
232 BrushDataPresetColors
= 1 << 2,
233 BrushDataBlendFactorsH
= 1 << 3,
234 BrushDataBlendFactorsV
= 1 << 4,
235 BrushDataFocusScales
= 1 << 6,
236 BrushDataIsGammaCorrected
= 1 << 7,
237 BrushDataDoNotTransform
= 1 << 8,
240 typedef struct EmfPlusSolidBrushData
242 EmfPlusARGB SolidColor
;
243 } EmfPlusSolidBrushData
;
245 typedef struct EmfPlusHatchBrushData
248 EmfPlusARGB ForeColor
;
249 EmfPlusARGB BackColor
;
250 } EmfPlusHatchBrushData
;
252 typedef struct EmfPlusTextureBrushData
254 DWORD BrushDataFlags
;
256 BYTE OptionalData
[1];
257 } EmfPlusTextureBrushData
;
259 typedef struct EmfPlusRectF
267 typedef struct EmfPlusLinearGradientBrushData
269 DWORD BrushDataFlags
;
272 EmfPlusARGB StartColor
;
273 EmfPlusARGB EndColor
;
276 BYTE OptionalData
[1];
277 } EmfPlusLinearGradientBrushData
;
279 typedef struct EmfPlusBrush
284 EmfPlusSolidBrushData solid
;
285 EmfPlusHatchBrushData hatch
;
286 EmfPlusTextureBrushData texture
;
287 EmfPlusLinearGradientBrushData lineargradient
;
291 typedef struct EmfPlusPen
300 typedef struct EmfPlusPath
303 DWORD PathPointCount
;
304 DWORD PathPointFlags
;
306 /* PathPointTypes[] */
307 /* AlignmentPadding */
311 typedef struct EmfPlusRegionNodePath
313 DWORD RegionNodePathLength
;
314 EmfPlusPath RegionNodePath
;
315 } EmfPlusRegionNodePath
;
317 typedef struct EmfPlusRegion
320 DWORD RegionNodeCount
;
324 typedef struct EmfPlusPalette
326 DWORD PaletteStyleFlags
;
328 BYTE PaletteEntries
[1];
334 BitmapDataTypeCompressed
,
337 typedef struct EmfPlusBitmap
347 typedef struct EmfPlusMetafile
350 DWORD MetafileDataSize
;
351 BYTE MetafileData
[1];
354 typedef enum ImageDataType
356 ImageDataTypeUnknown
,
358 ImageDataTypeMetafile
,
361 typedef struct EmfPlusImage
367 EmfPlusBitmap bitmap
;
368 EmfPlusMetafile metafile
;
372 typedef struct EmfPlusImageAttributes
377 EmfPlusARGB ClampColor
;
380 } EmfPlusImageAttributes
;
382 typedef struct EmfPlusObject
384 EmfPlusRecordHeader Header
;
390 EmfPlusRegion region
;
392 EmfPlusImageAttributes image_attributes
;
396 typedef struct EmfPlusPointR7
402 typedef struct EmfPlusPoint
408 typedef struct EmfPlusPointF
414 typedef struct EmfPlusDrawImage
416 EmfPlusRecordHeader Header
;
417 DWORD ImageAttributesID
;
419 EmfPlusRectF SrcRect
;
427 typedef struct EmfPlusDrawImagePoints
429 EmfPlusRecordHeader Header
;
430 DWORD ImageAttributesID
;
432 EmfPlusRectF SrcRect
;
436 EmfPlusPointR7 pointsR
[3];
437 EmfPlusPoint points
[3];
438 EmfPlusPointF pointsF
[3];
440 } EmfPlusDrawImagePoints
;
442 typedef struct EmfPlusDrawPath
444 EmfPlusRecordHeader Header
;
448 typedef struct EmfPlusDrawArc
450 EmfPlusRecordHeader Header
;
460 typedef struct EmfPlusDrawEllipse
462 EmfPlusRecordHeader Header
;
468 } EmfPlusDrawEllipse
;
470 typedef struct EmfPlusDrawPie
472 EmfPlusRecordHeader Header
;
482 typedef struct EmfPlusDrawRects
484 EmfPlusRecordHeader Header
;
489 EmfPlusRectF rectF
[1];
493 typedef struct EmfPlusFillPath
495 EmfPlusRecordHeader Header
;
503 typedef struct EmfPlusFillClosedCurve
505 EmfPlusRecordHeader Header
;
511 EmfPlusPointR7 pointsR
[1];
512 EmfPlusPoint points
[1];
513 EmfPlusPointF pointsF
[1];
515 } EmfPlusFillClosedCurve
;
517 typedef struct EmfPlusFillEllipse
519 EmfPlusRecordHeader Header
;
526 } EmfPlusFillEllipse
;
528 typedef struct EmfPlusFillPie
530 EmfPlusRecordHeader Header
;
541 typedef struct EmfPlusFont
546 DWORD FontStyleFlags
;
552 static void metafile_free_object_table_entry(GpMetafile
*metafile
, BYTE id
)
554 struct emfplus_object
*object
= &metafile
->objtable
[id
];
556 switch (object
->type
)
558 case ObjectTypeInvalid
:
560 case ObjectTypeBrush
:
561 GdipDeleteBrush(object
->u
.brush
);
564 GdipDeletePen(object
->u
.pen
);
567 GdipDeletePath(object
->u
.path
);
569 case ObjectTypeRegion
:
570 GdipDeleteRegion(object
->u
.region
);
572 case ObjectTypeImage
:
573 GdipDisposeImage(object
->u
.image
);
576 GdipDeleteFont(object
->u
.font
);
578 case ObjectTypeImageAttributes
:
579 GdipDisposeImageAttributes(object
->u
.image_attributes
);
582 FIXME("not implemented for object type %u.\n", object
->type
);
586 object
->type
= ObjectTypeInvalid
;
587 object
->u
.object
= NULL
;
590 void METAFILE_Free(GpMetafile
*metafile
)
594 heap_free(metafile
->comment_data
);
595 DeleteEnhMetaFile(CloseEnhMetaFile(metafile
->record_dc
));
596 if (!metafile
->preserve_hemf
)
597 DeleteEnhMetaFile(metafile
->hemf
);
598 if (metafile
->record_graphics
)
600 WARN("metafile closed while recording\n");
601 /* not sure what to do here; for now just prevent the graphics from functioning or using this object */
602 metafile
->record_graphics
->image
= NULL
;
603 metafile
->record_graphics
->busy
= TRUE
;
606 if (metafile
->record_stream
)
607 IStream_Release(metafile
->record_stream
);
609 for (i
= 0; i
< ARRAY_SIZE(metafile
->objtable
); i
++)
610 metafile_free_object_table_entry(metafile
, i
);
613 static DWORD
METAFILE_AddObjectId(GpMetafile
*metafile
)
615 return (metafile
->next_object_id
++) % EmfPlusObjectTableSize
;
618 static GpStatus
METAFILE_AllocateRecord(GpMetafile
*metafile
, DWORD size
, void **result
)
621 EmfPlusRecordHeader
*record
;
623 if (!metafile
->comment_data_size
)
625 DWORD data_size
= max(256, size
* 2 + 4);
626 metafile
->comment_data
= heap_alloc_zero(data_size
);
628 if (!metafile
->comment_data
)
631 memcpy(metafile
->comment_data
, "EMF+", 4);
633 metafile
->comment_data_size
= data_size
;
634 metafile
->comment_data_length
= 4;
637 size_needed
= size
+ metafile
->comment_data_length
;
639 if (size_needed
> metafile
->comment_data_size
)
641 DWORD data_size
= size_needed
* 2;
642 BYTE
*new_data
= heap_alloc_zero(data_size
);
647 memcpy(new_data
, metafile
->comment_data
, metafile
->comment_data_length
);
649 metafile
->comment_data_size
= data_size
;
650 heap_free(metafile
->comment_data
);
651 metafile
->comment_data
= new_data
;
654 *result
= metafile
->comment_data
+ metafile
->comment_data_length
;
655 metafile
->comment_data_length
+= size
;
657 record
= (EmfPlusRecordHeader
*)*result
;
659 record
->DataSize
= size
- sizeof(EmfPlusRecordHeader
);
664 static void METAFILE_RemoveLastRecord(GpMetafile
*metafile
, EmfPlusRecordHeader
*record
)
666 assert(metafile
->comment_data
+ metafile
->comment_data_length
== (BYTE
*)record
+ record
->Size
);
667 metafile
->comment_data_length
-= record
->Size
;
670 static void METAFILE_WriteRecords(GpMetafile
*metafile
)
672 if (metafile
->comment_data_length
> 4)
674 GdiComment(metafile
->record_dc
, metafile
->comment_data_length
, metafile
->comment_data
);
675 metafile
->comment_data_length
= 4;
679 static GpStatus
METAFILE_WriteHeader(GpMetafile
*metafile
, HDC hdc
)
683 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
685 EmfPlusHeader
*header
;
687 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusHeader
), (void**)&header
);
691 header
->Header
.Type
= EmfPlusRecordTypeHeader
;
693 if (metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
694 header
->Header
.Flags
= 1;
696 header
->Header
.Flags
= 0;
698 header
->Version
= VERSION_MAGIC2
;
700 if (GetDeviceCaps(hdc
, TECHNOLOGY
) == DT_RASDISPLAY
)
701 header
->EmfPlusFlags
= 1;
703 header
->EmfPlusFlags
= 0;
705 header
->LogicalDpiX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
706 header
->LogicalDpiY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
708 METAFILE_WriteRecords(metafile
);
714 static GpStatus
METAFILE_WriteEndOfFile(GpMetafile
*metafile
)
718 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
720 EmfPlusRecordHeader
*record
;
722 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
726 record
->Type
= EmfPlusRecordTypeEndOfFile
;
729 METAFILE_WriteRecords(metafile
);
735 GpStatus WINGDIPAPI
GdipRecordMetafile(HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
736 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
740 REAL framerect_factor_x
, framerect_factor_y
;
744 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
746 if (!hdc
|| type
< EmfTypeEmfOnly
|| type
> EmfTypeEmfPlusDual
|| !metafile
)
747 return InvalidParameter
;
749 dpix
= (REAL
)GetDeviceCaps(hdc
, HORZRES
) / GetDeviceCaps(hdc
, HORZSIZE
) * 25.4;
750 dpiy
= (REAL
)GetDeviceCaps(hdc
, VERTRES
) / GetDeviceCaps(hdc
, VERTSIZE
) * 25.4;
756 case MetafileFrameUnitPixel
:
757 framerect_factor_x
= 2540.0 / dpix
;
758 framerect_factor_y
= 2540.0 / dpiy
;
760 case MetafileFrameUnitPoint
:
761 framerect_factor_x
= framerect_factor_y
= 2540.0 / 72.0;
763 case MetafileFrameUnitInch
:
764 framerect_factor_x
= framerect_factor_y
= 2540.0;
766 case MetafileFrameUnitDocument
:
767 framerect_factor_x
= framerect_factor_y
= 2540.0 / 300.0;
769 case MetafileFrameUnitMillimeter
:
770 framerect_factor_x
= framerect_factor_y
= 100.0;
772 case MetafileFrameUnitGdi
:
773 framerect_factor_x
= framerect_factor_y
= 1.0;
776 return InvalidParameter
;
779 rc
.left
= framerect_factor_x
* frameRect
->X
;
780 rc
.top
= framerect_factor_y
* frameRect
->Y
;
781 rc
.right
= rc
.left
+ framerect_factor_x
* frameRect
->Width
;
782 rc
.bottom
= rc
.top
+ framerect_factor_y
* frameRect
->Height
;
789 record_dc
= CreateEnhMetaFileW(hdc
, NULL
, lprc
, desc
);
794 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
797 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
801 (*metafile
)->image
.type
= ImageTypeMetafile
;
802 (*metafile
)->image
.flags
= ImageFlagsNone
;
803 (*metafile
)->image
.palette
= NULL
;
804 (*metafile
)->image
.xres
= dpix
;
805 (*metafile
)->image
.yres
= dpiy
;
806 (*metafile
)->bounds
.X
= (*metafile
)->bounds
.Y
= 0.0;
807 (*metafile
)->bounds
.Width
= (*metafile
)->bounds
.Height
= 1.0;
808 (*metafile
)->unit
= UnitPixel
;
809 (*metafile
)->metafile_type
= type
;
810 (*metafile
)->record_dc
= record_dc
;
811 (*metafile
)->comment_data
= NULL
;
812 (*metafile
)->comment_data_size
= 0;
813 (*metafile
)->comment_data_length
= 0;
814 (*metafile
)->hemf
= NULL
;
815 list_init(&(*metafile
)->containers
);
819 (*metafile
)->auto_frame
= TRUE
;
820 (*metafile
)->auto_frame_min
.X
= 0;
821 (*metafile
)->auto_frame_min
.Y
= 0;
822 (*metafile
)->auto_frame_max
.X
= -1;
823 (*metafile
)->auto_frame_max
.Y
= -1;
826 stat
= METAFILE_WriteHeader(*metafile
, hdc
);
830 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
831 heap_free(*metafile
);
839 /*****************************************************************************
840 * GdipRecordMetafileI [GDIPLUS.@]
842 GpStatus WINGDIPAPI
GdipRecordMetafileI(HDC hdc
, EmfType type
, GDIPCONST GpRect
*frameRect
,
843 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
845 GpRectF frameRectF
, *pFrameRectF
;
847 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
851 frameRectF
.X
= frameRect
->X
;
852 frameRectF
.Y
= frameRect
->Y
;
853 frameRectF
.Width
= frameRect
->Width
;
854 frameRectF
.Height
= frameRect
->Height
;
855 pFrameRectF
= &frameRectF
;
860 return GdipRecordMetafile(hdc
, type
, pFrameRectF
, frameUnit
, desc
, metafile
);
863 GpStatus WINGDIPAPI
GdipRecordMetafileStream(IStream
*stream
, HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
864 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
868 TRACE("(%p %p %d %p %d %p %p)\n", stream
, hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
871 return InvalidParameter
;
873 stat
= GdipRecordMetafile(hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
877 (*metafile
)->record_stream
= stream
;
878 IStream_AddRef(stream
);
884 static void METAFILE_AdjustFrame(GpMetafile
* metafile
, const GpPointF
*points
,
889 if (!metafile
->auto_frame
|| !num_points
)
892 if (metafile
->auto_frame_max
.X
< metafile
->auto_frame_min
.X
)
893 metafile
->auto_frame_max
= metafile
->auto_frame_min
= points
[0];
895 for (i
=0; i
<num_points
; i
++)
897 if (points
[i
].X
< metafile
->auto_frame_min
.X
)
898 metafile
->auto_frame_min
.X
= points
[i
].X
;
899 if (points
[i
].X
> metafile
->auto_frame_max
.X
)
900 metafile
->auto_frame_max
.X
= points
[i
].X
;
901 if (points
[i
].Y
< metafile
->auto_frame_min
.Y
)
902 metafile
->auto_frame_min
.Y
= points
[i
].Y
;
903 if (points
[i
].Y
> metafile
->auto_frame_max
.Y
)
904 metafile
->auto_frame_max
.Y
= points
[i
].Y
;
908 GpStatus
METAFILE_GetGraphicsContext(GpMetafile
* metafile
, GpGraphics
**result
)
912 if (!metafile
->record_dc
|| metafile
->record_graphics
)
913 return InvalidParameter
;
915 stat
= graphics_from_image((GpImage
*)metafile
, &metafile
->record_graphics
);
919 *result
= metafile
->record_graphics
;
920 metafile
->record_graphics
->xres
= 96.0;
921 metafile
->record_graphics
->yres
= 96.0;
927 GpStatus
METAFILE_GetDC(GpMetafile
* metafile
, HDC
*hdc
)
929 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
931 EmfPlusRecordHeader
*record
;
934 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
938 record
->Type
= EmfPlusRecordTypeGetDC
;
941 METAFILE_WriteRecords(metafile
);
944 *hdc
= metafile
->record_dc
;
949 GpStatus
METAFILE_GraphicsClear(GpMetafile
* metafile
, ARGB color
)
951 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
953 EmfPlusClear
*record
;
956 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusClear
), (void**)&record
);
960 record
->Header
.Type
= EmfPlusRecordTypeClear
;
961 record
->Header
.Flags
= 0;
962 record
->Color
= color
;
964 METAFILE_WriteRecords(metafile
);
970 static BOOL
is_integer_rect(const GpRectF
*rect
)
972 SHORT x
, y
, width
, height
;
976 height
= rect
->Height
;
977 if (rect
->X
!= (REAL
)x
|| rect
->Y
!= (REAL
)y
||
978 rect
->Width
!= (REAL
)width
|| rect
->Height
!= (REAL
)height
)
983 static GpStatus
METAFILE_PrepareBrushData(GpBrush
*brush
, DWORD
*size
)
987 case BrushTypeSolidColor
:
988 *size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
) + sizeof(EmfPlusSolidBrushData
);
990 case BrushTypeHatchFill
:
991 *size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
) + sizeof(EmfPlusHatchBrushData
);
994 FIXME("unsupported brush type: %d\n", brush
->bt
);
995 return NotImplemented
;
1001 static void METAFILE_FillBrushData(GpBrush
*brush
, EmfPlusBrush
*data
)
1003 data
->Version
= VERSION_MAGIC2
;
1004 data
->Type
= brush
->bt
;
1008 case BrushTypeSolidColor
:
1010 GpSolidFill
*solid
= (GpSolidFill
*)brush
;
1011 data
->BrushData
.solid
.SolidColor
= solid
->color
;
1014 case BrushTypeHatchFill
:
1016 GpHatch
*hatch
= (GpHatch
*)brush
;
1017 data
->BrushData
.hatch
.HatchStyle
= hatch
->hatchstyle
;
1018 data
->BrushData
.hatch
.ForeColor
= hatch
->forecol
;
1019 data
->BrushData
.hatch
.BackColor
= hatch
->backcol
;
1023 FIXME("unsupported brush type: %d\n", brush
->bt
);
1027 static GpStatus
METAFILE_AddBrushObject(GpMetafile
*metafile
, GpBrush
*brush
, DWORD
*id
)
1029 EmfPlusObject
*object_record
;
1034 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
1037 stat
= METAFILE_PrepareBrushData(brush
, &size
);
1038 if (stat
!= Ok
) return stat
;
1040 stat
= METAFILE_AllocateRecord(metafile
,
1041 FIELD_OFFSET(EmfPlusObject
, ObjectData
) + size
, (void**)&object_record
);
1042 if (stat
!= Ok
) return stat
;
1044 *id
= METAFILE_AddObjectId(metafile
);
1045 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
1046 object_record
->Header
.Flags
= *id
| ObjectTypeBrush
<< 8;
1047 METAFILE_FillBrushData(brush
, &object_record
->ObjectData
.brush
);
1051 GpStatus
METAFILE_FillRectangles(GpMetafile
* metafile
, GpBrush
* brush
,
1052 GDIPCONST GpRectF
* rects
, INT count
)
1054 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1056 EmfPlusFillRects
*record
;
1058 BOOL integer_rects
= TRUE
;
1063 if (brush
->bt
== BrushTypeSolidColor
)
1066 brushid
= ((GpSolidFill
*)brush
)->color
;
1070 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brushid
);
1075 for (i
=0; i
<count
; i
++)
1077 if (!is_integer_rect(&rects
[i
]))
1079 integer_rects
= FALSE
;
1087 stat
= METAFILE_AllocateRecord(metafile
,
1088 sizeof(EmfPlusFillRects
) + count
* (integer_rects
? sizeof(EmfPlusRect
) : sizeof(GpRectF
)),
1093 record
->Header
.Type
= EmfPlusRecordTypeFillRects
;
1094 record
->Header
.Flags
= flags
;
1095 record
->BrushID
= brushid
;
1096 record
->Count
= count
;
1100 EmfPlusRect
*record_rects
= (EmfPlusRect
*)(record
+1);
1101 for (i
=0; i
<count
; i
++)
1103 record_rects
[i
].X
= (SHORT
)rects
[i
].X
;
1104 record_rects
[i
].Y
= (SHORT
)rects
[i
].Y
;
1105 record_rects
[i
].Width
= (SHORT
)rects
[i
].Width
;
1106 record_rects
[i
].Height
= (SHORT
)rects
[i
].Height
;
1110 memcpy(record
+1, rects
, sizeof(GpRectF
) * count
);
1112 METAFILE_WriteRecords(metafile
);
1115 if (metafile
->auto_frame
)
1117 GpPointF corners
[4];
1120 for (i
=0; i
<count
; i
++)
1122 corners
[0].X
= rects
[i
].X
;
1123 corners
[0].Y
= rects
[i
].Y
;
1124 corners
[1].X
= rects
[i
].X
+ rects
[i
].Width
;
1125 corners
[1].Y
= rects
[i
].Y
;
1126 corners
[2].X
= rects
[i
].X
;
1127 corners
[2].Y
= rects
[i
].Y
+ rects
[i
].Height
;
1128 corners
[3].X
= rects
[i
].X
+ rects
[i
].Width
;
1129 corners
[3].Y
= rects
[i
].Y
+ rects
[i
].Height
;
1131 GdipTransformPoints(metafile
->record_graphics
, CoordinateSpaceDevice
,
1132 CoordinateSpaceWorld
, corners
, 4);
1134 METAFILE_AdjustFrame(metafile
, corners
, 4);
1141 GpStatus
METAFILE_SetClipRect(GpMetafile
* metafile
, REAL x
, REAL y
, REAL width
, REAL height
, CombineMode mode
)
1143 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1145 EmfPlusSetClipRect
*record
;
1148 stat
= METAFILE_AllocateRecord(metafile
,
1149 sizeof(EmfPlusSetClipRect
),
1154 record
->Header
.Type
= EmfPlusRecordTypeSetClipRect
;
1155 record
->Header
.Flags
= (mode
& 0xf) << 8;
1156 record
->ClipRect
.X
= x
;
1157 record
->ClipRect
.Y
= y
;
1158 record
->ClipRect
.Width
= width
;
1159 record
->ClipRect
.Height
= height
;
1161 METAFILE_WriteRecords(metafile
);
1167 static GpStatus
METAFILE_AddRegionObject(GpMetafile
*metafile
, GpRegion
*region
, DWORD
*id
)
1169 EmfPlusObject
*object_record
;
1174 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
1177 size
= write_region_data(region
, NULL
);
1178 stat
= METAFILE_AllocateRecord(metafile
,
1179 FIELD_OFFSET(EmfPlusObject
, ObjectData
.region
) + size
, (void**)&object_record
);
1180 if (stat
!= Ok
) return stat
;
1182 *id
= METAFILE_AddObjectId(metafile
);
1183 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
1184 object_record
->Header
.Flags
= *id
| ObjectTypeRegion
<< 8;
1185 write_region_data(region
, &object_record
->ObjectData
.region
);
1189 GpStatus
METAFILE_SetClipRegion(GpMetafile
* metafile
, GpRegion
* region
, CombineMode mode
)
1191 EmfPlusRecordHeader
*record
;
1195 if (metafile
->metafile_type
== MetafileTypeEmf
)
1198 return NotImplemented
;
1201 stat
= METAFILE_AddRegionObject(metafile
, region
, ®ion_id
);
1202 if (stat
!= Ok
) return stat
;
1204 stat
= METAFILE_AllocateRecord(metafile
, sizeof(*record
), (void**)&record
);
1205 if (stat
!= Ok
) return stat
;
1207 record
->Type
= EmfPlusRecordTypeSetClipRegion
;
1208 record
->Flags
= region_id
| mode
<< 8;
1210 METAFILE_WriteRecords(metafile
);
1214 GpStatus
METAFILE_SetPageTransform(GpMetafile
* metafile
, GpUnit unit
, REAL scale
)
1216 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1218 EmfPlusSetPageTransform
*record
;
1221 stat
= METAFILE_AllocateRecord(metafile
,
1222 sizeof(EmfPlusSetPageTransform
),
1227 record
->Header
.Type
= EmfPlusRecordTypeSetPageTransform
;
1228 record
->Header
.Flags
= unit
;
1229 record
->PageScale
= scale
;
1231 METAFILE_WriteRecords(metafile
);
1237 GpStatus
METAFILE_SetWorldTransform(GpMetafile
* metafile
, GDIPCONST GpMatrix
* transform
)
1239 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1241 EmfPlusSetWorldTransform
*record
;
1244 stat
= METAFILE_AllocateRecord(metafile
,
1245 sizeof(EmfPlusSetWorldTransform
),
1250 record
->Header
.Type
= EmfPlusRecordTypeSetWorldTransform
;
1251 record
->Header
.Flags
= 0;
1252 memcpy(record
->MatrixData
, transform
->matrix
, sizeof(record
->MatrixData
));
1254 METAFILE_WriteRecords(metafile
);
1260 GpStatus
METAFILE_ScaleWorldTransform(GpMetafile
* metafile
, REAL sx
, REAL sy
, MatrixOrder order
)
1262 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1264 EmfPlusScaleWorldTransform
*record
;
1267 stat
= METAFILE_AllocateRecord(metafile
,
1268 sizeof(EmfPlusScaleWorldTransform
),
1273 record
->Header
.Type
= EmfPlusRecordTypeScaleWorldTransform
;
1274 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1278 METAFILE_WriteRecords(metafile
);
1284 GpStatus
METAFILE_MultiplyWorldTransform(GpMetafile
* metafile
, GDIPCONST GpMatrix
* matrix
, MatrixOrder order
)
1286 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1288 EmfPlusMultiplyWorldTransform
*record
;
1291 stat
= METAFILE_AllocateRecord(metafile
,
1292 sizeof(EmfPlusMultiplyWorldTransform
),
1297 record
->Header
.Type
= EmfPlusRecordTypeMultiplyWorldTransform
;
1298 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1299 memcpy(record
->MatrixData
, matrix
->matrix
, sizeof(record
->MatrixData
));
1301 METAFILE_WriteRecords(metafile
);
1307 GpStatus
METAFILE_RotateWorldTransform(GpMetafile
* metafile
, REAL angle
, MatrixOrder order
)
1309 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1311 EmfPlusRotateWorldTransform
*record
;
1314 stat
= METAFILE_AllocateRecord(metafile
,
1315 sizeof(EmfPlusRotateWorldTransform
),
1320 record
->Header
.Type
= EmfPlusRecordTypeRotateWorldTransform
;
1321 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1322 record
->Angle
= angle
;
1324 METAFILE_WriteRecords(metafile
);
1330 GpStatus
METAFILE_TranslateWorldTransform(GpMetafile
* metafile
, REAL dx
, REAL dy
, MatrixOrder order
)
1332 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1334 EmfPlusTranslateWorldTransform
*record
;
1337 stat
= METAFILE_AllocateRecord(metafile
,
1338 sizeof(EmfPlusTranslateWorldTransform
),
1343 record
->Header
.Type
= EmfPlusRecordTypeTranslateWorldTransform
;
1344 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1348 METAFILE_WriteRecords(metafile
);
1354 GpStatus
METAFILE_ResetWorldTransform(GpMetafile
* metafile
)
1356 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1358 EmfPlusRecordHeader
*record
;
1361 stat
= METAFILE_AllocateRecord(metafile
,
1362 sizeof(EmfPlusRecordHeader
),
1367 record
->Type
= EmfPlusRecordTypeResetWorldTransform
;
1370 METAFILE_WriteRecords(metafile
);
1376 GpStatus
METAFILE_BeginContainer(GpMetafile
* metafile
, GDIPCONST GpRectF
*dstrect
,
1377 GDIPCONST GpRectF
*srcrect
, GpUnit unit
, DWORD StackIndex
)
1379 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1381 EmfPlusBeginContainer
*record
;
1384 stat
= METAFILE_AllocateRecord(metafile
, sizeof(*record
), (void**)&record
);
1388 record
->Header
.Type
= EmfPlusRecordTypeBeginContainer
;
1389 record
->Header
.Flags
= unit
& 0xff;
1390 record
->DestRect
= *dstrect
;
1391 record
->SrcRect
= *srcrect
;
1392 record
->StackIndex
= StackIndex
;
1394 METAFILE_WriteRecords(metafile
);
1400 GpStatus
METAFILE_BeginContainerNoParams(GpMetafile
* metafile
, DWORD StackIndex
)
1402 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1404 EmfPlusContainerRecord
*record
;
1407 stat
= METAFILE_AllocateRecord(metafile
,
1408 sizeof(EmfPlusContainerRecord
),
1413 record
->Header
.Type
= EmfPlusRecordTypeBeginContainerNoParams
;
1414 record
->Header
.Flags
= 0;
1415 record
->StackIndex
= StackIndex
;
1417 METAFILE_WriteRecords(metafile
);
1423 GpStatus
METAFILE_EndContainer(GpMetafile
* metafile
, DWORD StackIndex
)
1425 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1427 EmfPlusContainerRecord
*record
;
1430 stat
= METAFILE_AllocateRecord(metafile
,
1431 sizeof(EmfPlusContainerRecord
),
1436 record
->Header
.Type
= EmfPlusRecordTypeEndContainer
;
1437 record
->Header
.Flags
= 0;
1438 record
->StackIndex
= StackIndex
;
1440 METAFILE_WriteRecords(metafile
);
1446 GpStatus
METAFILE_SaveGraphics(GpMetafile
* metafile
, DWORD StackIndex
)
1448 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1450 EmfPlusContainerRecord
*record
;
1453 stat
= METAFILE_AllocateRecord(metafile
,
1454 sizeof(EmfPlusContainerRecord
),
1459 record
->Header
.Type
= EmfPlusRecordTypeSave
;
1460 record
->Header
.Flags
= 0;
1461 record
->StackIndex
= StackIndex
;
1463 METAFILE_WriteRecords(metafile
);
1469 GpStatus
METAFILE_RestoreGraphics(GpMetafile
* metafile
, DWORD StackIndex
)
1471 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1473 EmfPlusContainerRecord
*record
;
1476 stat
= METAFILE_AllocateRecord(metafile
,
1477 sizeof(EmfPlusContainerRecord
),
1482 record
->Header
.Type
= EmfPlusRecordTypeRestore
;
1483 record
->Header
.Flags
= 0;
1484 record
->StackIndex
= StackIndex
;
1486 METAFILE_WriteRecords(metafile
);
1492 GpStatus
METAFILE_ReleaseDC(GpMetafile
* metafile
, HDC hdc
)
1494 if (hdc
!= metafile
->record_dc
)
1495 return InvalidParameter
;
1500 GpStatus
METAFILE_GraphicsDeleted(GpMetafile
* metafile
)
1504 stat
= METAFILE_WriteEndOfFile(metafile
);
1505 metafile
->record_graphics
= NULL
;
1507 metafile
->hemf
= CloseEnhMetaFile(metafile
->record_dc
);
1508 metafile
->record_dc
= NULL
;
1510 heap_free(metafile
->comment_data
);
1511 metafile
->comment_data
= NULL
;
1512 metafile
->comment_data_size
= 0;
1516 MetafileHeader header
;
1518 stat
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, &header
);
1519 if (stat
== Ok
&& metafile
->auto_frame
&&
1520 metafile
->auto_frame_max
.X
>= metafile
->auto_frame_min
.X
)
1522 RECTL bounds_rc
, gdi_bounds_rc
;
1523 REAL x_scale
= 2540.0 / header
.DpiX
;
1524 REAL y_scale
= 2540.0 / header
.DpiY
;
1528 bounds_rc
.left
= floorf(metafile
->auto_frame_min
.X
* x_scale
);
1529 bounds_rc
.top
= floorf(metafile
->auto_frame_min
.Y
* y_scale
);
1530 bounds_rc
.right
= ceilf(metafile
->auto_frame_max
.X
* x_scale
);
1531 bounds_rc
.bottom
= ceilf(metafile
->auto_frame_max
.Y
* y_scale
);
1533 gdi_bounds_rc
= header
.u
.EmfHeader
.rclBounds
;
1534 if (gdi_bounds_rc
.right
> gdi_bounds_rc
.left
&& gdi_bounds_rc
.bottom
> gdi_bounds_rc
.top
)
1536 bounds_rc
.left
= min(bounds_rc
.left
, gdi_bounds_rc
.left
);
1537 bounds_rc
.top
= min(bounds_rc
.top
, gdi_bounds_rc
.top
);
1538 bounds_rc
.right
= max(bounds_rc
.right
, gdi_bounds_rc
.right
);
1539 bounds_rc
.bottom
= max(bounds_rc
.bottom
, gdi_bounds_rc
.bottom
);
1542 buffer_size
= GetEnhMetaFileBits(metafile
->hemf
, 0, NULL
);
1543 buffer
= heap_alloc(buffer_size
);
1546 HENHMETAFILE new_hemf
;
1548 GetEnhMetaFileBits(metafile
->hemf
, buffer_size
, buffer
);
1550 ((ENHMETAHEADER
*)buffer
)->rclFrame
= bounds_rc
;
1552 new_hemf
= SetEnhMetaFileBits(buffer_size
, buffer
);
1556 DeleteEnhMetaFile(metafile
->hemf
);
1557 metafile
->hemf
= new_hemf
;
1568 stat
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, &header
);
1572 metafile
->bounds
.X
= header
.X
;
1573 metafile
->bounds
.Y
= header
.Y
;
1574 metafile
->bounds
.Width
= header
.Width
;
1575 metafile
->bounds
.Height
= header
.Height
;
1579 if (stat
== Ok
&& metafile
->record_stream
)
1584 buffer_size
= GetEnhMetaFileBits(metafile
->hemf
, 0, NULL
);
1586 buffer
= heap_alloc(buffer_size
);
1591 GetEnhMetaFileBits(metafile
->hemf
, buffer_size
, buffer
);
1593 hr
= IStream_Write(metafile
->record_stream
, buffer
, buffer_size
, NULL
);
1596 stat
= hresult_to_status(hr
);
1604 if (metafile
->record_stream
)
1606 IStream_Release(metafile
->record_stream
);
1607 metafile
->record_stream
= NULL
;
1613 GpStatus WINGDIPAPI
GdipGetHemfFromMetafile(GpMetafile
*metafile
, HENHMETAFILE
*hEmf
)
1615 TRACE("(%p,%p)\n", metafile
, hEmf
);
1617 if (!metafile
|| !hEmf
|| !metafile
->hemf
)
1618 return InvalidParameter
;
1620 *hEmf
= metafile
->hemf
;
1621 metafile
->hemf
= NULL
;
1626 static void METAFILE_GetFinalGdiTransform(const GpMetafile
*metafile
, XFORM
*result
)
1628 const GpRectF
*rect
;
1631 /* This transforms metafile device space to output points. */
1632 rect
= &metafile
->src_rect
;
1633 pt
= metafile
->playback_points
;
1634 result
->eM11
= (pt
[1].X
- pt
[0].X
) / rect
->Width
;
1635 result
->eM21
= (pt
[2].X
- pt
[0].X
) / rect
->Height
;
1636 result
->eDx
= pt
[0].X
- result
->eM11
* rect
->X
- result
->eM21
* rect
->Y
;
1637 result
->eM12
= (pt
[1].Y
- pt
[0].Y
) / rect
->Width
;
1638 result
->eM22
= (pt
[2].Y
- pt
[0].Y
) / rect
->Height
;
1639 result
->eDy
= pt
[0].Y
- result
->eM12
* rect
->X
- result
->eM22
* rect
->Y
;
1642 static GpStatus
METAFILE_PlaybackUpdateGdiTransform(GpMetafile
*metafile
)
1644 XFORM combined
, final
;
1646 METAFILE_GetFinalGdiTransform(metafile
, &final
);
1648 CombineTransform(&combined
, &metafile
->gdiworldtransform
, &final
);
1650 SetGraphicsMode(metafile
->playback_dc
, GM_ADVANCED
);
1651 SetWorldTransform(metafile
->playback_dc
, &combined
);
1656 static GpStatus
METAFILE_PlaybackGetDC(GpMetafile
*metafile
)
1660 stat
= GdipGetDC(metafile
->playback_graphics
, &metafile
->playback_dc
);
1664 static const XFORM identity
= {1, 0, 0, 1, 0, 0};
1666 metafile
->gdiworldtransform
= identity
;
1667 METAFILE_PlaybackUpdateGdiTransform(metafile
);
1673 static void METAFILE_PlaybackReleaseDC(GpMetafile
*metafile
)
1675 if (metafile
->playback_dc
)
1677 GdipReleaseDC(metafile
->playback_graphics
, metafile
->playback_dc
);
1678 metafile
->playback_dc
= NULL
;
1682 static GpStatus
METAFILE_PlaybackUpdateClip(GpMetafile
*metafile
)
1685 stat
= GdipCombineRegionRegion(metafile
->playback_graphics
->clip
, metafile
->base_clip
, CombineModeReplace
);
1687 stat
= GdipCombineRegionRegion(metafile
->playback_graphics
->clip
, metafile
->clip
, CombineModeIntersect
);
1691 static GpStatus
METAFILE_PlaybackUpdateWorldTransform(GpMetafile
*metafile
)
1693 GpMatrix
*real_transform
;
1696 stat
= GdipCreateMatrix3(&metafile
->src_rect
, metafile
->playback_points
, &real_transform
);
1700 REAL scale
= units_to_pixels(1.0, metafile
->page_unit
, 96.0);
1702 if (metafile
->page_unit
!= UnitDisplay
)
1703 scale
*= metafile
->page_scale
;
1705 stat
= GdipScaleMatrix(real_transform
, scale
, scale
, MatrixOrderPrepend
);
1708 stat
= GdipMultiplyMatrix(real_transform
, metafile
->world_transform
, MatrixOrderPrepend
);
1711 stat
= GdipSetWorldTransform(metafile
->playback_graphics
, real_transform
);
1713 GdipDeleteMatrix(real_transform
);
1719 static void metafile_set_object_table_entry(GpMetafile
*metafile
, BYTE id
, BYTE type
, void *object
)
1721 metafile_free_object_table_entry(metafile
, id
);
1722 metafile
->objtable
[id
].type
= type
;
1723 metafile
->objtable
[id
].u
.object
= object
;
1726 static GpStatus
metafile_deserialize_image(const BYTE
*record_data
, UINT data_size
, GpImage
**image
)
1728 EmfPlusImage
*data
= (EmfPlusImage
*)record_data
;
1733 if (data_size
< FIELD_OFFSET(EmfPlusImage
, ImageData
))
1734 return InvalidParameter
;
1735 data_size
-= FIELD_OFFSET(EmfPlusImage
, ImageData
);
1739 case ImageDataTypeBitmap
:
1741 EmfPlusBitmap
*bitmapdata
= &data
->ImageData
.bitmap
;
1743 if (data_size
<= FIELD_OFFSET(EmfPlusBitmap
, BitmapData
))
1744 return InvalidParameter
;
1745 data_size
-= FIELD_OFFSET(EmfPlusBitmap
, BitmapData
);
1747 switch (bitmapdata
->Type
)
1749 case BitmapDataTypePixel
:
1751 ColorPalette
*palette
;
1754 if (bitmapdata
->PixelFormat
& PixelFormatIndexed
)
1756 EmfPlusPalette
*palette_obj
= (EmfPlusPalette
*)bitmapdata
->BitmapData
;
1757 UINT palette_size
= FIELD_OFFSET(EmfPlusPalette
, PaletteEntries
);
1759 if (data_size
<= palette_size
)
1760 return InvalidParameter
;
1761 palette_size
+= palette_obj
->PaletteCount
* sizeof(EmfPlusARGB
);
1763 if (data_size
< palette_size
)
1764 return InvalidParameter
;
1765 data_size
-= palette_size
;
1767 palette
= (ColorPalette
*)bitmapdata
->BitmapData
;
1768 scan0
= (BYTE
*)bitmapdata
->BitmapData
+ palette_size
;
1773 scan0
= bitmapdata
->BitmapData
;
1776 if (data_size
< bitmapdata
->Height
* bitmapdata
->Stride
)
1777 return InvalidParameter
;
1779 status
= GdipCreateBitmapFromScan0(bitmapdata
->Width
, bitmapdata
->Height
, bitmapdata
->Stride
,
1780 bitmapdata
->PixelFormat
, scan0
, (GpBitmap
**)image
);
1781 if (status
== Ok
&& palette
)
1783 status
= GdipSetImagePalette(*image
, palette
);
1786 GdipDisposeImage(*image
);
1792 case BitmapDataTypeCompressed
:
1794 IWICImagingFactory
*factory
;
1798 if (WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION
, &factory
) != S_OK
)
1799 return GenericError
;
1801 hr
= IWICImagingFactory_CreateStream(factory
, &stream
);
1802 IWICImagingFactory_Release(factory
);
1804 return GenericError
;
1806 if (IWICStream_InitializeFromMemory(stream
, bitmapdata
->BitmapData
, data_size
) == S_OK
)
1807 status
= GdipCreateBitmapFromStream((IStream
*)stream
, (GpBitmap
**)image
);
1809 status
= GenericError
;
1811 IWICStream_Release(stream
);
1815 WARN("Invalid bitmap type %d.\n", bitmapdata
->Type
);
1816 return InvalidParameter
;
1821 FIXME("image type %d not supported.\n", data
->Type
);
1822 return NotImplemented
;
1828 static GpStatus
metafile_deserialize_path(const BYTE
*record_data
, UINT data_size
, GpPath
**path
)
1830 EmfPlusPath
*data
= (EmfPlusPath
*)record_data
;
1838 if (data_size
<= FIELD_OFFSET(EmfPlusPath
, data
))
1839 return InvalidParameter
;
1840 data_size
-= FIELD_OFFSET(EmfPlusPath
, data
);
1842 if (data
->PathPointFlags
& 0x800) /* R */
1844 FIXME("RLE encoded path data is not supported.\n");
1845 return NotImplemented
;
1849 if (data
->PathPointFlags
& 0x4000) /* C */
1850 size
= sizeof(EmfPlusPoint
);
1852 size
= sizeof(EmfPlusPointF
);
1853 size
+= sizeof(BYTE
); /* EmfPlusPathPointType */
1854 size
*= data
->PathPointCount
;
1857 if (data_size
< size
)
1858 return InvalidParameter
;
1860 status
= GdipCreatePath(FillModeAlternate
, path
);
1864 (*path
)->pathdata
.Count
= data
->PathPointCount
;
1865 (*path
)->pathdata
.Points
= GdipAlloc(data
->PathPointCount
* sizeof(*(*path
)->pathdata
.Points
));
1866 (*path
)->pathdata
.Types
= GdipAlloc(data
->PathPointCount
* sizeof(*(*path
)->pathdata
.Types
));
1867 (*path
)->datalen
= (*path
)->pathdata
.Count
;
1869 if (!(*path
)->pathdata
.Points
|| !(*path
)->pathdata
.Types
)
1871 GdipDeletePath(*path
);
1875 if (data
->PathPointFlags
& 0x4000) /* C */
1877 EmfPlusPoint
*points
= (EmfPlusPoint
*)data
->data
;
1878 for (i
= 0; i
< data
->PathPointCount
; i
++)
1880 (*path
)->pathdata
.Points
[i
].X
= points
[i
].X
;
1881 (*path
)->pathdata
.Points
[i
].Y
= points
[i
].Y
;
1883 types
= (BYTE
*)(points
+ i
);
1887 EmfPlusPointF
*points
= (EmfPlusPointF
*)data
->data
;
1888 memcpy((*path
)->pathdata
.Points
, points
, sizeof(*points
) * data
->PathPointCount
);
1889 types
= (BYTE
*)(points
+ data
->PathPointCount
);
1892 memcpy((*path
)->pathdata
.Types
, types
, sizeof(*types
) * data
->PathPointCount
);
1897 static GpStatus
metafile_read_region_node(struct memory_buffer
*mbuf
, GpRegion
*region
, region_element
*node
, UINT
*count
)
1902 type
= buffer_read(mbuf
, sizeof(*type
));
1903 if (!type
) return Ok
;
1909 case CombineModeReplace
:
1910 case CombineModeIntersect
:
1911 case CombineModeUnion
:
1912 case CombineModeXor
:
1913 case CombineModeExclude
:
1914 case CombineModeComplement
:
1916 region_element
*left
, *right
;
1918 left
= heap_alloc_zero(sizeof(*left
));
1922 right
= heap_alloc_zero(sizeof(*right
));
1929 status
= metafile_read_region_node(mbuf
, region
, left
, count
);
1932 status
= metafile_read_region_node(mbuf
, region
, right
, count
);
1935 node
->elementdata
.combine
.left
= left
;
1936 node
->elementdata
.combine
.right
= right
;
1937 region
->num_children
+= 2;
1946 case RegionDataRect
:
1948 const EmfPlusRectF
*rect
;
1950 rect
= buffer_read(mbuf
, sizeof(*rect
));
1952 return InvalidParameter
;
1954 memcpy(&node
->elementdata
.rect
, rect
, sizeof(*rect
));
1958 case RegionDataPath
:
1960 const BYTE
*path_data
;
1961 const UINT
*data_size
;
1964 data_size
= buffer_read(mbuf
, FIELD_OFFSET(EmfPlusRegionNodePath
, RegionNodePath
));
1966 return InvalidParameter
;
1968 path_data
= buffer_read(mbuf
, *data_size
);
1970 return InvalidParameter
;
1972 status
= metafile_deserialize_path(path_data
, *data_size
, &path
);
1975 node
->elementdata
.path
= path
;
1980 case RegionDataEmptyRect
:
1981 case RegionDataInfiniteRect
:
1985 FIXME("element type %#x is not supported\n", *type
);
1989 return InvalidParameter
;
1992 static GpStatus
metafile_deserialize_region(const BYTE
*record_data
, UINT data_size
, GpRegion
**region
)
1994 struct memory_buffer mbuf
;
2000 init_memory_buffer(&mbuf
, record_data
, data_size
);
2002 if (!buffer_read(&mbuf
, FIELD_OFFSET(EmfPlusRegion
, RegionNode
)))
2003 return InvalidParameter
;
2005 status
= GdipCreateRegion(region
);
2010 status
= metafile_read_region_node(&mbuf
, *region
, &(*region
)->node
, &count
);
2011 if (status
== Ok
&& !count
)
2012 status
= InvalidParameter
;
2016 GdipDeleteRegion(*region
);
2023 static GpStatus
metafile_deserialize_brush(const BYTE
*record_data
, UINT data_size
, GpBrush
**brush
)
2025 static const UINT header_size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
);
2026 EmfPlusBrush
*data
= (EmfPlusBrush
*)record_data
;
2027 EmfPlusTransformMatrix
*transform
= NULL
;
2034 if (data_size
< header_size
)
2035 return InvalidParameter
;
2039 case BrushTypeSolidColor
:
2040 if (data_size
!= header_size
+ sizeof(EmfPlusSolidBrushData
))
2041 return InvalidParameter
;
2043 status
= GdipCreateSolidFill(data
->BrushData
.solid
.SolidColor
, (GpSolidFill
**)brush
);
2045 case BrushTypeHatchFill
:
2046 if (data_size
!= header_size
+ sizeof(EmfPlusHatchBrushData
))
2047 return InvalidParameter
;
2049 status
= GdipCreateHatchBrush(data
->BrushData
.hatch
.HatchStyle
, data
->BrushData
.hatch
.ForeColor
,
2050 data
->BrushData
.hatch
.BackColor
, (GpHatch
**)brush
);
2052 case BrushTypeTextureFill
:
2056 offset
= header_size
+ FIELD_OFFSET(EmfPlusTextureBrushData
, OptionalData
);
2057 if (data_size
<= offset
)
2058 return InvalidParameter
;
2060 brushflags
= data
->BrushData
.texture
.BrushDataFlags
;
2061 if (brushflags
& BrushDataTransform
)
2063 if (data_size
<= offset
+ sizeof(EmfPlusTransformMatrix
))
2064 return InvalidParameter
;
2065 transform
= (EmfPlusTransformMatrix
*)(record_data
+ offset
);
2066 offset
+= sizeof(EmfPlusTransformMatrix
);
2069 status
= metafile_deserialize_image(record_data
+ offset
, data_size
- offset
, &image
);
2073 status
= GdipCreateTexture(image
, data
->BrushData
.texture
.WrapMode
, (GpTexture
**)brush
);
2074 if (status
== Ok
&& transform
&& !(brushflags
& BrushDataDoNotTransform
))
2075 GdipSetTextureTransform((GpTexture
*)*brush
, (const GpMatrix
*)transform
);
2077 GdipDisposeImage(image
);
2080 case BrushTypeLinearGradient
:
2082 GpLineGradient
*gradient
= NULL
;
2083 GpPointF startpoint
, endpoint
;
2084 UINT position_count
= 0;
2086 offset
= header_size
+ FIELD_OFFSET(EmfPlusLinearGradientBrushData
, OptionalData
);
2087 if (data_size
<= offset
)
2088 return InvalidParameter
;
2090 brushflags
= data
->BrushData
.lineargradient
.BrushDataFlags
;
2091 if ((brushflags
& BrushDataPresetColors
) && (brushflags
& (BrushDataBlendFactorsH
| BrushDataBlendFactorsV
)))
2092 return InvalidParameter
;
2094 if (brushflags
& BrushDataTransform
)
2096 if (data_size
<= offset
+ sizeof(EmfPlusTransformMatrix
))
2097 return InvalidParameter
;
2098 transform
= (EmfPlusTransformMatrix
*)(record_data
+ offset
);
2099 offset
+= sizeof(EmfPlusTransformMatrix
);
2102 if (brushflags
& (BrushDataPresetColors
| BrushDataBlendFactorsH
| BrushDataBlendFactorsV
))
2104 if (data_size
<= offset
+ sizeof(DWORD
)) /* Number of factors/preset colors. */
2105 return InvalidParameter
;
2106 position_count
= *(DWORD
*)(record_data
+ offset
);
2107 offset
+= sizeof(DWORD
);
2110 if (brushflags
& BrushDataPresetColors
)
2112 if (data_size
!= offset
+ position_count
* (sizeof(float) + sizeof(EmfPlusARGB
)))
2113 return InvalidParameter
;
2115 else if (brushflags
& BrushDataBlendFactorsH
)
2117 if (data_size
!= offset
+ position_count
* 2 * sizeof(float))
2118 return InvalidParameter
;
2121 startpoint
.X
= data
->BrushData
.lineargradient
.RectF
.X
;
2122 startpoint
.Y
= data
->BrushData
.lineargradient
.RectF
.Y
;
2123 endpoint
.X
= startpoint
.X
+ data
->BrushData
.lineargradient
.RectF
.Width
;
2124 endpoint
.Y
= startpoint
.Y
+ data
->BrushData
.lineargradient
.RectF
.Height
;
2126 status
= GdipCreateLineBrush(&startpoint
, &endpoint
, data
->BrushData
.lineargradient
.StartColor
,
2127 data
->BrushData
.lineargradient
.EndColor
, data
->BrushData
.lineargradient
.WrapMode
, &gradient
);
2131 status
= GdipSetLineTransform(gradient
, (const GpMatrix
*)transform
);
2135 if (brushflags
& BrushDataPresetColors
)
2136 status
= GdipSetLinePresetBlend(gradient
, (ARGB
*)(record_data
+ offset
+
2137 position_count
* sizeof(REAL
)), (REAL
*)(record_data
+ offset
), position_count
);
2138 else if (brushflags
& BrushDataBlendFactorsH
)
2139 status
= GdipSetLineBlend(gradient
, (REAL
*)(record_data
+ offset
+ position_count
* sizeof(REAL
)),
2140 (REAL
*)(record_data
+ offset
), position_count
);
2142 if (brushflags
& BrushDataIsGammaCorrected
)
2143 FIXME("BrushDataIsGammaCorrected is not handled.\n");
2148 *brush
= (GpBrush
*)gradient
;
2150 GdipDeleteBrush((GpBrush
*)gradient
);
2155 FIXME("brush type %u is not supported.\n", data
->Type
);
2156 return NotImplemented
;
2162 static GpStatus
metafile_get_pen_brush_data_offset(EmfPlusPen
*data
, UINT data_size
, DWORD
*ret
)
2164 EmfPlusPenData
*pendata
= (EmfPlusPenData
*)data
->data
;
2165 DWORD offset
= FIELD_OFFSET(EmfPlusPen
, data
);
2167 if (data_size
<= offset
)
2168 return InvalidParameter
;
2170 offset
+= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
2171 if (data_size
<= offset
)
2172 return InvalidParameter
;
2174 if (pendata
->PenDataFlags
& PenDataTransform
)
2175 offset
+= sizeof(EmfPlusTransformMatrix
);
2177 if (pendata
->PenDataFlags
& PenDataStartCap
)
2178 offset
+= sizeof(DWORD
);
2180 if (pendata
->PenDataFlags
& PenDataEndCap
)
2181 offset
+= sizeof(DWORD
);
2183 if (pendata
->PenDataFlags
& PenDataJoin
)
2184 offset
+= sizeof(DWORD
);
2186 if (pendata
->PenDataFlags
& PenDataMiterLimit
)
2187 offset
+= sizeof(REAL
);
2189 if (pendata
->PenDataFlags
& PenDataLineStyle
)
2190 offset
+= sizeof(DWORD
);
2192 if (pendata
->PenDataFlags
& PenDataDashedLineCap
)
2193 offset
+= sizeof(DWORD
);
2195 if (pendata
->PenDataFlags
& PenDataDashedLineOffset
)
2196 offset
+= sizeof(REAL
);
2198 if (pendata
->PenDataFlags
& PenDataDashedLine
)
2200 EmfPlusDashedLineData
*dashedline
= (EmfPlusDashedLineData
*)((BYTE
*)data
+ offset
);
2202 offset
+= FIELD_OFFSET(EmfPlusDashedLineData
, data
);
2203 if (data_size
<= offset
)
2204 return InvalidParameter
;
2206 offset
+= dashedline
->DashedLineDataSize
* sizeof(float);
2209 if (pendata
->PenDataFlags
& PenDataNonCenter
)
2210 offset
+= sizeof(DWORD
);
2212 if (pendata
->PenDataFlags
& PenDataCompoundLine
)
2214 EmfPlusCompoundLineData
*compoundline
= (EmfPlusCompoundLineData
*)((BYTE
*)data
+ offset
);
2216 offset
+= FIELD_OFFSET(EmfPlusCompoundLineData
, data
);
2217 if (data_size
<= offset
)
2218 return InvalidParameter
;
2220 offset
+= compoundline
->CompoundLineDataSize
* sizeof(float);
2223 if (pendata
->PenDataFlags
& PenDataCustomStartCap
)
2225 EmfPlusCustomStartCapData
*startcap
= (EmfPlusCustomStartCapData
*)((BYTE
*)data
+ offset
);
2227 offset
+= FIELD_OFFSET(EmfPlusCustomStartCapData
, data
);
2228 if (data_size
<= offset
)
2229 return InvalidParameter
;
2231 offset
+= startcap
->CustomStartCapSize
;
2234 if (pendata
->PenDataFlags
& PenDataCustomEndCap
)
2236 EmfPlusCustomEndCapData
*endcap
= (EmfPlusCustomEndCapData
*)((BYTE
*)data
+ offset
);
2238 offset
+= FIELD_OFFSET(EmfPlusCustomEndCapData
, data
);
2239 if (data_size
<= offset
)
2240 return InvalidParameter
;
2242 offset
+= endcap
->CustomEndCapSize
;
2249 static GpStatus
METAFILE_PlaybackObject(GpMetafile
*metafile
, UINT flags
, UINT data_size
, const BYTE
*record_data
)
2251 BYTE type
= (flags
>> 8) & 0xff;
2252 BYTE id
= flags
& 0xff;
2253 void *object
= NULL
;
2256 if (type
> ObjectTypeMax
|| id
>= EmfPlusObjectTableSize
)
2257 return InvalidParameter
;
2261 case ObjectTypeBrush
:
2262 status
= metafile_deserialize_brush(record_data
, data_size
, (GpBrush
**)&object
);
2266 EmfPlusPen
*data
= (EmfPlusPen
*)record_data
;
2267 EmfPlusPenData
*pendata
= (EmfPlusPenData
*)data
->data
;
2272 status
= metafile_get_pen_brush_data_offset(data
, data_size
, &offset
);
2276 status
= metafile_deserialize_brush(record_data
+ offset
, data_size
- offset
, &brush
);
2280 status
= GdipCreatePen2(brush
, pendata
->PenWidth
, pendata
->PenUnit
, &pen
);
2281 GdipDeleteBrush(brush
);
2285 offset
= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
2287 if (pendata
->PenDataFlags
& PenDataTransform
)
2289 FIXME("PenDataTransform is not supported.\n");
2290 offset
+= sizeof(EmfPlusTransformMatrix
);
2293 if (pendata
->PenDataFlags
& PenDataStartCap
)
2295 if ((status
= GdipSetPenStartCap(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2297 offset
+= sizeof(DWORD
);
2300 if (pendata
->PenDataFlags
& PenDataEndCap
)
2302 if ((status
= GdipSetPenEndCap(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2304 offset
+= sizeof(DWORD
);
2307 if (pendata
->PenDataFlags
& PenDataJoin
)
2309 if ((status
= GdipSetPenLineJoin(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2311 offset
+= sizeof(DWORD
);
2314 if (pendata
->PenDataFlags
& PenDataMiterLimit
)
2316 if ((status
= GdipSetPenMiterLimit(pen
, *(REAL
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2318 offset
+= sizeof(REAL
);
2321 if (pendata
->PenDataFlags
& PenDataLineStyle
)
2323 if ((status
= GdipSetPenDashStyle(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2325 offset
+= sizeof(DWORD
);
2328 if (pendata
->PenDataFlags
& PenDataDashedLineCap
)
2330 FIXME("PenDataDashedLineCap is not supported.\n");
2331 offset
+= sizeof(DWORD
);
2334 if (pendata
->PenDataFlags
& PenDataDashedLineOffset
)
2336 if ((status
= GdipSetPenDashOffset(pen
, *(REAL
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2338 offset
+= sizeof(REAL
);
2341 if (pendata
->PenDataFlags
& PenDataDashedLine
)
2343 EmfPlusDashedLineData
*dashedline
= (EmfPlusDashedLineData
*)((BYTE
*)pendata
+ offset
);
2344 FIXME("PenDataDashedLine is not supported.\n");
2345 offset
+= FIELD_OFFSET(EmfPlusDashedLineData
, data
) + dashedline
->DashedLineDataSize
* sizeof(float);
2348 if (pendata
->PenDataFlags
& PenDataNonCenter
)
2350 FIXME("PenDataNonCenter is not supported.\n");
2351 offset
+= sizeof(DWORD
);
2354 if (pendata
->PenDataFlags
& PenDataCompoundLine
)
2356 EmfPlusCompoundLineData
*compoundline
= (EmfPlusCompoundLineData
*)((BYTE
*)pendata
+ offset
);
2357 FIXME("PenDataCompundLine is not supported.\n");
2358 offset
+= FIELD_OFFSET(EmfPlusCompoundLineData
, data
) + compoundline
->CompoundLineDataSize
* sizeof(float);
2361 if (pendata
->PenDataFlags
& PenDataCustomStartCap
)
2363 EmfPlusCustomStartCapData
*startcap
= (EmfPlusCustomStartCapData
*)((BYTE
*)pendata
+ offset
);
2364 FIXME("PenDataCustomStartCap is not supported.\n");
2365 offset
+= FIELD_OFFSET(EmfPlusCustomStartCapData
, data
) + startcap
->CustomStartCapSize
;
2368 if (pendata
->PenDataFlags
& PenDataCustomEndCap
)
2370 EmfPlusCustomEndCapData
*endcap
= (EmfPlusCustomEndCapData
*)((BYTE
*)pendata
+ offset
);
2371 FIXME("PenDataCustomEndCap is not supported.\n");
2372 offset
+= FIELD_OFFSET(EmfPlusCustomEndCapData
, data
) + endcap
->CustomEndCapSize
;
2382 case ObjectTypePath
:
2383 status
= metafile_deserialize_path(record_data
, data_size
, (GpPath
**)&object
);
2385 case ObjectTypeRegion
:
2386 status
= metafile_deserialize_region(record_data
, data_size
, (GpRegion
**)&object
);
2388 case ObjectTypeImage
:
2389 status
= metafile_deserialize_image(record_data
, data_size
, (GpImage
**)&object
);
2391 case ObjectTypeFont
:
2393 EmfPlusFont
*data
= (EmfPlusFont
*)record_data
;
2394 GpFontFamily
*family
;
2397 if (data_size
<= FIELD_OFFSET(EmfPlusFont
, FamilyName
))
2398 return InvalidParameter
;
2399 data_size
-= FIELD_OFFSET(EmfPlusFont
, FamilyName
);
2401 if (data_size
< data
->Length
* sizeof(WCHAR
))
2402 return InvalidParameter
;
2404 if (!(familyname
= GdipAlloc((data
->Length
+ 1) * sizeof(*familyname
))))
2407 memcpy(familyname
, data
->FamilyName
, data
->Length
* sizeof(*familyname
));
2408 familyname
[data
->Length
] = 0;
2410 status
= GdipCreateFontFamilyFromName(familyname
, NULL
, &family
);
2411 GdipFree(familyname
);
2413 return InvalidParameter
;
2415 status
= GdipCreateFont(family
, data
->EmSize
, data
->FontStyleFlags
, data
->SizeUnit
, (GpFont
**)&object
);
2416 GdipDeleteFontFamily(family
);
2419 case ObjectTypeImageAttributes
:
2421 EmfPlusImageAttributes
*data
= (EmfPlusImageAttributes
*)record_data
;
2422 GpImageAttributes
*attributes
= NULL
;
2424 if (data_size
!= sizeof(*data
))
2425 return InvalidParameter
;
2427 if ((status
= GdipCreateImageAttributes(&attributes
)) != Ok
)
2430 status
= GdipSetImageAttributesWrapMode(attributes
, data
->WrapMode
, *(DWORD
*)&data
->ClampColor
,
2431 !!data
->ObjectClamp
);
2433 object
= attributes
;
2435 GdipDisposeImageAttributes(attributes
);
2439 FIXME("not implemented for object type %d.\n", type
);
2440 return NotImplemented
;
2444 metafile_set_object_table_entry(metafile
, id
, type
, object
);
2449 static GpStatus
metafile_set_clip_region(GpMetafile
*metafile
, GpRegion
*region
, CombineMode mode
)
2451 GpMatrix world_to_device
;
2453 get_graphics_transform(metafile
->playback_graphics
, CoordinateSpaceDevice
, CoordinateSpaceWorld
, &world_to_device
);
2455 GdipTransformRegion(region
, &world_to_device
);
2456 GdipCombineRegionRegion(metafile
->clip
, region
, mode
);
2458 return METAFILE_PlaybackUpdateClip(metafile
);
2461 GpStatus WINGDIPAPI
GdipPlayMetafileRecord(GDIPCONST GpMetafile
*metafile
,
2462 EmfPlusRecordType recordType
, UINT flags
, UINT dataSize
, GDIPCONST BYTE
*data
)
2465 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
;
2467 TRACE("(%p,%x,%x,%d,%p)\n", metafile
, recordType
, flags
, dataSize
, data
);
2469 if (!metafile
|| (dataSize
&& !data
) || !metafile
->playback_graphics
)
2470 return InvalidParameter
;
2472 if (recordType
>= 1 && recordType
<= 0x7a)
2474 /* regular EMF record */
2475 if (metafile
->playback_dc
)
2479 case EMR_SETMAPMODE
:
2482 case EMR_SETWINDOWORGEX
:
2483 case EMR_SETWINDOWEXTEX
:
2484 case EMR_SETVIEWPORTORGEX
:
2485 case EMR_SETVIEWPORTEXTEX
:
2486 case EMR_SCALEVIEWPORTEXTEX
:
2487 case EMR_SCALEWINDOWEXTEX
:
2488 case EMR_MODIFYWORLDTRANSFORM
:
2489 FIXME("not implemented for record type %x\n", recordType
);
2491 case EMR_SETWORLDTRANSFORM
:
2493 const XFORM
* xform
= (void*)data
;
2494 real_metafile
->gdiworldtransform
= *xform
;
2495 METAFILE_PlaybackUpdateGdiTransform(real_metafile
);
2498 case EMR_EXTSELECTCLIPRGN
:
2500 DWORD rgndatasize
= *(DWORD
*)data
;
2501 DWORD mode
= *(DWORD
*)(data
+ 4);
2502 const RGNDATA
*rgndata
= (const RGNDATA
*)(data
+ 8);
2509 METAFILE_GetFinalGdiTransform(metafile
, &final
);
2511 hrgn
= ExtCreateRegion(&final
, rgndatasize
, rgndata
);
2514 ExtSelectClipRgn(metafile
->playback_dc
, hrgn
, mode
);
2522 ENHMETARECORD
*record
= heap_alloc_zero(dataSize
+ 8);
2526 record
->iType
= recordType
;
2527 record
->nSize
= dataSize
+ 8;
2528 memcpy(record
->dParm
, data
, dataSize
);
2530 if(PlayEnhMetaFileRecord(metafile
->playback_dc
, metafile
->handle_table
,
2531 record
, metafile
->handle_count
) == 0)
2532 ERR("PlayEnhMetaFileRecord failed\n");
2546 EmfPlusRecordHeader
*header
= (EmfPlusRecordHeader
*)(data
)-1;
2548 METAFILE_PlaybackReleaseDC((GpMetafile
*)metafile
);
2552 case EmfPlusRecordTypeHeader
:
2553 case EmfPlusRecordTypeEndOfFile
:
2555 case EmfPlusRecordTypeGetDC
:
2556 METAFILE_PlaybackGetDC((GpMetafile
*)metafile
);
2558 case EmfPlusRecordTypeClear
:
2560 EmfPlusClear
*record
= (EmfPlusClear
*)header
;
2562 if (dataSize
!= sizeof(record
->Color
))
2563 return InvalidParameter
;
2565 return GdipGraphicsClear(metafile
->playback_graphics
, record
->Color
);
2567 case EmfPlusRecordTypeFillRects
:
2569 EmfPlusFillRects
*record
= (EmfPlusFillRects
*)header
;
2570 GpBrush
*brush
, *temp_brush
=NULL
;
2571 GpRectF
*rects
, *temp_rects
=NULL
;
2573 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
))
2574 return InvalidParameter
;
2578 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(EmfPlusRect
) * record
->Count
)
2579 return InvalidParameter
;
2583 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(GpRectF
) * record
->Count
)
2584 return InvalidParameter
;
2589 stat
= GdipCreateSolidFill(record
->BrushID
, (GpSolidFill
**)&temp_brush
);
2594 if (record
->BrushID
>= EmfPlusObjectTableSize
||
2595 real_metafile
->objtable
[record
->BrushID
].type
!= ObjectTypeBrush
)
2596 return InvalidParameter
;
2598 brush
= real_metafile
->objtable
[record
->BrushID
].u
.brush
;
2606 EmfPlusRect
*int_rects
= (EmfPlusRect
*)(record
+1);
2609 rects
= temp_rects
= heap_alloc_zero(sizeof(GpRectF
) * record
->Count
);
2612 for (i
=0; i
<record
->Count
; i
++)
2614 rects
[i
].X
= int_rects
[i
].X
;
2615 rects
[i
].Y
= int_rects
[i
].Y
;
2616 rects
[i
].Width
= int_rects
[i
].Width
;
2617 rects
[i
].Height
= int_rects
[i
].Height
;
2624 rects
= (GpRectF
*)(record
+1);
2629 stat
= GdipFillRectangles(metafile
->playback_graphics
, brush
, rects
, record
->Count
);
2632 GdipDeleteBrush(temp_brush
);
2633 heap_free(temp_rects
);
2637 case EmfPlusRecordTypeSetClipRect
:
2639 EmfPlusSetClipRect
*record
= (EmfPlusSetClipRect
*)header
;
2640 CombineMode mode
= (CombineMode
)((flags
>> 8) & 0xf);
2643 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(*record
))
2644 return InvalidParameter
;
2646 stat
= GdipCreateRegionRect(&record
->ClipRect
, ®ion
);
2650 stat
= metafile_set_clip_region(real_metafile
, region
, mode
);
2651 GdipDeleteRegion(region
);
2656 case EmfPlusRecordTypeSetClipRegion
:
2658 CombineMode mode
= (flags
>> 8) & 0xf;
2659 BYTE regionid
= flags
& 0xff;
2663 return InvalidParameter
;
2665 if (regionid
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[regionid
].type
!= ObjectTypeRegion
)
2666 return InvalidParameter
;
2668 stat
= GdipCloneRegion(real_metafile
->objtable
[regionid
].u
.region
, ®ion
);
2671 stat
= metafile_set_clip_region(real_metafile
, region
, mode
);
2672 GdipDeleteRegion(region
);
2677 case EmfPlusRecordTypeSetClipPath
:
2679 CombineMode mode
= (flags
>> 8) & 0xf;
2680 BYTE pathid
= flags
& 0xff;
2684 return InvalidParameter
;
2686 if (pathid
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pathid
].type
!= ObjectTypePath
)
2687 return InvalidParameter
;
2689 stat
= GdipCreateRegionPath(real_metafile
->objtable
[pathid
].u
.path
, ®ion
);
2692 stat
= metafile_set_clip_region(real_metafile
, region
, mode
);
2693 GdipDeleteRegion(region
);
2698 case EmfPlusRecordTypeSetPageTransform
:
2700 EmfPlusSetPageTransform
*record
= (EmfPlusSetPageTransform
*)header
;
2701 GpUnit unit
= (GpUnit
)flags
;
2703 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetPageTransform
))
2704 return InvalidParameter
;
2706 real_metafile
->page_unit
= unit
;
2707 real_metafile
->page_scale
= record
->PageScale
;
2709 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2711 case EmfPlusRecordTypeSetWorldTransform
:
2713 EmfPlusSetWorldTransform
*record
= (EmfPlusSetWorldTransform
*)header
;
2715 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetWorldTransform
))
2716 return InvalidParameter
;
2718 memcpy(real_metafile
->world_transform
->matrix
, record
->MatrixData
, sizeof(record
->MatrixData
));
2720 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2722 case EmfPlusRecordTypeScaleWorldTransform
:
2724 EmfPlusScaleWorldTransform
*record
= (EmfPlusScaleWorldTransform
*)header
;
2725 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2727 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusScaleWorldTransform
))
2728 return InvalidParameter
;
2730 GdipScaleMatrix(real_metafile
->world_transform
, record
->Sx
, record
->Sy
, order
);
2732 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2734 case EmfPlusRecordTypeMultiplyWorldTransform
:
2736 EmfPlusMultiplyWorldTransform
*record
= (EmfPlusMultiplyWorldTransform
*)header
;
2737 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2740 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusMultiplyWorldTransform
))
2741 return InvalidParameter
;
2743 memcpy(matrix
.matrix
, record
->MatrixData
, sizeof(matrix
.matrix
));
2745 GdipMultiplyMatrix(real_metafile
->world_transform
, &matrix
, order
);
2747 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2749 case EmfPlusRecordTypeRotateWorldTransform
:
2751 EmfPlusRotateWorldTransform
*record
= (EmfPlusRotateWorldTransform
*)header
;
2752 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2754 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusRotateWorldTransform
))
2755 return InvalidParameter
;
2757 GdipRotateMatrix(real_metafile
->world_transform
, record
->Angle
, order
);
2759 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2761 case EmfPlusRecordTypeTranslateWorldTransform
:
2763 EmfPlusTranslateWorldTransform
*record
= (EmfPlusTranslateWorldTransform
*)header
;
2764 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2766 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusTranslateWorldTransform
))
2767 return InvalidParameter
;
2769 GdipTranslateMatrix(real_metafile
->world_transform
, record
->dx
, record
->dy
, order
);
2771 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2773 case EmfPlusRecordTypeResetWorldTransform
:
2775 GdipSetMatrixElements(real_metafile
->world_transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
2777 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2779 case EmfPlusRecordTypeBeginContainer
:
2781 EmfPlusBeginContainer
*record
= (EmfPlusBeginContainer
*)header
;
2784 REAL scale_x
, scale_y
;
2785 GpRectF scaled_srcrect
;
2788 cont
= heap_alloc_zero(sizeof(*cont
));
2792 stat
= GdipCloneRegion(metafile
->clip
, &cont
->clip
);
2799 stat
= GdipBeginContainer2(metafile
->playback_graphics
, &cont
->state
);
2803 GdipDeleteRegion(cont
->clip
);
2808 cont
->id
= record
->StackIndex
;
2809 cont
->type
= BEGIN_CONTAINER
;
2810 cont
->world_transform
= *metafile
->world_transform
;
2811 cont
->page_unit
= metafile
->page_unit
;
2812 cont
->page_scale
= metafile
->page_scale
;
2813 list_add_head(&real_metafile
->containers
, &cont
->entry
);
2815 unit
= record
->Header
.Flags
& 0xff;
2817 scale_x
= units_to_pixels(1.0, unit
, metafile
->image
.xres
);
2818 scale_y
= units_to_pixels(1.0, unit
, metafile
->image
.yres
);
2820 scaled_srcrect
.X
= scale_x
* record
->SrcRect
.X
;
2821 scaled_srcrect
.Y
= scale_y
* record
->SrcRect
.Y
;
2822 scaled_srcrect
.Width
= scale_x
* record
->SrcRect
.Width
;
2823 scaled_srcrect
.Height
= scale_y
* record
->SrcRect
.Height
;
2825 transform
.matrix
[0] = record
->DestRect
.Width
/ scaled_srcrect
.Width
;
2826 transform
.matrix
[1] = 0.0;
2827 transform
.matrix
[2] = 0.0;
2828 transform
.matrix
[3] = record
->DestRect
.Height
/ scaled_srcrect
.Height
;
2829 transform
.matrix
[4] = record
->DestRect
.X
- scaled_srcrect
.X
;
2830 transform
.matrix
[5] = record
->DestRect
.Y
- scaled_srcrect
.Y
;
2832 GdipMultiplyMatrix(real_metafile
->world_transform
, &transform
, MatrixOrderPrepend
);
2834 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2836 case EmfPlusRecordTypeBeginContainerNoParams
:
2837 case EmfPlusRecordTypeSave
:
2839 EmfPlusContainerRecord
*record
= (EmfPlusContainerRecord
*)header
;
2842 cont
= heap_alloc_zero(sizeof(*cont
));
2846 stat
= GdipCloneRegion(metafile
->clip
, &cont
->clip
);
2853 if (recordType
== EmfPlusRecordTypeBeginContainerNoParams
)
2854 stat
= GdipBeginContainer2(metafile
->playback_graphics
, &cont
->state
);
2856 stat
= GdipSaveGraphics(metafile
->playback_graphics
, &cont
->state
);
2860 GdipDeleteRegion(cont
->clip
);
2865 cont
->id
= record
->StackIndex
;
2866 if (recordType
== EmfPlusRecordTypeBeginContainerNoParams
)
2867 cont
->type
= BEGIN_CONTAINER
;
2869 cont
->type
= SAVE_GRAPHICS
;
2870 cont
->world_transform
= *metafile
->world_transform
;
2871 cont
->page_unit
= metafile
->page_unit
;
2872 cont
->page_scale
= metafile
->page_scale
;
2873 list_add_head(&real_metafile
->containers
, &cont
->entry
);
2877 case EmfPlusRecordTypeEndContainer
:
2878 case EmfPlusRecordTypeRestore
:
2880 EmfPlusContainerRecord
*record
= (EmfPlusContainerRecord
*)header
;
2882 enum container_type type
;
2885 if (recordType
== EmfPlusRecordTypeEndContainer
)
2886 type
= BEGIN_CONTAINER
;
2888 type
= SAVE_GRAPHICS
;
2890 LIST_FOR_EACH_ENTRY(cont
, &real_metafile
->containers
, container
, entry
)
2892 if (cont
->id
== record
->StackIndex
&& cont
->type
== type
)
2903 /* pop any newer items on the stack */
2904 while ((cont2
= LIST_ENTRY(list_head(&real_metafile
->containers
), container
, entry
)) != cont
)
2906 list_remove(&cont2
->entry
);
2907 GdipDeleteRegion(cont2
->clip
);
2911 if (type
== BEGIN_CONTAINER
)
2912 GdipEndContainer(real_metafile
->playback_graphics
, cont
->state
);
2914 GdipRestoreGraphics(real_metafile
->playback_graphics
, cont
->state
);
2916 *real_metafile
->world_transform
= cont
->world_transform
;
2917 real_metafile
->page_unit
= cont
->page_unit
;
2918 real_metafile
->page_scale
= cont
->page_scale
;
2919 GdipCombineRegionRegion(real_metafile
->clip
, cont
->clip
, CombineModeReplace
);
2921 list_remove(&cont
->entry
);
2922 GdipDeleteRegion(cont
->clip
);
2928 case EmfPlusRecordTypeSetPixelOffsetMode
:
2930 return GdipSetPixelOffsetMode(real_metafile
->playback_graphics
, flags
& 0xff);
2932 case EmfPlusRecordTypeSetCompositingQuality
:
2934 return GdipSetCompositingQuality(real_metafile
->playback_graphics
, flags
& 0xff);
2936 case EmfPlusRecordTypeSetInterpolationMode
:
2938 return GdipSetInterpolationMode(real_metafile
->playback_graphics
, flags
& 0xff);
2940 case EmfPlusRecordTypeSetTextRenderingHint
:
2942 return GdipSetTextRenderingHint(real_metafile
->playback_graphics
, flags
& 0xff);
2944 case EmfPlusRecordTypeSetAntiAliasMode
:
2946 return GdipSetSmoothingMode(real_metafile
->playback_graphics
, (flags
>> 1) & 0xff);
2948 case EmfPlusRecordTypeSetCompositingMode
:
2950 return GdipSetCompositingMode(real_metafile
->playback_graphics
, flags
& 0xff);
2952 case EmfPlusRecordTypeObject
:
2954 return METAFILE_PlaybackObject(real_metafile
, flags
, dataSize
, data
);
2956 case EmfPlusRecordTypeDrawImage
:
2958 EmfPlusDrawImage
*draw
= (EmfPlusDrawImage
*)header
;
2959 BYTE image
= flags
& 0xff;
2962 if (image
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[image
].type
!= ObjectTypeImage
)
2963 return InvalidParameter
;
2965 if (dataSize
!= FIELD_OFFSET(EmfPlusDrawImage
, RectData
) - sizeof(EmfPlusRecordHeader
) +
2966 (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
2967 return InvalidParameter
;
2969 if (draw
->ImageAttributesID
>= EmfPlusObjectTableSize
||
2970 real_metafile
->objtable
[draw
->ImageAttributesID
].type
!= ObjectTypeImageAttributes
)
2971 return InvalidParameter
;
2973 if (flags
& 0x4000) /* C */
2975 points
[0].X
= draw
->RectData
.rect
.X
;
2976 points
[0].Y
= draw
->RectData
.rect
.Y
;
2977 points
[1].X
= points
[0].X
+ draw
->RectData
.rect
.Width
;
2978 points
[1].Y
= points
[0].Y
;
2979 points
[2].X
= points
[1].X
;
2980 points
[2].Y
= points
[1].Y
+ draw
->RectData
.rect
.Height
;
2984 points
[0].X
= draw
->RectData
.rectF
.X
;
2985 points
[0].Y
= draw
->RectData
.rectF
.Y
;
2986 points
[1].X
= points
[0].X
+ draw
->RectData
.rectF
.Width
;
2987 points
[1].Y
= points
[0].Y
;
2988 points
[2].X
= points
[1].X
;
2989 points
[2].Y
= points
[1].Y
+ draw
->RectData
.rectF
.Height
;
2992 return GdipDrawImagePointsRect(real_metafile
->playback_graphics
, real_metafile
->objtable
[image
].u
.image
,
2993 points
, 3, draw
->SrcRect
.X
, draw
->SrcRect
.Y
, draw
->SrcRect
.Width
, draw
->SrcRect
.Height
, draw
->SrcUnit
,
2994 real_metafile
->objtable
[draw
->ImageAttributesID
].u
.image_attributes
, NULL
, NULL
);
2996 case EmfPlusRecordTypeDrawImagePoints
:
2998 EmfPlusDrawImagePoints
*draw
= (EmfPlusDrawImagePoints
*)header
;
2999 static const UINT fixed_part_size
= FIELD_OFFSET(EmfPlusDrawImagePoints
, PointData
) -
3000 FIELD_OFFSET(EmfPlusDrawImagePoints
, ImageAttributesID
);
3001 BYTE image
= flags
& 0xff;
3006 if (image
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[image
].type
!= ObjectTypeImage
)
3007 return InvalidParameter
;
3009 if (dataSize
<= fixed_part_size
)
3010 return InvalidParameter
;
3011 dataSize
-= fixed_part_size
;
3013 if (draw
->ImageAttributesID
>= EmfPlusObjectTableSize
||
3014 real_metafile
->objtable
[draw
->ImageAttributesID
].type
!= ObjectTypeImageAttributes
)
3015 return InvalidParameter
;
3017 if (draw
->count
!= 3)
3018 return InvalidParameter
;
3020 if ((flags
>> 13) & 1) /* E */
3021 FIXME("image effects are not supported.\n");
3023 if ((flags
>> 11) & 1) /* P */
3024 size
= sizeof(EmfPlusPointR7
) * draw
->count
;
3025 else if ((flags
>> 14) & 1) /* C */
3026 size
= sizeof(EmfPlusPoint
) * draw
->count
;
3028 size
= sizeof(EmfPlusPointF
) * draw
->count
;
3030 if (dataSize
!= size
)
3031 return InvalidParameter
;
3033 if ((flags
>> 11) & 1) /* P */
3035 points
[0].X
= draw
->PointData
.pointsR
[0].X
;
3036 points
[0].Y
= draw
->PointData
.pointsR
[0].Y
;
3037 for (i
= 1; i
< 3; i
++)
3039 points
[i
].X
= points
[i
-1].X
+ draw
->PointData
.pointsR
[i
].X
;
3040 points
[i
].Y
= points
[i
-1].Y
+ draw
->PointData
.pointsR
[i
].Y
;
3043 else if ((flags
>> 14) & 1) /* C */
3045 for (i
= 0; i
< 3; i
++)
3047 points
[i
].X
= draw
->PointData
.points
[i
].X
;
3048 points
[i
].Y
= draw
->PointData
.points
[i
].Y
;
3052 memcpy(points
, draw
->PointData
.pointsF
, sizeof(points
));
3054 return GdipDrawImagePointsRect(real_metafile
->playback_graphics
, real_metafile
->objtable
[image
].u
.image
,
3055 points
, 3, draw
->SrcRect
.X
, draw
->SrcRect
.Y
, draw
->SrcRect
.Width
, draw
->SrcRect
.Height
, draw
->SrcUnit
,
3056 real_metafile
->objtable
[draw
->ImageAttributesID
].u
.image_attributes
, NULL
, NULL
);
3058 case EmfPlusRecordTypeFillPath
:
3060 EmfPlusFillPath
*fill
= (EmfPlusFillPath
*)header
;
3061 GpSolidFill
*solidfill
= NULL
;
3062 BYTE path
= flags
& 0xff;
3065 if (path
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[path
].type
!= ObjectTypePath
)
3066 return InvalidParameter
;
3068 if (dataSize
!= sizeof(fill
->data
.BrushId
))
3069 return InvalidParameter
;
3073 stat
= GdipCreateSolidFill(fill
->data
.Color
, (GpSolidFill
**)&solidfill
);
3076 brush
= (GpBrush
*)solidfill
;
3080 if (fill
->data
.BrushId
>= EmfPlusObjectTableSize
||
3081 real_metafile
->objtable
[fill
->data
.BrushId
].type
!= ObjectTypeBrush
)
3082 return InvalidParameter
;
3084 brush
= real_metafile
->objtable
[fill
->data
.BrushId
].u
.brush
;
3087 stat
= GdipFillPath(real_metafile
->playback_graphics
, brush
, real_metafile
->objtable
[path
].u
.path
);
3088 GdipDeleteBrush((GpBrush
*)solidfill
);
3091 case EmfPlusRecordTypeFillClosedCurve
:
3093 static const UINT fixed_part_size
= FIELD_OFFSET(EmfPlusFillClosedCurve
, PointData
) -
3094 sizeof(EmfPlusRecordHeader
);
3095 EmfPlusFillClosedCurve
*fill
= (EmfPlusFillClosedCurve
*)header
;
3096 GpSolidFill
*solidfill
= NULL
;
3101 if (dataSize
<= fixed_part_size
)
3102 return InvalidParameter
;
3104 if (fill
->Count
== 0)
3105 return InvalidParameter
;
3107 if (flags
& 0x800) /* P */
3108 size
= (fixed_part_size
+ sizeof(EmfPlusPointR7
) * fill
->Count
+ 3) & ~3;
3109 else if (flags
& 0x4000) /* C */
3110 size
= fixed_part_size
+ sizeof(EmfPlusPoint
) * fill
->Count
;
3112 size
= fixed_part_size
+ sizeof(EmfPlusPointF
) * fill
->Count
;
3114 if (dataSize
!= size
)
3115 return InvalidParameter
;
3117 mode
= flags
& 0x200 ? FillModeWinding
: FillModeAlternate
; /* W */
3119 if (flags
& 0x8000) /* S */
3121 stat
= GdipCreateSolidFill(fill
->BrushId
, (GpSolidFill
**)&solidfill
);
3124 brush
= (GpBrush
*)solidfill
;
3128 if (fill
->BrushId
>= EmfPlusObjectTableSize
||
3129 real_metafile
->objtable
[fill
->BrushId
].type
!= ObjectTypeBrush
)
3130 return InvalidParameter
;
3132 brush
= real_metafile
->objtable
[fill
->BrushId
].u
.brush
;
3135 if (flags
& (0x800 | 0x4000))
3137 GpPointF
*points
= GdipAlloc(fill
->Count
* sizeof(*points
));
3140 if (flags
& 0x800) /* P */
3142 for (i
= 1; i
< fill
->Count
; i
++)
3144 points
[i
].X
= points
[i
- 1].X
+ fill
->PointData
.pointsR
[i
].X
;
3145 points
[i
].Y
= points
[i
- 1].Y
+ fill
->PointData
.pointsR
[i
].Y
;
3150 for (i
= 0; i
< fill
->Count
; i
++)
3152 points
[i
].X
= fill
->PointData
.points
[i
].X
;
3153 points
[i
].Y
= fill
->PointData
.points
[i
].Y
;
3157 stat
= GdipFillClosedCurve2(real_metafile
->playback_graphics
, brush
,
3158 points
, fill
->Count
, fill
->Tension
, mode
);
3165 stat
= GdipFillClosedCurve2(real_metafile
->playback_graphics
, brush
,
3166 (const GpPointF
*)fill
->PointData
.pointsF
, fill
->Count
, fill
->Tension
, mode
);
3168 GdipDeleteBrush((GpBrush
*)solidfill
);
3171 case EmfPlusRecordTypeFillEllipse
:
3173 EmfPlusFillEllipse
*fill
= (EmfPlusFillEllipse
*)header
;
3174 GpSolidFill
*solidfill
= NULL
;
3177 if (dataSize
<= FIELD_OFFSET(EmfPlusFillEllipse
, RectData
) - sizeof(EmfPlusRecordHeader
))
3178 return InvalidParameter
;
3179 dataSize
-= FIELD_OFFSET(EmfPlusFillEllipse
, RectData
) - sizeof(EmfPlusRecordHeader
);
3181 if (dataSize
!= (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3182 return InvalidParameter
;
3186 stat
= GdipCreateSolidFill(fill
->BrushId
, (GpSolidFill
**)&solidfill
);
3189 brush
= (GpBrush
*)solidfill
;
3193 if (fill
->BrushId
>= EmfPlusObjectTableSize
||
3194 real_metafile
->objtable
[fill
->BrushId
].type
!= ObjectTypeBrush
)
3195 return InvalidParameter
;
3197 brush
= real_metafile
->objtable
[fill
->BrushId
].u
.brush
;
3201 stat
= GdipFillEllipseI(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rect
.X
,
3202 fill
->RectData
.rect
.Y
, fill
->RectData
.rect
.Width
, fill
->RectData
.rect
.Height
);
3204 stat
= GdipFillEllipse(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rectF
.X
,
3205 fill
->RectData
.rectF
.Y
, fill
->RectData
.rectF
.Width
, fill
->RectData
.rectF
.Height
);
3207 GdipDeleteBrush((GpBrush
*)solidfill
);
3210 case EmfPlusRecordTypeFillPie
:
3212 EmfPlusFillPie
*fill
= (EmfPlusFillPie
*)header
;
3213 GpSolidFill
*solidfill
= NULL
;
3216 if (dataSize
<= FIELD_OFFSET(EmfPlusFillPie
, RectData
) - sizeof(EmfPlusRecordHeader
))
3217 return InvalidParameter
;
3218 dataSize
-= FIELD_OFFSET(EmfPlusFillPie
, RectData
) - sizeof(EmfPlusRecordHeader
);
3220 if (dataSize
!= (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3221 return InvalidParameter
;
3223 if (flags
& 0x8000) /* S */
3225 stat
= GdipCreateSolidFill(fill
->BrushId
, (GpSolidFill
**)&solidfill
);
3228 brush
= (GpBrush
*)solidfill
;
3232 if (fill
->BrushId
>= EmfPlusObjectTableSize
||
3233 real_metafile
->objtable
[fill
->BrushId
].type
!= ObjectTypeBrush
)
3234 return InvalidParameter
;
3236 brush
= real_metafile
->objtable
[fill
->BrushId
].u
.brush
;
3239 if (flags
& 0x4000) /* C */
3240 stat
= GdipFillPieI(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rect
.X
,
3241 fill
->RectData
.rect
.Y
, fill
->RectData
.rect
.Width
, fill
->RectData
.rect
.Height
,
3242 fill
->StartAngle
, fill
->SweepAngle
);
3244 stat
= GdipFillPie(real_metafile
->playback_graphics
, brush
, fill
->RectData
.rectF
.X
,
3245 fill
->RectData
.rectF
.Y
, fill
->RectData
.rectF
.Width
, fill
->RectData
.rectF
.Height
,
3246 fill
->StartAngle
, fill
->SweepAngle
);
3248 GdipDeleteBrush((GpBrush
*)solidfill
);
3251 case EmfPlusRecordTypeDrawPath
:
3253 EmfPlusDrawPath
*draw
= (EmfPlusDrawPath
*)header
;
3254 BYTE path
= flags
& 0xff;
3256 if (dataSize
!= sizeof(draw
->PenId
))
3257 return InvalidParameter
;
3259 if (path
>= EmfPlusObjectTableSize
|| draw
->PenId
>= EmfPlusObjectTableSize
)
3260 return InvalidParameter
;
3262 if (real_metafile
->objtable
[path
].type
!= ObjectTypePath
||
3263 real_metafile
->objtable
[draw
->PenId
].type
!= ObjectTypePen
)
3264 return InvalidParameter
;
3266 return GdipDrawPath(real_metafile
->playback_graphics
, real_metafile
->objtable
[draw
->PenId
].u
.pen
,
3267 real_metafile
->objtable
[path
].u
.path
);
3269 case EmfPlusRecordTypeDrawArc
:
3271 EmfPlusDrawArc
*draw
= (EmfPlusDrawArc
*)header
;
3272 BYTE pen
= flags
& 0xff;
3274 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3275 return InvalidParameter
;
3277 if (dataSize
!= FIELD_OFFSET(EmfPlusDrawArc
, RectData
) - sizeof(EmfPlusRecordHeader
) +
3278 (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3279 return InvalidParameter
;
3281 if (flags
& 0x4000) /* C */
3282 return GdipDrawArcI(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3283 draw
->RectData
.rect
.X
, draw
->RectData
.rect
.Y
, draw
->RectData
.rect
.Width
,
3284 draw
->RectData
.rect
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3286 return GdipDrawArc(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3287 draw
->RectData
.rectF
.X
, draw
->RectData
.rectF
.Y
, draw
->RectData
.rectF
.Width
,
3288 draw
->RectData
.rectF
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3290 case EmfPlusRecordTypeDrawEllipse
:
3292 EmfPlusDrawEllipse
*draw
= (EmfPlusDrawEllipse
*)header
;
3293 BYTE pen
= flags
& 0xff;
3295 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3296 return InvalidParameter
;
3298 if (dataSize
!= (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3299 return InvalidParameter
;
3301 if (flags
& 0x4000) /* C */
3302 return GdipDrawEllipseI(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3303 draw
->RectData
.rect
.X
, draw
->RectData
.rect
.Y
, draw
->RectData
.rect
.Width
,
3304 draw
->RectData
.rect
.Height
);
3306 return GdipDrawEllipse(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3307 draw
->RectData
.rectF
.X
, draw
->RectData
.rectF
.Y
, draw
->RectData
.rectF
.Width
,
3308 draw
->RectData
.rectF
.Height
);
3310 case EmfPlusRecordTypeDrawPie
:
3312 EmfPlusDrawPie
*draw
= (EmfPlusDrawPie
*)header
;
3313 BYTE pen
= flags
& 0xff;
3315 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3316 return InvalidParameter
;
3318 if (dataSize
!= FIELD_OFFSET(EmfPlusDrawPie
, RectData
) - sizeof(EmfPlusRecordHeader
) +
3319 (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3320 return InvalidParameter
;
3322 if (flags
& 0x4000) /* C */
3323 return GdipDrawPieI(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3324 draw
->RectData
.rect
.X
, draw
->RectData
.rect
.Y
, draw
->RectData
.rect
.Width
,
3325 draw
->RectData
.rect
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3327 return GdipDrawPie(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3328 draw
->RectData
.rectF
.X
, draw
->RectData
.rectF
.Y
, draw
->RectData
.rectF
.Width
,
3329 draw
->RectData
.rectF
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
3331 case EmfPlusRecordTypeDrawRects
:
3333 EmfPlusDrawRects
*draw
= (EmfPlusDrawRects
*)header
;
3334 BYTE pen
= flags
& 0xff;
3335 GpRectF
*rects
= NULL
;
3337 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
3338 return InvalidParameter
;
3340 if (dataSize
<= FIELD_OFFSET(EmfPlusDrawRects
, RectData
) - sizeof(EmfPlusRecordHeader
))
3341 return InvalidParameter
;
3342 dataSize
-= FIELD_OFFSET(EmfPlusDrawRects
, RectData
) - sizeof(EmfPlusRecordHeader
);
3344 if (dataSize
!= draw
->Count
* (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
3345 return InvalidParameter
;
3351 rects
= GdipAlloc(draw
->Count
* sizeof(*rects
));
3355 for (i
= 0; i
< draw
->Count
; i
++)
3357 rects
[i
].X
= draw
->RectData
.rect
[i
].X
;
3358 rects
[i
].Y
= draw
->RectData
.rect
[i
].Y
;
3359 rects
[i
].Width
= draw
->RectData
.rect
[i
].Width
;
3360 rects
[i
].Height
= draw
->RectData
.rect
[i
].Height
;
3364 stat
= GdipDrawRectangles(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
3365 rects
? rects
: (GpRectF
*)draw
->RectData
.rectF
, draw
->Count
);
3370 FIXME("Not implemented for record type %x\n", recordType
);
3371 return NotImplemented
;
3378 struct enum_metafile_data
3380 EnumerateMetafileProc callback
;
3381 void *callback_data
;
3382 GpMetafile
*metafile
;
3385 static int CALLBACK
enum_metafile_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
3386 int nObj
, LPARAM lpData
)
3389 struct enum_metafile_data
*data
= (struct enum_metafile_data
*)lpData
;
3392 data
->metafile
->handle_table
= lpHTable
;
3393 data
->metafile
->handle_count
= nObj
;
3395 /* First check for an EMF+ record. */
3396 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
3398 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
3400 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
3404 while (offset
+ sizeof(EmfPlusRecordHeader
) <= comment
->cbData
)
3406 const EmfPlusRecordHeader
*record
= (const EmfPlusRecordHeader
*)&comment
->Data
[offset
];
3408 if (record
->DataSize
)
3409 pStr
= (const BYTE
*)(record
+1);
3413 ret
= data
->callback(record
->Type
, record
->Flags
, record
->DataSize
,
3414 pStr
, data
->callback_data
);
3419 offset
+= record
->Size
;
3426 if (lpEMFR
->nSize
!= 8)
3427 pStr
= (const BYTE
*)lpEMFR
->dParm
;
3431 return data
->callback(lpEMFR
->iType
, 0, lpEMFR
->nSize
-8,
3432 pStr
, data
->callback_data
);
3435 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestPoints(GpGraphics
*graphics
,
3436 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*destPoints
, INT count
,
3437 GDIPCONST GpRectF
*srcRect
, Unit srcUnit
, EnumerateMetafileProc callback
,
3438 VOID
*callbackData
, GDIPCONST GpImageAttributes
*imageAttributes
)
3440 struct enum_metafile_data data
;
3442 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
; /* whoever made this const was joking */
3443 GraphicsContainer state
;
3446 TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics
, metafile
,
3447 destPoints
, count
, srcRect
, srcUnit
, callback
, callbackData
,
3450 if (!graphics
|| !metafile
|| !destPoints
|| count
!= 3 || !srcRect
)
3451 return InvalidParameter
;
3453 if (!metafile
->hemf
)
3454 return InvalidParameter
;
3456 if (metafile
->playback_graphics
)
3459 TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect
), srcUnit
,
3460 debugstr_pointf(&destPoints
[0]), debugstr_pointf(&destPoints
[1]),
3461 debugstr_pointf(&destPoints
[2]));
3463 data
.callback
= callback
;
3464 data
.callback_data
= callbackData
;
3465 data
.metafile
= real_metafile
;
3467 real_metafile
->playback_graphics
= graphics
;
3468 real_metafile
->playback_dc
= NULL
;
3469 real_metafile
->src_rect
= *srcRect
;
3471 memcpy(real_metafile
->playback_points
, destPoints
, sizeof(PointF
) * 3);
3472 stat
= GdipTransformPoints(graphics
, CoordinateSpaceDevice
, CoordinateSpaceWorld
, real_metafile
->playback_points
, 3);
3475 stat
= GdipBeginContainer2(graphics
, &state
);
3479 stat
= GdipSetPageScale(graphics
, 1.0);
3482 stat
= GdipSetPageUnit(graphics
, UnitPixel
);
3485 stat
= GdipResetWorldTransform(graphics
);
3488 stat
= GdipCreateRegion(&real_metafile
->base_clip
);
3491 stat
= GdipGetClip(graphics
, real_metafile
->base_clip
);
3494 stat
= GdipCreateRegion(&real_metafile
->clip
);
3497 stat
= GdipCreatePath(FillModeAlternate
, &dst_path
);
3501 GpPointF clip_points
[4];
3503 clip_points
[0] = real_metafile
->playback_points
[0];
3504 clip_points
[1] = real_metafile
->playback_points
[1];
3505 clip_points
[2].X
= real_metafile
->playback_points
[1].X
+ real_metafile
->playback_points
[2].X
3506 - real_metafile
->playback_points
[0].X
;
3507 clip_points
[2].Y
= real_metafile
->playback_points
[1].Y
+ real_metafile
->playback_points
[2].Y
3508 - real_metafile
->playback_points
[0].Y
;
3509 clip_points
[3] = real_metafile
->playback_points
[2];
3511 stat
= GdipAddPathPolygon(dst_path
, clip_points
, 4);
3514 stat
= GdipCombineRegionPath(real_metafile
->base_clip
, dst_path
, CombineModeIntersect
);
3516 GdipDeletePath(dst_path
);
3520 stat
= GdipCreateMatrix(&real_metafile
->world_transform
);
3524 real_metafile
->page_unit
= UnitDisplay
;
3525 real_metafile
->page_scale
= 1.0;
3526 stat
= METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
3531 stat
= METAFILE_PlaybackUpdateClip(real_metafile
);
3534 if (stat
== Ok
&& (metafile
->metafile_type
== MetafileTypeEmf
||
3535 metafile
->metafile_type
== MetafileTypeWmfPlaceable
||
3536 metafile
->metafile_type
== MetafileTypeWmf
))
3537 stat
= METAFILE_PlaybackGetDC(real_metafile
);
3540 EnumEnhMetaFile(0, metafile
->hemf
, enum_metafile_proc
, &data
, NULL
);
3542 METAFILE_PlaybackReleaseDC(real_metafile
);
3544 GdipDeleteMatrix(real_metafile
->world_transform
);
3545 real_metafile
->world_transform
= NULL
;
3547 GdipDeleteRegion(real_metafile
->base_clip
);
3548 real_metafile
->base_clip
= NULL
;
3550 GdipDeleteRegion(real_metafile
->clip
);
3551 real_metafile
->clip
= NULL
;
3553 while (list_head(&real_metafile
->containers
))
3555 container
* cont
= LIST_ENTRY(list_head(&real_metafile
->containers
), container
, entry
);
3556 list_remove(&cont
->entry
);
3557 GdipDeleteRegion(cont
->clip
);
3561 GdipEndContainer(graphics
, state
);
3564 real_metafile
->playback_graphics
= NULL
;
3569 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRect(GpGraphics
*graphics
,
3570 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRectF
*dest
,
3571 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3575 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
3577 points
[0].X
= points
[2].X
= dest
->X
;
3578 points
[0].Y
= points
[1].Y
= dest
->Y
;
3579 points
[1].X
= dest
->X
+ dest
->Width
;
3580 points
[2].Y
= dest
->Y
+ dest
->Height
;
3582 return GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, points
, 3,
3583 &metafile
->bounds
, metafile
->unit
, callback
, cb_data
, attrs
);
3586 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRectI(GpGraphics
*graphics
,
3587 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRect
*dest
,
3588 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3592 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
3596 destf
.Width
= dest
->Width
;
3597 destf
.Height
= dest
->Height
;
3599 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
3602 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPoint(GpGraphics
*graphics
,
3603 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*dest
,
3604 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3608 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
3612 destf
.Width
= units_to_pixels(metafile
->bounds
.Width
, metafile
->unit
, metafile
->image
.xres
);
3613 destf
.Height
= units_to_pixels(metafile
->bounds
.Height
, metafile
->unit
, metafile
->image
.yres
);
3615 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
3618 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPointI(GpGraphics
*graphics
,
3619 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPoint
*dest
,
3620 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3624 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
3629 return GdipEnumerateMetafileDestPoint(graphics
, metafile
, &ptf
, callback
, cb_data
, attrs
);
3632 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromMetafile(GpMetafile
* metafile
,
3633 MetafileHeader
* header
)
3637 TRACE("(%p, %p)\n", metafile
, header
);
3639 if(!metafile
|| !header
)
3640 return InvalidParameter
;
3644 status
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, header
);
3645 if (status
!= Ok
) return status
;
3649 memset(header
, 0, sizeof(*header
));
3650 header
->Version
= VERSION_MAGIC2
;
3653 header
->Type
= metafile
->metafile_type
;
3654 header
->DpiX
= metafile
->image
.xres
;
3655 header
->DpiY
= metafile
->image
.yres
;
3656 header
->Width
= gdip_round(metafile
->bounds
.Width
);
3657 header
->Height
= gdip_round(metafile
->bounds
.Height
);
3662 static int CALLBACK
get_emfplus_header_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
3663 int nObj
, LPARAM lpData
)
3665 EmfPlusHeader
*dst_header
= (EmfPlusHeader
*)lpData
;
3667 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
3669 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
3671 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
3673 const EmfPlusRecordHeader
*header
= (const EmfPlusRecordHeader
*)&comment
->Data
[4];
3675 if (4 + sizeof(EmfPlusHeader
) <= comment
->cbData
&&
3676 header
->Type
== EmfPlusRecordTypeHeader
)
3678 memcpy(dst_header
, header
, sizeof(*dst_header
));
3682 else if (lpEMFR
->iType
== EMR_HEADER
)
3688 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromEmf(HENHMETAFILE hemf
,
3689 MetafileHeader
*header
)
3691 ENHMETAHEADER3 emfheader
;
3692 EmfPlusHeader emfplusheader
;
3693 MetafileType metafile_type
;
3695 TRACE("(%p,%p)\n", hemf
, header
);
3697 if(!hemf
|| !header
)
3698 return InvalidParameter
;
3700 if (GetEnhMetaFileHeader(hemf
, sizeof(emfheader
), (ENHMETAHEADER
*)&emfheader
) == 0)
3701 return GenericError
;
3703 emfplusheader
.Header
.Type
= 0;
3705 EnumEnhMetaFile(NULL
, hemf
, get_emfplus_header_proc
, &emfplusheader
, NULL
);
3707 if (emfplusheader
.Header
.Type
== EmfPlusRecordTypeHeader
)
3709 if ((emfplusheader
.Header
.Flags
& 1) == 1)
3710 metafile_type
= MetafileTypeEmfPlusDual
;
3712 metafile_type
= MetafileTypeEmfPlusOnly
;
3715 metafile_type
= MetafileTypeEmf
;
3717 header
->Type
= metafile_type
;
3718 header
->Size
= emfheader
.nBytes
;
3719 header
->DpiX
= (REAL
)emfheader
.szlDevice
.cx
* 25.4 / emfheader
.szlMillimeters
.cx
;
3720 header
->DpiY
= (REAL
)emfheader
.szlDevice
.cy
* 25.4 / emfheader
.szlMillimeters
.cy
;
3721 header
->X
= gdip_round((REAL
)emfheader
.rclFrame
.left
/ 2540.0 * header
->DpiX
);
3722 header
->Y
= gdip_round((REAL
)emfheader
.rclFrame
.top
/ 2540.0 * header
->DpiY
);
3723 header
->Width
= gdip_round((REAL
)(emfheader
.rclFrame
.right
- emfheader
.rclFrame
.left
) / 2540.0 * header
->DpiX
);
3724 header
->Height
= gdip_round((REAL
)(emfheader
.rclFrame
.bottom
- emfheader
.rclFrame
.top
) / 2540.0 * header
->DpiY
);
3725 header
->u
.EmfHeader
= emfheader
;
3727 if (metafile_type
== MetafileTypeEmfPlusDual
|| metafile_type
== MetafileTypeEmfPlusOnly
)
3729 header
->Version
= emfplusheader
.Version
;
3730 header
->EmfPlusFlags
= emfplusheader
.EmfPlusFlags
;
3731 header
->EmfPlusHeaderSize
= emfplusheader
.Header
.Size
;
3732 header
->LogicalDpiX
= emfplusheader
.LogicalDpiX
;
3733 header
->LogicalDpiY
= emfplusheader
.LogicalDpiY
;
3737 header
->Version
= emfheader
.nVersion
;
3738 header
->EmfPlusFlags
= 0;
3739 header
->EmfPlusHeaderSize
= 0;
3740 header
->LogicalDpiX
= 0;
3741 header
->LogicalDpiY
= 0;
3747 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromWmf(HMETAFILE hwmf
,
3748 GDIPCONST WmfPlaceableFileHeader
*placeable
, MetafileHeader
*header
)
3751 GpMetafile
*metafile
;
3753 TRACE("(%p,%p,%p)\n", hwmf
, placeable
, header
);
3755 status
= GdipCreateMetafileFromWmf(hwmf
, FALSE
, placeable
, &metafile
);
3758 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
3759 GdipDisposeImage(&metafile
->image
);
3764 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR
*filename
,
3765 MetafileHeader
*header
)
3768 GpMetafile
*metafile
;
3770 TRACE("(%s,%p)\n", debugstr_w(filename
), header
);
3772 if (!filename
|| !header
)
3773 return InvalidParameter
;
3775 status
= GdipCreateMetafileFromFile(filename
, &metafile
);
3778 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
3779 GdipDisposeImage(&metafile
->image
);
3784 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromStream(IStream
*stream
,
3785 MetafileHeader
*header
)
3788 GpMetafile
*metafile
;
3790 TRACE("(%p,%p)\n", stream
, header
);
3792 if (!stream
|| !header
)
3793 return InvalidParameter
;
3795 status
= GdipCreateMetafileFromStream(stream
, &metafile
);
3798 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
3799 GdipDisposeImage(&metafile
->image
);
3804 GpStatus WINGDIPAPI
GdipCreateMetafileFromEmf(HENHMETAFILE hemf
, BOOL
delete,
3805 GpMetafile
**metafile
)
3808 MetafileHeader header
;
3810 TRACE("(%p,%i,%p)\n", hemf
, delete, metafile
);
3812 if(!hemf
|| !metafile
)
3813 return InvalidParameter
;
3815 stat
= GdipGetMetafileHeaderFromEmf(hemf
, &header
);
3819 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
3823 (*metafile
)->image
.type
= ImageTypeMetafile
;
3824 (*metafile
)->image
.format
= ImageFormatEMF
;
3825 (*metafile
)->image
.frame_count
= 1;
3826 (*metafile
)->image
.xres
= header
.DpiX
;
3827 (*metafile
)->image
.yres
= header
.DpiY
;
3828 (*metafile
)->bounds
.X
= (REAL
)header
.u
.EmfHeader
.rclFrame
.left
/ 2540.0 * header
.DpiX
;
3829 (*metafile
)->bounds
.Y
= (REAL
)header
.u
.EmfHeader
.rclFrame
.top
/ 2540.0 * header
.DpiY
;
3830 (*metafile
)->bounds
.Width
= (REAL
)(header
.u
.EmfHeader
.rclFrame
.right
- header
.u
.EmfHeader
.rclFrame
.left
)
3831 / 2540.0 * header
.DpiX
;
3832 (*metafile
)->bounds
.Height
= (REAL
)(header
.u
.EmfHeader
.rclFrame
.bottom
- header
.u
.EmfHeader
.rclFrame
.top
)
3833 / 2540.0 * header
.DpiY
;
3834 (*metafile
)->unit
= UnitPixel
;
3835 (*metafile
)->metafile_type
= header
.Type
;
3836 (*metafile
)->hemf
= hemf
;
3837 (*metafile
)->preserve_hemf
= !delete;
3838 list_init(&(*metafile
)->containers
);
3840 TRACE("<-- %p\n", *metafile
);
3845 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmf(HMETAFILE hwmf
, BOOL
delete,
3846 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
3851 GpStatus retval
= Ok
;
3853 TRACE("(%p, %d, %p, %p)\n", hwmf
, delete, placeable
, metafile
);
3855 if(!hwmf
|| !metafile
)
3856 return InvalidParameter
;
3859 read
= GetMetaFileBitsEx(hwmf
, 0, NULL
);
3861 return GenericError
;
3862 copy
= heap_alloc_zero(read
);
3863 GetMetaFileBitsEx(hwmf
, read
, copy
);
3865 hemf
= SetWinMetaFileBits(read
, copy
, NULL
, NULL
);
3868 /* FIXME: We should store and use hwmf instead of converting to hemf */
3869 retval
= GdipCreateMetafileFromEmf(hemf
, TRUE
, metafile
);
3875 (*metafile
)->image
.xres
= (REAL
)placeable
->Inch
;
3876 (*metafile
)->image
.yres
= (REAL
)placeable
->Inch
;
3877 (*metafile
)->bounds
.X
= ((REAL
)placeable
->BoundingBox
.Left
) / ((REAL
)placeable
->Inch
);
3878 (*metafile
)->bounds
.Y
= ((REAL
)placeable
->BoundingBox
.Top
) / ((REAL
)placeable
->Inch
);
3879 (*metafile
)->bounds
.Width
= (REAL
)(placeable
->BoundingBox
.Right
-
3880 placeable
->BoundingBox
.Left
);
3881 (*metafile
)->bounds
.Height
= (REAL
)(placeable
->BoundingBox
.Bottom
-
3882 placeable
->BoundingBox
.Top
);
3883 (*metafile
)->metafile_type
= MetafileTypeWmfPlaceable
;
3886 (*metafile
)->metafile_type
= MetafileTypeWmf
;
3887 (*metafile
)->image
.format
= ImageFormatWMF
;
3889 if (delete) DeleteMetaFile(hwmf
);
3892 DeleteEnhMetaFile(hemf
);
3896 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR
*file
,
3897 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
3902 TRACE("(%s, %p, %p)\n", debugstr_w(file
), placeable
, metafile
);
3904 hmf
= GetMetaFileW(file
);
3906 return GdipCreateMetafileFromWmf(hmf
, TRUE
, placeable
, metafile
);
3908 emf
= GetEnhMetaFileW(file
);
3910 return GdipCreateMetafileFromEmf(emf
, TRUE
, metafile
);
3912 return GenericError
;
3915 GpStatus WINGDIPAPI
GdipCreateMetafileFromFile(GDIPCONST WCHAR
*file
,
3916 GpMetafile
**metafile
)
3921 TRACE("(%p, %p)\n", file
, metafile
);
3923 if (!file
|| !metafile
) return InvalidParameter
;
3927 status
= GdipCreateStreamOnFile(file
, GENERIC_READ
, &stream
);
3930 status
= GdipCreateMetafileFromStream(stream
, metafile
);
3931 IStream_Release(stream
);
3936 GpStatus WINGDIPAPI
GdipCreateMetafileFromStream(IStream
*stream
,
3937 GpMetafile
**metafile
)
3941 TRACE("%p %p\n", stream
, metafile
);
3943 stat
= GdipLoadImageFromStream(stream
, (GpImage
**)metafile
);
3944 if (stat
!= Ok
) return stat
;
3946 if ((*metafile
)->image
.type
!= ImageTypeMetafile
)
3948 GdipDisposeImage(&(*metafile
)->image
);
3950 return GenericError
;
3956 GpStatus WINGDIPAPI
GdipSetMetafileDownLevelRasterizationLimit(GpMetafile
*metafile
,
3959 TRACE("(%p,%u)\n", metafile
, limitDpi
);
3964 GpStatus WINGDIPAPI
GdipConvertToEmfPlus(const GpGraphics
* ref
,
3965 GpMetafile
* metafile
, BOOL
* succ
, EmfType emfType
,
3966 const WCHAR
* description
, GpMetafile
** out_metafile
)
3970 TRACE("(%p,%p,%p,%u,%s,%p)\n", ref
, metafile
, succ
, emfType
,
3971 debugstr_w(description
), out_metafile
);
3973 if(!ref
|| !metafile
|| !out_metafile
|| emfType
< EmfTypeEmfOnly
|| emfType
> EmfTypeEmfPlusDual
)
3974 return InvalidParameter
;
3978 *out_metafile
= NULL
;
3981 FIXME("not implemented\n");
3983 return NotImplemented
;
3986 GpStatus WINGDIPAPI
GdipEmfToWmfBits(HENHMETAFILE hemf
, UINT cbData16
,
3987 LPBYTE pData16
, INT iMapMode
, INT eFlags
)
3989 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf
, cbData16
, pData16
, iMapMode
, eFlags
);
3990 return NotImplemented
;
3993 GpStatus WINGDIPAPI
GdipRecordMetafileFileName(GDIPCONST WCHAR
* fileName
,
3994 HDC hdc
, EmfType type
, GDIPCONST GpRectF
*pFrameRect
,
3995 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
,
3996 GpMetafile
**metafile
)
3998 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
3999 frameUnit
, debugstr_w(desc
), metafile
);
4001 return NotImplemented
;
4004 GpStatus WINGDIPAPI
GdipRecordMetafileFileNameI(GDIPCONST WCHAR
* fileName
, HDC hdc
, EmfType type
,
4005 GDIPCONST GpRect
*pFrameRect
, MetafileFrameUnit frameUnit
,
4006 GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
4008 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
4009 frameUnit
, debugstr_w(desc
), metafile
);
4011 return NotImplemented
;
4014 /*****************************************************************************
4015 * GdipConvertToEmfPlusToFile [GDIPLUS.@]
4018 GpStatus WINGDIPAPI
GdipConvertToEmfPlusToFile(const GpGraphics
* refGraphics
,
4019 GpMetafile
* metafile
, BOOL
* conversionSuccess
,
4020 const WCHAR
* filename
, EmfType emfType
,
4021 const WCHAR
* description
, GpMetafile
** out_metafile
)
4023 FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics
, metafile
, conversionSuccess
, filename
, emfType
, description
, out_metafile
);
4024 return NotImplemented
;
4027 static GpStatus
METAFILE_CreateCompressedImageStream(GpImage
*image
, IStream
**stream
, DWORD
*size
)
4036 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, stream
);
4037 if (FAILED(hr
)) return hresult_to_status(hr
);
4039 stat
= encode_image_png(image
, *stream
, NULL
);
4042 IStream_Release(*stream
);
4046 hr
= IStream_Stat(*stream
, &statstg
, 1);
4049 IStream_Release(*stream
);
4050 return hresult_to_status(hr
);
4052 *size
= statstg
.cbSize
.u
.LowPart
;
4055 hr
= IStream_Seek(*stream
, zero
, STREAM_SEEK_SET
, NULL
);
4058 IStream_Release(*stream
);
4059 return hresult_to_status(hr
);
4065 static GpStatus
METAFILE_FillEmfPlusBitmap(EmfPlusBitmap
*record
, IStream
*stream
, DWORD size
)
4072 record
->PixelFormat
= 0;
4073 record
->Type
= BitmapDataTypeCompressed
;
4075 hr
= IStream_Read(stream
, record
->BitmapData
, size
, NULL
);
4076 if (FAILED(hr
)) return hresult_to_status(hr
);
4080 static GpStatus
METAFILE_AddImageObject(GpMetafile
*metafile
, GpImage
*image
, DWORD
*id
)
4082 EmfPlusObject
*object_record
;
4088 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4091 if (image
->type
== ImageTypeBitmap
)
4096 stat
= METAFILE_CreateCompressedImageStream(image
, &stream
, &size
);
4097 if (stat
!= Ok
) return stat
;
4098 aligned_size
= (size
+ 3) & ~3;
4100 stat
= METAFILE_AllocateRecord(metafile
,
4101 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image
.ImageData
.bitmap
.BitmapData
[aligned_size
]),
4102 (void**)&object_record
);
4105 IStream_Release(stream
);
4108 memset(object_record
->ObjectData
.image
.ImageData
.bitmap
.BitmapData
+ size
, 0, aligned_size
- size
);
4110 *id
= METAFILE_AddObjectId(metafile
);
4111 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
4112 object_record
->Header
.Flags
= *id
| ObjectTypeImage
<< 8;
4113 object_record
->ObjectData
.image
.Version
= VERSION_MAGIC2
;
4114 object_record
->ObjectData
.image
.Type
= ImageDataTypeBitmap
;
4116 stat
= METAFILE_FillEmfPlusBitmap(&object_record
->ObjectData
.image
.ImageData
.bitmap
, stream
, size
);
4117 IStream_Release(stream
);
4118 if (stat
!= Ok
) METAFILE_RemoveLastRecord(metafile
, &object_record
->Header
);
4121 else if (image
->type
== ImageTypeMetafile
)
4123 HENHMETAFILE hemf
= ((GpMetafile
*)image
)->hemf
;
4124 EmfPlusMetafile
*metafile_record
;
4126 if (!hemf
) return InvalidParameter
;
4128 size
= GetEnhMetaFileBits(hemf
, 0, NULL
);
4129 if (!size
) return GenericError
;
4131 stat
= METAFILE_AllocateRecord(metafile
,
4132 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image
.ImageData
.metafile
.MetafileData
[size
]),
4133 (void**)&object_record
);
4134 if (stat
!= Ok
) return stat
;
4136 *id
= METAFILE_AddObjectId(metafile
);
4137 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
4138 object_record
->Header
.Flags
= *id
| ObjectTypeImage
<< 8;
4139 object_record
->ObjectData
.image
.Version
= VERSION_MAGIC2
;
4140 object_record
->ObjectData
.image
.Type
= ImageDataTypeMetafile
;
4141 metafile_record
= &object_record
->ObjectData
.image
.ImageData
.metafile
;
4142 metafile_record
->Type
= ((GpMetafile
*)image
)->metafile_type
;
4143 metafile_record
->MetafileDataSize
= size
;
4144 if (GetEnhMetaFileBits(hemf
, size
, metafile_record
->MetafileData
) != size
)
4146 METAFILE_RemoveLastRecord(metafile
, &object_record
->Header
);
4147 return GenericError
;
4153 FIXME("not supported image type (%d)\n", image
->type
);
4154 return NotImplemented
;
4158 static GpStatus
METAFILE_AddImageAttributesObject(GpMetafile
*metafile
, const GpImageAttributes
*attrs
, DWORD
*id
)
4160 EmfPlusObject
*object_record
;
4161 EmfPlusImageAttributes
*attrs_record
;
4166 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4172 stat
= METAFILE_AllocateRecord(metafile
,
4173 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image_attributes
) + sizeof(EmfPlusImageAttributes
),
4174 (void**)&object_record
);
4175 if (stat
!= Ok
) return stat
;
4177 *id
= METAFILE_AddObjectId(metafile
);
4178 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
4179 object_record
->Header
.Flags
= *id
| (ObjectTypeImageAttributes
<< 8);
4180 attrs_record
= &object_record
->ObjectData
.image_attributes
;
4181 attrs_record
->Version
= VERSION_MAGIC2
;
4182 attrs_record
->Reserved1
= 0;
4183 attrs_record
->WrapMode
= attrs
->wrap
;
4184 attrs_record
->ClampColor
= attrs
->outside_color
;
4185 attrs_record
->ObjectClamp
= attrs
->clamp
;
4186 attrs_record
->Reserved2
= 0;
4190 GpStatus
METAFILE_DrawImagePointsRect(GpMetafile
*metafile
, GpImage
*image
,
4191 GDIPCONST GpPointF
*points
, INT count
, REAL srcx
, REAL srcy
, REAL srcwidth
,
4192 REAL srcheight
, GpUnit srcUnit
, GDIPCONST GpImageAttributes
* imageAttributes
,
4193 DrawImageAbort callback
, VOID
*callbackData
)
4195 EmfPlusDrawImagePoints
*draw_image_record
;
4196 DWORD image_id
, attributes_id
;
4199 if (count
!= 3) return InvalidParameter
;
4201 if (metafile
->metafile_type
== MetafileTypeEmf
)
4203 FIXME("MetafileTypeEmf metafiles not supported\n");
4204 return NotImplemented
;
4207 FIXME("semi-stub\n");
4209 if (!imageAttributes
)
4211 stat
= METAFILE_AddImageObject(metafile
, image
, &image_id
);
4213 else if (image
->type
== ImageTypeBitmap
)
4215 INT width
= ((GpBitmap
*)image
)->width
;
4216 INT height
= ((GpBitmap
*)image
)->height
;
4217 GpGraphics
*graphics
;
4220 stat
= GdipCreateBitmapFromScan0(width
, height
,
4221 0, PixelFormat32bppARGB
, NULL
, &bitmap
);
4222 if (stat
!= Ok
) return stat
;
4224 stat
= GdipGetImageGraphicsContext((GpImage
*)bitmap
, &graphics
);
4227 GdipDisposeImage((GpImage
*)bitmap
);
4231 stat
= GdipDrawImageRectRectI(graphics
, image
, 0, 0, width
, height
,
4232 0, 0, width
, height
, UnitPixel
, imageAttributes
, NULL
, NULL
);
4233 GdipDeleteGraphics(graphics
);
4236 GdipDisposeImage((GpImage
*)bitmap
);
4240 stat
= METAFILE_AddImageObject(metafile
, (GpImage
*)bitmap
, &image_id
);
4241 GdipDisposeImage((GpImage
*)bitmap
);
4245 FIXME("imageAttributes not supported (image type %d)\n", image
->type
);
4246 return NotImplemented
;
4248 if (stat
!= Ok
) return stat
;
4250 stat
= METAFILE_AddImageAttributesObject(metafile
, imageAttributes
, &attributes_id
);
4251 if (stat
!= Ok
) return stat
;
4253 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusDrawImagePoints
), (void**)&draw_image_record
);
4254 if (stat
!= Ok
) return stat
;
4255 draw_image_record
->Header
.Type
= EmfPlusRecordTypeDrawImagePoints
;
4256 draw_image_record
->Header
.Flags
= image_id
;
4257 draw_image_record
->ImageAttributesID
= attributes_id
;
4258 draw_image_record
->SrcUnit
= UnitPixel
;
4259 draw_image_record
->SrcRect
.X
= units_to_pixels(srcx
, srcUnit
, metafile
->image
.xres
);
4260 draw_image_record
->SrcRect
.Y
= units_to_pixels(srcy
, srcUnit
, metafile
->image
.yres
);
4261 draw_image_record
->SrcRect
.Width
= units_to_pixels(srcwidth
, srcUnit
, metafile
->image
.xres
);
4262 draw_image_record
->SrcRect
.Height
= units_to_pixels(srcheight
, srcUnit
, metafile
->image
.yres
);
4263 draw_image_record
->count
= 3;
4264 memcpy(draw_image_record
->PointData
.pointsF
, points
, 3 * sizeof(*points
));
4265 METAFILE_WriteRecords(metafile
);
4269 GpStatus
METAFILE_AddSimpleProperty(GpMetafile
*metafile
, SHORT prop
, SHORT val
)
4271 EmfPlusRecordHeader
*record
;
4274 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4277 stat
= METAFILE_AllocateRecord(metafile
, sizeof(*record
), (void**)&record
);
4278 if (stat
!= Ok
) return stat
;
4280 record
->Type
= prop
;
4281 record
->Flags
= val
;
4283 METAFILE_WriteRecords(metafile
);
4287 static GpStatus
METAFILE_AddPathObject(GpMetafile
*metafile
, GpPath
*path
, DWORD
*id
)
4289 EmfPlusObject
*object_record
;
4294 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4297 size
= write_path_data(path
, NULL
);
4298 stat
= METAFILE_AllocateRecord(metafile
,
4299 FIELD_OFFSET(EmfPlusObject
, ObjectData
.path
) + size
,
4300 (void**)&object_record
);
4301 if (stat
!= Ok
) return stat
;
4303 *id
= METAFILE_AddObjectId(metafile
);
4304 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
4305 object_record
->Header
.Flags
= *id
| ObjectTypePath
<< 8;
4306 write_path_data(path
, &object_record
->ObjectData
.path
);
4310 static GpStatus
METAFILE_AddPenObject(GpMetafile
*metafile
, GpPen
*pen
, DWORD
*id
)
4312 DWORD i
, data_flags
, pen_data_size
, brush_size
;
4313 EmfPlusObject
*object_record
;
4314 EmfPlusPenData
*pen_data
;
4319 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4323 pen_data_size
= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
4325 GdipIsMatrixIdentity(&pen
->transform
, &result
);
4328 data_flags
|= PenDataTransform
;
4329 pen_data_size
+= sizeof(EmfPlusTransformMatrix
);
4331 if (pen
->startcap
!= LineCapFlat
)
4333 data_flags
|= PenDataStartCap
;
4334 pen_data_size
+= sizeof(DWORD
);
4336 if (pen
->endcap
!= LineCapFlat
)
4338 data_flags
|= PenDataEndCap
;
4339 pen_data_size
+= sizeof(DWORD
);
4341 if (pen
->join
!= LineJoinMiter
)
4343 data_flags
|= PenDataJoin
;
4344 pen_data_size
+= sizeof(DWORD
);
4346 if (pen
->miterlimit
!= 10.0)
4348 data_flags
|= PenDataMiterLimit
;
4349 pen_data_size
+= sizeof(REAL
);
4351 if (pen
->style
!= GP_DEFAULT_PENSTYLE
)
4353 data_flags
|= PenDataLineStyle
;
4354 pen_data_size
+= sizeof(DWORD
);
4356 if (pen
->dashcap
!= DashCapFlat
)
4358 data_flags
|= PenDataDashedLineCap
;
4359 pen_data_size
+= sizeof(DWORD
);
4361 data_flags
|= PenDataDashedLineOffset
;
4362 pen_data_size
+= sizeof(REAL
);
4365 data_flags
|= PenDataDashedLine
;
4366 pen_data_size
+= sizeof(DWORD
) + pen
->numdashes
*sizeof(REAL
);
4368 if (pen
->align
!= PenAlignmentCenter
)
4370 data_flags
|= PenDataNonCenter
;
4371 pen_data_size
+= sizeof(DWORD
);
4373 /* TODO: Add support for PenDataCompoundLine */
4374 if (pen
->customstart
)
4376 FIXME("ignoring custom start cup\n");
4380 FIXME("ignoring custom end cup\n");
4383 stat
= METAFILE_PrepareBrushData(pen
->brush
, &brush_size
);
4384 if (stat
!= Ok
) return stat
;
4386 stat
= METAFILE_AllocateRecord(metafile
,
4387 FIELD_OFFSET(EmfPlusObject
, ObjectData
.pen
.data
) + pen_data_size
+ brush_size
,
4388 (void**)&object_record
);
4389 if (stat
!= Ok
) return stat
;
4391 *id
= METAFILE_AddObjectId(metafile
);
4392 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
4393 object_record
->Header
.Flags
= *id
| ObjectTypePen
<< 8;
4394 object_record
->ObjectData
.pen
.Version
= VERSION_MAGIC2
;
4395 object_record
->ObjectData
.pen
.Type
= 0;
4397 pen_data
= (EmfPlusPenData
*)object_record
->ObjectData
.pen
.data
;
4398 pen_data
->PenDataFlags
= data_flags
;
4399 pen_data
->PenUnit
= pen
->unit
;
4400 pen_data
->PenWidth
= pen
->width
;
4403 if (data_flags
& PenDataTransform
)
4405 EmfPlusTransformMatrix
*m
= (EmfPlusTransformMatrix
*)(pen_data
->OptionalData
+ i
);
4406 memcpy(m
, &pen
->transform
, sizeof(*m
));
4407 i
+= sizeof(EmfPlusTransformMatrix
);
4409 if (data_flags
& PenDataStartCap
)
4411 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->startcap
;
4414 if (data_flags
& PenDataEndCap
)
4416 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->endcap
;
4419 if (data_flags
& PenDataJoin
)
4421 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->join
;
4424 if (data_flags
& PenDataMiterLimit
)
4426 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->miterlimit
;
4429 if (data_flags
& PenDataLineStyle
)
4431 switch (pen
->style
& PS_STYLE_MASK
)
4433 case PS_SOLID
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleSolid
; break;
4434 case PS_DASH
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDash
; break;
4435 case PS_DOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDot
; break;
4436 case PS_DASHDOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDashDot
; break;
4437 case PS_DASHDOTDOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDashDotDot
; break;
4438 default: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleCustom
; break;
4442 if (data_flags
& PenDataDashedLineCap
)
4444 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->dashcap
;
4447 if (data_flags
& PenDataDashedLineOffset
)
4449 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->offset
;
4452 if (data_flags
& PenDataDashedLine
)
4456 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->numdashes
;
4459 for (j
=0; j
<pen
->numdashes
; j
++)
4461 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->dashes
[j
];
4465 if (data_flags
& PenDataNonCenter
)
4467 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->align
;
4471 METAFILE_FillBrushData(pen
->brush
,
4472 (EmfPlusBrush
*)(object_record
->ObjectData
.pen
.data
+ pen_data_size
));
4476 GpStatus
METAFILE_DrawPath(GpMetafile
*metafile
, GpPen
*pen
, GpPath
*path
)
4478 EmfPlusDrawPath
*draw_path_record
;
4483 if (metafile
->metafile_type
== MetafileTypeEmf
)
4486 return NotImplemented
;
4489 stat
= METAFILE_AddPenObject(metafile
, pen
, &pen_id
);
4490 if (stat
!= Ok
) return stat
;
4492 stat
= METAFILE_AddPathObject(metafile
, path
, &path_id
);
4493 if (stat
!= Ok
) return stat
;
4495 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusDrawPath
), (void**)&draw_path_record
);
4496 if (stat
!= Ok
) return stat
;
4497 draw_path_record
->Header
.Type
= EmfPlusRecordTypeDrawPath
;
4498 draw_path_record
->Header
.Flags
= path_id
;
4499 draw_path_record
->PenId
= pen_id
;
4501 METAFILE_WriteRecords(metafile
);
4505 GpStatus
METAFILE_FillPath(GpMetafile
*metafile
, GpBrush
*brush
, GpPath
*path
)
4507 EmfPlusFillPath
*fill_path_record
;
4508 DWORD brush_id
= -1, path_id
;
4512 if (metafile
->metafile_type
== MetafileTypeEmf
)
4515 return NotImplemented
;
4518 inline_color
= brush
->bt
== BrushTypeSolidColor
;
4521 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
4522 if (stat
!= Ok
) return stat
;
4525 stat
= METAFILE_AddPathObject(metafile
, path
, &path_id
);
4526 if (stat
!= Ok
) return stat
;
4528 stat
= METAFILE_AllocateRecord(metafile
,
4529 sizeof(EmfPlusFillPath
), (void**)&fill_path_record
);
4530 if (stat
!= Ok
) return stat
;
4531 fill_path_record
->Header
.Type
= EmfPlusRecordTypeFillPath
;
4534 fill_path_record
->Header
.Flags
= 0x8000 | path_id
;
4535 fill_path_record
->data
.Color
= ((GpSolidFill
*)brush
)->color
;
4539 fill_path_record
->Header
.Flags
= path_id
;
4540 fill_path_record
->data
.BrushId
= brush_id
;
4543 METAFILE_WriteRecords(metafile
);