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 struct EmfPlusARGB
56 typedef struct EmfPlusRecordHeader
62 } EmfPlusRecordHeader
;
64 typedef struct EmfPlusHeader
66 EmfPlusRecordHeader Header
;
73 typedef struct EmfPlusClear
75 EmfPlusRecordHeader Header
;
79 typedef struct EmfPlusFillRects
81 EmfPlusRecordHeader Header
;
86 typedef struct EmfPlusSetClipRect
88 EmfPlusRecordHeader Header
;
92 typedef struct EmfPlusSetPageTransform
94 EmfPlusRecordHeader Header
;
96 } EmfPlusSetPageTransform
;
98 typedef struct EmfPlusRect
106 typedef struct EmfPlusSetWorldTransform
108 EmfPlusRecordHeader Header
;
110 } EmfPlusSetWorldTransform
;
112 typedef struct EmfPlusScaleWorldTransform
114 EmfPlusRecordHeader Header
;
117 } EmfPlusScaleWorldTransform
;
119 typedef struct EmfPlusMultiplyWorldTransform
121 EmfPlusRecordHeader Header
;
123 } EmfPlusMultiplyWorldTransform
;
125 typedef struct EmfPlusRotateWorldTransform
127 EmfPlusRecordHeader Header
;
129 } EmfPlusRotateWorldTransform
;
131 typedef struct EmfPlusTranslateWorldTransform
133 EmfPlusRecordHeader Header
;
136 } EmfPlusTranslateWorldTransform
;
138 typedef struct EmfPlusBeginContainer
140 EmfPlusRecordHeader Header
;
144 } EmfPlusBeginContainer
;
146 typedef struct EmfPlusContainerRecord
148 EmfPlusRecordHeader Header
;
150 } EmfPlusContainerRecord
;
158 typedef struct container
162 enum container_type type
;
163 GraphicsContainer state
;
164 GpMatrix world_transform
;
172 PenDataTransform
= 0x0001,
173 PenDataStartCap
= 0x0002,
174 PenDataEndCap
= 0x0004,
175 PenDataJoin
= 0x0008,
176 PenDataMiterLimit
= 0x0010,
177 PenDataLineStyle
= 0x0020,
178 PenDataDashedLineCap
= 0x0040,
179 PenDataDashedLineOffset
= 0x0080,
180 PenDataDashedLine
= 0x0100,
181 PenDataNonCenter
= 0x0200,
182 PenDataCompoundLine
= 0x0400,
183 PenDataCustomStartCap
= 0x0800,
184 PenDataCustomEndCap
= 0x1000
187 typedef struct EmfPlusTransformMatrix
189 REAL TransformMatrix
[6];
190 } EmfPlusTransformMatrix
;
202 typedef struct EmfPlusPenData
207 BYTE OptionalData
[1];
210 typedef struct EmfPlusSolidBrushData
212 EmfPlusARGB SolidColor
;
213 } EmfPlusSolidBrushData
;
215 typedef struct EmfPlusBrush
220 EmfPlusSolidBrushData solid
;
224 typedef struct EmfPlusPen
233 typedef struct EmfPlusPath
236 DWORD PathPointCount
;
237 DWORD PathPointFlags
;
239 /* PathPointTypes[] */
240 /* AlignmentPadding */
244 typedef struct EmfPlusRegion
247 DWORD RegionNodeCount
;
251 typedef struct EmfPlusPalette
253 DWORD PaletteStyleFlags
;
255 BYTE PaletteEntries
[1];
261 BitmapDataTypeCompressed
,
264 typedef struct EmfPlusBitmap
274 typedef struct EmfPlusMetafile
277 DWORD MetafileDataSize
;
278 BYTE MetafileData
[1];
281 typedef enum ImageDataType
283 ImageDataTypeUnknown
,
285 ImageDataTypeMetafile
,
288 typedef struct EmfPlusImage
294 EmfPlusBitmap bitmap
;
295 EmfPlusMetafile metafile
;
299 typedef struct EmfPlusImageAttributes
304 EmfPlusARGB ClampColor
;
307 } EmfPlusImageAttributes
;
309 typedef struct EmfPlusObject
311 EmfPlusRecordHeader Header
;
317 EmfPlusRegion region
;
319 EmfPlusImageAttributes image_attributes
;
323 typedef struct EmfPlusRectF
331 typedef struct EmfPlusPointR7
337 typedef struct EmfPlusPoint
343 typedef struct EmfPlusPointF
349 typedef struct EmfPlusDrawImagePoints
351 EmfPlusRecordHeader Header
;
352 DWORD ImageAttributesID
;
354 EmfPlusRectF SrcRect
;
358 EmfPlusPointR7 pointsR
[3];
359 EmfPlusPoint points
[3];
360 EmfPlusPointF pointsF
[3];
362 } EmfPlusDrawImagePoints
;
364 typedef struct EmfPlusDrawPath
366 EmfPlusRecordHeader Header
;
370 typedef struct EmfPlusFillPath
372 EmfPlusRecordHeader Header
;
380 typedef struct EmfPlusFont
385 DWORD FontStyleFlags
;
391 static void metafile_free_object_table_entry(GpMetafile
*metafile
, BYTE id
)
393 struct emfplus_object
*object
= &metafile
->objtable
[id
];
395 switch (object
->type
)
397 case ObjectTypeInvalid
:
399 case ObjectTypeBrush
:
400 GdipDeleteBrush(object
->u
.brush
);
403 GdipDeletePath(object
->u
.path
);
405 case ObjectTypeImage
:
406 GdipDisposeImage(object
->u
.image
);
409 GdipDeleteFont(object
->u
.font
);
411 case ObjectTypeImageAttributes
:
412 GdipDisposeImageAttributes(object
->u
.image_attributes
);
415 FIXME("not implemented for object type %u.\n", object
->type
);
419 object
->type
= ObjectTypeInvalid
;
420 object
->u
.object
= NULL
;
423 void METAFILE_Free(GpMetafile
*metafile
)
427 heap_free(metafile
->comment_data
);
428 DeleteEnhMetaFile(CloseEnhMetaFile(metafile
->record_dc
));
429 if (!metafile
->preserve_hemf
)
430 DeleteEnhMetaFile(metafile
->hemf
);
431 if (metafile
->record_graphics
)
433 WARN("metafile closed while recording\n");
434 /* not sure what to do here; for now just prevent the graphics from functioning or using this object */
435 metafile
->record_graphics
->image
= NULL
;
436 metafile
->record_graphics
->busy
= TRUE
;
439 if (metafile
->record_stream
)
440 IStream_Release(metafile
->record_stream
);
442 for (i
= 0; i
< sizeof(metafile
->objtable
)/sizeof(metafile
->objtable
[0]); i
++)
443 metafile_free_object_table_entry(metafile
, i
);
446 static DWORD
METAFILE_AddObjectId(GpMetafile
*metafile
)
448 return (metafile
->next_object_id
++) % EmfPlusObjectTableSize
;
451 static GpStatus
METAFILE_AllocateRecord(GpMetafile
*metafile
, DWORD size
, void **result
)
454 EmfPlusRecordHeader
*record
;
456 if (!metafile
->comment_data_size
)
458 DWORD data_size
= max(256, size
* 2 + 4);
459 metafile
->comment_data
= heap_alloc_zero(data_size
);
461 if (!metafile
->comment_data
)
464 memcpy(metafile
->comment_data
, "EMF+", 4);
466 metafile
->comment_data_size
= data_size
;
467 metafile
->comment_data_length
= 4;
470 size_needed
= size
+ metafile
->comment_data_length
;
472 if (size_needed
> metafile
->comment_data_size
)
474 DWORD data_size
= size_needed
* 2;
475 BYTE
*new_data
= heap_alloc_zero(data_size
);
480 memcpy(new_data
, metafile
->comment_data
, metafile
->comment_data_length
);
482 metafile
->comment_data_size
= data_size
;
483 heap_free(metafile
->comment_data
);
484 metafile
->comment_data
= new_data
;
487 *result
= metafile
->comment_data
+ metafile
->comment_data_length
;
488 metafile
->comment_data_length
+= size
;
490 record
= (EmfPlusRecordHeader
*)*result
;
492 record
->DataSize
= size
- sizeof(EmfPlusRecordHeader
);
497 static void METAFILE_RemoveLastRecord(GpMetafile
*metafile
, EmfPlusRecordHeader
*record
)
499 assert(metafile
->comment_data
+ metafile
->comment_data_length
== (BYTE
*)record
+ record
->Size
);
500 metafile
->comment_data_length
-= record
->Size
;
503 static void METAFILE_WriteRecords(GpMetafile
*metafile
)
505 if (metafile
->comment_data_length
> 4)
507 GdiComment(metafile
->record_dc
, metafile
->comment_data_length
, metafile
->comment_data
);
508 metafile
->comment_data_length
= 4;
512 static GpStatus
METAFILE_WriteHeader(GpMetafile
*metafile
, HDC hdc
)
516 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
518 EmfPlusHeader
*header
;
520 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusHeader
), (void**)&header
);
524 header
->Header
.Type
= EmfPlusRecordTypeHeader
;
526 if (metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
527 header
->Header
.Flags
= 1;
529 header
->Header
.Flags
= 0;
531 header
->Version
= VERSION_MAGIC2
;
533 if (GetDeviceCaps(hdc
, TECHNOLOGY
) == DT_RASDISPLAY
)
534 header
->EmfPlusFlags
= 1;
536 header
->EmfPlusFlags
= 0;
538 header
->LogicalDpiX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
539 header
->LogicalDpiY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
541 METAFILE_WriteRecords(metafile
);
547 static GpStatus
METAFILE_WriteEndOfFile(GpMetafile
*metafile
)
551 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
553 EmfPlusRecordHeader
*record
;
555 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
559 record
->Type
= EmfPlusRecordTypeEndOfFile
;
562 METAFILE_WriteRecords(metafile
);
568 GpStatus WINGDIPAPI
GdipRecordMetafile(HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
569 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
573 REAL framerect_factor_x
, framerect_factor_y
;
577 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
579 if (!hdc
|| type
< EmfTypeEmfOnly
|| type
> EmfTypeEmfPlusDual
|| !metafile
)
580 return InvalidParameter
;
582 dpix
= (REAL
)GetDeviceCaps(hdc
, HORZRES
) / GetDeviceCaps(hdc
, HORZSIZE
) * 25.4;
583 dpiy
= (REAL
)GetDeviceCaps(hdc
, VERTRES
) / GetDeviceCaps(hdc
, VERTSIZE
) * 25.4;
589 case MetafileFrameUnitPixel
:
590 framerect_factor_x
= 2540.0 / dpix
;
591 framerect_factor_y
= 2540.0 / dpiy
;
593 case MetafileFrameUnitPoint
:
594 framerect_factor_x
= framerect_factor_y
= 2540.0 / 72.0;
596 case MetafileFrameUnitInch
:
597 framerect_factor_x
= framerect_factor_y
= 2540.0;
599 case MetafileFrameUnitDocument
:
600 framerect_factor_x
= framerect_factor_y
= 2540.0 / 300.0;
602 case MetafileFrameUnitMillimeter
:
603 framerect_factor_x
= framerect_factor_y
= 100.0;
605 case MetafileFrameUnitGdi
:
606 framerect_factor_x
= framerect_factor_y
= 1.0;
609 return InvalidParameter
;
612 rc
.left
= framerect_factor_x
* frameRect
->X
;
613 rc
.top
= framerect_factor_y
* frameRect
->Y
;
614 rc
.right
= rc
.left
+ framerect_factor_x
* frameRect
->Width
;
615 rc
.bottom
= rc
.top
+ framerect_factor_y
* frameRect
->Height
;
622 record_dc
= CreateEnhMetaFileW(hdc
, NULL
, lprc
, desc
);
627 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
630 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
634 (*metafile
)->image
.type
= ImageTypeMetafile
;
635 (*metafile
)->image
.flags
= ImageFlagsNone
;
636 (*metafile
)->image
.palette
= NULL
;
637 (*metafile
)->image
.xres
= dpix
;
638 (*metafile
)->image
.yres
= dpiy
;
639 (*metafile
)->bounds
.X
= (*metafile
)->bounds
.Y
= 0.0;
640 (*metafile
)->bounds
.Width
= (*metafile
)->bounds
.Height
= 1.0;
641 (*metafile
)->unit
= UnitPixel
;
642 (*metafile
)->metafile_type
= type
;
643 (*metafile
)->record_dc
= record_dc
;
644 (*metafile
)->comment_data
= NULL
;
645 (*metafile
)->comment_data_size
= 0;
646 (*metafile
)->comment_data_length
= 0;
647 (*metafile
)->hemf
= NULL
;
648 list_init(&(*metafile
)->containers
);
652 (*metafile
)->auto_frame
= TRUE
;
653 (*metafile
)->auto_frame_min
.X
= 0;
654 (*metafile
)->auto_frame_min
.Y
= 0;
655 (*metafile
)->auto_frame_max
.X
= -1;
656 (*metafile
)->auto_frame_max
.Y
= -1;
659 stat
= METAFILE_WriteHeader(*metafile
, hdc
);
663 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
664 heap_free(*metafile
);
672 /*****************************************************************************
673 * GdipRecordMetafileI [GDIPLUS.@]
675 GpStatus WINGDIPAPI
GdipRecordMetafileI(HDC hdc
, EmfType type
, GDIPCONST GpRect
*frameRect
,
676 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
678 GpRectF frameRectF
, *pFrameRectF
;
680 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
684 frameRectF
.X
= frameRect
->X
;
685 frameRectF
.Y
= frameRect
->Y
;
686 frameRectF
.Width
= frameRect
->Width
;
687 frameRectF
.Height
= frameRect
->Height
;
688 pFrameRectF
= &frameRectF
;
693 return GdipRecordMetafile(hdc
, type
, pFrameRectF
, frameUnit
, desc
, metafile
);
696 GpStatus WINGDIPAPI
GdipRecordMetafileStream(IStream
*stream
, HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
697 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
701 TRACE("(%p %p %d %p %d %p %p)\n", stream
, hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
704 return InvalidParameter
;
706 stat
= GdipRecordMetafile(hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
710 (*metafile
)->record_stream
= stream
;
711 IStream_AddRef(stream
);
717 static void METAFILE_AdjustFrame(GpMetafile
* metafile
, const GpPointF
*points
,
722 if (!metafile
->auto_frame
|| !num_points
)
725 if (metafile
->auto_frame_max
.X
< metafile
->auto_frame_min
.X
)
726 metafile
->auto_frame_max
= metafile
->auto_frame_min
= points
[0];
728 for (i
=0; i
<num_points
; i
++)
730 if (points
[i
].X
< metafile
->auto_frame_min
.X
)
731 metafile
->auto_frame_min
.X
= points
[i
].X
;
732 if (points
[i
].X
> metafile
->auto_frame_max
.X
)
733 metafile
->auto_frame_max
.X
= points
[i
].X
;
734 if (points
[i
].Y
< metafile
->auto_frame_min
.Y
)
735 metafile
->auto_frame_min
.Y
= points
[i
].Y
;
736 if (points
[i
].Y
> metafile
->auto_frame_max
.Y
)
737 metafile
->auto_frame_max
.Y
= points
[i
].Y
;
741 GpStatus
METAFILE_GetGraphicsContext(GpMetafile
* metafile
, GpGraphics
**result
)
745 if (!metafile
->record_dc
|| metafile
->record_graphics
)
746 return InvalidParameter
;
748 stat
= graphics_from_image((GpImage
*)metafile
, &metafile
->record_graphics
);
752 *result
= metafile
->record_graphics
;
753 metafile
->record_graphics
->xres
= 96.0;
754 metafile
->record_graphics
->yres
= 96.0;
760 GpStatus
METAFILE_GetDC(GpMetafile
* metafile
, HDC
*hdc
)
762 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
764 EmfPlusRecordHeader
*record
;
767 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
771 record
->Type
= EmfPlusRecordTypeGetDC
;
774 METAFILE_WriteRecords(metafile
);
777 *hdc
= metafile
->record_dc
;
782 GpStatus
METAFILE_GraphicsClear(GpMetafile
* metafile
, ARGB color
)
784 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
786 EmfPlusClear
*record
;
789 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusClear
), (void**)&record
);
793 record
->Header
.Type
= EmfPlusRecordTypeClear
;
794 record
->Header
.Flags
= 0;
795 record
->Color
= color
;
797 METAFILE_WriteRecords(metafile
);
803 static BOOL
is_integer_rect(const GpRectF
*rect
)
805 SHORT x
, y
, width
, height
;
809 height
= rect
->Height
;
810 if (rect
->X
!= (REAL
)x
|| rect
->Y
!= (REAL
)y
||
811 rect
->Width
!= (REAL
)width
|| rect
->Height
!= (REAL
)height
)
816 GpStatus
METAFILE_FillRectangles(GpMetafile
* metafile
, GpBrush
* brush
,
817 GDIPCONST GpRectF
* rects
, INT count
)
819 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
821 EmfPlusFillRects
*record
;
823 BOOL integer_rects
= TRUE
;
828 if (brush
->bt
== BrushTypeSolidColor
)
831 brushid
= ((GpSolidFill
*)brush
)->color
;
835 FIXME("brush serialization not implemented\n");
836 return NotImplemented
;
839 for (i
=0; i
<count
; i
++)
841 if (!is_integer_rect(&rects
[i
]))
843 integer_rects
= FALSE
;
851 stat
= METAFILE_AllocateRecord(metafile
,
852 sizeof(EmfPlusFillRects
) + count
* (integer_rects
? sizeof(EmfPlusRect
) : sizeof(GpRectF
)),
857 record
->Header
.Type
= EmfPlusRecordTypeFillRects
;
858 record
->Header
.Flags
= flags
;
859 record
->BrushID
= brushid
;
860 record
->Count
= count
;
864 EmfPlusRect
*record_rects
= (EmfPlusRect
*)(record
+1);
865 for (i
=0; i
<count
; i
++)
867 record_rects
[i
].X
= (SHORT
)rects
[i
].X
;
868 record_rects
[i
].Y
= (SHORT
)rects
[i
].Y
;
869 record_rects
[i
].Width
= (SHORT
)rects
[i
].Width
;
870 record_rects
[i
].Height
= (SHORT
)rects
[i
].Height
;
874 memcpy(record
+1, rects
, sizeof(GpRectF
) * count
);
876 METAFILE_WriteRecords(metafile
);
879 if (metafile
->auto_frame
)
884 for (i
=0; i
<count
; i
++)
886 corners
[0].X
= rects
[i
].X
;
887 corners
[0].Y
= rects
[i
].Y
;
888 corners
[1].X
= rects
[i
].X
+ rects
[i
].Width
;
889 corners
[1].Y
= rects
[i
].Y
;
890 corners
[2].X
= rects
[i
].X
;
891 corners
[2].Y
= rects
[i
].Y
+ rects
[i
].Height
;
892 corners
[3].X
= rects
[i
].X
+ rects
[i
].Width
;
893 corners
[3].Y
= rects
[i
].Y
+ rects
[i
].Height
;
895 GdipTransformPoints(metafile
->record_graphics
, CoordinateSpaceDevice
,
896 CoordinateSpaceWorld
, corners
, 4);
898 METAFILE_AdjustFrame(metafile
, corners
, 4);
905 GpStatus
METAFILE_SetClipRect(GpMetafile
* metafile
, REAL x
, REAL y
, REAL width
, REAL height
, CombineMode mode
)
907 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
909 EmfPlusSetClipRect
*record
;
912 stat
= METAFILE_AllocateRecord(metafile
,
913 sizeof(EmfPlusSetClipRect
),
918 record
->Header
.Type
= EmfPlusRecordTypeSetClipRect
;
919 record
->Header
.Flags
= (mode
& 0xf) << 8;
920 record
->ClipRect
.X
= x
;
921 record
->ClipRect
.Y
= y
;
922 record
->ClipRect
.Width
= width
;
923 record
->ClipRect
.Height
= height
;
925 METAFILE_WriteRecords(metafile
);
931 static GpStatus
METAFILE_AddRegionObject(GpMetafile
*metafile
, GpRegion
*region
, DWORD
*id
)
933 EmfPlusObject
*object_record
;
938 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
941 size
= write_region_data(region
, NULL
);
942 stat
= METAFILE_AllocateRecord(metafile
,
943 FIELD_OFFSET(EmfPlusObject
, ObjectData
.region
) + size
, (void**)&object_record
);
944 if (stat
!= Ok
) return stat
;
946 *id
= METAFILE_AddObjectId(metafile
);
947 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
948 object_record
->Header
.Flags
= *id
| ObjectTypeRegion
<< 8;
949 write_region_data(region
, &object_record
->ObjectData
.region
);
953 GpStatus
METAFILE_SetClipRegion(GpMetafile
* metafile
, GpRegion
* region
, CombineMode mode
)
955 EmfPlusRecordHeader
*record
;
959 if (metafile
->metafile_type
== MetafileTypeEmf
)
962 return NotImplemented
;
965 stat
= METAFILE_AddRegionObject(metafile
, region
, ®ion_id
);
966 if (stat
!= Ok
) return stat
;
968 stat
= METAFILE_AllocateRecord(metafile
, sizeof(*record
), (void**)&record
);
969 if (stat
!= Ok
) return stat
;
971 record
->Type
= EmfPlusRecordTypeSetClipRegion
;
972 record
->Flags
= region_id
| mode
<< 8;
974 METAFILE_WriteRecords(metafile
);
978 GpStatus
METAFILE_SetPageTransform(GpMetafile
* metafile
, GpUnit unit
, REAL scale
)
980 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
982 EmfPlusSetPageTransform
*record
;
985 stat
= METAFILE_AllocateRecord(metafile
,
986 sizeof(EmfPlusSetPageTransform
),
991 record
->Header
.Type
= EmfPlusRecordTypeSetPageTransform
;
992 record
->Header
.Flags
= unit
;
993 record
->PageScale
= scale
;
995 METAFILE_WriteRecords(metafile
);
1001 GpStatus
METAFILE_SetWorldTransform(GpMetafile
* metafile
, GDIPCONST GpMatrix
* transform
)
1003 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1005 EmfPlusSetWorldTransform
*record
;
1008 stat
= METAFILE_AllocateRecord(metafile
,
1009 sizeof(EmfPlusSetWorldTransform
),
1014 record
->Header
.Type
= EmfPlusRecordTypeSetWorldTransform
;
1015 record
->Header
.Flags
= 0;
1016 memcpy(record
->MatrixData
, transform
->matrix
, sizeof(record
->MatrixData
));
1018 METAFILE_WriteRecords(metafile
);
1024 GpStatus
METAFILE_ScaleWorldTransform(GpMetafile
* metafile
, REAL sx
, REAL sy
, MatrixOrder order
)
1026 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1028 EmfPlusScaleWorldTransform
*record
;
1031 stat
= METAFILE_AllocateRecord(metafile
,
1032 sizeof(EmfPlusScaleWorldTransform
),
1037 record
->Header
.Type
= EmfPlusRecordTypeScaleWorldTransform
;
1038 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1042 METAFILE_WriteRecords(metafile
);
1048 GpStatus
METAFILE_MultiplyWorldTransform(GpMetafile
* metafile
, GDIPCONST GpMatrix
* matrix
, MatrixOrder order
)
1050 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1052 EmfPlusMultiplyWorldTransform
*record
;
1055 stat
= METAFILE_AllocateRecord(metafile
,
1056 sizeof(EmfPlusMultiplyWorldTransform
),
1061 record
->Header
.Type
= EmfPlusRecordTypeMultiplyWorldTransform
;
1062 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1063 memcpy(record
->MatrixData
, matrix
->matrix
, sizeof(record
->MatrixData
));
1065 METAFILE_WriteRecords(metafile
);
1071 GpStatus
METAFILE_RotateWorldTransform(GpMetafile
* metafile
, REAL angle
, MatrixOrder order
)
1073 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1075 EmfPlusRotateWorldTransform
*record
;
1078 stat
= METAFILE_AllocateRecord(metafile
,
1079 sizeof(EmfPlusRotateWorldTransform
),
1084 record
->Header
.Type
= EmfPlusRecordTypeRotateWorldTransform
;
1085 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1086 record
->Angle
= angle
;
1088 METAFILE_WriteRecords(metafile
);
1094 GpStatus
METAFILE_TranslateWorldTransform(GpMetafile
* metafile
, REAL dx
, REAL dy
, MatrixOrder order
)
1096 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1098 EmfPlusTranslateWorldTransform
*record
;
1101 stat
= METAFILE_AllocateRecord(metafile
,
1102 sizeof(EmfPlusTranslateWorldTransform
),
1107 record
->Header
.Type
= EmfPlusRecordTypeTranslateWorldTransform
;
1108 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1112 METAFILE_WriteRecords(metafile
);
1118 GpStatus
METAFILE_ResetWorldTransform(GpMetafile
* metafile
)
1120 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1122 EmfPlusRecordHeader
*record
;
1125 stat
= METAFILE_AllocateRecord(metafile
,
1126 sizeof(EmfPlusRecordHeader
),
1131 record
->Type
= EmfPlusRecordTypeResetWorldTransform
;
1134 METAFILE_WriteRecords(metafile
);
1140 GpStatus
METAFILE_BeginContainer(GpMetafile
* metafile
, GDIPCONST GpRectF
*dstrect
,
1141 GDIPCONST GpRectF
*srcrect
, GpUnit unit
, DWORD StackIndex
)
1143 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1145 EmfPlusBeginContainer
*record
;
1148 stat
= METAFILE_AllocateRecord(metafile
, sizeof(*record
), (void**)&record
);
1152 record
->Header
.Type
= EmfPlusRecordTypeBeginContainer
;
1153 record
->Header
.Flags
= unit
& 0xff;
1154 record
->DestRect
= *dstrect
;
1155 record
->SrcRect
= *srcrect
;
1156 record
->StackIndex
= StackIndex
;
1158 METAFILE_WriteRecords(metafile
);
1164 GpStatus
METAFILE_BeginContainerNoParams(GpMetafile
* metafile
, DWORD StackIndex
)
1166 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1168 EmfPlusContainerRecord
*record
;
1171 stat
= METAFILE_AllocateRecord(metafile
,
1172 sizeof(EmfPlusContainerRecord
),
1177 record
->Header
.Type
= EmfPlusRecordTypeBeginContainerNoParams
;
1178 record
->Header
.Flags
= 0;
1179 record
->StackIndex
= StackIndex
;
1181 METAFILE_WriteRecords(metafile
);
1187 GpStatus
METAFILE_EndContainer(GpMetafile
* metafile
, DWORD StackIndex
)
1189 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1191 EmfPlusContainerRecord
*record
;
1194 stat
= METAFILE_AllocateRecord(metafile
,
1195 sizeof(EmfPlusContainerRecord
),
1200 record
->Header
.Type
= EmfPlusRecordTypeEndContainer
;
1201 record
->Header
.Flags
= 0;
1202 record
->StackIndex
= StackIndex
;
1204 METAFILE_WriteRecords(metafile
);
1210 GpStatus
METAFILE_SaveGraphics(GpMetafile
* metafile
, DWORD StackIndex
)
1212 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1214 EmfPlusContainerRecord
*record
;
1217 stat
= METAFILE_AllocateRecord(metafile
,
1218 sizeof(EmfPlusContainerRecord
),
1223 record
->Header
.Type
= EmfPlusRecordTypeSave
;
1224 record
->Header
.Flags
= 0;
1225 record
->StackIndex
= StackIndex
;
1227 METAFILE_WriteRecords(metafile
);
1233 GpStatus
METAFILE_RestoreGraphics(GpMetafile
* metafile
, DWORD StackIndex
)
1235 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1237 EmfPlusContainerRecord
*record
;
1240 stat
= METAFILE_AllocateRecord(metafile
,
1241 sizeof(EmfPlusContainerRecord
),
1246 record
->Header
.Type
= EmfPlusRecordTypeRestore
;
1247 record
->Header
.Flags
= 0;
1248 record
->StackIndex
= StackIndex
;
1250 METAFILE_WriteRecords(metafile
);
1256 GpStatus
METAFILE_ReleaseDC(GpMetafile
* metafile
, HDC hdc
)
1258 if (hdc
!= metafile
->record_dc
)
1259 return InvalidParameter
;
1264 GpStatus
METAFILE_GraphicsDeleted(GpMetafile
* metafile
)
1268 stat
= METAFILE_WriteEndOfFile(metafile
);
1269 metafile
->record_graphics
= NULL
;
1271 metafile
->hemf
= CloseEnhMetaFile(metafile
->record_dc
);
1272 metafile
->record_dc
= NULL
;
1274 heap_free(metafile
->comment_data
);
1275 metafile
->comment_data
= NULL
;
1276 metafile
->comment_data_size
= 0;
1280 MetafileHeader header
;
1282 stat
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, &header
);
1283 if (stat
== Ok
&& metafile
->auto_frame
&&
1284 metafile
->auto_frame_max
.X
>= metafile
->auto_frame_min
.X
)
1286 RECTL bounds_rc
, gdi_bounds_rc
;
1287 REAL x_scale
= 2540.0 / header
.DpiX
;
1288 REAL y_scale
= 2540.0 / header
.DpiY
;
1292 bounds_rc
.left
= floorf(metafile
->auto_frame_min
.X
* x_scale
);
1293 bounds_rc
.top
= floorf(metafile
->auto_frame_min
.Y
* y_scale
);
1294 bounds_rc
.right
= ceilf(metafile
->auto_frame_max
.X
* x_scale
);
1295 bounds_rc
.bottom
= ceilf(metafile
->auto_frame_max
.Y
* y_scale
);
1297 gdi_bounds_rc
= header
.u
.EmfHeader
.rclBounds
;
1298 if (gdi_bounds_rc
.right
> gdi_bounds_rc
.left
&& gdi_bounds_rc
.bottom
> gdi_bounds_rc
.top
)
1300 bounds_rc
.left
= min(bounds_rc
.left
, gdi_bounds_rc
.left
);
1301 bounds_rc
.top
= min(bounds_rc
.top
, gdi_bounds_rc
.top
);
1302 bounds_rc
.right
= max(bounds_rc
.right
, gdi_bounds_rc
.right
);
1303 bounds_rc
.bottom
= max(bounds_rc
.bottom
, gdi_bounds_rc
.bottom
);
1306 buffer_size
= GetEnhMetaFileBits(metafile
->hemf
, 0, NULL
);
1307 buffer
= heap_alloc(buffer_size
);
1310 HENHMETAFILE new_hemf
;
1312 GetEnhMetaFileBits(metafile
->hemf
, buffer_size
, buffer
);
1314 ((ENHMETAHEADER
*)buffer
)->rclFrame
= bounds_rc
;
1316 new_hemf
= SetEnhMetaFileBits(buffer_size
, buffer
);
1320 DeleteEnhMetaFile(metafile
->hemf
);
1321 metafile
->hemf
= new_hemf
;
1332 stat
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, &header
);
1336 metafile
->bounds
.X
= header
.X
;
1337 metafile
->bounds
.Y
= header
.Y
;
1338 metafile
->bounds
.Width
= header
.Width
;
1339 metafile
->bounds
.Height
= header
.Height
;
1343 if (stat
== Ok
&& metafile
->record_stream
)
1348 buffer_size
= GetEnhMetaFileBits(metafile
->hemf
, 0, NULL
);
1350 buffer
= heap_alloc(buffer_size
);
1355 GetEnhMetaFileBits(metafile
->hemf
, buffer_size
, buffer
);
1357 hr
= IStream_Write(metafile
->record_stream
, buffer
, buffer_size
, NULL
);
1360 stat
= hresult_to_status(hr
);
1368 if (metafile
->record_stream
)
1370 IStream_Release(metafile
->record_stream
);
1371 metafile
->record_stream
= NULL
;
1377 GpStatus WINGDIPAPI
GdipGetHemfFromMetafile(GpMetafile
*metafile
, HENHMETAFILE
*hEmf
)
1379 TRACE("(%p,%p)\n", metafile
, hEmf
);
1381 if (!metafile
|| !hEmf
|| !metafile
->hemf
)
1382 return InvalidParameter
;
1384 *hEmf
= metafile
->hemf
;
1385 metafile
->hemf
= NULL
;
1390 static void METAFILE_GetFinalGdiTransform(const GpMetafile
*metafile
, XFORM
*result
)
1392 const GpRectF
*rect
;
1395 /* This transforms metafile device space to output points. */
1396 rect
= &metafile
->src_rect
;
1397 pt
= metafile
->playback_points
;
1398 result
->eM11
= (pt
[1].X
- pt
[0].X
) / rect
->Width
;
1399 result
->eM21
= (pt
[2].X
- pt
[0].X
) / rect
->Height
;
1400 result
->eDx
= pt
[0].X
- result
->eM11
* rect
->X
- result
->eM21
* rect
->Y
;
1401 result
->eM12
= (pt
[1].Y
- pt
[0].Y
) / rect
->Width
;
1402 result
->eM22
= (pt
[2].Y
- pt
[0].Y
) / rect
->Height
;
1403 result
->eDy
= pt
[0].Y
- result
->eM12
* rect
->X
- result
->eM22
* rect
->Y
;
1406 static GpStatus
METAFILE_PlaybackUpdateGdiTransform(GpMetafile
*metafile
)
1408 XFORM combined
, final
;
1410 METAFILE_GetFinalGdiTransform(metafile
, &final
);
1412 CombineTransform(&combined
, &metafile
->gdiworldtransform
, &final
);
1414 SetGraphicsMode(metafile
->playback_dc
, GM_ADVANCED
);
1415 SetWorldTransform(metafile
->playback_dc
, &combined
);
1420 static GpStatus
METAFILE_PlaybackGetDC(GpMetafile
*metafile
)
1424 stat
= GdipGetDC(metafile
->playback_graphics
, &metafile
->playback_dc
);
1428 static const XFORM identity
= {1, 0, 0, 1, 0, 0};
1430 metafile
->gdiworldtransform
= identity
;
1431 METAFILE_PlaybackUpdateGdiTransform(metafile
);
1437 static void METAFILE_PlaybackReleaseDC(GpMetafile
*metafile
)
1439 if (metafile
->playback_dc
)
1441 GdipReleaseDC(metafile
->playback_graphics
, metafile
->playback_dc
);
1442 metafile
->playback_dc
= NULL
;
1446 static GpStatus
METAFILE_PlaybackUpdateClip(GpMetafile
*metafile
)
1449 stat
= GdipCombineRegionRegion(metafile
->playback_graphics
->clip
, metafile
->base_clip
, CombineModeReplace
);
1451 stat
= GdipCombineRegionRegion(metafile
->playback_graphics
->clip
, metafile
->clip
, CombineModeIntersect
);
1455 static GpStatus
METAFILE_PlaybackUpdateWorldTransform(GpMetafile
*metafile
)
1457 GpMatrix
*real_transform
;
1460 stat
= GdipCreateMatrix3(&metafile
->src_rect
, metafile
->playback_points
, &real_transform
);
1464 REAL scale
= units_to_pixels(1.0, metafile
->page_unit
, 96.0);
1466 if (metafile
->page_unit
!= UnitDisplay
)
1467 scale
*= metafile
->page_scale
;
1469 stat
= GdipScaleMatrix(real_transform
, scale
, scale
, MatrixOrderPrepend
);
1472 stat
= GdipMultiplyMatrix(real_transform
, metafile
->world_transform
, MatrixOrderPrepend
);
1475 stat
= GdipSetWorldTransform(metafile
->playback_graphics
, real_transform
);
1477 GdipDeleteMatrix(real_transform
);
1483 static void metafile_set_object_table_entry(GpMetafile
*metafile
, BYTE id
, BYTE type
, void *object
)
1485 metafile_free_object_table_entry(metafile
, id
);
1486 metafile
->objtable
[id
].type
= type
;
1487 metafile
->objtable
[id
].u
.object
= object
;
1490 static GpStatus
metafile_deserialize_image(const BYTE
*record_data
, UINT data_size
, GpImage
**image
)
1492 EmfPlusImage
*data
= (EmfPlusImage
*)record_data
;
1497 if (data_size
< FIELD_OFFSET(EmfPlusImage
, ImageData
))
1498 return InvalidParameter
;
1499 data_size
-= FIELD_OFFSET(EmfPlusImage
, ImageData
);
1503 case ImageDataTypeBitmap
:
1505 EmfPlusBitmap
*bitmapdata
= &data
->ImageData
.bitmap
;
1507 if (data_size
<= FIELD_OFFSET(EmfPlusBitmap
, BitmapData
))
1508 return InvalidParameter
;
1509 data_size
-= FIELD_OFFSET(EmfPlusBitmap
, BitmapData
);
1511 switch (bitmapdata
->Type
)
1513 case BitmapDataTypePixel
:
1515 ColorPalette
*palette
;
1518 if (bitmapdata
->PixelFormat
& PixelFormatIndexed
)
1520 EmfPlusPalette
*palette_obj
= (EmfPlusPalette
*)bitmapdata
->BitmapData
;
1521 UINT palette_size
= FIELD_OFFSET(EmfPlusPalette
, PaletteEntries
);
1523 if (data_size
<= palette_size
)
1524 return InvalidParameter
;
1525 palette_size
+= palette_obj
->PaletteCount
* sizeof(EmfPlusARGB
);
1527 if (data_size
< palette_size
)
1528 return InvalidParameter
;
1529 data_size
-= palette_size
;
1531 palette
= (ColorPalette
*)bitmapdata
->BitmapData
;
1532 scan0
= (BYTE
*)bitmapdata
->BitmapData
+ palette_size
;
1537 scan0
= bitmapdata
->BitmapData
;
1540 if (data_size
< bitmapdata
->Height
* bitmapdata
->Stride
)
1541 return InvalidParameter
;
1543 status
= GdipCreateBitmapFromScan0(bitmapdata
->Width
, bitmapdata
->Height
, bitmapdata
->Stride
,
1544 bitmapdata
->PixelFormat
, scan0
, (GpBitmap
**)image
);
1545 if (status
== Ok
&& palette
)
1547 status
= GdipSetImagePalette(*image
, palette
);
1550 GdipDisposeImage(*image
);
1556 case BitmapDataTypeCompressed
:
1558 IWICImagingFactory
*factory
;
1562 if (WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION
, &factory
) != S_OK
)
1563 return GenericError
;
1565 hr
= IWICImagingFactory_CreateStream(factory
, &stream
);
1566 IWICImagingFactory_Release(factory
);
1568 return GenericError
;
1570 if (IWICStream_InitializeFromMemory(stream
, bitmapdata
->BitmapData
, data_size
) == S_OK
)
1571 status
= GdipCreateBitmapFromStream((IStream
*)stream
, (GpBitmap
**)image
);
1573 status
= GenericError
;
1575 IWICStream_Release(stream
);
1579 WARN("Invalid bitmap type %d.\n", bitmapdata
->Type
);
1580 return InvalidParameter
;
1585 FIXME("image type %d not supported.\n", data
->Type
);
1586 return NotImplemented
;
1592 static GpStatus
metafile_deserialize_path(const BYTE
*record_data
, UINT data_size
, GpPath
**path
)
1594 EmfPlusPath
*data
= (EmfPlusPath
*)record_data
;
1602 if (data_size
<= FIELD_OFFSET(EmfPlusPath
, data
))
1603 return InvalidParameter
;
1604 data_size
-= FIELD_OFFSET(EmfPlusPath
, data
);
1606 if (data
->PathPointFlags
& 0x800) /* R */
1608 FIXME("RLE encoded path data is not supported.\n");
1609 return NotImplemented
;
1613 if (data
->PathPointFlags
& 0x4000) /* C */
1614 size
= sizeof(EmfPlusPoint
);
1616 size
= sizeof(EmfPlusPointF
);
1617 size
+= sizeof(BYTE
); /* EmfPlusPathPointType */
1618 size
*= data
->PathPointCount
;
1621 if (data_size
< size
)
1622 return InvalidParameter
;
1624 status
= GdipCreatePath(FillModeAlternate
, path
);
1628 (*path
)->pathdata
.Count
= data
->PathPointCount
;
1629 (*path
)->pathdata
.Points
= GdipAlloc(data
->PathPointCount
* sizeof(*(*path
)->pathdata
.Points
));
1630 (*path
)->pathdata
.Types
= GdipAlloc(data
->PathPointCount
* sizeof(*(*path
)->pathdata
.Types
));
1631 (*path
)->datalen
= (*path
)->pathdata
.Count
;
1633 if (!(*path
)->pathdata
.Points
|| !(*path
)->pathdata
.Types
)
1635 GdipDeletePath(*path
);
1639 if (data
->PathPointFlags
& 0x4000) /* C */
1641 EmfPlusPoint
*points
= (EmfPlusPoint
*)data
->data
;
1642 for (i
= 0; i
< data
->PathPointCount
; i
++)
1644 (*path
)->pathdata
.Points
[i
].X
= points
[i
].X
;
1645 (*path
)->pathdata
.Points
[i
].Y
= points
[i
].Y
;
1647 types
= (BYTE
*)(points
+ i
);
1651 EmfPlusPointF
*points
= (EmfPlusPointF
*)data
->data
;
1652 memcpy((*path
)->pathdata
.Points
, points
, sizeof(*points
) * data
->PathPointCount
);
1653 types
= (BYTE
*)(points
+ data
->PathPointCount
);
1656 memcpy((*path
)->pathdata
.Types
, types
, sizeof(*types
) * data
->PathPointCount
);
1661 static GpStatus
metafile_deserialize_brush(const BYTE
*record_data
, UINT data_size
, GpBrush
**brush
)
1663 static const UINT header_size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
);
1664 EmfPlusBrush
*data
= (EmfPlusBrush
*)record_data
;
1669 if (data_size
< header_size
)
1670 return InvalidParameter
;
1674 case BrushTypeSolidColor
:
1675 if (data_size
!= header_size
+ sizeof(EmfPlusSolidBrushData
))
1676 return InvalidParameter
;
1678 status
= GdipCreateSolidFill(*(ARGB
*)&data
->BrushData
.solid
.SolidColor
, (GpSolidFill
**)brush
);
1681 FIXME("brush type %u is not supported.\n", data
->Type
);
1682 return NotImplemented
;
1688 static GpStatus
METAFILE_PlaybackObject(GpMetafile
*metafile
, UINT flags
, UINT data_size
, const BYTE
*record_data
)
1690 BYTE type
= (flags
>> 8) & 0xff;
1691 BYTE id
= flags
& 0xff;
1692 void *object
= NULL
;
1695 if (type
> ObjectTypeMax
|| id
>= EmfPlusObjectTableSize
)
1696 return InvalidParameter
;
1700 case ObjectTypeBrush
:
1701 status
= metafile_deserialize_brush(record_data
, data_size
, (GpBrush
**)&object
);
1703 case ObjectTypePath
:
1704 status
= metafile_deserialize_path(record_data
, data_size
, (GpPath
**)&object
);
1706 case ObjectTypeImage
:
1707 status
= metafile_deserialize_image(record_data
, data_size
, (GpImage
**)&object
);
1709 case ObjectTypeFont
:
1711 EmfPlusFont
*data
= (EmfPlusFont
*)record_data
;
1712 GpFontFamily
*family
;
1715 if (data_size
<= FIELD_OFFSET(EmfPlusFont
, FamilyName
))
1716 return InvalidParameter
;
1717 data_size
-= FIELD_OFFSET(EmfPlusFont
, FamilyName
);
1719 if (data_size
< data
->Length
* sizeof(WCHAR
))
1720 return InvalidParameter
;
1722 if (!(familyname
= GdipAlloc((data
->Length
+ 1) * sizeof(*familyname
))))
1725 memcpy(familyname
, data
->FamilyName
, data
->Length
* sizeof(*familyname
));
1726 familyname
[data
->Length
] = 0;
1728 status
= GdipCreateFontFamilyFromName(familyname
, NULL
, &family
);
1729 GdipFree(familyname
);
1731 return InvalidParameter
;
1733 status
= GdipCreateFont(family
, data
->EmSize
, data
->FontStyleFlags
, data
->SizeUnit
, (GpFont
**)&object
);
1734 GdipDeleteFontFamily(family
);
1737 case ObjectTypeImageAttributes
:
1739 EmfPlusImageAttributes
*data
= (EmfPlusImageAttributes
*)record_data
;
1740 GpImageAttributes
*attributes
= NULL
;
1742 if (data_size
!= sizeof(*data
))
1743 return InvalidParameter
;
1745 if ((status
= GdipCreateImageAttributes(&attributes
)) != Ok
)
1748 status
= GdipSetImageAttributesWrapMode(attributes
, data
->WrapMode
, *(DWORD
*)&data
->ClampColor
,
1749 !!data
->ObjectClamp
);
1751 object
= attributes
;
1753 GdipDisposeImageAttributes(attributes
);
1757 FIXME("not implemented for object type %d.\n", type
);
1758 return NotImplemented
;
1762 metafile_set_object_table_entry(metafile
, id
, type
, object
);
1767 GpStatus WINGDIPAPI
GdipPlayMetafileRecord(GDIPCONST GpMetafile
*metafile
,
1768 EmfPlusRecordType recordType
, UINT flags
, UINT dataSize
, GDIPCONST BYTE
*data
)
1771 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
;
1773 TRACE("(%p,%x,%x,%d,%p)\n", metafile
, recordType
, flags
, dataSize
, data
);
1775 if (!metafile
|| (dataSize
&& !data
) || !metafile
->playback_graphics
)
1776 return InvalidParameter
;
1778 if (recordType
>= 1 && recordType
<= 0x7a)
1780 /* regular EMF record */
1781 if (metafile
->playback_dc
)
1785 case EMR_SETMAPMODE
:
1788 case EMR_SETWINDOWORGEX
:
1789 case EMR_SETWINDOWEXTEX
:
1790 case EMR_SETVIEWPORTORGEX
:
1791 case EMR_SETVIEWPORTEXTEX
:
1792 case EMR_SCALEVIEWPORTEXTEX
:
1793 case EMR_SCALEWINDOWEXTEX
:
1794 case EMR_MODIFYWORLDTRANSFORM
:
1795 FIXME("not implemented for record type %x\n", recordType
);
1797 case EMR_SETWORLDTRANSFORM
:
1799 const XFORM
* xform
= (void*)data
;
1800 real_metafile
->gdiworldtransform
= *xform
;
1801 METAFILE_PlaybackUpdateGdiTransform(real_metafile
);
1804 case EMR_EXTSELECTCLIPRGN
:
1806 DWORD rgndatasize
= *(DWORD
*)data
;
1807 DWORD mode
= *(DWORD
*)(data
+ 4);
1808 const RGNDATA
*rgndata
= (const RGNDATA
*)(data
+ 8);
1815 METAFILE_GetFinalGdiTransform(metafile
, &final
);
1817 hrgn
= ExtCreateRegion(&final
, rgndatasize
, rgndata
);
1820 ExtSelectClipRgn(metafile
->playback_dc
, hrgn
, mode
);
1828 ENHMETARECORD
*record
= heap_alloc_zero(dataSize
+ 8);
1832 record
->iType
= recordType
;
1833 record
->nSize
= dataSize
+ 8;
1834 memcpy(record
->dParm
, data
, dataSize
);
1836 if(PlayEnhMetaFileRecord(metafile
->playback_dc
, metafile
->handle_table
,
1837 record
, metafile
->handle_count
) == 0)
1838 ERR("PlayEnhMetaFileRecord failed\n");
1852 EmfPlusRecordHeader
*header
= (EmfPlusRecordHeader
*)(data
)-1;
1854 METAFILE_PlaybackReleaseDC((GpMetafile
*)metafile
);
1858 case EmfPlusRecordTypeHeader
:
1859 case EmfPlusRecordTypeEndOfFile
:
1861 case EmfPlusRecordTypeGetDC
:
1862 METAFILE_PlaybackGetDC((GpMetafile
*)metafile
);
1864 case EmfPlusRecordTypeClear
:
1866 EmfPlusClear
*record
= (EmfPlusClear
*)header
;
1868 if (dataSize
!= sizeof(record
->Color
))
1869 return InvalidParameter
;
1871 return GdipGraphicsClear(metafile
->playback_graphics
, record
->Color
);
1873 case EmfPlusRecordTypeFillRects
:
1875 EmfPlusFillRects
*record
= (EmfPlusFillRects
*)header
;
1876 GpBrush
*brush
, *temp_brush
=NULL
;
1877 GpRectF
*rects
, *temp_rects
=NULL
;
1879 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
))
1880 return InvalidParameter
;
1884 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(EmfPlusRect
) * record
->Count
)
1885 return InvalidParameter
;
1889 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(GpRectF
) * record
->Count
)
1890 return InvalidParameter
;
1895 stat
= GdipCreateSolidFill((ARGB
)record
->BrushID
, (GpSolidFill
**)&temp_brush
);
1900 if (record
->BrushID
>= EmfPlusObjectTableSize
||
1901 real_metafile
->objtable
[record
->BrushID
].type
!= ObjectTypeBrush
)
1902 return InvalidParameter
;
1904 brush
= real_metafile
->objtable
[record
->BrushID
].u
.brush
;
1912 EmfPlusRect
*int_rects
= (EmfPlusRect
*)(record
+1);
1915 rects
= temp_rects
= heap_alloc_zero(sizeof(GpRectF
) * record
->Count
);
1918 for (i
=0; i
<record
->Count
; i
++)
1920 rects
[i
].X
= int_rects
[i
].X
;
1921 rects
[i
].Y
= int_rects
[i
].Y
;
1922 rects
[i
].Width
= int_rects
[i
].Width
;
1923 rects
[i
].Height
= int_rects
[i
].Height
;
1930 rects
= (GpRectF
*)(record
+1);
1935 stat
= GdipFillRectangles(metafile
->playback_graphics
, brush
, rects
, record
->Count
);
1938 GdipDeleteBrush(temp_brush
);
1939 heap_free(temp_rects
);
1943 case EmfPlusRecordTypeSetClipRect
:
1945 EmfPlusSetClipRect
*record
= (EmfPlusSetClipRect
*)header
;
1946 CombineMode mode
= (CombineMode
)((flags
>> 8) & 0xf);
1948 GpMatrix world_to_device
;
1950 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(*record
))
1951 return InvalidParameter
;
1953 stat
= GdipCreateRegionRect(&record
->ClipRect
, ®ion
);
1957 get_graphics_transform(real_metafile
->playback_graphics
,
1958 CoordinateSpaceDevice
, CoordinateSpaceWorld
, &world_to_device
);
1960 GdipTransformRegion(region
, &world_to_device
);
1962 GdipCombineRegionRegion(real_metafile
->clip
, region
, mode
);
1964 GdipDeleteRegion(region
);
1967 return METAFILE_PlaybackUpdateClip(real_metafile
);
1969 case EmfPlusRecordTypeSetPageTransform
:
1971 EmfPlusSetPageTransform
*record
= (EmfPlusSetPageTransform
*)header
;
1972 GpUnit unit
= (GpUnit
)flags
;
1974 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetPageTransform
))
1975 return InvalidParameter
;
1977 real_metafile
->page_unit
= unit
;
1978 real_metafile
->page_scale
= record
->PageScale
;
1980 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
1982 case EmfPlusRecordTypeSetWorldTransform
:
1984 EmfPlusSetWorldTransform
*record
= (EmfPlusSetWorldTransform
*)header
;
1986 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetWorldTransform
))
1987 return InvalidParameter
;
1989 memcpy(real_metafile
->world_transform
->matrix
, record
->MatrixData
, sizeof(record
->MatrixData
));
1991 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
1993 case EmfPlusRecordTypeScaleWorldTransform
:
1995 EmfPlusScaleWorldTransform
*record
= (EmfPlusScaleWorldTransform
*)header
;
1996 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
1998 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusScaleWorldTransform
))
1999 return InvalidParameter
;
2001 GdipScaleMatrix(real_metafile
->world_transform
, record
->Sx
, record
->Sy
, order
);
2003 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2005 case EmfPlusRecordTypeMultiplyWorldTransform
:
2007 EmfPlusMultiplyWorldTransform
*record
= (EmfPlusMultiplyWorldTransform
*)header
;
2008 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2011 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusMultiplyWorldTransform
))
2012 return InvalidParameter
;
2014 memcpy(matrix
.matrix
, record
->MatrixData
, sizeof(matrix
.matrix
));
2016 GdipMultiplyMatrix(real_metafile
->world_transform
, &matrix
, order
);
2018 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2020 case EmfPlusRecordTypeRotateWorldTransform
:
2022 EmfPlusRotateWorldTransform
*record
= (EmfPlusRotateWorldTransform
*)header
;
2023 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2025 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusRotateWorldTransform
))
2026 return InvalidParameter
;
2028 GdipRotateMatrix(real_metafile
->world_transform
, record
->Angle
, order
);
2030 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2032 case EmfPlusRecordTypeTranslateWorldTransform
:
2034 EmfPlusTranslateWorldTransform
*record
= (EmfPlusTranslateWorldTransform
*)header
;
2035 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
2037 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusTranslateWorldTransform
))
2038 return InvalidParameter
;
2040 GdipTranslateMatrix(real_metafile
->world_transform
, record
->dx
, record
->dy
, order
);
2042 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2044 case EmfPlusRecordTypeResetWorldTransform
:
2046 GdipSetMatrixElements(real_metafile
->world_transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
2048 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2050 case EmfPlusRecordTypeBeginContainer
:
2052 EmfPlusBeginContainer
*record
= (EmfPlusBeginContainer
*)header
;
2055 REAL scale_x
, scale_y
;
2056 GpRectF scaled_srcrect
;
2059 cont
= heap_alloc_zero(sizeof(*cont
));
2063 stat
= GdipCloneRegion(metafile
->clip
, &cont
->clip
);
2070 stat
= GdipBeginContainer2(metafile
->playback_graphics
, &cont
->state
);
2074 GdipDeleteRegion(cont
->clip
);
2079 cont
->id
= record
->StackIndex
;
2080 cont
->type
= BEGIN_CONTAINER
;
2081 cont
->world_transform
= *metafile
->world_transform
;
2082 cont
->page_unit
= metafile
->page_unit
;
2083 cont
->page_scale
= metafile
->page_scale
;
2084 list_add_head(&real_metafile
->containers
, &cont
->entry
);
2086 unit
= record
->Header
.Flags
& 0xff;
2088 scale_x
= units_to_pixels(1.0, unit
, metafile
->image
.xres
);
2089 scale_y
= units_to_pixels(1.0, unit
, metafile
->image
.yres
);
2091 scaled_srcrect
.X
= scale_x
* record
->SrcRect
.X
;
2092 scaled_srcrect
.Y
= scale_y
* record
->SrcRect
.Y
;
2093 scaled_srcrect
.Width
= scale_x
* record
->SrcRect
.Width
;
2094 scaled_srcrect
.Height
= scale_y
* record
->SrcRect
.Height
;
2096 transform
.matrix
[0] = record
->DestRect
.Width
/ scaled_srcrect
.Width
;
2097 transform
.matrix
[1] = 0.0;
2098 transform
.matrix
[2] = 0.0;
2099 transform
.matrix
[3] = record
->DestRect
.Height
/ scaled_srcrect
.Height
;
2100 transform
.matrix
[4] = record
->DestRect
.X
- scaled_srcrect
.X
;
2101 transform
.matrix
[5] = record
->DestRect
.Y
- scaled_srcrect
.Y
;
2103 GdipMultiplyMatrix(real_metafile
->world_transform
, &transform
, MatrixOrderPrepend
);
2105 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2107 case EmfPlusRecordTypeBeginContainerNoParams
:
2108 case EmfPlusRecordTypeSave
:
2110 EmfPlusContainerRecord
*record
= (EmfPlusContainerRecord
*)header
;
2113 cont
= heap_alloc_zero(sizeof(*cont
));
2117 stat
= GdipCloneRegion(metafile
->clip
, &cont
->clip
);
2124 if (recordType
== EmfPlusRecordTypeBeginContainerNoParams
)
2125 stat
= GdipBeginContainer2(metafile
->playback_graphics
, &cont
->state
);
2127 stat
= GdipSaveGraphics(metafile
->playback_graphics
, &cont
->state
);
2131 GdipDeleteRegion(cont
->clip
);
2136 cont
->id
= record
->StackIndex
;
2137 if (recordType
== EmfPlusRecordTypeBeginContainerNoParams
)
2138 cont
->type
= BEGIN_CONTAINER
;
2140 cont
->type
= SAVE_GRAPHICS
;
2141 cont
->world_transform
= *metafile
->world_transform
;
2142 cont
->page_unit
= metafile
->page_unit
;
2143 cont
->page_scale
= metafile
->page_scale
;
2144 list_add_head(&real_metafile
->containers
, &cont
->entry
);
2148 case EmfPlusRecordTypeEndContainer
:
2149 case EmfPlusRecordTypeRestore
:
2151 EmfPlusContainerRecord
*record
= (EmfPlusContainerRecord
*)header
;
2153 enum container_type type
;
2156 if (recordType
== EmfPlusRecordTypeEndContainer
)
2157 type
= BEGIN_CONTAINER
;
2159 type
= SAVE_GRAPHICS
;
2161 LIST_FOR_EACH_ENTRY(cont
, &real_metafile
->containers
, container
, entry
)
2163 if (cont
->id
== record
->StackIndex
&& cont
->type
== type
)
2174 /* pop any newer items on the stack */
2175 while ((cont2
= LIST_ENTRY(list_head(&real_metafile
->containers
), container
, entry
)) != cont
)
2177 list_remove(&cont2
->entry
);
2178 GdipDeleteRegion(cont2
->clip
);
2182 if (type
== BEGIN_CONTAINER
)
2183 GdipEndContainer(real_metafile
->playback_graphics
, cont
->state
);
2185 GdipRestoreGraphics(real_metafile
->playback_graphics
, cont
->state
);
2187 *real_metafile
->world_transform
= cont
->world_transform
;
2188 real_metafile
->page_unit
= cont
->page_unit
;
2189 real_metafile
->page_scale
= cont
->page_scale
;
2190 GdipCombineRegionRegion(real_metafile
->clip
, cont
->clip
, CombineModeReplace
);
2192 list_remove(&cont
->entry
);
2193 GdipDeleteRegion(cont
->clip
);
2199 case EmfPlusRecordTypeSetPixelOffsetMode
:
2201 return GdipSetPixelOffsetMode(real_metafile
->playback_graphics
, flags
& 0xff);
2203 case EmfPlusRecordTypeSetCompositingQuality
:
2205 return GdipSetCompositingQuality(real_metafile
->playback_graphics
, flags
& 0xff);
2207 case EmfPlusRecordTypeSetInterpolationMode
:
2209 return GdipSetInterpolationMode(real_metafile
->playback_graphics
, flags
& 0xff);
2211 case EmfPlusRecordTypeSetTextRenderingHint
:
2213 return GdipSetTextRenderingHint(real_metafile
->playback_graphics
, flags
& 0xff);
2215 case EmfPlusRecordTypeSetAntiAliasMode
:
2217 return GdipSetSmoothingMode(real_metafile
->playback_graphics
, (flags
>> 1) & 0xff);
2219 case EmfPlusRecordTypeObject
:
2221 return METAFILE_PlaybackObject(real_metafile
, flags
, dataSize
, data
);
2223 case EmfPlusRecordTypeDrawImagePoints
:
2225 EmfPlusDrawImagePoints
*draw
= (EmfPlusDrawImagePoints
*)header
;
2226 static const UINT fixed_part_size
= FIELD_OFFSET(EmfPlusDrawImagePoints
, PointData
) -
2227 FIELD_OFFSET(EmfPlusDrawImagePoints
, ImageAttributesID
);
2228 BYTE image
= flags
& 0xff;
2233 if (image
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[image
].type
!= ObjectTypeImage
)
2234 return InvalidParameter
;
2236 if (dataSize
<= fixed_part_size
)
2237 return InvalidParameter
;
2238 dataSize
-= fixed_part_size
;
2240 if (draw
->ImageAttributesID
>= EmfPlusObjectTableSize
||
2241 real_metafile
->objtable
[draw
->ImageAttributesID
].type
!= ObjectTypeImageAttributes
)
2242 return InvalidParameter
;
2244 if (draw
->count
!= 3)
2245 return InvalidParameter
;
2247 if ((flags
>> 13) & 1) /* E */
2248 FIXME("image effects are not supported.\n");
2250 if ((flags
>> 11) & 1) /* P */
2251 size
= sizeof(EmfPlusPointR7
) * draw
->count
;
2252 else if ((flags
>> 14) & 1) /* C */
2253 size
= sizeof(EmfPlusPoint
) * draw
->count
;
2255 size
= sizeof(EmfPlusPointF
) * draw
->count
;
2257 if (dataSize
!= size
)
2258 return InvalidParameter
;
2260 if ((flags
>> 11) & 1) /* P */
2262 points
[0].X
= draw
->PointData
.pointsR
[0].X
;
2263 points
[0].Y
= draw
->PointData
.pointsR
[0].Y
;
2264 for (i
= 1; i
< 3; i
++)
2266 points
[i
].X
= points
[i
-1].X
+ draw
->PointData
.pointsR
[i
].X
;
2267 points
[i
].Y
= points
[i
-1].Y
+ draw
->PointData
.pointsR
[i
].Y
;
2270 else if ((flags
>> 14) & 1) /* C */
2272 for (i
= 0; i
< 3; i
++)
2274 points
[i
].X
= draw
->PointData
.points
[i
].X
;
2275 points
[i
].Y
= draw
->PointData
.points
[i
].Y
;
2279 memcpy(points
, draw
->PointData
.pointsF
, sizeof(points
));
2281 return GdipDrawImagePointsRect(real_metafile
->playback_graphics
, real_metafile
->objtable
[image
].u
.image
,
2282 points
, 3, draw
->SrcRect
.X
, draw
->SrcRect
.Y
, draw
->SrcRect
.Width
, draw
->SrcRect
.Height
, draw
->SrcUnit
,
2283 real_metafile
->objtable
[draw
->ImageAttributesID
].u
.image_attributes
, NULL
, NULL
);
2285 case EmfPlusRecordTypeFillPath
:
2287 EmfPlusFillPath
*fill
= (EmfPlusFillPath
*)header
;
2288 GpSolidFill
*solidfill
= NULL
;
2289 BYTE path
= flags
& 0xff;
2292 if (path
>= EmfPlusObjectTableSize
|| real_metafile
->objtable
[path
].type
!= ObjectTypePath
)
2293 return InvalidParameter
;
2295 if (dataSize
!= sizeof(fill
->data
.BrushId
))
2296 return InvalidParameter
;
2300 stat
= GdipCreateSolidFill(*(ARGB
*)&fill
->data
.Color
, (GpSolidFill
**)&solidfill
);
2303 brush
= (GpBrush
*)solidfill
;
2307 if (fill
->data
.BrushId
>= EmfPlusObjectTableSize
||
2308 real_metafile
->objtable
[fill
->data
.BrushId
].type
!= ObjectTypeBrush
)
2309 return InvalidParameter
;
2311 brush
= real_metafile
->objtable
[fill
->data
.BrushId
].u
.brush
;
2314 stat
= GdipFillPath(real_metafile
->playback_graphics
, brush
, real_metafile
->objtable
[path
].u
.path
);
2315 GdipDeleteBrush((GpBrush
*)solidfill
);
2319 FIXME("Not implemented for record type %x\n", recordType
);
2320 return NotImplemented
;
2327 struct enum_metafile_data
2329 EnumerateMetafileProc callback
;
2330 void *callback_data
;
2331 GpMetafile
*metafile
;
2334 static int CALLBACK
enum_metafile_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
2335 int nObj
, LPARAM lpData
)
2338 struct enum_metafile_data
*data
= (struct enum_metafile_data
*)lpData
;
2341 data
->metafile
->handle_table
= lpHTable
;
2342 data
->metafile
->handle_count
= nObj
;
2344 /* First check for an EMF+ record. */
2345 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
2347 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
2349 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
2353 while (offset
+ sizeof(EmfPlusRecordHeader
) <= comment
->cbData
)
2355 const EmfPlusRecordHeader
*record
= (const EmfPlusRecordHeader
*)&comment
->Data
[offset
];
2357 if (record
->DataSize
)
2358 pStr
= (const BYTE
*)(record
+1);
2362 ret
= data
->callback(record
->Type
, record
->Flags
, record
->DataSize
,
2363 pStr
, data
->callback_data
);
2368 offset
+= record
->Size
;
2375 if (lpEMFR
->nSize
!= 8)
2376 pStr
= (const BYTE
*)lpEMFR
->dParm
;
2380 return data
->callback(lpEMFR
->iType
, 0, lpEMFR
->nSize
-8,
2381 pStr
, data
->callback_data
);
2384 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestPoints(GpGraphics
*graphics
,
2385 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*destPoints
, INT count
,
2386 GDIPCONST GpRectF
*srcRect
, Unit srcUnit
, EnumerateMetafileProc callback
,
2387 VOID
*callbackData
, GDIPCONST GpImageAttributes
*imageAttributes
)
2389 struct enum_metafile_data data
;
2391 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
; /* whoever made this const was joking */
2392 GraphicsContainer state
;
2395 TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics
, metafile
,
2396 destPoints
, count
, srcRect
, srcUnit
, callback
, callbackData
,
2399 if (!graphics
|| !metafile
|| !destPoints
|| count
!= 3 || !srcRect
)
2400 return InvalidParameter
;
2402 if (!metafile
->hemf
)
2403 return InvalidParameter
;
2405 if (metafile
->playback_graphics
)
2408 TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect
), srcUnit
,
2409 debugstr_pointf(&destPoints
[0]), debugstr_pointf(&destPoints
[1]),
2410 debugstr_pointf(&destPoints
[2]));
2412 data
.callback
= callback
;
2413 data
.callback_data
= callbackData
;
2414 data
.metafile
= real_metafile
;
2416 real_metafile
->playback_graphics
= graphics
;
2417 real_metafile
->playback_dc
= NULL
;
2418 real_metafile
->src_rect
= *srcRect
;
2420 memcpy(real_metafile
->playback_points
, destPoints
, sizeof(PointF
) * 3);
2421 stat
= GdipTransformPoints(graphics
, CoordinateSpaceDevice
, CoordinateSpaceWorld
, real_metafile
->playback_points
, 3);
2424 stat
= GdipBeginContainer2(graphics
, &state
);
2428 stat
= GdipSetPageScale(graphics
, 1.0);
2431 stat
= GdipSetPageUnit(graphics
, UnitPixel
);
2434 stat
= GdipResetWorldTransform(graphics
);
2437 stat
= GdipCreateRegion(&real_metafile
->base_clip
);
2440 stat
= GdipGetClip(graphics
, real_metafile
->base_clip
);
2443 stat
= GdipCreateRegion(&real_metafile
->clip
);
2446 stat
= GdipCreatePath(FillModeAlternate
, &dst_path
);
2450 GpPointF clip_points
[4];
2452 clip_points
[0] = real_metafile
->playback_points
[0];
2453 clip_points
[1] = real_metafile
->playback_points
[1];
2454 clip_points
[2].X
= real_metafile
->playback_points
[1].X
+ real_metafile
->playback_points
[2].X
2455 - real_metafile
->playback_points
[0].X
;
2456 clip_points
[2].Y
= real_metafile
->playback_points
[1].Y
+ real_metafile
->playback_points
[2].Y
2457 - real_metafile
->playback_points
[0].Y
;
2458 clip_points
[3] = real_metafile
->playback_points
[2];
2460 stat
= GdipAddPathPolygon(dst_path
, clip_points
, 4);
2463 stat
= GdipCombineRegionPath(real_metafile
->base_clip
, dst_path
, CombineModeIntersect
);
2465 GdipDeletePath(dst_path
);
2469 stat
= GdipCreateMatrix(&real_metafile
->world_transform
);
2473 real_metafile
->page_unit
= UnitDisplay
;
2474 real_metafile
->page_scale
= 1.0;
2475 stat
= METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
2480 stat
= METAFILE_PlaybackUpdateClip(real_metafile
);
2483 if (stat
== Ok
&& (metafile
->metafile_type
== MetafileTypeEmf
||
2484 metafile
->metafile_type
== MetafileTypeWmfPlaceable
||
2485 metafile
->metafile_type
== MetafileTypeWmf
))
2486 stat
= METAFILE_PlaybackGetDC(real_metafile
);
2489 EnumEnhMetaFile(0, metafile
->hemf
, enum_metafile_proc
, &data
, NULL
);
2491 METAFILE_PlaybackReleaseDC(real_metafile
);
2493 GdipDeleteMatrix(real_metafile
->world_transform
);
2494 real_metafile
->world_transform
= NULL
;
2496 GdipDeleteRegion(real_metafile
->base_clip
);
2497 real_metafile
->base_clip
= NULL
;
2499 GdipDeleteRegion(real_metafile
->clip
);
2500 real_metafile
->clip
= NULL
;
2502 while (list_head(&real_metafile
->containers
))
2504 container
* cont
= LIST_ENTRY(list_head(&real_metafile
->containers
), container
, entry
);
2505 list_remove(&cont
->entry
);
2506 GdipDeleteRegion(cont
->clip
);
2510 GdipEndContainer(graphics
, state
);
2513 real_metafile
->playback_graphics
= NULL
;
2518 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRect(GpGraphics
*graphics
,
2519 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRectF
*dest
,
2520 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
2524 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
2526 points
[0].X
= points
[2].X
= dest
->X
;
2527 points
[0].Y
= points
[1].Y
= dest
->Y
;
2528 points
[1].X
= dest
->X
+ dest
->Width
;
2529 points
[2].Y
= dest
->Y
+ dest
->Height
;
2531 return GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, points
, 3,
2532 &metafile
->bounds
, metafile
->unit
, callback
, cb_data
, attrs
);
2535 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRectI(GpGraphics
*graphics
,
2536 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRect
*dest
,
2537 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
2541 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
2545 destf
.Width
= dest
->Width
;
2546 destf
.Height
= dest
->Height
;
2548 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
2551 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPoint(GpGraphics
*graphics
,
2552 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*dest
,
2553 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
2557 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
2561 destf
.Width
= units_to_pixels(metafile
->bounds
.Width
, metafile
->unit
, metafile
->image
.xres
);
2562 destf
.Height
= units_to_pixels(metafile
->bounds
.Height
, metafile
->unit
, metafile
->image
.yres
);
2564 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
2567 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPointI(GpGraphics
*graphics
,
2568 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPoint
*dest
,
2569 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
2573 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
2578 return GdipEnumerateMetafileDestPoint(graphics
, metafile
, &ptf
, callback
, cb_data
, attrs
);
2581 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromMetafile(GpMetafile
* metafile
,
2582 MetafileHeader
* header
)
2586 TRACE("(%p, %p)\n", metafile
, header
);
2588 if(!metafile
|| !header
)
2589 return InvalidParameter
;
2593 status
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, header
);
2594 if (status
!= Ok
) return status
;
2598 memset(header
, 0, sizeof(*header
));
2599 header
->Version
= VERSION_MAGIC2
;
2602 header
->Type
= metafile
->metafile_type
;
2603 header
->DpiX
= metafile
->image
.xres
;
2604 header
->DpiY
= metafile
->image
.yres
;
2605 header
->Width
= gdip_round(metafile
->bounds
.Width
);
2606 header
->Height
= gdip_round(metafile
->bounds
.Height
);
2611 static int CALLBACK
get_emfplus_header_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
2612 int nObj
, LPARAM lpData
)
2614 EmfPlusHeader
*dst_header
= (EmfPlusHeader
*)lpData
;
2616 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
2618 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
2620 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
2622 const EmfPlusRecordHeader
*header
= (const EmfPlusRecordHeader
*)&comment
->Data
[4];
2624 if (4 + sizeof(EmfPlusHeader
) <= comment
->cbData
&&
2625 header
->Type
== EmfPlusRecordTypeHeader
)
2627 memcpy(dst_header
, header
, sizeof(*dst_header
));
2631 else if (lpEMFR
->iType
== EMR_HEADER
)
2637 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromEmf(HENHMETAFILE hemf
,
2638 MetafileHeader
*header
)
2640 ENHMETAHEADER3 emfheader
;
2641 EmfPlusHeader emfplusheader
;
2642 MetafileType metafile_type
;
2644 TRACE("(%p,%p)\n", hemf
, header
);
2646 if(!hemf
|| !header
)
2647 return InvalidParameter
;
2649 if (GetEnhMetaFileHeader(hemf
, sizeof(emfheader
), (ENHMETAHEADER
*)&emfheader
) == 0)
2650 return GenericError
;
2652 emfplusheader
.Header
.Type
= 0;
2654 EnumEnhMetaFile(NULL
, hemf
, get_emfplus_header_proc
, &emfplusheader
, NULL
);
2656 if (emfplusheader
.Header
.Type
== EmfPlusRecordTypeHeader
)
2658 if ((emfplusheader
.Header
.Flags
& 1) == 1)
2659 metafile_type
= MetafileTypeEmfPlusDual
;
2661 metafile_type
= MetafileTypeEmfPlusOnly
;
2664 metafile_type
= MetafileTypeEmf
;
2666 header
->Type
= metafile_type
;
2667 header
->Size
= emfheader
.nBytes
;
2668 header
->DpiX
= (REAL
)emfheader
.szlDevice
.cx
* 25.4 / emfheader
.szlMillimeters
.cx
;
2669 header
->DpiY
= (REAL
)emfheader
.szlDevice
.cy
* 25.4 / emfheader
.szlMillimeters
.cy
;
2670 header
->X
= gdip_round((REAL
)emfheader
.rclFrame
.left
/ 2540.0 * header
->DpiX
);
2671 header
->Y
= gdip_round((REAL
)emfheader
.rclFrame
.top
/ 2540.0 * header
->DpiY
);
2672 header
->Width
= gdip_round((REAL
)(emfheader
.rclFrame
.right
- emfheader
.rclFrame
.left
) / 2540.0 * header
->DpiX
);
2673 header
->Height
= gdip_round((REAL
)(emfheader
.rclFrame
.bottom
- emfheader
.rclFrame
.top
) / 2540.0 * header
->DpiY
);
2674 header
->u
.EmfHeader
= emfheader
;
2676 if (metafile_type
== MetafileTypeEmfPlusDual
|| metafile_type
== MetafileTypeEmfPlusOnly
)
2678 header
->Version
= emfplusheader
.Version
;
2679 header
->EmfPlusFlags
= emfplusheader
.EmfPlusFlags
;
2680 header
->EmfPlusHeaderSize
= emfplusheader
.Header
.Size
;
2681 header
->LogicalDpiX
= emfplusheader
.LogicalDpiX
;
2682 header
->LogicalDpiY
= emfplusheader
.LogicalDpiY
;
2686 header
->Version
= emfheader
.nVersion
;
2687 header
->EmfPlusFlags
= 0;
2688 header
->EmfPlusHeaderSize
= 0;
2689 header
->LogicalDpiX
= 0;
2690 header
->LogicalDpiY
= 0;
2696 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromWmf(HMETAFILE hwmf
,
2697 GDIPCONST WmfPlaceableFileHeader
*placeable
, MetafileHeader
*header
)
2700 GpMetafile
*metafile
;
2702 TRACE("(%p,%p,%p)\n", hwmf
, placeable
, header
);
2704 status
= GdipCreateMetafileFromWmf(hwmf
, FALSE
, placeable
, &metafile
);
2707 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
2708 GdipDisposeImage(&metafile
->image
);
2713 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR
*filename
,
2714 MetafileHeader
*header
)
2717 GpMetafile
*metafile
;
2719 TRACE("(%s,%p)\n", debugstr_w(filename
), header
);
2721 if (!filename
|| !header
)
2722 return InvalidParameter
;
2724 status
= GdipCreateMetafileFromFile(filename
, &metafile
);
2727 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
2728 GdipDisposeImage(&metafile
->image
);
2733 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromStream(IStream
*stream
,
2734 MetafileHeader
*header
)
2737 GpMetafile
*metafile
;
2739 TRACE("(%p,%p)\n", stream
, header
);
2741 if (!stream
|| !header
)
2742 return InvalidParameter
;
2744 status
= GdipCreateMetafileFromStream(stream
, &metafile
);
2747 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
2748 GdipDisposeImage(&metafile
->image
);
2753 GpStatus WINGDIPAPI
GdipCreateMetafileFromEmf(HENHMETAFILE hemf
, BOOL
delete,
2754 GpMetafile
**metafile
)
2757 MetafileHeader header
;
2759 TRACE("(%p,%i,%p)\n", hemf
, delete, metafile
);
2761 if(!hemf
|| !metafile
)
2762 return InvalidParameter
;
2764 stat
= GdipGetMetafileHeaderFromEmf(hemf
, &header
);
2768 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
2772 (*metafile
)->image
.type
= ImageTypeMetafile
;
2773 (*metafile
)->image
.format
= ImageFormatEMF
;
2774 (*metafile
)->image
.frame_count
= 1;
2775 (*metafile
)->image
.xres
= header
.DpiX
;
2776 (*metafile
)->image
.yres
= header
.DpiY
;
2777 (*metafile
)->bounds
.X
= (REAL
)header
.u
.EmfHeader
.rclFrame
.left
/ 2540.0 * header
.DpiX
;
2778 (*metafile
)->bounds
.Y
= (REAL
)header
.u
.EmfHeader
.rclFrame
.top
/ 2540.0 * header
.DpiY
;
2779 (*metafile
)->bounds
.Width
= (REAL
)(header
.u
.EmfHeader
.rclFrame
.right
- header
.u
.EmfHeader
.rclFrame
.left
)
2780 / 2540.0 * header
.DpiX
;
2781 (*metafile
)->bounds
.Height
= (REAL
)(header
.u
.EmfHeader
.rclFrame
.bottom
- header
.u
.EmfHeader
.rclFrame
.top
)
2782 / 2540.0 * header
.DpiY
;
2783 (*metafile
)->unit
= UnitPixel
;
2784 (*metafile
)->metafile_type
= header
.Type
;
2785 (*metafile
)->hemf
= hemf
;
2786 (*metafile
)->preserve_hemf
= !delete;
2787 list_init(&(*metafile
)->containers
);
2789 TRACE("<-- %p\n", *metafile
);
2794 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmf(HMETAFILE hwmf
, BOOL
delete,
2795 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
2800 GpStatus retval
= Ok
;
2802 TRACE("(%p, %d, %p, %p)\n", hwmf
, delete, placeable
, metafile
);
2804 if(!hwmf
|| !metafile
)
2805 return InvalidParameter
;
2808 read
= GetMetaFileBitsEx(hwmf
, 0, NULL
);
2810 return GenericError
;
2811 copy
= heap_alloc_zero(read
);
2812 GetMetaFileBitsEx(hwmf
, read
, copy
);
2814 hemf
= SetWinMetaFileBits(read
, copy
, NULL
, NULL
);
2817 /* FIXME: We should store and use hwmf instead of converting to hemf */
2818 retval
= GdipCreateMetafileFromEmf(hemf
, TRUE
, metafile
);
2824 (*metafile
)->image
.xres
= (REAL
)placeable
->Inch
;
2825 (*metafile
)->image
.yres
= (REAL
)placeable
->Inch
;
2826 (*metafile
)->bounds
.X
= ((REAL
)placeable
->BoundingBox
.Left
) / ((REAL
)placeable
->Inch
);
2827 (*metafile
)->bounds
.Y
= ((REAL
)placeable
->BoundingBox
.Top
) / ((REAL
)placeable
->Inch
);
2828 (*metafile
)->bounds
.Width
= (REAL
)(placeable
->BoundingBox
.Right
-
2829 placeable
->BoundingBox
.Left
);
2830 (*metafile
)->bounds
.Height
= (REAL
)(placeable
->BoundingBox
.Bottom
-
2831 placeable
->BoundingBox
.Top
);
2832 (*metafile
)->metafile_type
= MetafileTypeWmfPlaceable
;
2835 (*metafile
)->metafile_type
= MetafileTypeWmf
;
2836 (*metafile
)->image
.format
= ImageFormatWMF
;
2838 if (delete) DeleteMetaFile(hwmf
);
2841 DeleteEnhMetaFile(hemf
);
2845 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR
*file
,
2846 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
2851 TRACE("(%s, %p, %p)\n", debugstr_w(file
), placeable
, metafile
);
2853 hmf
= GetMetaFileW(file
);
2855 return GdipCreateMetafileFromWmf(hmf
, TRUE
, placeable
, metafile
);
2857 emf
= GetEnhMetaFileW(file
);
2859 return GdipCreateMetafileFromEmf(emf
, TRUE
, metafile
);
2861 return GenericError
;
2864 GpStatus WINGDIPAPI
GdipCreateMetafileFromFile(GDIPCONST WCHAR
*file
,
2865 GpMetafile
**metafile
)
2870 TRACE("(%p, %p)\n", file
, metafile
);
2872 if (!file
|| !metafile
) return InvalidParameter
;
2876 status
= GdipCreateStreamOnFile(file
, GENERIC_READ
, &stream
);
2879 status
= GdipCreateMetafileFromStream(stream
, metafile
);
2880 IStream_Release(stream
);
2885 GpStatus WINGDIPAPI
GdipCreateMetafileFromStream(IStream
*stream
,
2886 GpMetafile
**metafile
)
2890 TRACE("%p %p\n", stream
, metafile
);
2892 stat
= GdipLoadImageFromStream(stream
, (GpImage
**)metafile
);
2893 if (stat
!= Ok
) return stat
;
2895 if ((*metafile
)->image
.type
!= ImageTypeMetafile
)
2897 GdipDisposeImage(&(*metafile
)->image
);
2899 return GenericError
;
2905 GpStatus WINGDIPAPI
GdipSetMetafileDownLevelRasterizationLimit(GpMetafile
*metafile
,
2908 TRACE("(%p,%u)\n", metafile
, limitDpi
);
2913 GpStatus WINGDIPAPI
GdipConvertToEmfPlus(const GpGraphics
* ref
,
2914 GpMetafile
* metafile
, BOOL
* succ
, EmfType emfType
,
2915 const WCHAR
* description
, GpMetafile
** out_metafile
)
2919 TRACE("(%p,%p,%p,%u,%s,%p)\n", ref
, metafile
, succ
, emfType
,
2920 debugstr_w(description
), out_metafile
);
2922 if(!ref
|| !metafile
|| !out_metafile
|| emfType
< EmfTypeEmfOnly
|| emfType
> EmfTypeEmfPlusDual
)
2923 return InvalidParameter
;
2927 *out_metafile
= NULL
;
2930 FIXME("not implemented\n");
2932 return NotImplemented
;
2935 GpStatus WINGDIPAPI
GdipEmfToWmfBits(HENHMETAFILE hemf
, UINT cbData16
,
2936 LPBYTE pData16
, INT iMapMode
, INT eFlags
)
2938 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf
, cbData16
, pData16
, iMapMode
, eFlags
);
2939 return NotImplemented
;
2942 GpStatus WINGDIPAPI
GdipRecordMetafileFileName(GDIPCONST WCHAR
* fileName
,
2943 HDC hdc
, EmfType type
, GDIPCONST GpRectF
*pFrameRect
,
2944 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
,
2945 GpMetafile
**metafile
)
2947 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
2948 frameUnit
, debugstr_w(desc
), metafile
);
2950 return NotImplemented
;
2953 GpStatus WINGDIPAPI
GdipRecordMetafileFileNameI(GDIPCONST WCHAR
* fileName
, HDC hdc
, EmfType type
,
2954 GDIPCONST GpRect
*pFrameRect
, MetafileFrameUnit frameUnit
,
2955 GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
2957 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
2958 frameUnit
, debugstr_w(desc
), metafile
);
2960 return NotImplemented
;
2963 /*****************************************************************************
2964 * GdipConvertToEmfPlusToFile [GDIPLUS.@]
2967 GpStatus WINGDIPAPI
GdipConvertToEmfPlusToFile(const GpGraphics
* refGraphics
,
2968 GpMetafile
* metafile
, BOOL
* conversionSuccess
,
2969 const WCHAR
* filename
, EmfType emfType
,
2970 const WCHAR
* description
, GpMetafile
** out_metafile
)
2972 FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics
, metafile
, conversionSuccess
, filename
, emfType
, description
, out_metafile
);
2973 return NotImplemented
;
2976 static GpStatus
METAFILE_CreateCompressedImageStream(GpImage
*image
, IStream
**stream
, DWORD
*size
)
2985 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, stream
);
2986 if (FAILED(hr
)) return hresult_to_status(hr
);
2988 stat
= encode_image_png(image
, *stream
, NULL
);
2991 IStream_Release(*stream
);
2995 hr
= IStream_Stat(*stream
, &statstg
, 1);
2998 IStream_Release(*stream
);
2999 return hresult_to_status(hr
);
3001 *size
= statstg
.cbSize
.u
.LowPart
;
3004 hr
= IStream_Seek(*stream
, zero
, STREAM_SEEK_SET
, NULL
);
3007 IStream_Release(*stream
);
3008 return hresult_to_status(hr
);
3014 static GpStatus
METAFILE_FillEmfPlusBitmap(EmfPlusBitmap
*record
, IStream
*stream
, DWORD size
)
3021 record
->PixelFormat
= 0;
3022 record
->Type
= BitmapDataTypeCompressed
;
3024 hr
= IStream_Read(stream
, record
->BitmapData
, size
, NULL
);
3025 if (FAILED(hr
)) return hresult_to_status(hr
);
3029 static GpStatus
METAFILE_AddImageObject(GpMetafile
*metafile
, GpImage
*image
, DWORD
*id
)
3031 EmfPlusObject
*object_record
;
3037 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
3040 if (image
->type
== ImageTypeBitmap
)
3045 stat
= METAFILE_CreateCompressedImageStream(image
, &stream
, &size
);
3046 if (stat
!= Ok
) return stat
;
3047 aligned_size
= (size
+ 3) & ~3;
3049 stat
= METAFILE_AllocateRecord(metafile
,
3050 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image
.ImageData
.bitmap
.BitmapData
[aligned_size
]),
3051 (void**)&object_record
);
3054 IStream_Release(stream
);
3057 memset(object_record
->ObjectData
.image
.ImageData
.bitmap
.BitmapData
+ size
, 0, aligned_size
- size
);
3059 *id
= METAFILE_AddObjectId(metafile
);
3060 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
3061 object_record
->Header
.Flags
= *id
| ObjectTypeImage
<< 8;
3062 object_record
->ObjectData
.image
.Version
= VERSION_MAGIC2
;
3063 object_record
->ObjectData
.image
.Type
= ImageDataTypeBitmap
;
3065 stat
= METAFILE_FillEmfPlusBitmap(&object_record
->ObjectData
.image
.ImageData
.bitmap
, stream
, size
);
3066 IStream_Release(stream
);
3067 if (stat
!= Ok
) METAFILE_RemoveLastRecord(metafile
, &object_record
->Header
);
3070 else if (image
->type
== ImageTypeMetafile
)
3072 HENHMETAFILE hemf
= ((GpMetafile
*)image
)->hemf
;
3073 EmfPlusMetafile
*metafile_record
;
3075 if (!hemf
) return InvalidParameter
;
3077 size
= GetEnhMetaFileBits(hemf
, 0, NULL
);
3078 if (!size
) return GenericError
;
3080 stat
= METAFILE_AllocateRecord(metafile
,
3081 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image
.ImageData
.metafile
.MetafileData
[size
]),
3082 (void**)&object_record
);
3083 if (stat
!= Ok
) return stat
;
3085 *id
= METAFILE_AddObjectId(metafile
);
3086 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
3087 object_record
->Header
.Flags
= *id
| ObjectTypeImage
<< 8;
3088 object_record
->ObjectData
.image
.Version
= VERSION_MAGIC2
;
3089 object_record
->ObjectData
.image
.Type
= ImageDataTypeMetafile
;
3090 metafile_record
= &object_record
->ObjectData
.image
.ImageData
.metafile
;
3091 metafile_record
->Type
= ((GpMetafile
*)image
)->metafile_type
;
3092 metafile_record
->MetafileDataSize
= size
;
3093 if (GetEnhMetaFileBits(hemf
, size
, metafile_record
->MetafileData
) != size
)
3095 METAFILE_RemoveLastRecord(metafile
, &object_record
->Header
);
3096 return GenericError
;
3102 FIXME("not supported image type (%d)\n", image
->type
);
3103 return NotImplemented
;
3107 static GpStatus
METAFILE_AddImageAttributesObject(GpMetafile
*metafile
, const GpImageAttributes
*attrs
, DWORD
*id
)
3109 EmfPlusObject
*object_record
;
3110 EmfPlusImageAttributes
*attrs_record
;
3115 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
3121 stat
= METAFILE_AllocateRecord(metafile
,
3122 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image_attributes
) + sizeof(EmfPlusImageAttributes
),
3123 (void**)&object_record
);
3124 if (stat
!= Ok
) return stat
;
3126 *id
= METAFILE_AddObjectId(metafile
);
3127 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
3128 object_record
->Header
.Flags
= *id
| (ObjectTypeImageAttributes
<< 8);
3129 attrs_record
= &object_record
->ObjectData
.image_attributes
;
3130 attrs_record
->Version
= VERSION_MAGIC2
;
3131 attrs_record
->Reserved1
= 0;
3132 attrs_record
->WrapMode
= attrs
->wrap
;
3133 attrs_record
->ClampColor
.Blue
= attrs
->outside_color
& 0xff;
3134 attrs_record
->ClampColor
.Green
= (attrs
->outside_color
>> 8) & 0xff;
3135 attrs_record
->ClampColor
.Red
= (attrs
->outside_color
>> 16) & 0xff;
3136 attrs_record
->ClampColor
.Alpha
= attrs
->outside_color
>> 24;
3137 attrs_record
->ObjectClamp
= attrs
->clamp
;
3138 attrs_record
->Reserved2
= 0;
3142 GpStatus
METAFILE_DrawImagePointsRect(GpMetafile
*metafile
, GpImage
*image
,
3143 GDIPCONST GpPointF
*points
, INT count
, REAL srcx
, REAL srcy
, REAL srcwidth
,
3144 REAL srcheight
, GpUnit srcUnit
, GDIPCONST GpImageAttributes
* imageAttributes
,
3145 DrawImageAbort callback
, VOID
*callbackData
)
3147 EmfPlusDrawImagePoints
*draw_image_record
;
3148 DWORD image_id
, attributes_id
;
3151 if (count
!= 3) return InvalidParameter
;
3153 if (metafile
->metafile_type
== MetafileTypeEmf
)
3155 FIXME("MetafileTypeEmf metafiles not supported\n");
3156 return NotImplemented
;
3159 FIXME("semi-stub\n");
3161 if (!imageAttributes
)
3163 stat
= METAFILE_AddImageObject(metafile
, image
, &image_id
);
3165 else if (image
->type
== ImageTypeBitmap
)
3167 INT width
= ((GpBitmap
*)image
)->width
;
3168 INT height
= ((GpBitmap
*)image
)->height
;
3169 GpGraphics
*graphics
;
3172 stat
= GdipCreateBitmapFromScan0(width
, height
,
3173 0, PixelFormat32bppARGB
, NULL
, &bitmap
);
3174 if (stat
!= Ok
) return stat
;
3176 stat
= GdipGetImageGraphicsContext((GpImage
*)bitmap
, &graphics
);
3179 GdipDisposeImage((GpImage
*)bitmap
);
3183 stat
= GdipDrawImageRectRectI(graphics
, image
, 0, 0, width
, height
,
3184 0, 0, width
, height
, UnitPixel
, imageAttributes
, NULL
, NULL
);
3185 GdipDeleteGraphics(graphics
);
3188 GdipDisposeImage((GpImage
*)bitmap
);
3192 stat
= METAFILE_AddImageObject(metafile
, (GpImage
*)bitmap
, &image_id
);
3193 GdipDisposeImage((GpImage
*)bitmap
);
3197 FIXME("imageAttributes not supported (image type %d)\n", image
->type
);
3198 return NotImplemented
;
3200 if (stat
!= Ok
) return stat
;
3202 stat
= METAFILE_AddImageAttributesObject(metafile
, imageAttributes
, &attributes_id
);
3203 if (stat
!= Ok
) return stat
;
3205 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusDrawImagePoints
), (void**)&draw_image_record
);
3206 if (stat
!= Ok
) return stat
;
3207 draw_image_record
->Header
.Type
= EmfPlusRecordTypeDrawImagePoints
;
3208 draw_image_record
->Header
.Flags
= image_id
;
3209 draw_image_record
->ImageAttributesID
= attributes_id
;
3210 draw_image_record
->SrcUnit
= UnitPixel
;
3211 draw_image_record
->SrcRect
.X
= units_to_pixels(srcx
, srcUnit
, metafile
->image
.xres
);
3212 draw_image_record
->SrcRect
.Y
= units_to_pixels(srcy
, srcUnit
, metafile
->image
.yres
);
3213 draw_image_record
->SrcRect
.Width
= units_to_pixels(srcwidth
, srcUnit
, metafile
->image
.xres
);
3214 draw_image_record
->SrcRect
.Height
= units_to_pixels(srcheight
, srcUnit
, metafile
->image
.yres
);
3215 draw_image_record
->count
= 3;
3216 memcpy(draw_image_record
->PointData
.pointsF
, points
, 3 * sizeof(*points
));
3217 METAFILE_WriteRecords(metafile
);
3221 GpStatus
METAFILE_AddSimpleProperty(GpMetafile
*metafile
, SHORT prop
, SHORT val
)
3223 EmfPlusRecordHeader
*record
;
3226 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
3229 stat
= METAFILE_AllocateRecord(metafile
, sizeof(*record
), (void**)&record
);
3230 if (stat
!= Ok
) return stat
;
3232 record
->Type
= prop
;
3233 record
->Flags
= val
;
3235 METAFILE_WriteRecords(metafile
);
3239 static GpStatus
METAFILE_AddPathObject(GpMetafile
*metafile
, GpPath
*path
, DWORD
*id
)
3241 EmfPlusObject
*object_record
;
3246 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
3249 size
= write_path_data(path
, NULL
);
3250 stat
= METAFILE_AllocateRecord(metafile
,
3251 FIELD_OFFSET(EmfPlusObject
, ObjectData
.path
) + size
,
3252 (void**)&object_record
);
3253 if (stat
!= Ok
) return stat
;
3255 *id
= METAFILE_AddObjectId(metafile
);
3256 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
3257 object_record
->Header
.Flags
= *id
| ObjectTypePath
<< 8;
3258 write_path_data(path
, &object_record
->ObjectData
.path
);
3262 static GpStatus
METAFILE_PrepareBrushData(GpBrush
*brush
, DWORD
*size
)
3264 if (brush
->bt
== BrushTypeSolidColor
)
3266 *size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
.solid
) + sizeof(EmfPlusSolidBrushData
);
3270 FIXME("unsupported brush type: %d\n", brush
->bt
);
3271 return NotImplemented
;
3274 static void METAFILE_FillBrushData(GpBrush
*brush
, EmfPlusBrush
*data
)
3276 if (brush
->bt
== BrushTypeSolidColor
)
3278 GpSolidFill
*solid
= (GpSolidFill
*)brush
;
3280 data
->Version
= VERSION_MAGIC2
;
3281 data
->Type
= solid
->brush
.bt
;
3282 data
->BrushData
.solid
.SolidColor
.Blue
= solid
->color
& 0xff;
3283 data
->BrushData
.solid
.SolidColor
.Green
= (solid
->color
>> 8) & 0xff;
3284 data
->BrushData
.solid
.SolidColor
.Red
= (solid
->color
>> 16) & 0xff;
3285 data
->BrushData
.solid
.SolidColor
.Alpha
= solid
->color
>> 24;
3289 static GpStatus
METAFILE_AddPenObject(GpMetafile
*metafile
, GpPen
*pen
, DWORD
*id
)
3291 DWORD i
, data_flags
, pen_data_size
, brush_size
;
3292 EmfPlusObject
*object_record
;
3293 EmfPlusPenData
*pen_data
;
3298 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
3302 pen_data_size
= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
3304 GdipIsMatrixIdentity(&pen
->transform
, &result
);
3307 data_flags
|= PenDataTransform
;
3308 pen_data_size
+= sizeof(EmfPlusTransformMatrix
);
3310 if (pen
->startcap
!= LineCapFlat
)
3312 data_flags
|= PenDataStartCap
;
3313 pen_data_size
+= sizeof(DWORD
);
3315 if (pen
->endcap
!= LineCapFlat
)
3317 data_flags
|= PenDataEndCap
;
3318 pen_data_size
+= sizeof(DWORD
);
3320 if (pen
->join
!= LineJoinMiter
)
3322 data_flags
|= PenDataJoin
;
3323 pen_data_size
+= sizeof(DWORD
);
3325 if (pen
->miterlimit
!= 10.0)
3327 data_flags
|= PenDataMiterLimit
;
3328 pen_data_size
+= sizeof(REAL
);
3330 if (pen
->style
!= GP_DEFAULT_PENSTYLE
)
3332 data_flags
|= PenDataLineStyle
;
3333 pen_data_size
+= sizeof(DWORD
);
3335 if (pen
->dashcap
!= DashCapFlat
)
3337 data_flags
|= PenDataDashedLineCap
;
3338 pen_data_size
+= sizeof(DWORD
);
3340 data_flags
|= PenDataDashedLineOffset
;
3341 pen_data_size
+= sizeof(REAL
);
3344 data_flags
|= PenDataDashedLine
;
3345 pen_data_size
+= sizeof(DWORD
) + pen
->numdashes
*sizeof(REAL
);
3347 if (pen
->align
!= PenAlignmentCenter
)
3349 data_flags
|= PenDataNonCenter
;
3350 pen_data_size
+= sizeof(DWORD
);
3352 /* TODO: Add support for PenDataCompoundLine */
3353 if (pen
->customstart
)
3355 FIXME("ignoring custom start cup\n");
3359 FIXME("ignoring custom end cup\n");
3362 stat
= METAFILE_PrepareBrushData(pen
->brush
, &brush_size
);
3363 if (stat
!= Ok
) return stat
;
3365 stat
= METAFILE_AllocateRecord(metafile
,
3366 FIELD_OFFSET(EmfPlusObject
, ObjectData
.pen
.data
) + pen_data_size
+ brush_size
,
3367 (void**)&object_record
);
3368 if (stat
!= Ok
) return stat
;
3370 *id
= METAFILE_AddObjectId(metafile
);
3371 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
3372 object_record
->Header
.Flags
= *id
| ObjectTypePen
<< 8;
3373 object_record
->ObjectData
.pen
.Version
= VERSION_MAGIC2
;
3374 object_record
->ObjectData
.pen
.Type
= 0;
3376 pen_data
= (EmfPlusPenData
*)object_record
->ObjectData
.pen
.data
;
3377 pen_data
->PenDataFlags
= data_flags
;
3378 pen_data
->PenUnit
= pen
->unit
;
3379 pen_data
->PenWidth
= pen
->width
;
3382 if (data_flags
& PenDataTransform
)
3384 EmfPlusTransformMatrix
*m
= (EmfPlusTransformMatrix
*)(pen_data
->OptionalData
+ i
);
3385 memcpy(m
, &pen
->transform
, sizeof(*m
));
3386 i
+= sizeof(EmfPlusTransformMatrix
);
3388 if (data_flags
& PenDataStartCap
)
3390 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->startcap
;
3393 if (data_flags
& PenDataEndCap
)
3395 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->endcap
;
3398 if (data_flags
& PenDataJoin
)
3400 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->join
;
3403 if (data_flags
& PenDataMiterLimit
)
3405 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->miterlimit
;
3408 if (data_flags
& PenDataLineStyle
)
3410 switch (pen
->style
& PS_STYLE_MASK
)
3412 case PS_SOLID
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleSolid
; break;
3413 case PS_DASH
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDash
; break;
3414 case PS_DOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDot
; break;
3415 case PS_DASHDOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDashDot
; break;
3416 case PS_DASHDOTDOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDashDotDot
; break;
3417 default: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleCustom
; break;
3421 if (data_flags
& PenDataDashedLineCap
)
3423 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->dashcap
;
3426 if (data_flags
& PenDataDashedLineOffset
)
3428 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->offset
;
3431 if (data_flags
& PenDataDashedLine
)
3435 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->numdashes
;
3438 for (j
=0; j
<pen
->numdashes
; j
++)
3440 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->dashes
[j
];
3444 if (data_flags
& PenDataNonCenter
)
3446 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->align
;
3450 METAFILE_FillBrushData(pen
->brush
,
3451 (EmfPlusBrush
*)(object_record
->ObjectData
.pen
.data
+ pen_data_size
));
3455 GpStatus
METAFILE_DrawPath(GpMetafile
*metafile
, GpPen
*pen
, GpPath
*path
)
3457 EmfPlusDrawPath
*draw_path_record
;
3462 if (metafile
->metafile_type
== MetafileTypeEmf
)
3465 return NotImplemented
;
3468 stat
= METAFILE_AddPenObject(metafile
, pen
, &pen_id
);
3469 if (stat
!= Ok
) return stat
;
3471 stat
= METAFILE_AddPathObject(metafile
, path
, &path_id
);
3472 if (stat
!= Ok
) return stat
;
3474 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusDrawPath
), (void**)&draw_path_record
);
3475 if (stat
!= Ok
) return stat
;
3476 draw_path_record
->Header
.Type
= EmfPlusRecordTypeDrawPath
;
3477 draw_path_record
->Header
.Flags
= path_id
;
3478 draw_path_record
->PenId
= pen_id
;
3480 METAFILE_WriteRecords(metafile
);
3484 static GpStatus
METAFILE_AddBrushObject(GpMetafile
*metafile
, GpBrush
*brush
, DWORD
*id
)
3486 EmfPlusObject
*object_record
;
3491 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
3494 stat
= METAFILE_PrepareBrushData(brush
, &size
);
3495 if (stat
!= Ok
) return stat
;
3497 stat
= METAFILE_AllocateRecord(metafile
,
3498 FIELD_OFFSET(EmfPlusObject
, ObjectData
) + size
, (void**)&object_record
);
3499 if (stat
!= Ok
) return stat
;
3501 *id
= METAFILE_AddObjectId(metafile
);
3502 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
3503 object_record
->Header
.Flags
= *id
| ObjectTypeBrush
<< 8;
3504 METAFILE_FillBrushData(brush
, &object_record
->ObjectData
.brush
);
3508 GpStatus
METAFILE_FillPath(GpMetafile
*metafile
, GpBrush
*brush
, GpPath
*path
)
3510 EmfPlusFillPath
*fill_path_record
;
3511 DWORD brush_id
= -1, path_id
;
3515 if (metafile
->metafile_type
== MetafileTypeEmf
)
3518 return NotImplemented
;
3521 inline_color
= brush
->bt
== BrushTypeSolidColor
;
3524 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
3525 if (stat
!= Ok
) return stat
;
3528 stat
= METAFILE_AddPathObject(metafile
, path
, &path_id
);
3529 if (stat
!= Ok
) return stat
;
3531 stat
= METAFILE_AllocateRecord(metafile
,
3532 sizeof(EmfPlusFillPath
), (void**)&fill_path_record
);
3533 if (stat
!= Ok
) return stat
;
3534 fill_path_record
->Header
.Type
= EmfPlusRecordTypeFillPath
;
3537 fill_path_record
->Header
.Flags
= 0x8000 | path_id
;
3538 fill_path_record
->data
.Color
.Blue
= ((GpSolidFill
*)brush
)->color
& 0xff;
3539 fill_path_record
->data
.Color
.Green
= (((GpSolidFill
*)brush
)->color
>> 8) & 0xff;
3540 fill_path_record
->data
.Color
.Red
= (((GpSolidFill
*)brush
)->color
>> 16) & 0xff;
3541 fill_path_record
->data
.Color
.Alpha
= ((GpSolidFill
*)brush
)->color
>> 24;
3545 fill_path_record
->Header
.Flags
= path_id
;
3546 fill_path_record
->data
.BrushId
= brush_id
;
3549 METAFILE_WriteRecords(metafile
);