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 EmfPlusBrush
264 EmfPlusSolidBrushData solid
;
265 EmfPlusHatchBrushData hatch
;
266 EmfPlusTextureBrushData texture
;
270 typedef struct EmfPlusPen
279 typedef struct EmfPlusPath
282 DWORD PathPointCount
;
283 DWORD PathPointFlags
;
285 /* PathPointTypes[] */
286 /* AlignmentPadding */
290 typedef struct EmfPlusRegionNodePath
292 DWORD RegionNodePathLength
;
293 EmfPlusPath RegionNodePath
;
294 } EmfPlusRegionNodePath
;
296 typedef struct EmfPlusRegion
299 DWORD RegionNodeCount
;
303 typedef struct EmfPlusPalette
305 DWORD PaletteStyleFlags
;
307 BYTE PaletteEntries
[1];
313 BitmapDataTypeCompressed
,
316 typedef struct EmfPlusBitmap
326 typedef struct EmfPlusMetafile
329 DWORD MetafileDataSize
;
330 BYTE MetafileData
[1];
333 typedef enum ImageDataType
335 ImageDataTypeUnknown
,
337 ImageDataTypeMetafile
,
340 typedef struct EmfPlusImage
346 EmfPlusBitmap bitmap
;
347 EmfPlusMetafile metafile
;
351 typedef struct EmfPlusImageAttributes
356 EmfPlusARGB ClampColor
;
359 } EmfPlusImageAttributes
;
361 typedef struct EmfPlusObject
363 EmfPlusRecordHeader Header
;
369 EmfPlusRegion region
;
371 EmfPlusImageAttributes image_attributes
;
375 typedef struct EmfPlusRectF
383 typedef struct EmfPlusPointR7
389 typedef struct EmfPlusPoint
395 typedef struct EmfPlusPointF
401 typedef struct EmfPlusDrawImage
403 EmfPlusRecordHeader Header
;
404 DWORD ImageAttributesID
;
406 EmfPlusRectF SrcRect
;
414 typedef struct EmfPlusDrawImagePoints
416 EmfPlusRecordHeader Header
;
417 DWORD ImageAttributesID
;
419 EmfPlusRectF SrcRect
;
423 EmfPlusPointR7 pointsR
[3];
424 EmfPlusPoint points
[3];
425 EmfPlusPointF pointsF
[3];
427 } EmfPlusDrawImagePoints
;
429 typedef struct EmfPlusDrawPath
431 EmfPlusRecordHeader Header
;
435 typedef struct EmfPlusDrawPie
437 EmfPlusRecordHeader Header
;
447 typedef struct EmfPlusDrawRects
449 EmfPlusRecordHeader Header
;
454 EmfPlusRectF rectF
[1];
458 typedef struct EmfPlusFillPath
460 EmfPlusRecordHeader Header
;
468 typedef struct EmfPlusFont
473 DWORD FontStyleFlags
;
479 static void metafile_free_object_table_entry(GpMetafile
*metafile
, BYTE id
)
481 struct emfplus_object
*object
= &metafile
->objtable
[id
];
483 switch (object
->type
)
485 case ObjectTypeInvalid
:
487 case ObjectTypeBrush
:
488 GdipDeleteBrush(object
->u
.brush
);
491 GdipDeletePen(object
->u
.pen
);
494 GdipDeletePath(object
->u
.path
);
496 case ObjectTypeRegion
:
497 GdipDeleteRegion(object
->u
.region
);
499 case ObjectTypeImage
:
500 GdipDisposeImage(object
->u
.image
);
503 GdipDeleteFont(object
->u
.font
);
505 case ObjectTypeImageAttributes
:
506 GdipDisposeImageAttributes(object
->u
.image_attributes
);
509 FIXME("not implemented for object type %u.\n", object
->type
);
513 object
->type
= ObjectTypeInvalid
;
514 object
->u
.object
= NULL
;
517 void METAFILE_Free(GpMetafile
*metafile
)
521 heap_free(metafile
->comment_data
);
522 DeleteEnhMetaFile(CloseEnhMetaFile(metafile
->record_dc
));
523 if (!metafile
->preserve_hemf
)
524 DeleteEnhMetaFile(metafile
->hemf
);
525 if (metafile
->record_graphics
)
527 WARN("metafile closed while recording\n");
528 /* not sure what to do here; for now just prevent the graphics from functioning or using this object */
529 metafile
->record_graphics
->image
= NULL
;
530 metafile
->record_graphics
->busy
= TRUE
;
533 if (metafile
->record_stream
)
534 IStream_Release(metafile
->record_stream
);
536 for (i
= 0; i
< sizeof(metafile
->objtable
)/sizeof(metafile
->objtable
[0]); i
++)
537 metafile_free_object_table_entry(metafile
, i
);
540 static DWORD
METAFILE_AddObjectId(GpMetafile
*metafile
)
542 return (metafile
->next_object_id
++) % EmfPlusObjectTableSize
;
545 static GpStatus
METAFILE_AllocateRecord(GpMetafile
*metafile
, DWORD size
, void **result
)
548 EmfPlusRecordHeader
*record
;
550 if (!metafile
->comment_data_size
)
552 DWORD data_size
= max(256, size
* 2 + 4);
553 metafile
->comment_data
= heap_alloc_zero(data_size
);
555 if (!metafile
->comment_data
)
558 memcpy(metafile
->comment_data
, "EMF+", 4);
560 metafile
->comment_data_size
= data_size
;
561 metafile
->comment_data_length
= 4;
564 size_needed
= size
+ metafile
->comment_data_length
;
566 if (size_needed
> metafile
->comment_data_size
)
568 DWORD data_size
= size_needed
* 2;
569 BYTE
*new_data
= heap_alloc_zero(data_size
);
574 memcpy(new_data
, metafile
->comment_data
, metafile
->comment_data_length
);
576 metafile
->comment_data_size
= data_size
;
577 heap_free(metafile
->comment_data
);
578 metafile
->comment_data
= new_data
;
581 *result
= metafile
->comment_data
+ metafile
->comment_data_length
;
582 metafile
->comment_data_length
+= size
;
584 record
= (EmfPlusRecordHeader
*)*result
;
586 record
->DataSize
= size
- sizeof(EmfPlusRecordHeader
);
591 static void METAFILE_RemoveLastRecord(GpMetafile
*metafile
, EmfPlusRecordHeader
*record
)
593 assert(metafile
->comment_data
+ metafile
->comment_data_length
== (BYTE
*)record
+ record
->Size
);
594 metafile
->comment_data_length
-= record
->Size
;
597 static void METAFILE_WriteRecords(GpMetafile
*metafile
)
599 if (metafile
->comment_data_length
> 4)
601 GdiComment(metafile
->record_dc
, metafile
->comment_data_length
, metafile
->comment_data
);
602 metafile
->comment_data_length
= 4;
606 static GpStatus
METAFILE_WriteHeader(GpMetafile
*metafile
, HDC hdc
)
610 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
612 EmfPlusHeader
*header
;
614 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusHeader
), (void**)&header
);
618 header
->Header
.Type
= EmfPlusRecordTypeHeader
;
620 if (metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
621 header
->Header
.Flags
= 1;
623 header
->Header
.Flags
= 0;
625 header
->Version
= VERSION_MAGIC2
;
627 if (GetDeviceCaps(hdc
, TECHNOLOGY
) == DT_RASDISPLAY
)
628 header
->EmfPlusFlags
= 1;
630 header
->EmfPlusFlags
= 0;
632 header
->LogicalDpiX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
633 header
->LogicalDpiY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
635 METAFILE_WriteRecords(metafile
);
641 static GpStatus
METAFILE_WriteEndOfFile(GpMetafile
*metafile
)
645 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
647 EmfPlusRecordHeader
*record
;
649 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
653 record
->Type
= EmfPlusRecordTypeEndOfFile
;
656 METAFILE_WriteRecords(metafile
);
662 GpStatus WINGDIPAPI
GdipRecordMetafile(HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
663 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
667 REAL framerect_factor_x
, framerect_factor_y
;
671 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
673 if (!hdc
|| type
< EmfTypeEmfOnly
|| type
> EmfTypeEmfPlusDual
|| !metafile
)
674 return InvalidParameter
;
676 dpix
= (REAL
)GetDeviceCaps(hdc
, HORZRES
) / GetDeviceCaps(hdc
, HORZSIZE
) * 25.4;
677 dpiy
= (REAL
)GetDeviceCaps(hdc
, VERTRES
) / GetDeviceCaps(hdc
, VERTSIZE
) * 25.4;
683 case MetafileFrameUnitPixel
:
684 framerect_factor_x
= 2540.0 / dpix
;
685 framerect_factor_y
= 2540.0 / dpiy
;
687 case MetafileFrameUnitPoint
:
688 framerect_factor_x
= framerect_factor_y
= 2540.0 / 72.0;
690 case MetafileFrameUnitInch
:
691 framerect_factor_x
= framerect_factor_y
= 2540.0;
693 case MetafileFrameUnitDocument
:
694 framerect_factor_x
= framerect_factor_y
= 2540.0 / 300.0;
696 case MetafileFrameUnitMillimeter
:
697 framerect_factor_x
= framerect_factor_y
= 100.0;
699 case MetafileFrameUnitGdi
:
700 framerect_factor_x
= framerect_factor_y
= 1.0;
703 return InvalidParameter
;
706 rc
.left
= framerect_factor_x
* frameRect
->X
;
707 rc
.top
= framerect_factor_y
* frameRect
->Y
;
708 rc
.right
= rc
.left
+ framerect_factor_x
* frameRect
->Width
;
709 rc
.bottom
= rc
.top
+ framerect_factor_y
* frameRect
->Height
;
716 record_dc
= CreateEnhMetaFileW(hdc
, NULL
, lprc
, desc
);
721 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
724 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
728 (*metafile
)->image
.type
= ImageTypeMetafile
;
729 (*metafile
)->image
.flags
= ImageFlagsNone
;
730 (*metafile
)->image
.palette
= NULL
;
731 (*metafile
)->image
.xres
= dpix
;
732 (*metafile
)->image
.yres
= dpiy
;
733 (*metafile
)->bounds
.X
= (*metafile
)->bounds
.Y
= 0.0;
734 (*metafile
)->bounds
.Width
= (*metafile
)->bounds
.Height
= 1.0;
735 (*metafile
)->unit
= UnitPixel
;
736 (*metafile
)->metafile_type
= type
;
737 (*metafile
)->record_dc
= record_dc
;
738 (*metafile
)->comment_data
= NULL
;
739 (*metafile
)->comment_data_size
= 0;
740 (*metafile
)->comment_data_length
= 0;
741 (*metafile
)->hemf
= NULL
;
742 list_init(&(*metafile
)->containers
);
746 (*metafile
)->auto_frame
= TRUE
;
747 (*metafile
)->auto_frame_min
.X
= 0;
748 (*metafile
)->auto_frame_min
.Y
= 0;
749 (*metafile
)->auto_frame_max
.X
= -1;
750 (*metafile
)->auto_frame_max
.Y
= -1;
753 stat
= METAFILE_WriteHeader(*metafile
, hdc
);
757 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
758 heap_free(*metafile
);
766 /*****************************************************************************
767 * GdipRecordMetafileI [GDIPLUS.@]
769 GpStatus WINGDIPAPI
GdipRecordMetafileI(HDC hdc
, EmfType type
, GDIPCONST GpRect
*frameRect
,
770 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
772 GpRectF frameRectF
, *pFrameRectF
;
774 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
778 frameRectF
.X
= frameRect
->X
;
779 frameRectF
.Y
= frameRect
->Y
;
780 frameRectF
.Width
= frameRect
->Width
;
781 frameRectF
.Height
= frameRect
->Height
;
782 pFrameRectF
= &frameRectF
;
787 return GdipRecordMetafile(hdc
, type
, pFrameRectF
, frameUnit
, desc
, metafile
);
790 GpStatus WINGDIPAPI
GdipRecordMetafileStream(IStream
*stream
, HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
791 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
795 TRACE("(%p %p %d %p %d %p %p)\n", stream
, hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
798 return InvalidParameter
;
800 stat
= GdipRecordMetafile(hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
804 (*metafile
)->record_stream
= stream
;
805 IStream_AddRef(stream
);
811 static void METAFILE_AdjustFrame(GpMetafile
* metafile
, const GpPointF
*points
,
816 if (!metafile
->auto_frame
|| !num_points
)
819 if (metafile
->auto_frame_max
.X
< metafile
->auto_frame_min
.X
)
820 metafile
->auto_frame_max
= metafile
->auto_frame_min
= points
[0];
822 for (i
=0; i
<num_points
; i
++)
824 if (points
[i
].X
< metafile
->auto_frame_min
.X
)
825 metafile
->auto_frame_min
.X
= points
[i
].X
;
826 if (points
[i
].X
> metafile
->auto_frame_max
.X
)
827 metafile
->auto_frame_max
.X
= points
[i
].X
;
828 if (points
[i
].Y
< metafile
->auto_frame_min
.Y
)
829 metafile
->auto_frame_min
.Y
= points
[i
].Y
;
830 if (points
[i
].Y
> metafile
->auto_frame_max
.Y
)
831 metafile
->auto_frame_max
.Y
= points
[i
].Y
;
835 GpStatus
METAFILE_GetGraphicsContext(GpMetafile
* metafile
, GpGraphics
**result
)
839 if (!metafile
->record_dc
|| metafile
->record_graphics
)
840 return InvalidParameter
;
842 stat
= graphics_from_image((GpImage
*)metafile
, &metafile
->record_graphics
);
846 *result
= metafile
->record_graphics
;
847 metafile
->record_graphics
->xres
= 96.0;
848 metafile
->record_graphics
->yres
= 96.0;
854 GpStatus
METAFILE_GetDC(GpMetafile
* metafile
, HDC
*hdc
)
856 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
858 EmfPlusRecordHeader
*record
;
861 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
865 record
->Type
= EmfPlusRecordTypeGetDC
;
868 METAFILE_WriteRecords(metafile
);
871 *hdc
= metafile
->record_dc
;
876 GpStatus
METAFILE_GraphicsClear(GpMetafile
* metafile
, ARGB color
)
878 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
880 EmfPlusClear
*record
;
883 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusClear
), (void**)&record
);
887 record
->Header
.Type
= EmfPlusRecordTypeClear
;
888 record
->Header
.Flags
= 0;
889 record
->Color
= color
;
891 METAFILE_WriteRecords(metafile
);
897 static BOOL
is_integer_rect(const GpRectF
*rect
)
899 SHORT x
, y
, width
, height
;
903 height
= rect
->Height
;
904 if (rect
->X
!= (REAL
)x
|| rect
->Y
!= (REAL
)y
||
905 rect
->Width
!= (REAL
)width
|| rect
->Height
!= (REAL
)height
)
910 GpStatus
METAFILE_FillRectangles(GpMetafile
* metafile
, GpBrush
* brush
,
911 GDIPCONST GpRectF
* rects
, INT count
)
913 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
915 EmfPlusFillRects
*record
;
917 BOOL integer_rects
= TRUE
;
922 if (brush
->bt
== BrushTypeSolidColor
)
925 brushid
= ((GpSolidFill
*)brush
)->color
;
929 FIXME("brush serialization not implemented\n");
930 return NotImplemented
;
933 for (i
=0; i
<count
; i
++)
935 if (!is_integer_rect(&rects
[i
]))
937 integer_rects
= FALSE
;
945 stat
= METAFILE_AllocateRecord(metafile
,
946 sizeof(EmfPlusFillRects
) + count
* (integer_rects
? sizeof(EmfPlusRect
) : sizeof(GpRectF
)),
951 record
->Header
.Type
= EmfPlusRecordTypeFillRects
;
952 record
->Header
.Flags
= flags
;
953 record
->BrushID
= brushid
;
954 record
->Count
= count
;
958 EmfPlusRect
*record_rects
= (EmfPlusRect
*)(record
+1);
959 for (i
=0; i
<count
; i
++)
961 record_rects
[i
].X
= (SHORT
)rects
[i
].X
;
962 record_rects
[i
].Y
= (SHORT
)rects
[i
].Y
;
963 record_rects
[i
].Width
= (SHORT
)rects
[i
].Width
;
964 record_rects
[i
].Height
= (SHORT
)rects
[i
].Height
;
968 memcpy(record
+1, rects
, sizeof(GpRectF
) * count
);
970 METAFILE_WriteRecords(metafile
);
973 if (metafile
->auto_frame
)
978 for (i
=0; i
<count
; i
++)
980 corners
[0].X
= rects
[i
].X
;
981 corners
[0].Y
= rects
[i
].Y
;
982 corners
[1].X
= rects
[i
].X
+ rects
[i
].Width
;
983 corners
[1].Y
= rects
[i
].Y
;
984 corners
[2].X
= rects
[i
].X
;
985 corners
[2].Y
= rects
[i
].Y
+ rects
[i
].Height
;
986 corners
[3].X
= rects
[i
].X
+ rects
[i
].Width
;
987 corners
[3].Y
= rects
[i
].Y
+ rects
[i
].Height
;
989 GdipTransformPoints(metafile
->record_graphics
, CoordinateSpaceDevice
,
990 CoordinateSpaceWorld
, corners
, 4);
992 METAFILE_AdjustFrame(metafile
, corners
, 4);
999 GpStatus
METAFILE_SetClipRect(GpMetafile
* metafile
, REAL x
, REAL y
, REAL width
, REAL height
, CombineMode mode
)
1001 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1003 EmfPlusSetClipRect
*record
;
1006 stat
= METAFILE_AllocateRecord(metafile
,
1007 sizeof(EmfPlusSetClipRect
),
1012 record
->Header
.Type
= EmfPlusRecordTypeSetClipRect
;
1013 record
->Header
.Flags
= (mode
& 0xf) << 8;
1014 record
->ClipRect
.X
= x
;
1015 record
->ClipRect
.Y
= y
;
1016 record
->ClipRect
.Width
= width
;
1017 record
->ClipRect
.Height
= height
;
1019 METAFILE_WriteRecords(metafile
);
1025 static GpStatus
METAFILE_AddRegionObject(GpMetafile
*metafile
, GpRegion
*region
, DWORD
*id
)
1027 EmfPlusObject
*object_record
;
1032 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
1035 size
= write_region_data(region
, NULL
);
1036 stat
= METAFILE_AllocateRecord(metafile
,
1037 FIELD_OFFSET(EmfPlusObject
, ObjectData
.region
) + size
, (void**)&object_record
);
1038 if (stat
!= Ok
) return stat
;
1040 *id
= METAFILE_AddObjectId(metafile
);
1041 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
1042 object_record
->Header
.Flags
= *id
| ObjectTypeRegion
<< 8;
1043 write_region_data(region
, &object_record
->ObjectData
.region
);
1047 GpStatus
METAFILE_SetClipRegion(GpMetafile
* metafile
, GpRegion
* region
, CombineMode mode
)
1049 EmfPlusRecordHeader
*record
;
1053 if (metafile
->metafile_type
== MetafileTypeEmf
)
1056 return NotImplemented
;
1059 stat
= METAFILE_AddRegionObject(metafile
, region
, ®ion_id
);
1060 if (stat
!= Ok
) return stat
;
1062 stat
= METAFILE_AllocateRecord(metafile
, sizeof(*record
), (void**)&record
);
1063 if (stat
!= Ok
) return stat
;
1065 record
->Type
= EmfPlusRecordTypeSetClipRegion
;
1066 record
->Flags
= region_id
| mode
<< 8;
1068 METAFILE_WriteRecords(metafile
);
1072 GpStatus
METAFILE_SetPageTransform(GpMetafile
* metafile
, GpUnit unit
, REAL scale
)
1074 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1076 EmfPlusSetPageTransform
*record
;
1079 stat
= METAFILE_AllocateRecord(metafile
,
1080 sizeof(EmfPlusSetPageTransform
),
1085 record
->Header
.Type
= EmfPlusRecordTypeSetPageTransform
;
1086 record
->Header
.Flags
= unit
;
1087 record
->PageScale
= scale
;
1089 METAFILE_WriteRecords(metafile
);
1095 GpStatus
METAFILE_SetWorldTransform(GpMetafile
* metafile
, GDIPCONST GpMatrix
* transform
)
1097 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1099 EmfPlusSetWorldTransform
*record
;
1102 stat
= METAFILE_AllocateRecord(metafile
,
1103 sizeof(EmfPlusSetWorldTransform
),
1108 record
->Header
.Type
= EmfPlusRecordTypeSetWorldTransform
;
1109 record
->Header
.Flags
= 0;
1110 memcpy(record
->MatrixData
, transform
->matrix
, sizeof(record
->MatrixData
));
1112 METAFILE_WriteRecords(metafile
);
1118 GpStatus
METAFILE_ScaleWorldTransform(GpMetafile
* metafile
, REAL sx
, REAL sy
, MatrixOrder order
)
1120 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1122 EmfPlusScaleWorldTransform
*record
;
1125 stat
= METAFILE_AllocateRecord(metafile
,
1126 sizeof(EmfPlusScaleWorldTransform
),
1131 record
->Header
.Type
= EmfPlusRecordTypeScaleWorldTransform
;
1132 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1136 METAFILE_WriteRecords(metafile
);
1142 GpStatus
METAFILE_MultiplyWorldTransform(GpMetafile
* metafile
, GDIPCONST GpMatrix
* matrix
, MatrixOrder order
)
1144 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1146 EmfPlusMultiplyWorldTransform
*record
;
1149 stat
= METAFILE_AllocateRecord(metafile
,
1150 sizeof(EmfPlusMultiplyWorldTransform
),
1155 record
->Header
.Type
= EmfPlusRecordTypeMultiplyWorldTransform
;
1156 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1157 memcpy(record
->MatrixData
, matrix
->matrix
, sizeof(record
->MatrixData
));
1159 METAFILE_WriteRecords(metafile
);
1165 GpStatus
METAFILE_RotateWorldTransform(GpMetafile
* metafile
, REAL angle
, MatrixOrder order
)
1167 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1169 EmfPlusRotateWorldTransform
*record
;
1172 stat
= METAFILE_AllocateRecord(metafile
,
1173 sizeof(EmfPlusRotateWorldTransform
),
1178 record
->Header
.Type
= EmfPlusRecordTypeRotateWorldTransform
;
1179 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1180 record
->Angle
= angle
;
1182 METAFILE_WriteRecords(metafile
);
1188 GpStatus
METAFILE_TranslateWorldTransform(GpMetafile
* metafile
, REAL dx
, REAL dy
, MatrixOrder order
)
1190 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1192 EmfPlusTranslateWorldTransform
*record
;
1195 stat
= METAFILE_AllocateRecord(metafile
,
1196 sizeof(EmfPlusTranslateWorldTransform
),
1201 record
->Header
.Type
= EmfPlusRecordTypeTranslateWorldTransform
;
1202 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1206 METAFILE_WriteRecords(metafile
);
1212 GpStatus
METAFILE_ResetWorldTransform(GpMetafile
* metafile
)
1214 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1216 EmfPlusRecordHeader
*record
;
1219 stat
= METAFILE_AllocateRecord(metafile
,
1220 sizeof(EmfPlusRecordHeader
),
1225 record
->Type
= EmfPlusRecordTypeResetWorldTransform
;
1228 METAFILE_WriteRecords(metafile
);
1234 GpStatus
METAFILE_BeginContainer(GpMetafile
* metafile
, GDIPCONST GpRectF
*dstrect
,
1235 GDIPCONST GpRectF
*srcrect
, GpUnit unit
, DWORD StackIndex
)
1237 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1239 EmfPlusBeginContainer
*record
;
1242 stat
= METAFILE_AllocateRecord(metafile
, sizeof(*record
), (void**)&record
);
1246 record
->Header
.Type
= EmfPlusRecordTypeBeginContainer
;
1247 record
->Header
.Flags
= unit
& 0xff;
1248 record
->DestRect
= *dstrect
;
1249 record
->SrcRect
= *srcrect
;
1250 record
->StackIndex
= StackIndex
;
1252 METAFILE_WriteRecords(metafile
);
1258 GpStatus
METAFILE_BeginContainerNoParams(GpMetafile
* metafile
, DWORD StackIndex
)
1260 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1262 EmfPlusContainerRecord
*record
;
1265 stat
= METAFILE_AllocateRecord(metafile
,
1266 sizeof(EmfPlusContainerRecord
),
1271 record
->Header
.Type
= EmfPlusRecordTypeBeginContainerNoParams
;
1272 record
->Header
.Flags
= 0;
1273 record
->StackIndex
= StackIndex
;
1275 METAFILE_WriteRecords(metafile
);
1281 GpStatus
METAFILE_EndContainer(GpMetafile
* metafile
, DWORD StackIndex
)
1283 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1285 EmfPlusContainerRecord
*record
;
1288 stat
= METAFILE_AllocateRecord(metafile
,
1289 sizeof(EmfPlusContainerRecord
),
1294 record
->Header
.Type
= EmfPlusRecordTypeEndContainer
;
1295 record
->Header
.Flags
= 0;
1296 record
->StackIndex
= StackIndex
;
1298 METAFILE_WriteRecords(metafile
);
1304 GpStatus
METAFILE_SaveGraphics(GpMetafile
* metafile
, DWORD StackIndex
)
1306 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1308 EmfPlusContainerRecord
*record
;
1311 stat
= METAFILE_AllocateRecord(metafile
,
1312 sizeof(EmfPlusContainerRecord
),
1317 record
->Header
.Type
= EmfPlusRecordTypeSave
;
1318 record
->Header
.Flags
= 0;
1319 record
->StackIndex
= StackIndex
;
1321 METAFILE_WriteRecords(metafile
);
1327 GpStatus
METAFILE_RestoreGraphics(GpMetafile
* metafile
, DWORD StackIndex
)
1329 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1331 EmfPlusContainerRecord
*record
;
1334 stat
= METAFILE_AllocateRecord(metafile
,
1335 sizeof(EmfPlusContainerRecord
),
1340 record
->Header
.Type
= EmfPlusRecordTypeRestore
;
1341 record
->Header
.Flags
= 0;
1342 record
->StackIndex
= StackIndex
;
1344 METAFILE_WriteRecords(metafile
);
1350 GpStatus
METAFILE_ReleaseDC(GpMetafile
* metafile
, HDC hdc
)
1352 if (hdc
!= metafile
->record_dc
)
1353 return InvalidParameter
;
1358 GpStatus
METAFILE_GraphicsDeleted(GpMetafile
* metafile
)
1362 stat
= METAFILE_WriteEndOfFile(metafile
);
1363 metafile
->record_graphics
= NULL
;
1365 metafile
->hemf
= CloseEnhMetaFile(metafile
->record_dc
);
1366 metafile
->record_dc
= NULL
;
1368 heap_free(metafile
->comment_data
);
1369 metafile
->comment_data
= NULL
;
1370 metafile
->comment_data_size
= 0;
1374 MetafileHeader header
;
1376 stat
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, &header
);
1377 if (stat
== Ok
&& metafile
->auto_frame
&&
1378 metafile
->auto_frame_max
.X
>= metafile
->auto_frame_min
.X
)
1380 RECTL bounds_rc
, gdi_bounds_rc
;
1381 REAL x_scale
= 2540.0 / header
.DpiX
;
1382 REAL y_scale
= 2540.0 / header
.DpiY
;
1386 bounds_rc
.left
= floorf(metafile
->auto_frame_min
.X
* x_scale
);
1387 bounds_rc
.top
= floorf(metafile
->auto_frame_min
.Y
* y_scale
);
1388 bounds_rc
.right
= ceilf(metafile
->auto_frame_max
.X
* x_scale
);
1389 bounds_rc
.bottom
= ceilf(metafile
->auto_frame_max
.Y
* y_scale
);
1391 gdi_bounds_rc
= header
.u
.EmfHeader
.rclBounds
;
1392 if (gdi_bounds_rc
.right
> gdi_bounds_rc
.left
&& gdi_bounds_rc
.bottom
> gdi_bounds_rc
.top
)
1394 bounds_rc
.left
= min(bounds_rc
.left
, gdi_bounds_rc
.left
);
1395 bounds_rc
.top
= min(bounds_rc
.top
, gdi_bounds_rc
.top
);
1396 bounds_rc
.right
= max(bounds_rc
.right
, gdi_bounds_rc
.right
);
1397 bounds_rc
.bottom
= max(bounds_rc
.bottom
, gdi_bounds_rc
.bottom
);
1400 buffer_size
= GetEnhMetaFileBits(metafile
->hemf
, 0, NULL
);
1401 buffer
= heap_alloc(buffer_size
);
1404 HENHMETAFILE new_hemf
;
1406 GetEnhMetaFileBits(metafile
->hemf
, buffer_size
, buffer
);
1408 ((ENHMETAHEADER
*)buffer
)->rclFrame
= bounds_rc
;
1410 new_hemf
= SetEnhMetaFileBits(buffer_size
, buffer
);
1414 DeleteEnhMetaFile(metafile
->hemf
);
1415 metafile
->hemf
= new_hemf
;
1426 stat
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, &header
);
1430 metafile
->bounds
.X
= header
.X
;
1431 metafile
->bounds
.Y
= header
.Y
;
1432 metafile
->bounds
.Width
= header
.Width
;
1433 metafile
->bounds
.Height
= header
.Height
;
1437 if (stat
== Ok
&& metafile
->record_stream
)
1442 buffer_size
= GetEnhMetaFileBits(metafile
->hemf
, 0, NULL
);
1444 buffer
= heap_alloc(buffer_size
);
1449 GetEnhMetaFileBits(metafile
->hemf
, buffer_size
, buffer
);
1451 hr
= IStream_Write(metafile
->record_stream
, buffer
, buffer_size
, NULL
);
1454 stat
= hresult_to_status(hr
);
1462 if (metafile
->record_stream
)
1464 IStream_Release(metafile
->record_stream
);
1465 metafile
->record_stream
= NULL
;
1471 GpStatus WINGDIPAPI
GdipGetHemfFromMetafile(GpMetafile
*metafile
, HENHMETAFILE
*hEmf
)
1473 TRACE("(%p,%p)\n", metafile
, hEmf
);
1475 if (!metafile
|| !hEmf
|| !metafile
->hemf
)
1476 return InvalidParameter
;
1478 *hEmf
= metafile
->hemf
;
1479 metafile
->hemf
= NULL
;
1484 static void METAFILE_GetFinalGdiTransform(const GpMetafile
*metafile
, XFORM
*result
)
1486 const GpRectF
*rect
;
1489 /* This transforms metafile device space to output points. */
1490 rect
= &metafile
->src_rect
;
1491 pt
= metafile
->playback_points
;
1492 result
->eM11
= (pt
[1].X
- pt
[0].X
) / rect
->Width
;
1493 result
->eM21
= (pt
[2].X
- pt
[0].X
) / rect
->Height
;
1494 result
->eDx
= pt
[0].X
- result
->eM11
* rect
->X
- result
->eM21
* rect
->Y
;
1495 result
->eM12
= (pt
[1].Y
- pt
[0].Y
) / rect
->Width
;
1496 result
->eM22
= (pt
[2].Y
- pt
[0].Y
) / rect
->Height
;
1497 result
->eDy
= pt
[0].Y
- result
->eM12
* rect
->X
- result
->eM22
* rect
->Y
;
1500 static GpStatus
METAFILE_PlaybackUpdateGdiTransform(GpMetafile
*metafile
)
1502 XFORM combined
, final
;
1504 METAFILE_GetFinalGdiTransform(metafile
, &final
);
1506 CombineTransform(&combined
, &metafile
->gdiworldtransform
, &final
);
1508 SetGraphicsMode(metafile
->playback_dc
, GM_ADVANCED
);
1509 SetWorldTransform(metafile
->playback_dc
, &combined
);
1514 static GpStatus
METAFILE_PlaybackGetDC(GpMetafile
*metafile
)
1518 stat
= GdipGetDC(metafile
->playback_graphics
, &metafile
->playback_dc
);
1522 static const XFORM identity
= {1, 0, 0, 1, 0, 0};
1524 metafile
->gdiworldtransform
= identity
;
1525 METAFILE_PlaybackUpdateGdiTransform(metafile
);
1531 static void METAFILE_PlaybackReleaseDC(GpMetafile
*metafile
)
1533 if (metafile
->playback_dc
)
1535 GdipReleaseDC(metafile
->playback_graphics
, metafile
->playback_dc
);
1536 metafile
->playback_dc
= NULL
;
1540 static GpStatus
METAFILE_PlaybackUpdateClip(GpMetafile
*metafile
)
1543 stat
= GdipCombineRegionRegion(metafile
->playback_graphics
->clip
, metafile
->base_clip
, CombineModeReplace
);
1545 stat
= GdipCombineRegionRegion(metafile
->playback_graphics
->clip
, metafile
->clip
, CombineModeIntersect
);
1549 static GpStatus
METAFILE_PlaybackUpdateWorldTransform(GpMetafile
*metafile
)
1551 GpMatrix
*real_transform
;
1554 stat
= GdipCreateMatrix3(&metafile
->src_rect
, metafile
->playback_points
, &real_transform
);
1558 REAL scale
= units_to_pixels(1.0, metafile
->page_unit
, 96.0);
1560 if (metafile
->page_unit
!= UnitDisplay
)
1561 scale
*= metafile
->page_scale
;
1563 stat
= GdipScaleMatrix(real_transform
, scale
, scale
, MatrixOrderPrepend
);
1566 stat
= GdipMultiplyMatrix(real_transform
, metafile
->world_transform
, MatrixOrderPrepend
);
1569 stat
= GdipSetWorldTransform(metafile
->playback_graphics
, real_transform
);
1571 GdipDeleteMatrix(real_transform
);
1577 static void metafile_set_object_table_entry(GpMetafile
*metafile
, BYTE id
, BYTE type
, void *object
)
1579 metafile_free_object_table_entry(metafile
, id
);
1580 metafile
->objtable
[id
].type
= type
;
1581 metafile
->objtable
[id
].u
.object
= object
;
1584 static GpStatus
metafile_deserialize_image(const BYTE
*record_data
, UINT data_size
, GpImage
**image
)
1586 EmfPlusImage
*data
= (EmfPlusImage
*)record_data
;
1591 if (data_size
< FIELD_OFFSET(EmfPlusImage
, ImageData
))
1592 return InvalidParameter
;
1593 data_size
-= FIELD_OFFSET(EmfPlusImage
, ImageData
);
1597 case ImageDataTypeBitmap
:
1599 EmfPlusBitmap
*bitmapdata
= &data
->ImageData
.bitmap
;
1601 if (data_size
<= FIELD_OFFSET(EmfPlusBitmap
, BitmapData
))
1602 return InvalidParameter
;
1603 data_size
-= FIELD_OFFSET(EmfPlusBitmap
, BitmapData
);
1605 switch (bitmapdata
->Type
)
1607 case BitmapDataTypePixel
:
1609 ColorPalette
*palette
;
1612 if (bitmapdata
->PixelFormat
& PixelFormatIndexed
)
1614 EmfPlusPalette
*palette_obj
= (EmfPlusPalette
*)bitmapdata
->BitmapData
;
1615 UINT palette_size
= FIELD_OFFSET(EmfPlusPalette
, PaletteEntries
);
1617 if (data_size
<= palette_size
)
1618 return InvalidParameter
;
1619 palette_size
+= palette_obj
->PaletteCount
* sizeof(EmfPlusARGB
);
1621 if (data_size
< palette_size
)
1622 return InvalidParameter
;
1623 data_size
-= palette_size
;
1625 palette
= (ColorPalette
*)bitmapdata
->BitmapData
;
1626 scan0
= (BYTE
*)bitmapdata
->BitmapData
+ palette_size
;
1631 scan0
= bitmapdata
->BitmapData
;
1634 if (data_size
< bitmapdata
->Height
* bitmapdata
->Stride
)
1635 return InvalidParameter
;
1637 status
= GdipCreateBitmapFromScan0(bitmapdata
->Width
, bitmapdata
->Height
, bitmapdata
->Stride
,
1638 bitmapdata
->PixelFormat
, scan0
, (GpBitmap
**)image
);
1639 if (status
== Ok
&& palette
)
1641 status
= GdipSetImagePalette(*image
, palette
);
1644 GdipDisposeImage(*image
);
1650 case BitmapDataTypeCompressed
:
1652 IWICImagingFactory
*factory
;
1656 if (WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION
, &factory
) != S_OK
)
1657 return GenericError
;
1659 hr
= IWICImagingFactory_CreateStream(factory
, &stream
);
1660 IWICImagingFactory_Release(factory
);
1662 return GenericError
;
1664 if (IWICStream_InitializeFromMemory(stream
, bitmapdata
->BitmapData
, data_size
) == S_OK
)
1665 status
= GdipCreateBitmapFromStream((IStream
*)stream
, (GpBitmap
**)image
);
1667 status
= GenericError
;
1669 IWICStream_Release(stream
);
1673 WARN("Invalid bitmap type %d.\n", bitmapdata
->Type
);
1674 return InvalidParameter
;
1679 FIXME("image type %d not supported.\n", data
->Type
);
1680 return NotImplemented
;
1686 static GpStatus
metafile_deserialize_path(const BYTE
*record_data
, UINT data_size
, GpPath
**path
)
1688 EmfPlusPath
*data
= (EmfPlusPath
*)record_data
;
1696 if (data_size
<= FIELD_OFFSET(EmfPlusPath
, data
))
1697 return InvalidParameter
;
1698 data_size
-= FIELD_OFFSET(EmfPlusPath
, data
);
1700 if (data
->PathPointFlags
& 0x800) /* R */
1702 FIXME("RLE encoded path data is not supported.\n");
1703 return NotImplemented
;
1707 if (data
->PathPointFlags
& 0x4000) /* C */
1708 size
= sizeof(EmfPlusPoint
);
1710 size
= sizeof(EmfPlusPointF
);
1711 size
+= sizeof(BYTE
); /* EmfPlusPathPointType */
1712 size
*= data
->PathPointCount
;
1715 if (data_size
< size
)
1716 return InvalidParameter
;
1718 status
= GdipCreatePath(FillModeAlternate
, path
);
1722 (*path
)->pathdata
.Count
= data
->PathPointCount
;
1723 (*path
)->pathdata
.Points
= GdipAlloc(data
->PathPointCount
* sizeof(*(*path
)->pathdata
.Points
));
1724 (*path
)->pathdata
.Types
= GdipAlloc(data
->PathPointCount
* sizeof(*(*path
)->pathdata
.Types
));
1725 (*path
)->datalen
= (*path
)->pathdata
.Count
;
1727 if (!(*path
)->pathdata
.Points
|| !(*path
)->pathdata
.Types
)
1729 GdipDeletePath(*path
);
1733 if (data
->PathPointFlags
& 0x4000) /* C */
1735 EmfPlusPoint
*points
= (EmfPlusPoint
*)data
->data
;
1736 for (i
= 0; i
< data
->PathPointCount
; i
++)
1738 (*path
)->pathdata
.Points
[i
].X
= points
[i
].X
;
1739 (*path
)->pathdata
.Points
[i
].Y
= points
[i
].Y
;
1741 types
= (BYTE
*)(points
+ i
);
1745 EmfPlusPointF
*points
= (EmfPlusPointF
*)data
->data
;
1746 memcpy((*path
)->pathdata
.Points
, points
, sizeof(*points
) * data
->PathPointCount
);
1747 types
= (BYTE
*)(points
+ data
->PathPointCount
);
1750 memcpy((*path
)->pathdata
.Types
, types
, sizeof(*types
) * data
->PathPointCount
);
1755 static GpStatus
metafile_read_region_node(struct memory_buffer
*mbuf
, GpRegion
*region
, region_element
*node
, UINT
*count
)
1760 type
= buffer_read(mbuf
, sizeof(*type
));
1761 if (!type
) return Ok
;
1767 case CombineModeReplace
:
1768 case CombineModeIntersect
:
1769 case CombineModeUnion
:
1770 case CombineModeXor
:
1771 case CombineModeExclude
:
1772 case CombineModeComplement
:
1774 region_element
*left
, *right
;
1776 left
= heap_alloc_zero(sizeof(*left
));
1780 right
= heap_alloc_zero(sizeof(*right
));
1787 status
= metafile_read_region_node(mbuf
, region
, left
, count
);
1790 status
= metafile_read_region_node(mbuf
, region
, right
, count
);
1793 node
->elementdata
.combine
.left
= left
;
1794 node
->elementdata
.combine
.right
= right
;
1795 region
->num_children
+= 2;
1804 case RegionDataRect
:
1806 const EmfPlusRectF
*rect
;
1808 rect
= buffer_read(mbuf
, sizeof(*rect
));
1810 return InvalidParameter
;
1812 memcpy(&node
->elementdata
.rect
, rect
, sizeof(*rect
));
1816 case RegionDataPath
:
1818 const BYTE
*path_data
;
1819 const UINT
*data_size
;
1822 data_size
= buffer_read(mbuf
, FIELD_OFFSET(EmfPlusRegionNodePath
, RegionNodePath
));
1824 return InvalidParameter
;
1826 path_data
= buffer_read(mbuf
, *data_size
);
1828 return InvalidParameter
;
1830 status
= metafile_deserialize_path(path_data
, *data_size
, &path
);
1833 node
->elementdata
.path
= path
;
1838 case RegionDataEmptyRect
:
1839 case RegionDataInfiniteRect
:
1843 FIXME("element type %#x is not supported\n", *type
);
1847 return InvalidParameter
;
1850 static GpStatus
metafile_deserialize_region(const BYTE
*record_data
, UINT data_size
, GpRegion
**region
)
1852 struct memory_buffer mbuf
;
1858 init_memory_buffer(&mbuf
, record_data
, data_size
);
1860 if (!buffer_read(&mbuf
, FIELD_OFFSET(EmfPlusRegion
, RegionNode
)))
1861 return InvalidParameter
;
1863 status
= GdipCreateRegion(region
);
1868 status
= metafile_read_region_node(&mbuf
, *region
, &(*region
)->node
, &count
);
1869 if (status
== Ok
&& !count
)
1870 status
= InvalidParameter
;
1874 GdipDeleteRegion(*region
);
1881 static GpStatus
metafile_deserialize_brush(const BYTE
*record_data
, UINT data_size
, GpBrush
**brush
)
1883 static const UINT header_size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
);
1884 EmfPlusBrush
*data
= (EmfPlusBrush
*)record_data
;
1889 if (data_size
< header_size
)
1890 return InvalidParameter
;
1894 case BrushTypeSolidColor
:
1895 if (data_size
!= header_size
+ sizeof(EmfPlusSolidBrushData
))
1896 return InvalidParameter
;
1898 status
= GdipCreateSolidFill(data
->BrushData
.solid
.SolidColor
, (GpSolidFill
**)brush
);
1900 case BrushTypeHatchFill
:
1901 if (data_size
!= header_size
+ sizeof(EmfPlusHatchBrushData
))
1902 return InvalidParameter
;
1904 status
= GdipCreateHatchBrush(data
->BrushData
.hatch
.HatchStyle
, data
->BrushData
.hatch
.ForeColor
,
1905 data
->BrushData
.hatch
.BackColor
, (GpHatch
**)brush
);
1907 case BrushTypeTextureFill
:
1909 UINT offset
= header_size
+ FIELD_OFFSET(EmfPlusTextureBrushData
, OptionalData
);
1910 EmfPlusTransformMatrix
*transform
= NULL
;
1914 if (data_size
<= offset
)
1915 return InvalidParameter
;
1917 brushflags
= data
->BrushData
.texture
.BrushDataFlags
;
1918 if (brushflags
& BrushDataTransform
)
1920 if (data_size
<= offset
+ sizeof(EmfPlusTransformMatrix
))
1921 return InvalidParameter
;
1922 transform
= (EmfPlusTransformMatrix
*)(record_data
+ offset
);
1923 offset
+= sizeof(EmfPlusTransformMatrix
);
1926 status
= metafile_deserialize_image(record_data
+ offset
, data_size
- offset
, &image
);
1930 status
= GdipCreateTexture(image
, data
->BrushData
.texture
.WrapMode
, (GpTexture
**)brush
);
1931 if (status
== Ok
&& transform
&& !(brushflags
& BrushDataDoNotTransform
))
1932 GdipSetTextureTransform((GpTexture
*)*brush
, (const GpMatrix
*)transform
);
1934 GdipDisposeImage(image
);
1938 FIXME("brush type %u is not supported.\n", data
->Type
);
1939 return NotImplemented
;
1945 static GpStatus
metafile_get_pen_brush_data_offset(EmfPlusPen
*data
, UINT data_size
, DWORD
*ret
)
1947 EmfPlusPenData
*pendata
= (EmfPlusPenData
*)data
->data
;
1948 DWORD offset
= FIELD_OFFSET(EmfPlusPen
, data
);
1950 if (data_size
<= offset
)
1951 return InvalidParameter
;
1953 offset
+= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
1954 if (data_size
<= offset
)
1955 return InvalidParameter
;
1957 if (pendata
->PenDataFlags
& PenDataTransform
)
1958 offset
+= sizeof(EmfPlusTransformMatrix
);
1960 if (pendata
->PenDataFlags
& PenDataStartCap
)
1961 offset
+= sizeof(DWORD
);
1963 if (pendata
->PenDataFlags
& PenDataEndCap
)
1964 offset
+= sizeof(DWORD
);
1966 if (pendata
->PenDataFlags
& PenDataJoin
)
1967 offset
+= sizeof(DWORD
);
1969 if (pendata
->PenDataFlags
& PenDataMiterLimit
)
1970 offset
+= sizeof(REAL
);
1972 if (pendata
->PenDataFlags
& PenDataLineStyle
)
1973 offset
+= sizeof(DWORD
);
1975 if (pendata
->PenDataFlags
& PenDataDashedLineCap
)
1976 offset
+= sizeof(DWORD
);
1978 if (pendata
->PenDataFlags
& PenDataDashedLineOffset
)
1979 offset
+= sizeof(REAL
);
1981 if (pendata
->PenDataFlags
& PenDataDashedLine
)
1983 EmfPlusDashedLineData
*dashedline
= (EmfPlusDashedLineData
*)((BYTE
*)data
+ offset
);
1985 offset
+= FIELD_OFFSET(EmfPlusDashedLineData
, data
);
1986 if (data_size
<= offset
)
1987 return InvalidParameter
;
1989 offset
+= dashedline
->DashedLineDataSize
* sizeof(float);
1992 if (pendata
->PenDataFlags
& PenDataNonCenter
)
1993 offset
+= sizeof(DWORD
);
1995 if (pendata
->PenDataFlags
& PenDataCompoundLine
)
1997 EmfPlusCompoundLineData
*compoundline
= (EmfPlusCompoundLineData
*)((BYTE
*)data
+ offset
);
1999 offset
+= FIELD_OFFSET(EmfPlusCompoundLineData
, data
);
2000 if (data_size
<= offset
)
2001 return InvalidParameter
;
2003 offset
+= compoundline
->CompoundLineDataSize
* sizeof(float);
2006 if (pendata
->PenDataFlags
& PenDataCustomStartCap
)
2008 EmfPlusCustomStartCapData
*startcap
= (EmfPlusCustomStartCapData
*)((BYTE
*)data
+ offset
);
2010 offset
+= FIELD_OFFSET(EmfPlusCustomStartCapData
, data
);
2011 if (data_size
<= offset
)
2012 return InvalidParameter
;
2014 offset
+= startcap
->CustomStartCapSize
;
2017 if (pendata
->PenDataFlags
& PenDataCustomEndCap
)
2019 EmfPlusCustomEndCapData
*endcap
= (EmfPlusCustomEndCapData
*)((BYTE
*)data
+ offset
);
2021 offset
+= FIELD_OFFSET(EmfPlusCustomEndCapData
, data
);
2022 if (data_size
<= offset
)
2023 return InvalidParameter
;
2025 offset
+= endcap
->CustomEndCapSize
;
2032 static GpStatus
METAFILE_PlaybackObject(GpMetafile
*metafile
, UINT flags
, UINT data_size
, const BYTE
*record_data
)
2034 BYTE type
= (flags
>> 8) & 0xff;
2035 BYTE id
= flags
& 0xff;
2036 void *object
= NULL
;
2039 if (type
> ObjectTypeMax
|| id
>= EmfPlusObjectTableSize
)
2040 return InvalidParameter
;
2044 case ObjectTypeBrush
:
2045 status
= metafile_deserialize_brush(record_data
, data_size
, (GpBrush
**)&object
);
2049 EmfPlusPen
*data
= (EmfPlusPen
*)record_data
;
2050 EmfPlusPenData
*pendata
= (EmfPlusPenData
*)data
->data
;
2055 status
= metafile_get_pen_brush_data_offset(data
, data_size
, &offset
);
2059 status
= metafile_deserialize_brush(record_data
+ offset
, data_size
- offset
, &brush
);
2063 status
= GdipCreatePen2(brush
, pendata
->PenWidth
, pendata
->PenUnit
, &pen
);
2064 GdipDeleteBrush(brush
);
2068 offset
= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
2070 if (pendata
->PenDataFlags
& PenDataTransform
)
2072 FIXME("PenDataTransform is not supported.\n");
2073 offset
+= sizeof(EmfPlusTransformMatrix
);
2076 if (pendata
->PenDataFlags
& PenDataStartCap
)
2078 if ((status
= GdipSetPenStartCap(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2080 offset
+= sizeof(DWORD
);
2083 if (pendata
->PenDataFlags
& PenDataEndCap
)
2085 if ((status
= GdipSetPenEndCap(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2087 offset
+= sizeof(DWORD
);
2090 if (pendata
->PenDataFlags
& PenDataJoin
)
2092 if ((status
= GdipSetPenLineJoin(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2094 offset
+= sizeof(DWORD
);
2097 if (pendata
->PenDataFlags
& PenDataMiterLimit
)
2099 if ((status
= GdipSetPenMiterLimit(pen
, *(REAL
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2101 offset
+= sizeof(REAL
);
2104 if (pendata
->PenDataFlags
& PenDataLineStyle
)
2106 if ((status
= GdipSetPenDashStyle(pen
, *(DWORD
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2108 offset
+= sizeof(DWORD
);
2111 if (pendata
->PenDataFlags
& PenDataDashedLineCap
)
2113 FIXME("PenDataDashedLineCap is not supported.\n");
2114 offset
+= sizeof(DWORD
);
2117 if (pendata
->PenDataFlags
& PenDataDashedLineOffset
)
2119 if ((status
= GdipSetPenDashOffset(pen
, *(REAL
*)((BYTE
*)pendata
+ offset
))) != Ok
)
2121 offset
+= sizeof(REAL
);
2124 if (pendata
->PenDataFlags
& PenDataDashedLine
)
2126 EmfPlusDashedLineData
*dashedline
= (EmfPlusDashedLineData
*)((BYTE
*)pendata
+ offset
);
2127 FIXME("PenDataDashedLine is not supported.\n");
2128 offset
+= FIELD_OFFSET(EmfPlusDashedLineData
, data
) + dashedline
->DashedLineDataSize
* sizeof(float);
2131 if (pendata
->PenDataFlags
& PenDataNonCenter
)
2133 FIXME("PenDataNonCenter is not supported.\n");
2134 offset
+= sizeof(DWORD
);
2137 if (pendata
->PenDataFlags
& PenDataCompoundLine
)
2139 EmfPlusCompoundLineData
*compoundline
= (EmfPlusCompoundLineData
*)((BYTE
*)pendata
+ offset
);
2140 FIXME("PenDataCompundLine is not supported.\n");
2141 offset
+= FIELD_OFFSET(EmfPlusCompoundLineData
, data
) + compoundline
->CompoundLineDataSize
* sizeof(float);
2144 if (pendata
->PenDataFlags
& PenDataCustomStartCap
)
2146 EmfPlusCustomStartCapData
*startcap
= (EmfPlusCustomStartCapData
*)((BYTE
*)pendata
+ offset
);
2147 FIXME("PenDataCustomStartCap is not supported.\n");
2148 offset
+= FIELD_OFFSET(EmfPlusCustomStartCapData
, data
) + startcap
->CustomStartCapSize
;
2151 if (pendata
->PenDataFlags
& PenDataCustomEndCap
)
2153 EmfPlusCustomEndCapData
*endcap
= (EmfPlusCustomEndCapData
*)((BYTE
*)pendata
+ offset
);
2154 FIXME("PenDataCustomEndCap is not supported.\n");
2155 offset
+= FIELD_OFFSET(EmfPlusCustomEndCapData
, data
) + endcap
->CustomEndCapSize
;
2165 case ObjectTypePath
:
2166 status
= metafile_deserialize_path(record_data
, data_size
, (GpPath
**)&object
);
2168 case ObjectTypeRegion
:
2169 status
= metafile_deserialize_region(record_data
, data_size
, (GpRegion
**)&object
);
2171 case ObjectTypeImage
:
2172 status
= metafile_deserialize_image(record_data
, data_size
, (GpImage
**)&object
);
2174 case ObjectTypeFont
:
2176 EmfPlusFont
*data
= (EmfPlusFont
*)record_data
;
2177 GpFontFamily
*family
;
2180 if (data_size
<= FIELD_OFFSET(EmfPlusFont
, FamilyName
))
2181 return InvalidParameter
;
2182 data_size
-= FIELD_OFFSET(EmfPlusFont
, FamilyName
);
2184 if (data_size
< data
->Length
* sizeof(WCHAR
))
2185 return InvalidParameter
;
2187 if (!(familyname
= GdipAlloc((data
->Length
+ 1) * sizeof(*familyname
))))
2190 memcpy(familyname
, data
->FamilyName
, data
->Length
* sizeof(*familyname
));
2191 familyname
[data
->Length
] = 0;
2193 status
= GdipCreateFontFamilyFromName(familyname
, NULL
, &family
);
2194 GdipFree(familyname
);
2196 return InvalidParameter
;
2198 status
= GdipCreateFont(family
, data
->EmSize
, data
->FontStyleFlags
, data
->SizeUnit
, (GpFont
**)&object
);
2199 GdipDeleteFontFamily(family
);
2202 case ObjectTypeImageAttributes
:
2204 EmfPlusImageAttributes
*data
= (EmfPlusImageAttributes
*)record_data
;
2205 GpImageAttributes
*attributes
= NULL
;
2207 if (data_size
!= sizeof(*data
))
2208 return InvalidParameter
;
2210 if ((status
= GdipCreateImageAttributes(&attributes
)) != Ok
)
2213 status
= GdipSetImageAttributesWrapMode(attributes
, data
->WrapMode
, *(DWORD
*)&data
->ClampColor
,
2214 !!data
->ObjectClamp
);
2216 object
= attributes
;
2218 GdipDisposeImageAttributes(attributes
);
2222 FIXME("not implemented for object type %d.\n", type
);
2223 return NotImplemented
;
2227 metafile_set_object_table_entry(metafile
, id
, type
, object
);
2232 static GpStatus
metafile_set_clip_region(GpMetafile
*metafile
, GpRegion
*region
, CombineMode mode
)
2234 GpMatrix world_to_device
;
2236 get_graphics_transform(metafile
->playback_graphics
, CoordinateSpaceDevice
, CoordinateSpaceWorld
, &world_to_device
);
2238 GdipTransformRegion(region
, &world_to_device
);
2239 GdipCombineRegionRegion(metafile
->clip
, region
, mode
);
2241 return METAFILE_PlaybackUpdateClip(metafile
);
2244 GpStatus WINGDIPAPI
GdipPlayMetafileRecord(GDIPCONST GpMetafile
*metafile
,
2245 EmfPlusRecordType recordType
, UINT flags
, UINT dataSize
, GDIPCONST BYTE
*data
)
2248 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
;
2250 TRACE("(%p,%x,%x,%d,%p)\n", metafile
, recordType
, flags
, dataSize
, data
);
2252 if (!metafile
|| (dataSize
&& !data
) || !metafile
->playback_graphics
)
2253 return InvalidParameter
;
2255 if (recordType
>= 1 && recordType
<= 0x7a)
2257 /* regular EMF record */
2258 if (metafile
->playback_dc
)
2262 case EMR_SETMAPMODE
:
2265 case EMR_SETWINDOWORGEX
:
2266 case EMR_SETWINDOWEXTEX
:
2267 case EMR_SETVIEWPORTORGEX
:
2268 case EMR_SETVIEWPORTEXTEX
:
2269 case EMR_SCALEVIEWPORTEXTEX
:
2270 case EMR_SCALEWINDOWEXTEX
:
2271 case EMR_MODIFYWORLDTRANSFORM
:
2272 FIXME("not implemented for record type %x\n", recordType
);
2274 case EMR_SETWORLDTRANSFORM
:
2276 const XFORM
* xform
= (void*)data
;
2277 real_metafile
->gdiworldtransform
= *xform
;
2278 METAFILE_PlaybackUpdateGdiTransform(real_metafile
);
2281 case EMR_EXTSELECTCLIPRGN
:
2283 DWORD rgndatasize
= *(DWORD
*)data
;
2284 DWORD mode
= *(DWORD
*)(data
+ 4);
2285 const RGNDATA
*rgndata
= (const RGNDATA
*)(data
+ 8);
2292 METAFILE_GetFinalGdiTransform(metafile
, &final
);
2294 hrgn
= ExtCreateRegion(&final
, rgndatasize
, rgndata
);
2297 ExtSelectClipRgn(metafile
->playback_dc
, hrgn
, mode
);
2305 ENHMETARECORD
*record
= heap_alloc_zero(dataSize
+ 8);
2309 record
->iType
= recordType
;
2310 record
->nSize
= dataSize
+ 8;
2311 memcpy(record
->dParm
, data
, dataSize
);
2313 if(PlayEnhMetaFileRecord(metafile
->playback_dc
, metafile
->handle_table
,
2314 record
, metafile
->handle_count
) == 0)
2315 ERR("PlayEnhMetaFileRecord failed\n");
2329 EmfPlusRecordHeader
*header
= (EmfPlusRecordHeader
*)(data
)-1;
2331 METAFILE_PlaybackReleaseDC((GpMetafile
*)metafile
);
2335 case EmfPlusRecordTypeHeader
:
2336 case EmfPlusRecordTypeEndOfFile
:
2338 case EmfPlusRecordTypeGetDC
:
2339 METAFILE_PlaybackGetDC((GpMetafile
*)metafile
);
2341 case EmfPlusRecordTypeClear
:
2343 EmfPlusClear
*record
= (EmfPlusClear
*)header
;
2345 if (dataSize
!= sizeof(record
->Color
))
2346 return InvalidParameter
;
2348 return GdipGraphicsClear(metafile
->playback_graphics
, record
->Color
);
2350 case EmfPlusRecordTypeFillRects
:
2352 EmfPlusFillRects
*record
= (EmfPlusFillRects
*)header
;
2353 GpBrush
*brush
, *temp_brush
=NULL
;
2354 GpRectF
*rects
, *temp_rects
=NULL
;
2356 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
))
2357 return InvalidParameter
;
2361 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(EmfPlusRect
) * record
->Count
)
2362 return InvalidParameter
;
2366 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(GpRectF
) * record
->Count
)
2367 return InvalidParameter
;
2372 stat
= GdipCreateSolidFill(record
->BrushID
, (GpSolidFill
**)&temp_brush
);
2377 if (record
->BrushID
>= EmfPlusObjectTableSize
||
2378 real_metafile
->objtable
[record
->BrushID
].type
!= ObjectTypeBrush
)
2379 return InvalidParameter
;
2381 brush
= real_metafile
->objtable
[record
->BrushID
].u
.brush
;
2389 EmfPlusRect
*int_rects
= (EmfPlusRect
*)(record
+1);
2392 rects
= temp_rects
= heap_alloc_zero(sizeof(GpRectF
) * record
->Count
);
2395 for (i
=0; i
<record
->Count
; i
++)
2397 rects
[i
].X
= int_rects
[i
].X
;
2398 rects
[i
].Y
= int_rects
[i
].Y
;
2399 rects
[i
].Width
= int_rects
[i
].Width
;
2400 rects
[i
].Height
= int_rects
[i
].Height
;
2407 rects
= (GpRectF
*)(record
+1);
2412 stat
= GdipFillRectangles(metafile
->playback_graphics
, brush
, rects
, record
->Count
);
2415 GdipDeleteBrush(temp_brush
);
2416 heap_free(temp_rects
);
2420 case EmfPlusRecordTypeSetClipRect
:
2422 EmfPlusSetClipRect
*record
= (EmfPlusSetClipRect
*)header
;
2423 CombineMode mode
= (CombineMode
)((flags
>> 8) & 0xf);
2426 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(*record
))
2427 return InvalidParameter
;
2429 stat
= GdipCreateRegionRect(&record
->ClipRect
, ®ion
);
2433 stat
= metafile_set_clip_region(real_metafile
, region
, mode
);
2434 GdipDeleteRegion(region
);
2439 case EmfPlusRecordTypeSetClipRegion
:
2441 CombineMode mode
= (flags
>> 8) & 0xf;
2442 BYTE regionid
= flags
& 0xff;
2446 return InvalidParameter
;
2448 if (regionid
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[regionid
].type
!= ObjectTypeRegion
)
2449 return InvalidParameter
;
2451 stat
= GdipCloneRegion(real_metafile
->objtable
[regionid
].u
.region
, ®ion
);
2454 stat
= metafile_set_clip_region(real_metafile
, region
, mode
);
2455 GdipDeleteRegion(region
);
2460 case EmfPlusRecordTypeSetClipPath
:
2462 CombineMode mode
= (flags
>> 8) & 0xf;
2463 BYTE pathid
= flags
& 0xff;
2467 return InvalidParameter
;
2469 if (pathid
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pathid
].type
!= ObjectTypePath
)
2470 return InvalidParameter
;
2472 stat
= GdipCreateRegionPath(real_metafile
->objtable
[pathid
].u
.path
, ®ion
);
2475 stat
= metafile_set_clip_region(real_metafile
, region
, mode
);
2476 GdipDeleteRegion(region
);
2481 case EmfPlusRecordTypeSetPageTransform
:
2483 EmfPlusSetPageTransform
*record
= (EmfPlusSetPageTransform
*)header
;
2484 GpUnit unit
= (GpUnit
)flags
;
2486 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetPageTransform
))
2487 return InvalidParameter
;
2489 real_metafile
->page_unit
= unit
;
2490 real_metafile
->page_scale
= record
->PageScale
;
2492 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2494 case EmfPlusRecordTypeSetWorldTransform
:
2496 EmfPlusSetWorldTransform
*record
= (EmfPlusSetWorldTransform
*)header
;
2498 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetWorldTransform
))
2499 return InvalidParameter
;
2501 memcpy(real_metafile
->world_transform
->matrix
, record
->MatrixData
, sizeof(record
->MatrixData
));
2503 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2505 case EmfPlusRecordTypeScaleWorldTransform
:
2507 EmfPlusScaleWorldTransform
*record
= (EmfPlusScaleWorldTransform
*)header
;
2508 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2510 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusScaleWorldTransform
))
2511 return InvalidParameter
;
2513 GdipScaleMatrix(real_metafile
->world_transform
, record
->Sx
, record
->Sy
, order
);
2515 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2517 case EmfPlusRecordTypeMultiplyWorldTransform
:
2519 EmfPlusMultiplyWorldTransform
*record
= (EmfPlusMultiplyWorldTransform
*)header
;
2520 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2523 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusMultiplyWorldTransform
))
2524 return InvalidParameter
;
2526 memcpy(matrix
.matrix
, record
->MatrixData
, sizeof(matrix
.matrix
));
2528 GdipMultiplyMatrix(real_metafile
->world_transform
, &matrix
, order
);
2530 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2532 case EmfPlusRecordTypeRotateWorldTransform
:
2534 EmfPlusRotateWorldTransform
*record
= (EmfPlusRotateWorldTransform
*)header
;
2535 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2537 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusRotateWorldTransform
))
2538 return InvalidParameter
;
2540 GdipRotateMatrix(real_metafile
->world_transform
, record
->Angle
, order
);
2542 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2544 case EmfPlusRecordTypeTranslateWorldTransform
:
2546 EmfPlusTranslateWorldTransform
*record
= (EmfPlusTranslateWorldTransform
*)header
;
2547 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2549 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusTranslateWorldTransform
))
2550 return InvalidParameter
;
2552 GdipTranslateMatrix(real_metafile
->world_transform
, record
->dx
, record
->dy
, order
);
2554 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2556 case EmfPlusRecordTypeResetWorldTransform
:
2558 GdipSetMatrixElements(real_metafile
->world_transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
2560 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2562 case EmfPlusRecordTypeBeginContainer
:
2564 EmfPlusBeginContainer
*record
= (EmfPlusBeginContainer
*)header
;
2567 REAL scale_x
, scale_y
;
2568 GpRectF scaled_srcrect
;
2571 cont
= heap_alloc_zero(sizeof(*cont
));
2575 stat
= GdipCloneRegion(metafile
->clip
, &cont
->clip
);
2582 stat
= GdipBeginContainer2(metafile
->playback_graphics
, &cont
->state
);
2586 GdipDeleteRegion(cont
->clip
);
2591 cont
->id
= record
->StackIndex
;
2592 cont
->type
= BEGIN_CONTAINER
;
2593 cont
->world_transform
= *metafile
->world_transform
;
2594 cont
->page_unit
= metafile
->page_unit
;
2595 cont
->page_scale
= metafile
->page_scale
;
2596 list_add_head(&real_metafile
->containers
, &cont
->entry
);
2598 unit
= record
->Header
.Flags
& 0xff;
2600 scale_x
= units_to_pixels(1.0, unit
, metafile
->image
.xres
);
2601 scale_y
= units_to_pixels(1.0, unit
, metafile
->image
.yres
);
2603 scaled_srcrect
.X
= scale_x
* record
->SrcRect
.X
;
2604 scaled_srcrect
.Y
= scale_y
* record
->SrcRect
.Y
;
2605 scaled_srcrect
.Width
= scale_x
* record
->SrcRect
.Width
;
2606 scaled_srcrect
.Height
= scale_y
* record
->SrcRect
.Height
;
2608 transform
.matrix
[0] = record
->DestRect
.Width
/ scaled_srcrect
.Width
;
2609 transform
.matrix
[1] = 0.0;
2610 transform
.matrix
[2] = 0.0;
2611 transform
.matrix
[3] = record
->DestRect
.Height
/ scaled_srcrect
.Height
;
2612 transform
.matrix
[4] = record
->DestRect
.X
- scaled_srcrect
.X
;
2613 transform
.matrix
[5] = record
->DestRect
.Y
- scaled_srcrect
.Y
;
2615 GdipMultiplyMatrix(real_metafile
->world_transform
, &transform
, MatrixOrderPrepend
);
2617 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2619 case EmfPlusRecordTypeBeginContainerNoParams
:
2620 case EmfPlusRecordTypeSave
:
2622 EmfPlusContainerRecord
*record
= (EmfPlusContainerRecord
*)header
;
2625 cont
= heap_alloc_zero(sizeof(*cont
));
2629 stat
= GdipCloneRegion(metafile
->clip
, &cont
->clip
);
2636 if (recordType
== EmfPlusRecordTypeBeginContainerNoParams
)
2637 stat
= GdipBeginContainer2(metafile
->playback_graphics
, &cont
->state
);
2639 stat
= GdipSaveGraphics(metafile
->playback_graphics
, &cont
->state
);
2643 GdipDeleteRegion(cont
->clip
);
2648 cont
->id
= record
->StackIndex
;
2649 if (recordType
== EmfPlusRecordTypeBeginContainerNoParams
)
2650 cont
->type
= BEGIN_CONTAINER
;
2652 cont
->type
= SAVE_GRAPHICS
;
2653 cont
->world_transform
= *metafile
->world_transform
;
2654 cont
->page_unit
= metafile
->page_unit
;
2655 cont
->page_scale
= metafile
->page_scale
;
2656 list_add_head(&real_metafile
->containers
, &cont
->entry
);
2660 case EmfPlusRecordTypeEndContainer
:
2661 case EmfPlusRecordTypeRestore
:
2663 EmfPlusContainerRecord
*record
= (EmfPlusContainerRecord
*)header
;
2665 enum container_type type
;
2668 if (recordType
== EmfPlusRecordTypeEndContainer
)
2669 type
= BEGIN_CONTAINER
;
2671 type
= SAVE_GRAPHICS
;
2673 LIST_FOR_EACH_ENTRY(cont
, &real_metafile
->containers
, container
, entry
)
2675 if (cont
->id
== record
->StackIndex
&& cont
->type
== type
)
2686 /* pop any newer items on the stack */
2687 while ((cont2
= LIST_ENTRY(list_head(&real_metafile
->containers
), container
, entry
)) != cont
)
2689 list_remove(&cont2
->entry
);
2690 GdipDeleteRegion(cont2
->clip
);
2694 if (type
== BEGIN_CONTAINER
)
2695 GdipEndContainer(real_metafile
->playback_graphics
, cont
->state
);
2697 GdipRestoreGraphics(real_metafile
->playback_graphics
, cont
->state
);
2699 *real_metafile
->world_transform
= cont
->world_transform
;
2700 real_metafile
->page_unit
= cont
->page_unit
;
2701 real_metafile
->page_scale
= cont
->page_scale
;
2702 GdipCombineRegionRegion(real_metafile
->clip
, cont
->clip
, CombineModeReplace
);
2704 list_remove(&cont
->entry
);
2705 GdipDeleteRegion(cont
->clip
);
2711 case EmfPlusRecordTypeSetPixelOffsetMode
:
2713 return GdipSetPixelOffsetMode(real_metafile
->playback_graphics
, flags
& 0xff);
2715 case EmfPlusRecordTypeSetCompositingQuality
:
2717 return GdipSetCompositingQuality(real_metafile
->playback_graphics
, flags
& 0xff);
2719 case EmfPlusRecordTypeSetInterpolationMode
:
2721 return GdipSetInterpolationMode(real_metafile
->playback_graphics
, flags
& 0xff);
2723 case EmfPlusRecordTypeSetTextRenderingHint
:
2725 return GdipSetTextRenderingHint(real_metafile
->playback_graphics
, flags
& 0xff);
2727 case EmfPlusRecordTypeSetAntiAliasMode
:
2729 return GdipSetSmoothingMode(real_metafile
->playback_graphics
, (flags
>> 1) & 0xff);
2731 case EmfPlusRecordTypeObject
:
2733 return METAFILE_PlaybackObject(real_metafile
, flags
, dataSize
, data
);
2735 case EmfPlusRecordTypeDrawImage
:
2737 EmfPlusDrawImage
*draw
= (EmfPlusDrawImage
*)header
;
2738 BYTE image
= flags
& 0xff;
2741 if (image
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[image
].type
!= ObjectTypeImage
)
2742 return InvalidParameter
;
2744 if (dataSize
!= FIELD_OFFSET(EmfPlusDrawImage
, RectData
) - sizeof(EmfPlusRecordHeader
) +
2745 (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
2746 return InvalidParameter
;
2748 if (draw
->ImageAttributesID
>= EmfPlusObjectTableSize
||
2749 real_metafile
->objtable
[draw
->ImageAttributesID
].type
!= ObjectTypeImageAttributes
)
2750 return InvalidParameter
;
2752 if (flags
& 0x4000) /* C */
2754 points
[0].X
= draw
->RectData
.rect
.X
;
2755 points
[0].Y
= draw
->RectData
.rect
.Y
;
2756 points
[1].X
= points
[0].X
+ draw
->RectData
.rect
.Width
;
2757 points
[1].Y
= points
[0].Y
;
2758 points
[2].X
= points
[1].X
;
2759 points
[2].Y
= points
[1].Y
+ draw
->RectData
.rect
.Height
;
2763 points
[0].X
= draw
->RectData
.rectF
.X
;
2764 points
[0].Y
= draw
->RectData
.rectF
.Y
;
2765 points
[1].X
= points
[0].X
+ draw
->RectData
.rectF
.Width
;
2766 points
[1].Y
= points
[0].Y
;
2767 points
[2].X
= points
[1].X
;
2768 points
[2].Y
= points
[1].Y
+ draw
->RectData
.rectF
.Height
;
2771 return GdipDrawImagePointsRect(real_metafile
->playback_graphics
, real_metafile
->objtable
[image
].u
.image
,
2772 points
, 3, draw
->SrcRect
.X
, draw
->SrcRect
.Y
, draw
->SrcRect
.Width
, draw
->SrcRect
.Height
, draw
->SrcUnit
,
2773 real_metafile
->objtable
[draw
->ImageAttributesID
].u
.image_attributes
, NULL
, NULL
);
2775 case EmfPlusRecordTypeDrawImagePoints
:
2777 EmfPlusDrawImagePoints
*draw
= (EmfPlusDrawImagePoints
*)header
;
2778 static const UINT fixed_part_size
= FIELD_OFFSET(EmfPlusDrawImagePoints
, PointData
) -
2779 FIELD_OFFSET(EmfPlusDrawImagePoints
, ImageAttributesID
);
2780 BYTE image
= flags
& 0xff;
2785 if (image
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[image
].type
!= ObjectTypeImage
)
2786 return InvalidParameter
;
2788 if (dataSize
<= fixed_part_size
)
2789 return InvalidParameter
;
2790 dataSize
-= fixed_part_size
;
2792 if (draw
->ImageAttributesID
>= EmfPlusObjectTableSize
||
2793 real_metafile
->objtable
[draw
->ImageAttributesID
].type
!= ObjectTypeImageAttributes
)
2794 return InvalidParameter
;
2796 if (draw
->count
!= 3)
2797 return InvalidParameter
;
2799 if ((flags
>> 13) & 1) /* E */
2800 FIXME("image effects are not supported.\n");
2802 if ((flags
>> 11) & 1) /* P */
2803 size
= sizeof(EmfPlusPointR7
) * draw
->count
;
2804 else if ((flags
>> 14) & 1) /* C */
2805 size
= sizeof(EmfPlusPoint
) * draw
->count
;
2807 size
= sizeof(EmfPlusPointF
) * draw
->count
;
2809 if (dataSize
!= size
)
2810 return InvalidParameter
;
2812 if ((flags
>> 11) & 1) /* P */
2814 points
[0].X
= draw
->PointData
.pointsR
[0].X
;
2815 points
[0].Y
= draw
->PointData
.pointsR
[0].Y
;
2816 for (i
= 1; i
< 3; i
++)
2818 points
[i
].X
= points
[i
-1].X
+ draw
->PointData
.pointsR
[i
].X
;
2819 points
[i
].Y
= points
[i
-1].Y
+ draw
->PointData
.pointsR
[i
].Y
;
2822 else if ((flags
>> 14) & 1) /* C */
2824 for (i
= 0; i
< 3; i
++)
2826 points
[i
].X
= draw
->PointData
.points
[i
].X
;
2827 points
[i
].Y
= draw
->PointData
.points
[i
].Y
;
2831 memcpy(points
, draw
->PointData
.pointsF
, sizeof(points
));
2833 return GdipDrawImagePointsRect(real_metafile
->playback_graphics
, real_metafile
->objtable
[image
].u
.image
,
2834 points
, 3, draw
->SrcRect
.X
, draw
->SrcRect
.Y
, draw
->SrcRect
.Width
, draw
->SrcRect
.Height
, draw
->SrcUnit
,
2835 real_metafile
->objtable
[draw
->ImageAttributesID
].u
.image_attributes
, NULL
, NULL
);
2837 case EmfPlusRecordTypeFillPath
:
2839 EmfPlusFillPath
*fill
= (EmfPlusFillPath
*)header
;
2840 GpSolidFill
*solidfill
= NULL
;
2841 BYTE path
= flags
& 0xff;
2844 if (path
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[path
].type
!= ObjectTypePath
)
2845 return InvalidParameter
;
2847 if (dataSize
!= sizeof(fill
->data
.BrushId
))
2848 return InvalidParameter
;
2852 stat
= GdipCreateSolidFill(fill
->data
.Color
, (GpSolidFill
**)&solidfill
);
2855 brush
= (GpBrush
*)solidfill
;
2859 if (fill
->data
.BrushId
>= EmfPlusObjectTableSize
||
2860 real_metafile
->objtable
[fill
->data
.BrushId
].type
!= ObjectTypeBrush
)
2861 return InvalidParameter
;
2863 brush
= real_metafile
->objtable
[fill
->data
.BrushId
].u
.brush
;
2866 stat
= GdipFillPath(real_metafile
->playback_graphics
, brush
, real_metafile
->objtable
[path
].u
.path
);
2867 GdipDeleteBrush((GpBrush
*)solidfill
);
2870 case EmfPlusRecordTypeDrawPath
:
2872 EmfPlusDrawPath
*draw
= (EmfPlusDrawPath
*)header
;
2873 BYTE path
= flags
& 0xff;
2875 if (dataSize
!= sizeof(draw
->PenId
))
2876 return InvalidParameter
;
2878 if (path
>= EmfPlusObjectTableSize
|| draw
->PenId
>= EmfPlusObjectTableSize
)
2879 return InvalidParameter
;
2881 if (real_metafile
->objtable
[path
].type
!= ObjectTypePath
||
2882 real_metafile
->objtable
[draw
->PenId
].type
!= ObjectTypePen
)
2883 return InvalidParameter
;
2885 return GdipDrawPath(real_metafile
->playback_graphics
, real_metafile
->objtable
[draw
->PenId
].u
.pen
,
2886 real_metafile
->objtable
[path
].u
.path
);
2888 case EmfPlusRecordTypeDrawPie
:
2890 EmfPlusDrawPie
*draw
= (EmfPlusDrawPie
*)header
;
2891 BYTE pen
= flags
& 0xff;
2893 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
2894 return InvalidParameter
;
2896 if (dataSize
!= FIELD_OFFSET(EmfPlusDrawPie
, RectData
) - sizeof(EmfPlusRecordHeader
) +
2897 (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
2898 return InvalidParameter
;
2900 if (flags
& 0x4000) /* C */
2901 return GdipDrawPieI(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
2902 draw
->RectData
.rect
.X
, draw
->RectData
.rect
.Y
, draw
->RectData
.rect
.Width
,
2903 draw
->RectData
.rect
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
2905 return GdipDrawPie(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
2906 draw
->RectData
.rectF
.X
, draw
->RectData
.rectF
.Y
, draw
->RectData
.rectF
.Width
,
2907 draw
->RectData
.rectF
.Height
, draw
->StartAngle
, draw
->SweepAngle
);
2909 case EmfPlusRecordTypeDrawRects
:
2911 EmfPlusDrawRects
*draw
= (EmfPlusDrawRects
*)header
;
2912 BYTE pen
= flags
& 0xff;
2913 GpRectF
*rects
= NULL
;
2915 if (pen
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[pen
].type
!= ObjectTypePen
)
2916 return InvalidParameter
;
2918 if (dataSize
<= FIELD_OFFSET(EmfPlusDrawRects
, RectData
) - sizeof(EmfPlusRecordHeader
))
2919 return InvalidParameter
;
2920 dataSize
-= FIELD_OFFSET(EmfPlusDrawRects
, RectData
) - sizeof(EmfPlusRecordHeader
);
2922 if (dataSize
!= draw
->Count
* (flags
& 0x4000 ? sizeof(EmfPlusRect
) : sizeof(EmfPlusRectF
)))
2923 return InvalidParameter
;
2929 rects
= GdipAlloc(draw
->Count
* sizeof(*rects
));
2933 for (i
= 0; i
< draw
->Count
; i
++)
2935 rects
[i
].X
= draw
->RectData
.rect
[i
].X
;
2936 rects
[i
].Y
= draw
->RectData
.rect
[i
].Y
;
2937 rects
[i
].Width
= draw
->RectData
.rect
[i
].Width
;
2938 rects
[i
].Height
= draw
->RectData
.rect
[i
].Height
;
2942 stat
= GdipDrawRectangles(real_metafile
->playback_graphics
, real_metafile
->objtable
[pen
].u
.pen
,
2943 rects
? rects
: (GpRectF
*)draw
->RectData
.rectF
, draw
->Count
);
2948 FIXME("Not implemented for record type %x\n", recordType
);
2949 return NotImplemented
;
2956 struct enum_metafile_data
2958 EnumerateMetafileProc callback
;
2959 void *callback_data
;
2960 GpMetafile
*metafile
;
2963 static int CALLBACK
enum_metafile_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
2964 int nObj
, LPARAM lpData
)
2967 struct enum_metafile_data
*data
= (struct enum_metafile_data
*)lpData
;
2970 data
->metafile
->handle_table
= lpHTable
;
2971 data
->metafile
->handle_count
= nObj
;
2973 /* First check for an EMF+ record. */
2974 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
2976 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
2978 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
2982 while (offset
+ sizeof(EmfPlusRecordHeader
) <= comment
->cbData
)
2984 const EmfPlusRecordHeader
*record
= (const EmfPlusRecordHeader
*)&comment
->Data
[offset
];
2986 if (record
->DataSize
)
2987 pStr
= (const BYTE
*)(record
+1);
2991 ret
= data
->callback(record
->Type
, record
->Flags
, record
->DataSize
,
2992 pStr
, data
->callback_data
);
2997 offset
+= record
->Size
;
3004 if (lpEMFR
->nSize
!= 8)
3005 pStr
= (const BYTE
*)lpEMFR
->dParm
;
3009 return data
->callback(lpEMFR
->iType
, 0, lpEMFR
->nSize
-8,
3010 pStr
, data
->callback_data
);
3013 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestPoints(GpGraphics
*graphics
,
3014 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*destPoints
, INT count
,
3015 GDIPCONST GpRectF
*srcRect
, Unit srcUnit
, EnumerateMetafileProc callback
,
3016 VOID
*callbackData
, GDIPCONST GpImageAttributes
*imageAttributes
)
3018 struct enum_metafile_data data
;
3020 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
; /* whoever made this const was joking */
3021 GraphicsContainer state
;
3024 TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics
, metafile
,
3025 destPoints
, count
, srcRect
, srcUnit
, callback
, callbackData
,
3028 if (!graphics
|| !metafile
|| !destPoints
|| count
!= 3 || !srcRect
)
3029 return InvalidParameter
;
3031 if (!metafile
->hemf
)
3032 return InvalidParameter
;
3034 if (metafile
->playback_graphics
)
3037 TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect
), srcUnit
,
3038 debugstr_pointf(&destPoints
[0]), debugstr_pointf(&destPoints
[1]),
3039 debugstr_pointf(&destPoints
[2]));
3041 data
.callback
= callback
;
3042 data
.callback_data
= callbackData
;
3043 data
.metafile
= real_metafile
;
3045 real_metafile
->playback_graphics
= graphics
;
3046 real_metafile
->playback_dc
= NULL
;
3047 real_metafile
->src_rect
= *srcRect
;
3049 memcpy(real_metafile
->playback_points
, destPoints
, sizeof(PointF
) * 3);
3050 stat
= GdipTransformPoints(graphics
, CoordinateSpaceDevice
, CoordinateSpaceWorld
, real_metafile
->playback_points
, 3);
3053 stat
= GdipBeginContainer2(graphics
, &state
);
3057 stat
= GdipSetPageScale(graphics
, 1.0);
3060 stat
= GdipSetPageUnit(graphics
, UnitPixel
);
3063 stat
= GdipResetWorldTransform(graphics
);
3066 stat
= GdipCreateRegion(&real_metafile
->base_clip
);
3069 stat
= GdipGetClip(graphics
, real_metafile
->base_clip
);
3072 stat
= GdipCreateRegion(&real_metafile
->clip
);
3075 stat
= GdipCreatePath(FillModeAlternate
, &dst_path
);
3079 GpPointF clip_points
[4];
3081 clip_points
[0] = real_metafile
->playback_points
[0];
3082 clip_points
[1] = real_metafile
->playback_points
[1];
3083 clip_points
[2].X
= real_metafile
->playback_points
[1].X
+ real_metafile
->playback_points
[2].X
3084 - real_metafile
->playback_points
[0].X
;
3085 clip_points
[2].Y
= real_metafile
->playback_points
[1].Y
+ real_metafile
->playback_points
[2].Y
3086 - real_metafile
->playback_points
[0].Y
;
3087 clip_points
[3] = real_metafile
->playback_points
[2];
3089 stat
= GdipAddPathPolygon(dst_path
, clip_points
, 4);
3092 stat
= GdipCombineRegionPath(real_metafile
->base_clip
, dst_path
, CombineModeIntersect
);
3094 GdipDeletePath(dst_path
);
3098 stat
= GdipCreateMatrix(&real_metafile
->world_transform
);
3102 real_metafile
->page_unit
= UnitDisplay
;
3103 real_metafile
->page_scale
= 1.0;
3104 stat
= METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
3109 stat
= METAFILE_PlaybackUpdateClip(real_metafile
);
3112 if (stat
== Ok
&& (metafile
->metafile_type
== MetafileTypeEmf
||
3113 metafile
->metafile_type
== MetafileTypeWmfPlaceable
||
3114 metafile
->metafile_type
== MetafileTypeWmf
))
3115 stat
= METAFILE_PlaybackGetDC(real_metafile
);
3118 EnumEnhMetaFile(0, metafile
->hemf
, enum_metafile_proc
, &data
, NULL
);
3120 METAFILE_PlaybackReleaseDC(real_metafile
);
3122 GdipDeleteMatrix(real_metafile
->world_transform
);
3123 real_metafile
->world_transform
= NULL
;
3125 GdipDeleteRegion(real_metafile
->base_clip
);
3126 real_metafile
->base_clip
= NULL
;
3128 GdipDeleteRegion(real_metafile
->clip
);
3129 real_metafile
->clip
= NULL
;
3131 while (list_head(&real_metafile
->containers
))
3133 container
* cont
= LIST_ENTRY(list_head(&real_metafile
->containers
), container
, entry
);
3134 list_remove(&cont
->entry
);
3135 GdipDeleteRegion(cont
->clip
);
3139 GdipEndContainer(graphics
, state
);
3142 real_metafile
->playback_graphics
= NULL
;
3147 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRect(GpGraphics
*graphics
,
3148 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRectF
*dest
,
3149 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3153 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
3155 points
[0].X
= points
[2].X
= dest
->X
;
3156 points
[0].Y
= points
[1].Y
= dest
->Y
;
3157 points
[1].X
= dest
->X
+ dest
->Width
;
3158 points
[2].Y
= dest
->Y
+ dest
->Height
;
3160 return GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, points
, 3,
3161 &metafile
->bounds
, metafile
->unit
, callback
, cb_data
, attrs
);
3164 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRectI(GpGraphics
*graphics
,
3165 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRect
*dest
,
3166 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3170 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
3174 destf
.Width
= dest
->Width
;
3175 destf
.Height
= dest
->Height
;
3177 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
3180 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPoint(GpGraphics
*graphics
,
3181 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*dest
,
3182 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3186 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
3190 destf
.Width
= units_to_pixels(metafile
->bounds
.Width
, metafile
->unit
, metafile
->image
.xres
);
3191 destf
.Height
= units_to_pixels(metafile
->bounds
.Height
, metafile
->unit
, metafile
->image
.yres
);
3193 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
3196 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPointI(GpGraphics
*graphics
,
3197 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPoint
*dest
,
3198 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
3202 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
3207 return GdipEnumerateMetafileDestPoint(graphics
, metafile
, &ptf
, callback
, cb_data
, attrs
);
3210 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromMetafile(GpMetafile
* metafile
,
3211 MetafileHeader
* header
)
3215 TRACE("(%p, %p)\n", metafile
, header
);
3217 if(!metafile
|| !header
)
3218 return InvalidParameter
;
3222 status
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, header
);
3223 if (status
!= Ok
) return status
;
3227 memset(header
, 0, sizeof(*header
));
3228 header
->Version
= VERSION_MAGIC2
;
3231 header
->Type
= metafile
->metafile_type
;
3232 header
->DpiX
= metafile
->image
.xres
;
3233 header
->DpiY
= metafile
->image
.yres
;
3234 header
->Width
= gdip_round(metafile
->bounds
.Width
);
3235 header
->Height
= gdip_round(metafile
->bounds
.Height
);
3240 static int CALLBACK
get_emfplus_header_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
3241 int nObj
, LPARAM lpData
)
3243 EmfPlusHeader
*dst_header
= (EmfPlusHeader
*)lpData
;
3245 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
3247 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
3249 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
3251 const EmfPlusRecordHeader
*header
= (const EmfPlusRecordHeader
*)&comment
->Data
[4];
3253 if (4 + sizeof(EmfPlusHeader
) <= comment
->cbData
&&
3254 header
->Type
== EmfPlusRecordTypeHeader
)
3256 memcpy(dst_header
, header
, sizeof(*dst_header
));
3260 else if (lpEMFR
->iType
== EMR_HEADER
)
3266 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromEmf(HENHMETAFILE hemf
,
3267 MetafileHeader
*header
)
3269 ENHMETAHEADER3 emfheader
;
3270 EmfPlusHeader emfplusheader
;
3271 MetafileType metafile_type
;
3273 TRACE("(%p,%p)\n", hemf
, header
);
3275 if(!hemf
|| !header
)
3276 return InvalidParameter
;
3278 if (GetEnhMetaFileHeader(hemf
, sizeof(emfheader
), (ENHMETAHEADER
*)&emfheader
) == 0)
3279 return GenericError
;
3281 emfplusheader
.Header
.Type
= 0;
3283 EnumEnhMetaFile(NULL
, hemf
, get_emfplus_header_proc
, &emfplusheader
, NULL
);
3285 if (emfplusheader
.Header
.Type
== EmfPlusRecordTypeHeader
)
3287 if ((emfplusheader
.Header
.Flags
& 1) == 1)
3288 metafile_type
= MetafileTypeEmfPlusDual
;
3290 metafile_type
= MetafileTypeEmfPlusOnly
;
3293 metafile_type
= MetafileTypeEmf
;
3295 header
->Type
= metafile_type
;
3296 header
->Size
= emfheader
.nBytes
;
3297 header
->DpiX
= (REAL
)emfheader
.szlDevice
.cx
* 25.4 / emfheader
.szlMillimeters
.cx
;
3298 header
->DpiY
= (REAL
)emfheader
.szlDevice
.cy
* 25.4 / emfheader
.szlMillimeters
.cy
;
3299 header
->X
= gdip_round((REAL
)emfheader
.rclFrame
.left
/ 2540.0 * header
->DpiX
);
3300 header
->Y
= gdip_round((REAL
)emfheader
.rclFrame
.top
/ 2540.0 * header
->DpiY
);
3301 header
->Width
= gdip_round((REAL
)(emfheader
.rclFrame
.right
- emfheader
.rclFrame
.left
) / 2540.0 * header
->DpiX
);
3302 header
->Height
= gdip_round((REAL
)(emfheader
.rclFrame
.bottom
- emfheader
.rclFrame
.top
) / 2540.0 * header
->DpiY
);
3303 header
->u
.EmfHeader
= emfheader
;
3305 if (metafile_type
== MetafileTypeEmfPlusDual
|| metafile_type
== MetafileTypeEmfPlusOnly
)
3307 header
->Version
= emfplusheader
.Version
;
3308 header
->EmfPlusFlags
= emfplusheader
.EmfPlusFlags
;
3309 header
->EmfPlusHeaderSize
= emfplusheader
.Header
.Size
;
3310 header
->LogicalDpiX
= emfplusheader
.LogicalDpiX
;
3311 header
->LogicalDpiY
= emfplusheader
.LogicalDpiY
;
3315 header
->Version
= emfheader
.nVersion
;
3316 header
->EmfPlusFlags
= 0;
3317 header
->EmfPlusHeaderSize
= 0;
3318 header
->LogicalDpiX
= 0;
3319 header
->LogicalDpiY
= 0;
3325 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromWmf(HMETAFILE hwmf
,
3326 GDIPCONST WmfPlaceableFileHeader
*placeable
, MetafileHeader
*header
)
3329 GpMetafile
*metafile
;
3331 TRACE("(%p,%p,%p)\n", hwmf
, placeable
, header
);
3333 status
= GdipCreateMetafileFromWmf(hwmf
, FALSE
, placeable
, &metafile
);
3336 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
3337 GdipDisposeImage(&metafile
->image
);
3342 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR
*filename
,
3343 MetafileHeader
*header
)
3346 GpMetafile
*metafile
;
3348 TRACE("(%s,%p)\n", debugstr_w(filename
), header
);
3350 if (!filename
|| !header
)
3351 return InvalidParameter
;
3353 status
= GdipCreateMetafileFromFile(filename
, &metafile
);
3356 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
3357 GdipDisposeImage(&metafile
->image
);
3362 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromStream(IStream
*stream
,
3363 MetafileHeader
*header
)
3366 GpMetafile
*metafile
;
3368 TRACE("(%p,%p)\n", stream
, header
);
3370 if (!stream
|| !header
)
3371 return InvalidParameter
;
3373 status
= GdipCreateMetafileFromStream(stream
, &metafile
);
3376 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
3377 GdipDisposeImage(&metafile
->image
);
3382 GpStatus WINGDIPAPI
GdipCreateMetafileFromEmf(HENHMETAFILE hemf
, BOOL
delete,
3383 GpMetafile
**metafile
)
3386 MetafileHeader header
;
3388 TRACE("(%p,%i,%p)\n", hemf
, delete, metafile
);
3390 if(!hemf
|| !metafile
)
3391 return InvalidParameter
;
3393 stat
= GdipGetMetafileHeaderFromEmf(hemf
, &header
);
3397 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
3401 (*metafile
)->image
.type
= ImageTypeMetafile
;
3402 (*metafile
)->image
.format
= ImageFormatEMF
;
3403 (*metafile
)->image
.frame_count
= 1;
3404 (*metafile
)->image
.xres
= header
.DpiX
;
3405 (*metafile
)->image
.yres
= header
.DpiY
;
3406 (*metafile
)->bounds
.X
= (REAL
)header
.u
.EmfHeader
.rclFrame
.left
/ 2540.0 * header
.DpiX
;
3407 (*metafile
)->bounds
.Y
= (REAL
)header
.u
.EmfHeader
.rclFrame
.top
/ 2540.0 * header
.DpiY
;
3408 (*metafile
)->bounds
.Width
= (REAL
)(header
.u
.EmfHeader
.rclFrame
.right
- header
.u
.EmfHeader
.rclFrame
.left
)
3409 / 2540.0 * header
.DpiX
;
3410 (*metafile
)->bounds
.Height
= (REAL
)(header
.u
.EmfHeader
.rclFrame
.bottom
- header
.u
.EmfHeader
.rclFrame
.top
)
3411 / 2540.0 * header
.DpiY
;
3412 (*metafile
)->unit
= UnitPixel
;
3413 (*metafile
)->metafile_type
= header
.Type
;
3414 (*metafile
)->hemf
= hemf
;
3415 (*metafile
)->preserve_hemf
= !delete;
3416 list_init(&(*metafile
)->containers
);
3418 TRACE("<-- %p\n", *metafile
);
3423 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmf(HMETAFILE hwmf
, BOOL
delete,
3424 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
3429 GpStatus retval
= Ok
;
3431 TRACE("(%p, %d, %p, %p)\n", hwmf
, delete, placeable
, metafile
);
3433 if(!hwmf
|| !metafile
)
3434 return InvalidParameter
;
3437 read
= GetMetaFileBitsEx(hwmf
, 0, NULL
);
3439 return GenericError
;
3440 copy
= heap_alloc_zero(read
);
3441 GetMetaFileBitsEx(hwmf
, read
, copy
);
3443 hemf
= SetWinMetaFileBits(read
, copy
, NULL
, NULL
);
3446 /* FIXME: We should store and use hwmf instead of converting to hemf */
3447 retval
= GdipCreateMetafileFromEmf(hemf
, TRUE
, metafile
);
3453 (*metafile
)->image
.xres
= (REAL
)placeable
->Inch
;
3454 (*metafile
)->image
.yres
= (REAL
)placeable
->Inch
;
3455 (*metafile
)->bounds
.X
= ((REAL
)placeable
->BoundingBox
.Left
) / ((REAL
)placeable
->Inch
);
3456 (*metafile
)->bounds
.Y
= ((REAL
)placeable
->BoundingBox
.Top
) / ((REAL
)placeable
->Inch
);
3457 (*metafile
)->bounds
.Width
= (REAL
)(placeable
->BoundingBox
.Right
-
3458 placeable
->BoundingBox
.Left
);
3459 (*metafile
)->bounds
.Height
= (REAL
)(placeable
->BoundingBox
.Bottom
-
3460 placeable
->BoundingBox
.Top
);
3461 (*metafile
)->metafile_type
= MetafileTypeWmfPlaceable
;
3464 (*metafile
)->metafile_type
= MetafileTypeWmf
;
3465 (*metafile
)->image
.format
= ImageFormatWMF
;
3467 if (delete) DeleteMetaFile(hwmf
);
3470 DeleteEnhMetaFile(hemf
);
3474 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR
*file
,
3475 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
3480 TRACE("(%s, %p, %p)\n", debugstr_w(file
), placeable
, metafile
);
3482 hmf
= GetMetaFileW(file
);
3484 return GdipCreateMetafileFromWmf(hmf
, TRUE
, placeable
, metafile
);
3486 emf
= GetEnhMetaFileW(file
);
3488 return GdipCreateMetafileFromEmf(emf
, TRUE
, metafile
);
3490 return GenericError
;
3493 GpStatus WINGDIPAPI
GdipCreateMetafileFromFile(GDIPCONST WCHAR
*file
,
3494 GpMetafile
**metafile
)
3499 TRACE("(%p, %p)\n", file
, metafile
);
3501 if (!file
|| !metafile
) return InvalidParameter
;
3505 status
= GdipCreateStreamOnFile(file
, GENERIC_READ
, &stream
);
3508 status
= GdipCreateMetafileFromStream(stream
, metafile
);
3509 IStream_Release(stream
);
3514 GpStatus WINGDIPAPI
GdipCreateMetafileFromStream(IStream
*stream
,
3515 GpMetafile
**metafile
)
3519 TRACE("%p %p\n", stream
, metafile
);
3521 stat
= GdipLoadImageFromStream(stream
, (GpImage
**)metafile
);
3522 if (stat
!= Ok
) return stat
;
3524 if ((*metafile
)->image
.type
!= ImageTypeMetafile
)
3526 GdipDisposeImage(&(*metafile
)->image
);
3528 return GenericError
;
3534 GpStatus WINGDIPAPI
GdipSetMetafileDownLevelRasterizationLimit(GpMetafile
*metafile
,
3537 TRACE("(%p,%u)\n", metafile
, limitDpi
);
3542 GpStatus WINGDIPAPI
GdipConvertToEmfPlus(const GpGraphics
* ref
,
3543 GpMetafile
* metafile
, BOOL
* succ
, EmfType emfType
,
3544 const WCHAR
* description
, GpMetafile
** out_metafile
)
3548 TRACE("(%p,%p,%p,%u,%s,%p)\n", ref
, metafile
, succ
, emfType
,
3549 debugstr_w(description
), out_metafile
);
3551 if(!ref
|| !metafile
|| !out_metafile
|| emfType
< EmfTypeEmfOnly
|| emfType
> EmfTypeEmfPlusDual
)
3552 return InvalidParameter
;
3556 *out_metafile
= NULL
;
3559 FIXME("not implemented\n");
3561 return NotImplemented
;
3564 GpStatus WINGDIPAPI
GdipEmfToWmfBits(HENHMETAFILE hemf
, UINT cbData16
,
3565 LPBYTE pData16
, INT iMapMode
, INT eFlags
)
3567 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf
, cbData16
, pData16
, iMapMode
, eFlags
);
3568 return NotImplemented
;
3571 GpStatus WINGDIPAPI
GdipRecordMetafileFileName(GDIPCONST WCHAR
* fileName
,
3572 HDC hdc
, EmfType type
, GDIPCONST GpRectF
*pFrameRect
,
3573 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
,
3574 GpMetafile
**metafile
)
3576 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
3577 frameUnit
, debugstr_w(desc
), metafile
);
3579 return NotImplemented
;
3582 GpStatus WINGDIPAPI
GdipRecordMetafileFileNameI(GDIPCONST WCHAR
* fileName
, HDC hdc
, EmfType type
,
3583 GDIPCONST GpRect
*pFrameRect
, MetafileFrameUnit frameUnit
,
3584 GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
3586 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
3587 frameUnit
, debugstr_w(desc
), metafile
);
3589 return NotImplemented
;
3592 /*****************************************************************************
3593 * GdipConvertToEmfPlusToFile [GDIPLUS.@]
3596 GpStatus WINGDIPAPI
GdipConvertToEmfPlusToFile(const GpGraphics
* refGraphics
,
3597 GpMetafile
* metafile
, BOOL
* conversionSuccess
,
3598 const WCHAR
* filename
, EmfType emfType
,
3599 const WCHAR
* description
, GpMetafile
** out_metafile
)
3601 FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics
, metafile
, conversionSuccess
, filename
, emfType
, description
, out_metafile
);
3602 return NotImplemented
;
3605 static GpStatus
METAFILE_CreateCompressedImageStream(GpImage
*image
, IStream
**stream
, DWORD
*size
)
3614 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, stream
);
3615 if (FAILED(hr
)) return hresult_to_status(hr
);
3617 stat
= encode_image_png(image
, *stream
, NULL
);
3620 IStream_Release(*stream
);
3624 hr
= IStream_Stat(*stream
, &statstg
, 1);
3627 IStream_Release(*stream
);
3628 return hresult_to_status(hr
);
3630 *size
= statstg
.cbSize
.u
.LowPart
;
3633 hr
= IStream_Seek(*stream
, zero
, STREAM_SEEK_SET
, NULL
);
3636 IStream_Release(*stream
);
3637 return hresult_to_status(hr
);
3643 static GpStatus
METAFILE_FillEmfPlusBitmap(EmfPlusBitmap
*record
, IStream
*stream
, DWORD size
)
3650 record
->PixelFormat
= 0;
3651 record
->Type
= BitmapDataTypeCompressed
;
3653 hr
= IStream_Read(stream
, record
->BitmapData
, size
, NULL
);
3654 if (FAILED(hr
)) return hresult_to_status(hr
);
3658 static GpStatus
METAFILE_AddImageObject(GpMetafile
*metafile
, GpImage
*image
, DWORD
*id
)
3660 EmfPlusObject
*object_record
;
3666 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
3669 if (image
->type
== ImageTypeBitmap
)
3674 stat
= METAFILE_CreateCompressedImageStream(image
, &stream
, &size
);
3675 if (stat
!= Ok
) return stat
;
3676 aligned_size
= (size
+ 3) & ~3;
3678 stat
= METAFILE_AllocateRecord(metafile
,
3679 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image
.ImageData
.bitmap
.BitmapData
[aligned_size
]),
3680 (void**)&object_record
);
3683 IStream_Release(stream
);
3686 memset(object_record
->ObjectData
.image
.ImageData
.bitmap
.BitmapData
+ size
, 0, aligned_size
- size
);
3688 *id
= METAFILE_AddObjectId(metafile
);
3689 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
3690 object_record
->Header
.Flags
= *id
| ObjectTypeImage
<< 8;
3691 object_record
->ObjectData
.image
.Version
= VERSION_MAGIC2
;
3692 object_record
->ObjectData
.image
.Type
= ImageDataTypeBitmap
;
3694 stat
= METAFILE_FillEmfPlusBitmap(&object_record
->ObjectData
.image
.ImageData
.bitmap
, stream
, size
);
3695 IStream_Release(stream
);
3696 if (stat
!= Ok
) METAFILE_RemoveLastRecord(metafile
, &object_record
->Header
);
3699 else if (image
->type
== ImageTypeMetafile
)
3701 HENHMETAFILE hemf
= ((GpMetafile
*)image
)->hemf
;
3702 EmfPlusMetafile
*metafile_record
;
3704 if (!hemf
) return InvalidParameter
;
3706 size
= GetEnhMetaFileBits(hemf
, 0, NULL
);
3707 if (!size
) return GenericError
;
3709 stat
= METAFILE_AllocateRecord(metafile
,
3710 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image
.ImageData
.metafile
.MetafileData
[size
]),
3711 (void**)&object_record
);
3712 if (stat
!= Ok
) return stat
;
3714 *id
= METAFILE_AddObjectId(metafile
);
3715 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
3716 object_record
->Header
.Flags
= *id
| ObjectTypeImage
<< 8;
3717 object_record
->ObjectData
.image
.Version
= VERSION_MAGIC2
;
3718 object_record
->ObjectData
.image
.Type
= ImageDataTypeMetafile
;
3719 metafile_record
= &object_record
->ObjectData
.image
.ImageData
.metafile
;
3720 metafile_record
->Type
= ((GpMetafile
*)image
)->metafile_type
;
3721 metafile_record
->MetafileDataSize
= size
;
3722 if (GetEnhMetaFileBits(hemf
, size
, metafile_record
->MetafileData
) != size
)
3724 METAFILE_RemoveLastRecord(metafile
, &object_record
->Header
);
3725 return GenericError
;
3731 FIXME("not supported image type (%d)\n", image
->type
);
3732 return NotImplemented
;
3736 static GpStatus
METAFILE_AddImageAttributesObject(GpMetafile
*metafile
, const GpImageAttributes
*attrs
, DWORD
*id
)
3738 EmfPlusObject
*object_record
;
3739 EmfPlusImageAttributes
*attrs_record
;
3744 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
3750 stat
= METAFILE_AllocateRecord(metafile
,
3751 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image_attributes
) + sizeof(EmfPlusImageAttributes
),
3752 (void**)&object_record
);
3753 if (stat
!= Ok
) return stat
;
3755 *id
= METAFILE_AddObjectId(metafile
);
3756 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
3757 object_record
->Header
.Flags
= *id
| (ObjectTypeImageAttributes
<< 8);
3758 attrs_record
= &object_record
->ObjectData
.image_attributes
;
3759 attrs_record
->Version
= VERSION_MAGIC2
;
3760 attrs_record
->Reserved1
= 0;
3761 attrs_record
->WrapMode
= attrs
->wrap
;
3762 attrs_record
->ClampColor
= attrs
->outside_color
;
3763 attrs_record
->ObjectClamp
= attrs
->clamp
;
3764 attrs_record
->Reserved2
= 0;
3768 GpStatus
METAFILE_DrawImagePointsRect(GpMetafile
*metafile
, GpImage
*image
,
3769 GDIPCONST GpPointF
*points
, INT count
, REAL srcx
, REAL srcy
, REAL srcwidth
,
3770 REAL srcheight
, GpUnit srcUnit
, GDIPCONST GpImageAttributes
* imageAttributes
,
3771 DrawImageAbort callback
, VOID
*callbackData
)
3773 EmfPlusDrawImagePoints
*draw_image_record
;
3774 DWORD image_id
, attributes_id
;
3777 if (count
!= 3) return InvalidParameter
;
3779 if (metafile
->metafile_type
== MetafileTypeEmf
)
3781 FIXME("MetafileTypeEmf metafiles not supported\n");
3782 return NotImplemented
;
3785 FIXME("semi-stub\n");
3787 if (!imageAttributes
)
3789 stat
= METAFILE_AddImageObject(metafile
, image
, &image_id
);
3791 else if (image
->type
== ImageTypeBitmap
)
3793 INT width
= ((GpBitmap
*)image
)->width
;
3794 INT height
= ((GpBitmap
*)image
)->height
;
3795 GpGraphics
*graphics
;
3798 stat
= GdipCreateBitmapFromScan0(width
, height
,
3799 0, PixelFormat32bppARGB
, NULL
, &bitmap
);
3800 if (stat
!= Ok
) return stat
;
3802 stat
= GdipGetImageGraphicsContext((GpImage
*)bitmap
, &graphics
);
3805 GdipDisposeImage((GpImage
*)bitmap
);
3809 stat
= GdipDrawImageRectRectI(graphics
, image
, 0, 0, width
, height
,
3810 0, 0, width
, height
, UnitPixel
, imageAttributes
, NULL
, NULL
);
3811 GdipDeleteGraphics(graphics
);
3814 GdipDisposeImage((GpImage
*)bitmap
);
3818 stat
= METAFILE_AddImageObject(metafile
, (GpImage
*)bitmap
, &image_id
);
3819 GdipDisposeImage((GpImage
*)bitmap
);
3823 FIXME("imageAttributes not supported (image type %d)\n", image
->type
);
3824 return NotImplemented
;
3826 if (stat
!= Ok
) return stat
;
3828 stat
= METAFILE_AddImageAttributesObject(metafile
, imageAttributes
, &attributes_id
);
3829 if (stat
!= Ok
) return stat
;
3831 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusDrawImagePoints
), (void**)&draw_image_record
);
3832 if (stat
!= Ok
) return stat
;
3833 draw_image_record
->Header
.Type
= EmfPlusRecordTypeDrawImagePoints
;
3834 draw_image_record
->Header
.Flags
= image_id
;
3835 draw_image_record
->ImageAttributesID
= attributes_id
;
3836 draw_image_record
->SrcUnit
= UnitPixel
;
3837 draw_image_record
->SrcRect
.X
= units_to_pixels(srcx
, srcUnit
, metafile
->image
.xres
);
3838 draw_image_record
->SrcRect
.Y
= units_to_pixels(srcy
, srcUnit
, metafile
->image
.yres
);
3839 draw_image_record
->SrcRect
.Width
= units_to_pixels(srcwidth
, srcUnit
, metafile
->image
.xres
);
3840 draw_image_record
->SrcRect
.Height
= units_to_pixels(srcheight
, srcUnit
, metafile
->image
.yres
);
3841 draw_image_record
->count
= 3;
3842 memcpy(draw_image_record
->PointData
.pointsF
, points
, 3 * sizeof(*points
));
3843 METAFILE_WriteRecords(metafile
);
3847 GpStatus
METAFILE_AddSimpleProperty(GpMetafile
*metafile
, SHORT prop
, SHORT val
)
3849 EmfPlusRecordHeader
*record
;
3852 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
3855 stat
= METAFILE_AllocateRecord(metafile
, sizeof(*record
), (void**)&record
);
3856 if (stat
!= Ok
) return stat
;
3858 record
->Type
= prop
;
3859 record
->Flags
= val
;
3861 METAFILE_WriteRecords(metafile
);
3865 static GpStatus
METAFILE_AddPathObject(GpMetafile
*metafile
, GpPath
*path
, DWORD
*id
)
3867 EmfPlusObject
*object_record
;
3872 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
3875 size
= write_path_data(path
, NULL
);
3876 stat
= METAFILE_AllocateRecord(metafile
,
3877 FIELD_OFFSET(EmfPlusObject
, ObjectData
.path
) + size
,
3878 (void**)&object_record
);
3879 if (stat
!= Ok
) return stat
;
3881 *id
= METAFILE_AddObjectId(metafile
);
3882 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
3883 object_record
->Header
.Flags
= *id
| ObjectTypePath
<< 8;
3884 write_path_data(path
, &object_record
->ObjectData
.path
);
3888 static GpStatus
METAFILE_PrepareBrushData(GpBrush
*brush
, DWORD
*size
)
3892 case BrushTypeSolidColor
:
3893 *size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
) + sizeof(EmfPlusSolidBrushData
);
3895 case BrushTypeHatchFill
:
3896 *size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
) + sizeof(EmfPlusHatchBrushData
);
3899 FIXME("unsupported brush type: %d\n", brush
->bt
);
3900 return NotImplemented
;
3906 static void METAFILE_FillBrushData(GpBrush
*brush
, EmfPlusBrush
*data
)
3908 data
->Version
= VERSION_MAGIC2
;
3909 data
->Type
= brush
->bt
;
3913 case BrushTypeSolidColor
:
3915 GpSolidFill
*solid
= (GpSolidFill
*)brush
;
3916 data
->BrushData
.solid
.SolidColor
= solid
->color
;
3919 case BrushTypeHatchFill
:
3921 GpHatch
*hatch
= (GpHatch
*)brush
;
3922 data
->BrushData
.hatch
.HatchStyle
= hatch
->hatchstyle
;
3923 data
->BrushData
.hatch
.ForeColor
= hatch
->forecol
;
3924 data
->BrushData
.hatch
.BackColor
= hatch
->backcol
;
3928 FIXME("unsupported brush type: %d\n", brush
->bt
);
3932 static GpStatus
METAFILE_AddPenObject(GpMetafile
*metafile
, GpPen
*pen
, DWORD
*id
)
3934 DWORD i
, data_flags
, pen_data_size
, brush_size
;
3935 EmfPlusObject
*object_record
;
3936 EmfPlusPenData
*pen_data
;
3941 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
3945 pen_data_size
= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
3947 GdipIsMatrixIdentity(&pen
->transform
, &result
);
3950 data_flags
|= PenDataTransform
;
3951 pen_data_size
+= sizeof(EmfPlusTransformMatrix
);
3953 if (pen
->startcap
!= LineCapFlat
)
3955 data_flags
|= PenDataStartCap
;
3956 pen_data_size
+= sizeof(DWORD
);
3958 if (pen
->endcap
!= LineCapFlat
)
3960 data_flags
|= PenDataEndCap
;
3961 pen_data_size
+= sizeof(DWORD
);
3963 if (pen
->join
!= LineJoinMiter
)
3965 data_flags
|= PenDataJoin
;
3966 pen_data_size
+= sizeof(DWORD
);
3968 if (pen
->miterlimit
!= 10.0)
3970 data_flags
|= PenDataMiterLimit
;
3971 pen_data_size
+= sizeof(REAL
);
3973 if (pen
->style
!= GP_DEFAULT_PENSTYLE
)
3975 data_flags
|= PenDataLineStyle
;
3976 pen_data_size
+= sizeof(DWORD
);
3978 if (pen
->dashcap
!= DashCapFlat
)
3980 data_flags
|= PenDataDashedLineCap
;
3981 pen_data_size
+= sizeof(DWORD
);
3983 data_flags
|= PenDataDashedLineOffset
;
3984 pen_data_size
+= sizeof(REAL
);
3987 data_flags
|= PenDataDashedLine
;
3988 pen_data_size
+= sizeof(DWORD
) + pen
->numdashes
*sizeof(REAL
);
3990 if (pen
->align
!= PenAlignmentCenter
)
3992 data_flags
|= PenDataNonCenter
;
3993 pen_data_size
+= sizeof(DWORD
);
3995 /* TODO: Add support for PenDataCompoundLine */
3996 if (pen
->customstart
)
3998 FIXME("ignoring custom start cup\n");
4002 FIXME("ignoring custom end cup\n");
4005 stat
= METAFILE_PrepareBrushData(pen
->brush
, &brush_size
);
4006 if (stat
!= Ok
) return stat
;
4008 stat
= METAFILE_AllocateRecord(metafile
,
4009 FIELD_OFFSET(EmfPlusObject
, ObjectData
.pen
.data
) + pen_data_size
+ brush_size
,
4010 (void**)&object_record
);
4011 if (stat
!= Ok
) return stat
;
4013 *id
= METAFILE_AddObjectId(metafile
);
4014 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
4015 object_record
->Header
.Flags
= *id
| ObjectTypePen
<< 8;
4016 object_record
->ObjectData
.pen
.Version
= VERSION_MAGIC2
;
4017 object_record
->ObjectData
.pen
.Type
= 0;
4019 pen_data
= (EmfPlusPenData
*)object_record
->ObjectData
.pen
.data
;
4020 pen_data
->PenDataFlags
= data_flags
;
4021 pen_data
->PenUnit
= pen
->unit
;
4022 pen_data
->PenWidth
= pen
->width
;
4025 if (data_flags
& PenDataTransform
)
4027 EmfPlusTransformMatrix
*m
= (EmfPlusTransformMatrix
*)(pen_data
->OptionalData
+ i
);
4028 memcpy(m
, &pen
->transform
, sizeof(*m
));
4029 i
+= sizeof(EmfPlusTransformMatrix
);
4031 if (data_flags
& PenDataStartCap
)
4033 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->startcap
;
4036 if (data_flags
& PenDataEndCap
)
4038 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->endcap
;
4041 if (data_flags
& PenDataJoin
)
4043 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->join
;
4046 if (data_flags
& PenDataMiterLimit
)
4048 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->miterlimit
;
4051 if (data_flags
& PenDataLineStyle
)
4053 switch (pen
->style
& PS_STYLE_MASK
)
4055 case PS_SOLID
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleSolid
; break;
4056 case PS_DASH
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDash
; break;
4057 case PS_DOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDot
; break;
4058 case PS_DASHDOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDashDot
; break;
4059 case PS_DASHDOTDOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDashDotDot
; break;
4060 default: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleCustom
; break;
4064 if (data_flags
& PenDataDashedLineCap
)
4066 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->dashcap
;
4069 if (data_flags
& PenDataDashedLineOffset
)
4071 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->offset
;
4074 if (data_flags
& PenDataDashedLine
)
4078 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->numdashes
;
4081 for (j
=0; j
<pen
->numdashes
; j
++)
4083 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->dashes
[j
];
4087 if (data_flags
& PenDataNonCenter
)
4089 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->align
;
4093 METAFILE_FillBrushData(pen
->brush
,
4094 (EmfPlusBrush
*)(object_record
->ObjectData
.pen
.data
+ pen_data_size
));
4098 GpStatus
METAFILE_DrawPath(GpMetafile
*metafile
, GpPen
*pen
, GpPath
*path
)
4100 EmfPlusDrawPath
*draw_path_record
;
4105 if (metafile
->metafile_type
== MetafileTypeEmf
)
4108 return NotImplemented
;
4111 stat
= METAFILE_AddPenObject(metafile
, pen
, &pen_id
);
4112 if (stat
!= Ok
) return stat
;
4114 stat
= METAFILE_AddPathObject(metafile
, path
, &path_id
);
4115 if (stat
!= Ok
) return stat
;
4117 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusDrawPath
), (void**)&draw_path_record
);
4118 if (stat
!= Ok
) return stat
;
4119 draw_path_record
->Header
.Type
= EmfPlusRecordTypeDrawPath
;
4120 draw_path_record
->Header
.Flags
= path_id
;
4121 draw_path_record
->PenId
= pen_id
;
4123 METAFILE_WriteRecords(metafile
);
4127 static GpStatus
METAFILE_AddBrushObject(GpMetafile
*metafile
, GpBrush
*brush
, DWORD
*id
)
4129 EmfPlusObject
*object_record
;
4134 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
4137 stat
= METAFILE_PrepareBrushData(brush
, &size
);
4138 if (stat
!= Ok
) return stat
;
4140 stat
= METAFILE_AllocateRecord(metafile
,
4141 FIELD_OFFSET(EmfPlusObject
, ObjectData
) + size
, (void**)&object_record
);
4142 if (stat
!= Ok
) return stat
;
4144 *id
= METAFILE_AddObjectId(metafile
);
4145 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
4146 object_record
->Header
.Flags
= *id
| ObjectTypeBrush
<< 8;
4147 METAFILE_FillBrushData(brush
, &object_record
->ObjectData
.brush
);
4151 GpStatus
METAFILE_FillPath(GpMetafile
*metafile
, GpBrush
*brush
, GpPath
*path
)
4153 EmfPlusFillPath
*fill_path_record
;
4154 DWORD brush_id
= -1, path_id
;
4158 if (metafile
->metafile_type
== MetafileTypeEmf
)
4161 return NotImplemented
;
4164 inline_color
= brush
->bt
== BrushTypeSolidColor
;
4167 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
4168 if (stat
!= Ok
) return stat
;
4171 stat
= METAFILE_AddPathObject(metafile
, path
, &path_id
);
4172 if (stat
!= Ok
) return stat
;
4174 stat
= METAFILE_AllocateRecord(metafile
,
4175 sizeof(EmfPlusFillPath
), (void**)&fill_path_record
);
4176 if (stat
!= Ok
) return stat
;
4177 fill_path_record
->Header
.Type
= EmfPlusRecordTypeFillPath
;
4180 fill_path_record
->Header
.Flags
= 0x8000 | path_id
;
4181 fill_path_record
->data
.Color
= ((GpSolidFill
*)brush
)->color
;
4185 fill_path_record
->Header
.Flags
= path_id
;
4186 fill_path_record
->data
.BrushId
= brush_id
;
4189 METAFILE_WriteRecords(metafile
);