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 typedef struct EmfPlusARGB
54 typedef struct EmfPlusRecordHeader
60 } EmfPlusRecordHeader
;
62 typedef struct EmfPlusHeader
64 EmfPlusRecordHeader Header
;
71 typedef struct EmfPlusClear
73 EmfPlusRecordHeader Header
;
77 typedef struct EmfPlusFillRects
79 EmfPlusRecordHeader Header
;
84 typedef struct EmfPlusSetClipRect
86 EmfPlusRecordHeader Header
;
90 typedef struct EmfPlusSetPageTransform
92 EmfPlusRecordHeader Header
;
94 } EmfPlusSetPageTransform
;
96 typedef struct EmfPlusRect
104 typedef struct EmfPlusSetWorldTransform
106 EmfPlusRecordHeader Header
;
108 } EmfPlusSetWorldTransform
;
110 typedef struct EmfPlusScaleWorldTransform
112 EmfPlusRecordHeader Header
;
115 } EmfPlusScaleWorldTransform
;
117 typedef struct EmfPlusMultiplyWorldTransform
119 EmfPlusRecordHeader Header
;
121 } EmfPlusMultiplyWorldTransform
;
123 typedef struct EmfPlusRotateWorldTransform
125 EmfPlusRecordHeader Header
;
127 } EmfPlusRotateWorldTransform
;
129 typedef struct EmfPlusTranslateWorldTransform
131 EmfPlusRecordHeader Header
;
134 } EmfPlusTranslateWorldTransform
;
136 typedef struct EmfPlusBeginContainer
138 EmfPlusRecordHeader Header
;
142 } EmfPlusBeginContainer
;
144 typedef struct EmfPlusContainerRecord
146 EmfPlusRecordHeader Header
;
148 } EmfPlusContainerRecord
;
156 typedef struct container
160 enum container_type type
;
161 GraphicsContainer state
;
162 GpMatrix world_transform
;
170 PenDataTransform
= 0x0001,
171 PenDataStartCap
= 0x0002,
172 PenDataEndCap
= 0x0004,
173 PenDataJoin
= 0x0008,
174 PenDataMiterLimit
= 0x0010,
175 PenDataLineStyle
= 0x0020,
176 PenDataDashedLineCap
= 0x0040,
177 PenDataDashedLineOffset
= 0x0080,
178 PenDataDashedLine
= 0x0100,
179 PenDataNonCenter
= 0x0200,
180 PenDataCompoundLine
= 0x0400,
181 PenDataCustomStartCap
= 0x0800,
182 PenDataCustomEndCap
= 0x1000
185 typedef struct EmfPlusTransformMatrix
187 REAL TransformMatrix
[6];
188 } EmfPlusTransformMatrix
;
200 typedef struct EmfPlusPenData
205 BYTE OptionalData
[1];
208 typedef struct EmfPlusSolidBrushData
210 EmfPlusARGB SolidColor
;
211 } EmfPlusSolidBrushData
;
213 typedef struct EmfPlusBrush
218 EmfPlusSolidBrushData solid
;
222 typedef struct EmfPlusPen
231 typedef struct EmfPlusPath
234 DWORD PathPointCount
;
235 DWORD PathPointFlags
;
237 /* PathPointTypes[] */
238 /* AlignmentPadding */
242 typedef struct EmfPlusRegion
245 DWORD RegionNodeCount
;
252 BitmapDataTypeCompressed
,
255 typedef struct EmfPlusBitmap
265 typedef struct EmfPlusMetafile
268 DWORD MetafileDataSize
;
269 BYTE MetafileData
[1];
272 typedef enum ImageDataType
274 ImageDataTypeUnknown
,
276 ImageDataTypeMetafile
,
279 typedef struct EmfPlusImage
285 EmfPlusBitmap bitmap
;
286 EmfPlusMetafile metafile
;
290 typedef struct EmfPlusImageAttributes
295 EmfPlusARGB ClampColor
;
298 } EmfPlusImageAttributes
;
300 typedef enum ObjectType
309 ObjectTypeStringFormat
,
310 ObjectTypeImageAttributes
,
311 ObjectTypeCustomLineCap
,
314 typedef struct EmfPlusObject
316 EmfPlusRecordHeader Header
;
322 EmfPlusRegion region
;
324 EmfPlusImageAttributes image_attributes
;
328 typedef struct EmfPlusRectF
336 typedef struct EmfPlusPointF
342 typedef struct EmfPlusDrawImagePoints
344 EmfPlusRecordHeader Header
;
345 DWORD ImageAttributesID
;
347 EmfPlusRectF SrcRect
;
351 /*EmfPlusPointR pointR;
352 EmfPlusPoint point;*/
353 EmfPlusPointF pointF
;
355 } EmfPlusDrawImagePoints
;
357 typedef struct EmfPlusDrawPath
359 EmfPlusRecordHeader Header
;
363 typedef struct EmfPlusFillPath
365 EmfPlusRecordHeader Header
;
373 static DWORD
METAFILE_AddObjectId(GpMetafile
*metafile
)
375 return (metafile
->next_object_id
++) % 64;
378 static GpStatus
METAFILE_AllocateRecord(GpMetafile
*metafile
, DWORD size
, void **result
)
381 EmfPlusRecordHeader
*record
;
383 if (!metafile
->comment_data_size
)
385 DWORD data_size
= max(256, size
* 2 + 4);
386 metafile
->comment_data
= heap_alloc_zero(data_size
);
388 if (!metafile
->comment_data
)
391 memcpy(metafile
->comment_data
, "EMF+", 4);
393 metafile
->comment_data_size
= data_size
;
394 metafile
->comment_data_length
= 4;
397 size_needed
= size
+ metafile
->comment_data_length
;
399 if (size_needed
> metafile
->comment_data_size
)
401 DWORD data_size
= size_needed
* 2;
402 BYTE
*new_data
= heap_alloc_zero(data_size
);
407 memcpy(new_data
, metafile
->comment_data
, metafile
->comment_data_length
);
409 metafile
->comment_data_size
= data_size
;
410 heap_free(metafile
->comment_data
);
411 metafile
->comment_data
= new_data
;
414 *result
= metafile
->comment_data
+ metafile
->comment_data_length
;
415 metafile
->comment_data_length
+= size
;
417 record
= (EmfPlusRecordHeader
*)*result
;
419 record
->DataSize
= size
- sizeof(EmfPlusRecordHeader
);
424 static void METAFILE_RemoveLastRecord(GpMetafile
*metafile
, EmfPlusRecordHeader
*record
)
426 assert(metafile
->comment_data
+ metafile
->comment_data_length
== (BYTE
*)record
+ record
->Size
);
427 metafile
->comment_data_length
-= record
->Size
;
430 static void METAFILE_WriteRecords(GpMetafile
*metafile
)
432 if (metafile
->comment_data_length
> 4)
434 GdiComment(metafile
->record_dc
, metafile
->comment_data_length
, metafile
->comment_data
);
435 metafile
->comment_data_length
= 4;
439 static GpStatus
METAFILE_WriteHeader(GpMetafile
*metafile
, HDC hdc
)
443 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
445 EmfPlusHeader
*header
;
447 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusHeader
), (void**)&header
);
451 header
->Header
.Type
= EmfPlusRecordTypeHeader
;
453 if (metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
454 header
->Header
.Flags
= 1;
456 header
->Header
.Flags
= 0;
458 header
->Version
= VERSION_MAGIC2
;
460 if (GetDeviceCaps(hdc
, TECHNOLOGY
) == DT_RASDISPLAY
)
461 header
->EmfPlusFlags
= 1;
463 header
->EmfPlusFlags
= 0;
465 header
->LogicalDpiX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
466 header
->LogicalDpiY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
468 METAFILE_WriteRecords(metafile
);
474 static GpStatus
METAFILE_WriteEndOfFile(GpMetafile
*metafile
)
478 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
480 EmfPlusRecordHeader
*record
;
482 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
486 record
->Type
= EmfPlusRecordTypeEndOfFile
;
489 METAFILE_WriteRecords(metafile
);
495 GpStatus WINGDIPAPI
GdipRecordMetafile(HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
496 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
500 REAL framerect_factor_x
, framerect_factor_y
;
504 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
506 if (!hdc
|| type
< EmfTypeEmfOnly
|| type
> EmfTypeEmfPlusDual
|| !metafile
)
507 return InvalidParameter
;
509 dpix
= (REAL
)GetDeviceCaps(hdc
, HORZRES
) / GetDeviceCaps(hdc
, HORZSIZE
) * 25.4;
510 dpiy
= (REAL
)GetDeviceCaps(hdc
, VERTRES
) / GetDeviceCaps(hdc
, VERTSIZE
) * 25.4;
516 case MetafileFrameUnitPixel
:
517 framerect_factor_x
= 2540.0 / dpix
;
518 framerect_factor_y
= 2540.0 / dpiy
;
520 case MetafileFrameUnitPoint
:
521 framerect_factor_x
= framerect_factor_y
= 2540.0 / 72.0;
523 case MetafileFrameUnitInch
:
524 framerect_factor_x
= framerect_factor_y
= 2540.0;
526 case MetafileFrameUnitDocument
:
527 framerect_factor_x
= framerect_factor_y
= 2540.0 / 300.0;
529 case MetafileFrameUnitMillimeter
:
530 framerect_factor_x
= framerect_factor_y
= 100.0;
532 case MetafileFrameUnitGdi
:
533 framerect_factor_x
= framerect_factor_y
= 1.0;
536 return InvalidParameter
;
539 rc
.left
= framerect_factor_x
* frameRect
->X
;
540 rc
.top
= framerect_factor_y
* frameRect
->Y
;
541 rc
.right
= rc
.left
+ framerect_factor_x
* frameRect
->Width
;
542 rc
.bottom
= rc
.top
+ framerect_factor_y
* frameRect
->Height
;
549 record_dc
= CreateEnhMetaFileW(hdc
, NULL
, lprc
, desc
);
554 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
557 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
561 (*metafile
)->image
.type
= ImageTypeMetafile
;
562 (*metafile
)->image
.flags
= ImageFlagsNone
;
563 (*metafile
)->image
.palette
= NULL
;
564 (*metafile
)->image
.xres
= dpix
;
565 (*metafile
)->image
.yres
= dpiy
;
566 (*metafile
)->bounds
.X
= (*metafile
)->bounds
.Y
= 0.0;
567 (*metafile
)->bounds
.Width
= (*metafile
)->bounds
.Height
= 1.0;
568 (*metafile
)->unit
= UnitPixel
;
569 (*metafile
)->metafile_type
= type
;
570 (*metafile
)->record_dc
= record_dc
;
571 (*metafile
)->comment_data
= NULL
;
572 (*metafile
)->comment_data_size
= 0;
573 (*metafile
)->comment_data_length
= 0;
574 (*metafile
)->hemf
= NULL
;
575 list_init(&(*metafile
)->containers
);
579 (*metafile
)->auto_frame
= TRUE
;
580 (*metafile
)->auto_frame_min
.X
= 0;
581 (*metafile
)->auto_frame_min
.Y
= 0;
582 (*metafile
)->auto_frame_max
.X
= -1;
583 (*metafile
)->auto_frame_max
.Y
= -1;
586 stat
= METAFILE_WriteHeader(*metafile
, hdc
);
590 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
591 heap_free(*metafile
);
599 /*****************************************************************************
600 * GdipRecordMetafileI [GDIPLUS.@]
602 GpStatus WINGDIPAPI
GdipRecordMetafileI(HDC hdc
, EmfType type
, GDIPCONST GpRect
*frameRect
,
603 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
605 GpRectF frameRectF
, *pFrameRectF
;
607 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
611 frameRectF
.X
= frameRect
->X
;
612 frameRectF
.Y
= frameRect
->Y
;
613 frameRectF
.Width
= frameRect
->Width
;
614 frameRectF
.Height
= frameRect
->Height
;
615 pFrameRectF
= &frameRectF
;
620 return GdipRecordMetafile(hdc
, type
, pFrameRectF
, frameUnit
, desc
, metafile
);
623 GpStatus WINGDIPAPI
GdipRecordMetafileStream(IStream
*stream
, HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
624 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
628 TRACE("(%p %p %d %p %d %p %p)\n", stream
, hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
631 return InvalidParameter
;
633 stat
= GdipRecordMetafile(hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
637 (*metafile
)->record_stream
= stream
;
638 IStream_AddRef(stream
);
644 static void METAFILE_AdjustFrame(GpMetafile
* metafile
, const GpPointF
*points
,
649 if (!metafile
->auto_frame
|| !num_points
)
652 if (metafile
->auto_frame_max
.X
< metafile
->auto_frame_min
.X
)
653 metafile
->auto_frame_max
= metafile
->auto_frame_min
= points
[0];
655 for (i
=0; i
<num_points
; i
++)
657 if (points
[i
].X
< metafile
->auto_frame_min
.X
)
658 metafile
->auto_frame_min
.X
= points
[i
].X
;
659 if (points
[i
].X
> metafile
->auto_frame_max
.X
)
660 metafile
->auto_frame_max
.X
= points
[i
].X
;
661 if (points
[i
].Y
< metafile
->auto_frame_min
.Y
)
662 metafile
->auto_frame_min
.Y
= points
[i
].Y
;
663 if (points
[i
].Y
> metafile
->auto_frame_max
.Y
)
664 metafile
->auto_frame_max
.Y
= points
[i
].Y
;
668 GpStatus
METAFILE_GetGraphicsContext(GpMetafile
* metafile
, GpGraphics
**result
)
672 if (!metafile
->record_dc
|| metafile
->record_graphics
)
673 return InvalidParameter
;
675 stat
= graphics_from_image((GpImage
*)metafile
, &metafile
->record_graphics
);
679 *result
= metafile
->record_graphics
;
680 metafile
->record_graphics
->xres
= 96.0;
681 metafile
->record_graphics
->yres
= 96.0;
687 GpStatus
METAFILE_GetDC(GpMetafile
* metafile
, HDC
*hdc
)
689 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
691 EmfPlusRecordHeader
*record
;
694 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
698 record
->Type
= EmfPlusRecordTypeGetDC
;
701 METAFILE_WriteRecords(metafile
);
704 *hdc
= metafile
->record_dc
;
709 GpStatus
METAFILE_GraphicsClear(GpMetafile
* metafile
, ARGB color
)
711 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
713 EmfPlusClear
*record
;
716 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusClear
), (void**)&record
);
720 record
->Header
.Type
= EmfPlusRecordTypeClear
;
721 record
->Header
.Flags
= 0;
722 record
->Color
= color
;
724 METAFILE_WriteRecords(metafile
);
730 static BOOL
is_integer_rect(const GpRectF
*rect
)
732 SHORT x
, y
, width
, height
;
736 height
= rect
->Height
;
737 if (rect
->X
!= (REAL
)x
|| rect
->Y
!= (REAL
)y
||
738 rect
->Width
!= (REAL
)width
|| rect
->Height
!= (REAL
)height
)
743 GpStatus
METAFILE_FillRectangles(GpMetafile
* metafile
, GpBrush
* brush
,
744 GDIPCONST GpRectF
* rects
, INT count
)
746 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
748 EmfPlusFillRects
*record
;
750 BOOL integer_rects
= TRUE
;
755 if (brush
->bt
== BrushTypeSolidColor
)
758 brushid
= ((GpSolidFill
*)brush
)->color
;
762 FIXME("brush serialization not implemented\n");
763 return NotImplemented
;
766 for (i
=0; i
<count
; i
++)
768 if (!is_integer_rect(&rects
[i
]))
770 integer_rects
= FALSE
;
778 stat
= METAFILE_AllocateRecord(metafile
,
779 sizeof(EmfPlusFillRects
) + count
* (integer_rects
? sizeof(EmfPlusRect
) : sizeof(GpRectF
)),
784 record
->Header
.Type
= EmfPlusRecordTypeFillRects
;
785 record
->Header
.Flags
= flags
;
786 record
->BrushID
= brushid
;
787 record
->Count
= count
;
791 EmfPlusRect
*record_rects
= (EmfPlusRect
*)(record
+1);
792 for (i
=0; i
<count
; i
++)
794 record_rects
[i
].X
= (SHORT
)rects
[i
].X
;
795 record_rects
[i
].Y
= (SHORT
)rects
[i
].Y
;
796 record_rects
[i
].Width
= (SHORT
)rects
[i
].Width
;
797 record_rects
[i
].Height
= (SHORT
)rects
[i
].Height
;
801 memcpy(record
+1, rects
, sizeof(GpRectF
) * count
);
803 METAFILE_WriteRecords(metafile
);
806 if (metafile
->auto_frame
)
811 for (i
=0; i
<count
; i
++)
813 corners
[0].X
= rects
[i
].X
;
814 corners
[0].Y
= rects
[i
].Y
;
815 corners
[1].X
= rects
[i
].X
+ rects
[i
].Width
;
816 corners
[1].Y
= rects
[i
].Y
;
817 corners
[2].X
= rects
[i
].X
;
818 corners
[2].Y
= rects
[i
].Y
+ rects
[i
].Height
;
819 corners
[3].X
= rects
[i
].X
+ rects
[i
].Width
;
820 corners
[3].Y
= rects
[i
].Y
+ rects
[i
].Height
;
822 GdipTransformPoints(metafile
->record_graphics
, CoordinateSpaceDevice
,
823 CoordinateSpaceWorld
, corners
, 4);
825 METAFILE_AdjustFrame(metafile
, corners
, 4);
832 GpStatus
METAFILE_SetClipRect(GpMetafile
* metafile
, REAL x
, REAL y
, REAL width
, REAL height
, CombineMode mode
)
834 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
836 EmfPlusSetClipRect
*record
;
839 stat
= METAFILE_AllocateRecord(metafile
,
840 sizeof(EmfPlusSetClipRect
),
845 record
->Header
.Type
= EmfPlusRecordTypeSetClipRect
;
846 record
->Header
.Flags
= (mode
& 0xf) << 8;
847 record
->ClipRect
.X
= x
;
848 record
->ClipRect
.Y
= y
;
849 record
->ClipRect
.Width
= width
;
850 record
->ClipRect
.Height
= height
;
852 METAFILE_WriteRecords(metafile
);
858 static GpStatus
METAFILE_AddRegionObject(GpMetafile
*metafile
, GpRegion
*region
, DWORD
*id
)
860 EmfPlusObject
*object_record
;
865 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
868 size
= write_region_data(region
, NULL
);
869 stat
= METAFILE_AllocateRecord(metafile
,
870 FIELD_OFFSET(EmfPlusObject
, ObjectData
.region
) + size
, (void**)&object_record
);
871 if (stat
!= Ok
) return stat
;
873 *id
= METAFILE_AddObjectId(metafile
);
874 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
875 object_record
->Header
.Flags
= *id
| ObjectTypeRegion
<< 8;
876 write_region_data(region
, &object_record
->ObjectData
.region
);
880 GpStatus
METAFILE_SetClipRegion(GpMetafile
* metafile
, GpRegion
* region
, CombineMode mode
)
882 EmfPlusRecordHeader
*record
;
886 if (metafile
->metafile_type
== MetafileTypeEmf
)
889 return NotImplemented
;
892 stat
= METAFILE_AddRegionObject(metafile
, region
, ®ion_id
);
893 if (stat
!= Ok
) return stat
;
895 stat
= METAFILE_AllocateRecord(metafile
, sizeof(*record
), (void**)&record
);
896 if (stat
!= Ok
) return stat
;
898 record
->Type
= EmfPlusRecordTypeSetClipRegion
;
899 record
->Flags
= region_id
| mode
<< 8;
901 METAFILE_WriteRecords(metafile
);
905 GpStatus
METAFILE_SetPageTransform(GpMetafile
* metafile
, GpUnit unit
, REAL scale
)
907 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
909 EmfPlusSetPageTransform
*record
;
912 stat
= METAFILE_AllocateRecord(metafile
,
913 sizeof(EmfPlusSetPageTransform
),
918 record
->Header
.Type
= EmfPlusRecordTypeSetPageTransform
;
919 record
->Header
.Flags
= unit
;
920 record
->PageScale
= scale
;
922 METAFILE_WriteRecords(metafile
);
928 GpStatus
METAFILE_SetWorldTransform(GpMetafile
* metafile
, GDIPCONST GpMatrix
* transform
)
930 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
932 EmfPlusSetWorldTransform
*record
;
935 stat
= METAFILE_AllocateRecord(metafile
,
936 sizeof(EmfPlusSetWorldTransform
),
941 record
->Header
.Type
= EmfPlusRecordTypeSetWorldTransform
;
942 record
->Header
.Flags
= 0;
943 memcpy(record
->MatrixData
, transform
->matrix
, sizeof(record
->MatrixData
));
945 METAFILE_WriteRecords(metafile
);
951 GpStatus
METAFILE_ScaleWorldTransform(GpMetafile
* metafile
, REAL sx
, REAL sy
, MatrixOrder order
)
953 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
955 EmfPlusScaleWorldTransform
*record
;
958 stat
= METAFILE_AllocateRecord(metafile
,
959 sizeof(EmfPlusScaleWorldTransform
),
964 record
->Header
.Type
= EmfPlusRecordTypeScaleWorldTransform
;
965 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
969 METAFILE_WriteRecords(metafile
);
975 GpStatus
METAFILE_MultiplyWorldTransform(GpMetafile
* metafile
, GDIPCONST GpMatrix
* matrix
, MatrixOrder order
)
977 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
979 EmfPlusMultiplyWorldTransform
*record
;
982 stat
= METAFILE_AllocateRecord(metafile
,
983 sizeof(EmfPlusMultiplyWorldTransform
),
988 record
->Header
.Type
= EmfPlusRecordTypeMultiplyWorldTransform
;
989 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
990 memcpy(record
->MatrixData
, matrix
->matrix
, sizeof(record
->MatrixData
));
992 METAFILE_WriteRecords(metafile
);
998 GpStatus
METAFILE_RotateWorldTransform(GpMetafile
* metafile
, REAL angle
, MatrixOrder order
)
1000 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1002 EmfPlusRotateWorldTransform
*record
;
1005 stat
= METAFILE_AllocateRecord(metafile
,
1006 sizeof(EmfPlusRotateWorldTransform
),
1011 record
->Header
.Type
= EmfPlusRecordTypeRotateWorldTransform
;
1012 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1013 record
->Angle
= angle
;
1015 METAFILE_WriteRecords(metafile
);
1021 GpStatus
METAFILE_TranslateWorldTransform(GpMetafile
* metafile
, REAL dx
, REAL dy
, MatrixOrder order
)
1023 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1025 EmfPlusTranslateWorldTransform
*record
;
1028 stat
= METAFILE_AllocateRecord(metafile
,
1029 sizeof(EmfPlusTranslateWorldTransform
),
1034 record
->Header
.Type
= EmfPlusRecordTypeTranslateWorldTransform
;
1035 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
1039 METAFILE_WriteRecords(metafile
);
1045 GpStatus
METAFILE_ResetWorldTransform(GpMetafile
* metafile
)
1047 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1049 EmfPlusRecordHeader
*record
;
1052 stat
= METAFILE_AllocateRecord(metafile
,
1053 sizeof(EmfPlusRecordHeader
),
1058 record
->Type
= EmfPlusRecordTypeResetWorldTransform
;
1061 METAFILE_WriteRecords(metafile
);
1067 GpStatus
METAFILE_BeginContainer(GpMetafile
* metafile
, GDIPCONST GpRectF
*dstrect
,
1068 GDIPCONST GpRectF
*srcrect
, GpUnit unit
, DWORD StackIndex
)
1070 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1072 EmfPlusBeginContainer
*record
;
1075 stat
= METAFILE_AllocateRecord(metafile
, sizeof(*record
), (void**)&record
);
1079 record
->Header
.Type
= EmfPlusRecordTypeBeginContainer
;
1080 record
->Header
.Flags
= unit
& 0xff;
1081 record
->DestRect
= *dstrect
;
1082 record
->SrcRect
= *srcrect
;
1083 record
->StackIndex
= StackIndex
;
1085 METAFILE_WriteRecords(metafile
);
1091 GpStatus
METAFILE_BeginContainerNoParams(GpMetafile
* metafile
, DWORD StackIndex
)
1093 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1095 EmfPlusContainerRecord
*record
;
1098 stat
= METAFILE_AllocateRecord(metafile
,
1099 sizeof(EmfPlusContainerRecord
),
1104 record
->Header
.Type
= EmfPlusRecordTypeBeginContainerNoParams
;
1105 record
->Header
.Flags
= 0;
1106 record
->StackIndex
= StackIndex
;
1108 METAFILE_WriteRecords(metafile
);
1114 GpStatus
METAFILE_EndContainer(GpMetafile
* metafile
, DWORD StackIndex
)
1116 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1118 EmfPlusContainerRecord
*record
;
1121 stat
= METAFILE_AllocateRecord(metafile
,
1122 sizeof(EmfPlusContainerRecord
),
1127 record
->Header
.Type
= EmfPlusRecordTypeEndContainer
;
1128 record
->Header
.Flags
= 0;
1129 record
->StackIndex
= StackIndex
;
1131 METAFILE_WriteRecords(metafile
);
1137 GpStatus
METAFILE_SaveGraphics(GpMetafile
* metafile
, DWORD StackIndex
)
1139 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1141 EmfPlusContainerRecord
*record
;
1144 stat
= METAFILE_AllocateRecord(metafile
,
1145 sizeof(EmfPlusContainerRecord
),
1150 record
->Header
.Type
= EmfPlusRecordTypeSave
;
1151 record
->Header
.Flags
= 0;
1152 record
->StackIndex
= StackIndex
;
1154 METAFILE_WriteRecords(metafile
);
1160 GpStatus
METAFILE_RestoreGraphics(GpMetafile
* metafile
, DWORD StackIndex
)
1162 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
1164 EmfPlusContainerRecord
*record
;
1167 stat
= METAFILE_AllocateRecord(metafile
,
1168 sizeof(EmfPlusContainerRecord
),
1173 record
->Header
.Type
= EmfPlusRecordTypeRestore
;
1174 record
->Header
.Flags
= 0;
1175 record
->StackIndex
= StackIndex
;
1177 METAFILE_WriteRecords(metafile
);
1183 GpStatus
METAFILE_ReleaseDC(GpMetafile
* metafile
, HDC hdc
)
1185 if (hdc
!= metafile
->record_dc
)
1186 return InvalidParameter
;
1191 GpStatus
METAFILE_GraphicsDeleted(GpMetafile
* metafile
)
1195 stat
= METAFILE_WriteEndOfFile(metafile
);
1196 metafile
->record_graphics
= NULL
;
1198 metafile
->hemf
= CloseEnhMetaFile(metafile
->record_dc
);
1199 metafile
->record_dc
= NULL
;
1201 heap_free(metafile
->comment_data
);
1202 metafile
->comment_data
= NULL
;
1203 metafile
->comment_data_size
= 0;
1207 MetafileHeader header
;
1209 stat
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, &header
);
1210 if (stat
== Ok
&& metafile
->auto_frame
&&
1211 metafile
->auto_frame_max
.X
>= metafile
->auto_frame_min
.X
)
1213 RECTL bounds_rc
, gdi_bounds_rc
;
1214 REAL x_scale
= 2540.0 / header
.DpiX
;
1215 REAL y_scale
= 2540.0 / header
.DpiY
;
1219 bounds_rc
.left
= floorf(metafile
->auto_frame_min
.X
* x_scale
);
1220 bounds_rc
.top
= floorf(metafile
->auto_frame_min
.Y
* y_scale
);
1221 bounds_rc
.right
= ceilf(metafile
->auto_frame_max
.X
* x_scale
);
1222 bounds_rc
.bottom
= ceilf(metafile
->auto_frame_max
.Y
* y_scale
);
1224 gdi_bounds_rc
= header
.u
.EmfHeader
.rclBounds
;
1225 if (gdi_bounds_rc
.right
> gdi_bounds_rc
.left
&& gdi_bounds_rc
.bottom
> gdi_bounds_rc
.top
)
1227 bounds_rc
.left
= min(bounds_rc
.left
, gdi_bounds_rc
.left
);
1228 bounds_rc
.top
= min(bounds_rc
.top
, gdi_bounds_rc
.top
);
1229 bounds_rc
.right
= max(bounds_rc
.right
, gdi_bounds_rc
.right
);
1230 bounds_rc
.bottom
= max(bounds_rc
.bottom
, gdi_bounds_rc
.bottom
);
1233 buffer_size
= GetEnhMetaFileBits(metafile
->hemf
, 0, NULL
);
1234 buffer
= heap_alloc(buffer_size
);
1237 HENHMETAFILE new_hemf
;
1239 GetEnhMetaFileBits(metafile
->hemf
, buffer_size
, buffer
);
1241 ((ENHMETAHEADER
*)buffer
)->rclFrame
= bounds_rc
;
1243 new_hemf
= SetEnhMetaFileBits(buffer_size
, buffer
);
1247 DeleteEnhMetaFile(metafile
->hemf
);
1248 metafile
->hemf
= new_hemf
;
1259 stat
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, &header
);
1263 metafile
->bounds
.X
= header
.X
;
1264 metafile
->bounds
.Y
= header
.Y
;
1265 metafile
->bounds
.Width
= header
.Width
;
1266 metafile
->bounds
.Height
= header
.Height
;
1270 if (stat
== Ok
&& metafile
->record_stream
)
1275 buffer_size
= GetEnhMetaFileBits(metafile
->hemf
, 0, NULL
);
1277 buffer
= heap_alloc(buffer_size
);
1282 GetEnhMetaFileBits(metafile
->hemf
, buffer_size
, buffer
);
1284 hr
= IStream_Write(metafile
->record_stream
, buffer
, buffer_size
, NULL
);
1287 stat
= hresult_to_status(hr
);
1295 if (metafile
->record_stream
)
1297 IStream_Release(metafile
->record_stream
);
1298 metafile
->record_stream
= NULL
;
1304 GpStatus WINGDIPAPI
GdipGetHemfFromMetafile(GpMetafile
*metafile
, HENHMETAFILE
*hEmf
)
1306 TRACE("(%p,%p)\n", metafile
, hEmf
);
1308 if (!metafile
|| !hEmf
|| !metafile
->hemf
)
1309 return InvalidParameter
;
1311 *hEmf
= metafile
->hemf
;
1312 metafile
->hemf
= NULL
;
1317 static void METAFILE_GetFinalGdiTransform(const GpMetafile
*metafile
, XFORM
*result
)
1319 const GpRectF
*rect
;
1322 /* This transforms metafile device space to output points. */
1323 rect
= &metafile
->src_rect
;
1324 pt
= metafile
->playback_points
;
1325 result
->eM11
= (pt
[1].X
- pt
[0].X
) / rect
->Width
;
1326 result
->eM21
= (pt
[2].X
- pt
[0].X
) / rect
->Height
;
1327 result
->eDx
= pt
[0].X
- result
->eM11
* rect
->X
- result
->eM21
* rect
->Y
;
1328 result
->eM12
= (pt
[1].Y
- pt
[0].Y
) / rect
->Width
;
1329 result
->eM22
= (pt
[2].Y
- pt
[0].Y
) / rect
->Height
;
1330 result
->eDy
= pt
[0].Y
- result
->eM12
* rect
->X
- result
->eM22
* rect
->Y
;
1333 static GpStatus
METAFILE_PlaybackUpdateGdiTransform(GpMetafile
*metafile
)
1335 XFORM combined
, final
;
1337 METAFILE_GetFinalGdiTransform(metafile
, &final
);
1339 CombineTransform(&combined
, &metafile
->gdiworldtransform
, &final
);
1341 SetGraphicsMode(metafile
->playback_dc
, GM_ADVANCED
);
1342 SetWorldTransform(metafile
->playback_dc
, &combined
);
1347 static GpStatus
METAFILE_PlaybackGetDC(GpMetafile
*metafile
)
1351 stat
= GdipGetDC(metafile
->playback_graphics
, &metafile
->playback_dc
);
1355 static const XFORM identity
= {1, 0, 0, 1, 0, 0};
1357 metafile
->gdiworldtransform
= identity
;
1358 METAFILE_PlaybackUpdateGdiTransform(metafile
);
1364 static void METAFILE_PlaybackReleaseDC(GpMetafile
*metafile
)
1366 if (metafile
->playback_dc
)
1368 GdipReleaseDC(metafile
->playback_graphics
, metafile
->playback_dc
);
1369 metafile
->playback_dc
= NULL
;
1373 static GpStatus
METAFILE_PlaybackUpdateClip(GpMetafile
*metafile
)
1376 stat
= GdipCombineRegionRegion(metafile
->playback_graphics
->clip
, metafile
->base_clip
, CombineModeReplace
);
1378 stat
= GdipCombineRegionRegion(metafile
->playback_graphics
->clip
, metafile
->clip
, CombineModeIntersect
);
1382 static GpStatus
METAFILE_PlaybackUpdateWorldTransform(GpMetafile
*metafile
)
1384 GpMatrix
*real_transform
;
1387 stat
= GdipCreateMatrix3(&metafile
->src_rect
, metafile
->playback_points
, &real_transform
);
1391 REAL scale
= units_to_pixels(1.0, metafile
->page_unit
, 96.0);
1393 if (metafile
->page_unit
!= UnitDisplay
)
1394 scale
*= metafile
->page_scale
;
1396 stat
= GdipScaleMatrix(real_transform
, scale
, scale
, MatrixOrderPrepend
);
1399 stat
= GdipMultiplyMatrix(real_transform
, metafile
->world_transform
, MatrixOrderPrepend
);
1402 stat
= GdipSetWorldTransform(metafile
->playback_graphics
, real_transform
);
1404 GdipDeleteMatrix(real_transform
);
1410 GpStatus WINGDIPAPI
GdipPlayMetafileRecord(GDIPCONST GpMetafile
*metafile
,
1411 EmfPlusRecordType recordType
, UINT flags
, UINT dataSize
, GDIPCONST BYTE
*data
)
1414 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
;
1416 TRACE("(%p,%x,%x,%d,%p)\n", metafile
, recordType
, flags
, dataSize
, data
);
1418 if (!metafile
|| (dataSize
&& !data
) || !metafile
->playback_graphics
)
1419 return InvalidParameter
;
1421 if (recordType
>= 1 && recordType
<= 0x7a)
1423 /* regular EMF record */
1424 if (metafile
->playback_dc
)
1428 case EMR_SETMAPMODE
:
1431 case EMR_SETWINDOWORGEX
:
1432 case EMR_SETWINDOWEXTEX
:
1433 case EMR_SETVIEWPORTORGEX
:
1434 case EMR_SETVIEWPORTEXTEX
:
1435 case EMR_SCALEVIEWPORTEXTEX
:
1436 case EMR_SCALEWINDOWEXTEX
:
1437 case EMR_MODIFYWORLDTRANSFORM
:
1438 FIXME("not implemented for record type %x\n", recordType
);
1440 case EMR_SETWORLDTRANSFORM
:
1442 const XFORM
* xform
= (void*)data
;
1443 real_metafile
->gdiworldtransform
= *xform
;
1444 METAFILE_PlaybackUpdateGdiTransform(real_metafile
);
1447 case EMR_EXTSELECTCLIPRGN
:
1449 DWORD rgndatasize
= *(DWORD
*)data
;
1450 DWORD mode
= *(DWORD
*)(data
+ 4);
1451 const RGNDATA
*rgndata
= (const RGNDATA
*)(data
+ 8);
1458 METAFILE_GetFinalGdiTransform(metafile
, &final
);
1460 hrgn
= ExtCreateRegion(&final
, rgndatasize
, rgndata
);
1463 ExtSelectClipRgn(metafile
->playback_dc
, hrgn
, mode
);
1471 ENHMETARECORD
*record
= heap_alloc_zero(dataSize
+ 8);
1475 record
->iType
= recordType
;
1476 record
->nSize
= dataSize
+ 8;
1477 memcpy(record
->dParm
, data
, dataSize
);
1479 if(PlayEnhMetaFileRecord(metafile
->playback_dc
, metafile
->handle_table
,
1480 record
, metafile
->handle_count
) == 0)
1481 ERR("PlayEnhMetaFileRecord failed\n");
1495 EmfPlusRecordHeader
*header
= (EmfPlusRecordHeader
*)(data
)-1;
1497 METAFILE_PlaybackReleaseDC((GpMetafile
*)metafile
);
1501 case EmfPlusRecordTypeHeader
:
1502 case EmfPlusRecordTypeEndOfFile
:
1504 case EmfPlusRecordTypeGetDC
:
1505 METAFILE_PlaybackGetDC((GpMetafile
*)metafile
);
1507 case EmfPlusRecordTypeClear
:
1509 EmfPlusClear
*record
= (EmfPlusClear
*)header
;
1511 return GdipGraphicsClear(metafile
->playback_graphics
, record
->Color
);
1513 case EmfPlusRecordTypeFillRects
:
1515 EmfPlusFillRects
*record
= (EmfPlusFillRects
*)header
;
1516 GpBrush
*brush
, *temp_brush
=NULL
;
1517 GpRectF
*rects
, *temp_rects
=NULL
;
1519 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
))
1520 return InvalidParameter
;
1524 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(EmfPlusRect
) * record
->Count
)
1525 return InvalidParameter
;
1529 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(GpRectF
) * record
->Count
)
1530 return InvalidParameter
;
1535 stat
= GdipCreateSolidFill((ARGB
)record
->BrushID
, (GpSolidFill
**)&temp_brush
);
1540 FIXME("brush deserialization not implemented\n");
1541 return NotImplemented
;
1548 EmfPlusRect
*int_rects
= (EmfPlusRect
*)(record
+1);
1551 rects
= temp_rects
= heap_alloc_zero(sizeof(GpRectF
) * record
->Count
);
1554 for (i
=0; i
<record
->Count
; i
++)
1556 rects
[i
].X
= int_rects
[i
].X
;
1557 rects
[i
].Y
= int_rects
[i
].Y
;
1558 rects
[i
].Width
= int_rects
[i
].Width
;
1559 rects
[i
].Height
= int_rects
[i
].Height
;
1566 rects
= (GpRectF
*)(record
+1);
1571 stat
= GdipFillRectangles(metafile
->playback_graphics
, brush
, rects
, record
->Count
);
1574 GdipDeleteBrush(temp_brush
);
1575 heap_free(temp_rects
);
1579 case EmfPlusRecordTypeSetClipRect
:
1581 EmfPlusSetClipRect
*record
= (EmfPlusSetClipRect
*)header
;
1582 CombineMode mode
= (CombineMode
)((flags
>> 8) & 0xf);
1584 GpMatrix world_to_device
;
1586 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(*record
))
1587 return InvalidParameter
;
1589 stat
= GdipCreateRegionRect(&record
->ClipRect
, ®ion
);
1593 get_graphics_transform(real_metafile
->playback_graphics
,
1594 CoordinateSpaceDevice
, CoordinateSpaceWorld
, &world_to_device
);
1596 GdipTransformRegion(region
, &world_to_device
);
1598 GdipCombineRegionRegion(real_metafile
->clip
, region
, mode
);
1600 GdipDeleteRegion(region
);
1603 return METAFILE_PlaybackUpdateClip(real_metafile
);
1605 case EmfPlusRecordTypeSetPageTransform
:
1607 EmfPlusSetPageTransform
*record
= (EmfPlusSetPageTransform
*)header
;
1608 GpUnit unit
= (GpUnit
)flags
;
1610 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetPageTransform
))
1611 return InvalidParameter
;
1613 real_metafile
->page_unit
= unit
;
1614 real_metafile
->page_scale
= record
->PageScale
;
1616 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
1618 case EmfPlusRecordTypeSetWorldTransform
:
1620 EmfPlusSetWorldTransform
*record
= (EmfPlusSetWorldTransform
*)header
;
1622 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetWorldTransform
))
1623 return InvalidParameter
;
1625 memcpy(real_metafile
->world_transform
->matrix
, record
->MatrixData
, sizeof(record
->MatrixData
));
1627 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
1629 case EmfPlusRecordTypeScaleWorldTransform
:
1631 EmfPlusScaleWorldTransform
*record
= (EmfPlusScaleWorldTransform
*)header
;
1632 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
1634 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusScaleWorldTransform
))
1635 return InvalidParameter
;
1637 GdipScaleMatrix(real_metafile
->world_transform
, record
->Sx
, record
->Sy
, order
);
1639 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
1641 case EmfPlusRecordTypeMultiplyWorldTransform
:
1643 EmfPlusMultiplyWorldTransform
*record
= (EmfPlusMultiplyWorldTransform
*)header
;
1644 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
1647 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusMultiplyWorldTransform
))
1648 return InvalidParameter
;
1650 memcpy(matrix
.matrix
, record
->MatrixData
, sizeof(matrix
.matrix
));
1652 GdipMultiplyMatrix(real_metafile
->world_transform
, &matrix
, order
);
1654 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
1656 case EmfPlusRecordTypeRotateWorldTransform
:
1658 EmfPlusRotateWorldTransform
*record
= (EmfPlusRotateWorldTransform
*)header
;
1659 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
1661 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusRotateWorldTransform
))
1662 return InvalidParameter
;
1664 GdipRotateMatrix(real_metafile
->world_transform
, record
->Angle
, order
);
1666 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
1668 case EmfPlusRecordTypeTranslateWorldTransform
:
1670 EmfPlusTranslateWorldTransform
*record
= (EmfPlusTranslateWorldTransform
*)header
;
1671 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
1673 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusTranslateWorldTransform
))
1674 return InvalidParameter
;
1676 GdipTranslateMatrix(real_metafile
->world_transform
, record
->dx
, record
->dy
, order
);
1678 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
1680 case EmfPlusRecordTypeResetWorldTransform
:
1682 GdipSetMatrixElements(real_metafile
->world_transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1684 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
1686 case EmfPlusRecordTypeBeginContainer
:
1688 EmfPlusBeginContainer
*record
= (EmfPlusBeginContainer
*)header
;
1691 REAL scale_x
, scale_y
;
1692 GpRectF scaled_srcrect
;
1695 cont
= heap_alloc_zero(sizeof(*cont
));
1699 stat
= GdipCloneRegion(metafile
->clip
, &cont
->clip
);
1706 stat
= GdipBeginContainer2(metafile
->playback_graphics
, &cont
->state
);
1710 GdipDeleteRegion(cont
->clip
);
1715 cont
->id
= record
->StackIndex
;
1716 cont
->type
= BEGIN_CONTAINER
;
1717 cont
->world_transform
= *metafile
->world_transform
;
1718 cont
->page_unit
= metafile
->page_unit
;
1719 cont
->page_scale
= metafile
->page_scale
;
1720 list_add_head(&real_metafile
->containers
, &cont
->entry
);
1722 unit
= record
->Header
.Flags
& 0xff;
1724 scale_x
= units_to_pixels(1.0, unit
, metafile
->image
.xres
);
1725 scale_y
= units_to_pixels(1.0, unit
, metafile
->image
.yres
);
1727 scaled_srcrect
.X
= scale_x
* record
->SrcRect
.X
;
1728 scaled_srcrect
.Y
= scale_y
* record
->SrcRect
.Y
;
1729 scaled_srcrect
.Width
= scale_x
* record
->SrcRect
.Width
;
1730 scaled_srcrect
.Height
= scale_y
* record
->SrcRect
.Height
;
1732 transform
.matrix
[0] = record
->DestRect
.Width
/ scaled_srcrect
.Width
;
1733 transform
.matrix
[1] = 0.0;
1734 transform
.matrix
[2] = 0.0;
1735 transform
.matrix
[3] = record
->DestRect
.Height
/ scaled_srcrect
.Height
;
1736 transform
.matrix
[4] = record
->DestRect
.X
- scaled_srcrect
.X
;
1737 transform
.matrix
[5] = record
->DestRect
.Y
- scaled_srcrect
.Y
;
1739 GdipMultiplyMatrix(real_metafile
->world_transform
, &transform
, MatrixOrderPrepend
);
1741 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
1743 case EmfPlusRecordTypeBeginContainerNoParams
:
1744 case EmfPlusRecordTypeSave
:
1746 EmfPlusContainerRecord
*record
= (EmfPlusContainerRecord
*)header
;
1749 cont
= heap_alloc_zero(sizeof(*cont
));
1753 stat
= GdipCloneRegion(metafile
->clip
, &cont
->clip
);
1760 if (recordType
== EmfPlusRecordTypeBeginContainerNoParams
)
1761 stat
= GdipBeginContainer2(metafile
->playback_graphics
, &cont
->state
);
1763 stat
= GdipSaveGraphics(metafile
->playback_graphics
, &cont
->state
);
1767 GdipDeleteRegion(cont
->clip
);
1772 cont
->id
= record
->StackIndex
;
1773 if (recordType
== EmfPlusRecordTypeBeginContainerNoParams
)
1774 cont
->type
= BEGIN_CONTAINER
;
1776 cont
->type
= SAVE_GRAPHICS
;
1777 cont
->world_transform
= *metafile
->world_transform
;
1778 cont
->page_unit
= metafile
->page_unit
;
1779 cont
->page_scale
= metafile
->page_scale
;
1780 list_add_head(&real_metafile
->containers
, &cont
->entry
);
1784 case EmfPlusRecordTypeEndContainer
:
1785 case EmfPlusRecordTypeRestore
:
1787 EmfPlusContainerRecord
*record
= (EmfPlusContainerRecord
*)header
;
1789 enum container_type type
;
1792 if (recordType
== EmfPlusRecordTypeEndContainer
)
1793 type
= BEGIN_CONTAINER
;
1795 type
= SAVE_GRAPHICS
;
1797 LIST_FOR_EACH_ENTRY(cont
, &real_metafile
->containers
, container
, entry
)
1799 if (cont
->id
== record
->StackIndex
&& cont
->type
== type
)
1810 /* pop any newer items on the stack */
1811 while ((cont2
= LIST_ENTRY(list_head(&real_metafile
->containers
), container
, entry
)) != cont
)
1813 list_remove(&cont2
->entry
);
1814 GdipDeleteRegion(cont2
->clip
);
1818 if (type
== BEGIN_CONTAINER
)
1819 GdipEndContainer(real_metafile
->playback_graphics
, cont
->state
);
1821 GdipRestoreGraphics(real_metafile
->playback_graphics
, cont
->state
);
1823 *real_metafile
->world_transform
= cont
->world_transform
;
1824 real_metafile
->page_unit
= cont
->page_unit
;
1825 real_metafile
->page_scale
= cont
->page_scale
;
1826 GdipCombineRegionRegion(real_metafile
->clip
, cont
->clip
, CombineModeReplace
);
1828 list_remove(&cont
->entry
);
1829 GdipDeleteRegion(cont
->clip
);
1836 FIXME("Not implemented for record type %x\n", recordType
);
1837 return NotImplemented
;
1844 struct enum_metafile_data
1846 EnumerateMetafileProc callback
;
1847 void *callback_data
;
1848 GpMetafile
*metafile
;
1851 static int CALLBACK
enum_metafile_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
1852 int nObj
, LPARAM lpData
)
1855 struct enum_metafile_data
*data
= (struct enum_metafile_data
*)lpData
;
1858 data
->metafile
->handle_table
= lpHTable
;
1859 data
->metafile
->handle_count
= nObj
;
1861 /* First check for an EMF+ record. */
1862 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
1864 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
1866 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
1870 while (offset
+ sizeof(EmfPlusRecordHeader
) <= comment
->cbData
)
1872 const EmfPlusRecordHeader
*record
= (const EmfPlusRecordHeader
*)&comment
->Data
[offset
];
1874 if (record
->DataSize
)
1875 pStr
= (const BYTE
*)(record
+1);
1879 ret
= data
->callback(record
->Type
, record
->Flags
, record
->DataSize
,
1880 pStr
, data
->callback_data
);
1885 offset
+= record
->Size
;
1892 if (lpEMFR
->nSize
!= 8)
1893 pStr
= (const BYTE
*)lpEMFR
->dParm
;
1897 return data
->callback(lpEMFR
->iType
, 0, lpEMFR
->nSize
-8,
1898 pStr
, data
->callback_data
);
1901 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestPoints(GpGraphics
*graphics
,
1902 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*destPoints
, INT count
,
1903 GDIPCONST GpRectF
*srcRect
, Unit srcUnit
, EnumerateMetafileProc callback
,
1904 VOID
*callbackData
, GDIPCONST GpImageAttributes
*imageAttributes
)
1906 struct enum_metafile_data data
;
1908 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
; /* whoever made this const was joking */
1909 GraphicsContainer state
;
1912 TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics
, metafile
,
1913 destPoints
, count
, srcRect
, srcUnit
, callback
, callbackData
,
1916 if (!graphics
|| !metafile
|| !destPoints
|| count
!= 3 || !srcRect
)
1917 return InvalidParameter
;
1919 if (!metafile
->hemf
)
1920 return InvalidParameter
;
1922 if (metafile
->playback_graphics
)
1925 TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect
), srcUnit
,
1926 debugstr_pointf(&destPoints
[0]), debugstr_pointf(&destPoints
[1]),
1927 debugstr_pointf(&destPoints
[2]));
1929 data
.callback
= callback
;
1930 data
.callback_data
= callbackData
;
1931 data
.metafile
= real_metafile
;
1933 real_metafile
->playback_graphics
= graphics
;
1934 real_metafile
->playback_dc
= NULL
;
1935 real_metafile
->src_rect
= *srcRect
;
1937 memcpy(real_metafile
->playback_points
, destPoints
, sizeof(PointF
) * 3);
1938 stat
= GdipTransformPoints(graphics
, CoordinateSpaceDevice
, CoordinateSpaceWorld
, real_metafile
->playback_points
, 3);
1941 stat
= GdipBeginContainer2(graphics
, &state
);
1945 stat
= GdipSetPageScale(graphics
, 1.0);
1948 stat
= GdipSetPageUnit(graphics
, UnitPixel
);
1951 stat
= GdipResetWorldTransform(graphics
);
1954 stat
= GdipCreateRegion(&real_metafile
->base_clip
);
1957 stat
= GdipGetClip(graphics
, real_metafile
->base_clip
);
1960 stat
= GdipCreateRegion(&real_metafile
->clip
);
1963 stat
= GdipCreatePath(FillModeAlternate
, &dst_path
);
1967 GpPointF clip_points
[4];
1969 clip_points
[0] = real_metafile
->playback_points
[0];
1970 clip_points
[1] = real_metafile
->playback_points
[1];
1971 clip_points
[2].X
= real_metafile
->playback_points
[1].X
+ real_metafile
->playback_points
[2].X
1972 - real_metafile
->playback_points
[0].X
;
1973 clip_points
[2].Y
= real_metafile
->playback_points
[1].Y
+ real_metafile
->playback_points
[2].Y
1974 - real_metafile
->playback_points
[0].Y
;
1975 clip_points
[3] = real_metafile
->playback_points
[2];
1977 stat
= GdipAddPathPolygon(dst_path
, clip_points
, 4);
1980 stat
= GdipCombineRegionPath(real_metafile
->base_clip
, dst_path
, CombineModeIntersect
);
1982 GdipDeletePath(dst_path
);
1986 stat
= GdipCreateMatrix(&real_metafile
->world_transform
);
1990 real_metafile
->page_unit
= UnitDisplay
;
1991 real_metafile
->page_scale
= 1.0;
1992 stat
= METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
1997 stat
= METAFILE_PlaybackUpdateClip(real_metafile
);
2000 if (stat
== Ok
&& (metafile
->metafile_type
== MetafileTypeEmf
||
2001 metafile
->metafile_type
== MetafileTypeWmfPlaceable
||
2002 metafile
->metafile_type
== MetafileTypeWmf
))
2003 stat
= METAFILE_PlaybackGetDC(real_metafile
);
2006 EnumEnhMetaFile(0, metafile
->hemf
, enum_metafile_proc
, &data
, NULL
);
2008 METAFILE_PlaybackReleaseDC(real_metafile
);
2010 GdipDeleteMatrix(real_metafile
->world_transform
);
2011 real_metafile
->world_transform
= NULL
;
2013 GdipDeleteRegion(real_metafile
->base_clip
);
2014 real_metafile
->base_clip
= NULL
;
2016 GdipDeleteRegion(real_metafile
->clip
);
2017 real_metafile
->clip
= NULL
;
2019 while (list_head(&real_metafile
->containers
))
2021 container
* cont
= LIST_ENTRY(list_head(&real_metafile
->containers
), container
, entry
);
2022 list_remove(&cont
->entry
);
2023 GdipDeleteRegion(cont
->clip
);
2027 GdipEndContainer(graphics
, state
);
2030 real_metafile
->playback_graphics
= NULL
;
2035 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRect(GpGraphics
*graphics
,
2036 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRectF
*dest
,
2037 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
2041 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
2043 points
[0].X
= points
[2].X
= dest
->X
;
2044 points
[0].Y
= points
[1].Y
= dest
->Y
;
2045 points
[1].X
= dest
->X
+ dest
->Width
;
2046 points
[2].Y
= dest
->Y
+ dest
->Height
;
2048 return GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, points
, 3,
2049 &metafile
->bounds
, metafile
->unit
, callback
, cb_data
, attrs
);
2052 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRectI(GpGraphics
*graphics
,
2053 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRect
*dest
,
2054 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
2058 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
2062 destf
.Width
= dest
->Width
;
2063 destf
.Height
= dest
->Height
;
2065 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
2068 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPoint(GpGraphics
*graphics
,
2069 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*dest
,
2070 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
2074 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
2078 destf
.Width
= units_to_pixels(metafile
->bounds
.Width
, metafile
->unit
, metafile
->image
.xres
);
2079 destf
.Height
= units_to_pixels(metafile
->bounds
.Height
, metafile
->unit
, metafile
->image
.yres
);
2081 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
2084 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPointI(GpGraphics
*graphics
,
2085 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPoint
*dest
,
2086 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
2090 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
2095 return GdipEnumerateMetafileDestPoint(graphics
, metafile
, &ptf
, callback
, cb_data
, attrs
);
2098 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromMetafile(GpMetafile
* metafile
,
2099 MetafileHeader
* header
)
2103 TRACE("(%p, %p)\n", metafile
, header
);
2105 if(!metafile
|| !header
)
2106 return InvalidParameter
;
2110 status
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, header
);
2111 if (status
!= Ok
) return status
;
2115 memset(header
, 0, sizeof(*header
));
2116 header
->Version
= VERSION_MAGIC2
;
2119 header
->Type
= metafile
->metafile_type
;
2120 header
->DpiX
= metafile
->image
.xres
;
2121 header
->DpiY
= metafile
->image
.yres
;
2122 header
->Width
= gdip_round(metafile
->bounds
.Width
);
2123 header
->Height
= gdip_round(metafile
->bounds
.Height
);
2128 static int CALLBACK
get_emfplus_header_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
2129 int nObj
, LPARAM lpData
)
2131 EmfPlusHeader
*dst_header
= (EmfPlusHeader
*)lpData
;
2133 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
2135 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
2137 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
2139 const EmfPlusRecordHeader
*header
= (const EmfPlusRecordHeader
*)&comment
->Data
[4];
2141 if (4 + sizeof(EmfPlusHeader
) <= comment
->cbData
&&
2142 header
->Type
== EmfPlusRecordTypeHeader
)
2144 memcpy(dst_header
, header
, sizeof(*dst_header
));
2148 else if (lpEMFR
->iType
== EMR_HEADER
)
2154 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromEmf(HENHMETAFILE hemf
,
2155 MetafileHeader
*header
)
2157 ENHMETAHEADER3 emfheader
;
2158 EmfPlusHeader emfplusheader
;
2159 MetafileType metafile_type
;
2161 TRACE("(%p,%p)\n", hemf
, header
);
2163 if(!hemf
|| !header
)
2164 return InvalidParameter
;
2166 if (GetEnhMetaFileHeader(hemf
, sizeof(emfheader
), (ENHMETAHEADER
*)&emfheader
) == 0)
2167 return GenericError
;
2169 emfplusheader
.Header
.Type
= 0;
2171 EnumEnhMetaFile(NULL
, hemf
, get_emfplus_header_proc
, &emfplusheader
, NULL
);
2173 if (emfplusheader
.Header
.Type
== EmfPlusRecordTypeHeader
)
2175 if ((emfplusheader
.Header
.Flags
& 1) == 1)
2176 metafile_type
= MetafileTypeEmfPlusDual
;
2178 metafile_type
= MetafileTypeEmfPlusOnly
;
2181 metafile_type
= MetafileTypeEmf
;
2183 header
->Type
= metafile_type
;
2184 header
->Size
= emfheader
.nBytes
;
2185 header
->DpiX
= (REAL
)emfheader
.szlDevice
.cx
* 25.4 / emfheader
.szlMillimeters
.cx
;
2186 header
->DpiY
= (REAL
)emfheader
.szlDevice
.cy
* 25.4 / emfheader
.szlMillimeters
.cy
;
2187 header
->X
= gdip_round((REAL
)emfheader
.rclFrame
.left
/ 2540.0 * header
->DpiX
);
2188 header
->Y
= gdip_round((REAL
)emfheader
.rclFrame
.top
/ 2540.0 * header
->DpiY
);
2189 header
->Width
= gdip_round((REAL
)(emfheader
.rclFrame
.right
- emfheader
.rclFrame
.left
) / 2540.0 * header
->DpiX
);
2190 header
->Height
= gdip_round((REAL
)(emfheader
.rclFrame
.bottom
- emfheader
.rclFrame
.top
) / 2540.0 * header
->DpiY
);
2191 header
->u
.EmfHeader
= emfheader
;
2193 if (metafile_type
== MetafileTypeEmfPlusDual
|| metafile_type
== MetafileTypeEmfPlusOnly
)
2195 header
->Version
= emfplusheader
.Version
;
2196 header
->EmfPlusFlags
= emfplusheader
.EmfPlusFlags
;
2197 header
->EmfPlusHeaderSize
= emfplusheader
.Header
.Size
;
2198 header
->LogicalDpiX
= emfplusheader
.LogicalDpiX
;
2199 header
->LogicalDpiY
= emfplusheader
.LogicalDpiY
;
2203 header
->Version
= emfheader
.nVersion
;
2204 header
->EmfPlusFlags
= 0;
2205 header
->EmfPlusHeaderSize
= 0;
2206 header
->LogicalDpiX
= 0;
2207 header
->LogicalDpiY
= 0;
2213 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromWmf(HMETAFILE hwmf
,
2214 GDIPCONST WmfPlaceableFileHeader
*placeable
, MetafileHeader
*header
)
2217 GpMetafile
*metafile
;
2219 TRACE("(%p,%p,%p)\n", hwmf
, placeable
, header
);
2221 status
= GdipCreateMetafileFromWmf(hwmf
, FALSE
, placeable
, &metafile
);
2224 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
2225 GdipDisposeImage(&metafile
->image
);
2230 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR
*filename
,
2231 MetafileHeader
*header
)
2234 GpMetafile
*metafile
;
2236 TRACE("(%s,%p)\n", debugstr_w(filename
), header
);
2238 if (!filename
|| !header
)
2239 return InvalidParameter
;
2241 status
= GdipCreateMetafileFromFile(filename
, &metafile
);
2244 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
2245 GdipDisposeImage(&metafile
->image
);
2250 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromStream(IStream
*stream
,
2251 MetafileHeader
*header
)
2254 GpMetafile
*metafile
;
2256 TRACE("(%p,%p)\n", stream
, header
);
2258 if (!stream
|| !header
)
2259 return InvalidParameter
;
2261 status
= GdipCreateMetafileFromStream(stream
, &metafile
);
2264 status
= GdipGetMetafileHeaderFromMetafile(metafile
, header
);
2265 GdipDisposeImage(&metafile
->image
);
2270 GpStatus WINGDIPAPI
GdipCreateMetafileFromEmf(HENHMETAFILE hemf
, BOOL
delete,
2271 GpMetafile
**metafile
)
2274 MetafileHeader header
;
2276 TRACE("(%p,%i,%p)\n", hemf
, delete, metafile
);
2278 if(!hemf
|| !metafile
)
2279 return InvalidParameter
;
2281 stat
= GdipGetMetafileHeaderFromEmf(hemf
, &header
);
2285 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
2289 (*metafile
)->image
.type
= ImageTypeMetafile
;
2290 (*metafile
)->image
.format
= ImageFormatEMF
;
2291 (*metafile
)->image
.frame_count
= 1;
2292 (*metafile
)->image
.xres
= header
.DpiX
;
2293 (*metafile
)->image
.yres
= header
.DpiY
;
2294 (*metafile
)->bounds
.X
= (REAL
)header
.u
.EmfHeader
.rclFrame
.left
/ 2540.0 * header
.DpiX
;
2295 (*metafile
)->bounds
.Y
= (REAL
)header
.u
.EmfHeader
.rclFrame
.top
/ 2540.0 * header
.DpiY
;
2296 (*metafile
)->bounds
.Width
= (REAL
)(header
.u
.EmfHeader
.rclFrame
.right
- header
.u
.EmfHeader
.rclFrame
.left
)
2297 / 2540.0 * header
.DpiX
;
2298 (*metafile
)->bounds
.Height
= (REAL
)(header
.u
.EmfHeader
.rclFrame
.bottom
- header
.u
.EmfHeader
.rclFrame
.top
)
2299 / 2540.0 * header
.DpiY
;
2300 (*metafile
)->unit
= UnitPixel
;
2301 (*metafile
)->metafile_type
= header
.Type
;
2302 (*metafile
)->hemf
= hemf
;
2303 (*metafile
)->preserve_hemf
= !delete;
2304 list_init(&(*metafile
)->containers
);
2306 TRACE("<-- %p\n", *metafile
);
2311 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmf(HMETAFILE hwmf
, BOOL
delete,
2312 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
2317 GpStatus retval
= Ok
;
2319 TRACE("(%p, %d, %p, %p)\n", hwmf
, delete, placeable
, metafile
);
2321 if(!hwmf
|| !metafile
)
2322 return InvalidParameter
;
2325 read
= GetMetaFileBitsEx(hwmf
, 0, NULL
);
2327 return GenericError
;
2328 copy
= heap_alloc_zero(read
);
2329 GetMetaFileBitsEx(hwmf
, read
, copy
);
2331 hemf
= SetWinMetaFileBits(read
, copy
, NULL
, NULL
);
2334 /* FIXME: We should store and use hwmf instead of converting to hemf */
2335 retval
= GdipCreateMetafileFromEmf(hemf
, TRUE
, metafile
);
2341 (*metafile
)->image
.xres
= (REAL
)placeable
->Inch
;
2342 (*metafile
)->image
.yres
= (REAL
)placeable
->Inch
;
2343 (*metafile
)->bounds
.X
= ((REAL
)placeable
->BoundingBox
.Left
) / ((REAL
)placeable
->Inch
);
2344 (*metafile
)->bounds
.Y
= ((REAL
)placeable
->BoundingBox
.Top
) / ((REAL
)placeable
->Inch
);
2345 (*metafile
)->bounds
.Width
= (REAL
)(placeable
->BoundingBox
.Right
-
2346 placeable
->BoundingBox
.Left
);
2347 (*metafile
)->bounds
.Height
= (REAL
)(placeable
->BoundingBox
.Bottom
-
2348 placeable
->BoundingBox
.Top
);
2349 (*metafile
)->metafile_type
= MetafileTypeWmfPlaceable
;
2352 (*metafile
)->metafile_type
= MetafileTypeWmf
;
2353 (*metafile
)->image
.format
= ImageFormatWMF
;
2355 if (delete) DeleteMetaFile(hwmf
);
2358 DeleteEnhMetaFile(hemf
);
2362 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR
*file
,
2363 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
2368 TRACE("(%s, %p, %p)\n", debugstr_w(file
), placeable
, metafile
);
2370 hmf
= GetMetaFileW(file
);
2372 return GdipCreateMetafileFromWmf(hmf
, TRUE
, placeable
, metafile
);
2374 emf
= GetEnhMetaFileW(file
);
2376 return GdipCreateMetafileFromEmf(emf
, TRUE
, metafile
);
2378 return GenericError
;
2381 GpStatus WINGDIPAPI
GdipCreateMetafileFromFile(GDIPCONST WCHAR
*file
,
2382 GpMetafile
**metafile
)
2387 TRACE("(%p, %p)\n", file
, metafile
);
2389 if (!file
|| !metafile
) return InvalidParameter
;
2393 status
= GdipCreateStreamOnFile(file
, GENERIC_READ
, &stream
);
2396 status
= GdipCreateMetafileFromStream(stream
, metafile
);
2397 IStream_Release(stream
);
2402 GpStatus WINGDIPAPI
GdipCreateMetafileFromStream(IStream
*stream
,
2403 GpMetafile
**metafile
)
2407 TRACE("%p %p\n", stream
, metafile
);
2409 stat
= GdipLoadImageFromStream(stream
, (GpImage
**)metafile
);
2410 if (stat
!= Ok
) return stat
;
2412 if ((*metafile
)->image
.type
!= ImageTypeMetafile
)
2414 GdipDisposeImage(&(*metafile
)->image
);
2416 return GenericError
;
2422 GpStatus WINGDIPAPI
GdipSetMetafileDownLevelRasterizationLimit(GpMetafile
*metafile
,
2425 TRACE("(%p,%u)\n", metafile
, limitDpi
);
2430 GpStatus WINGDIPAPI
GdipConvertToEmfPlus(const GpGraphics
* ref
,
2431 GpMetafile
* metafile
, BOOL
* succ
, EmfType emfType
,
2432 const WCHAR
* description
, GpMetafile
** out_metafile
)
2436 TRACE("(%p,%p,%p,%u,%s,%p)\n", ref
, metafile
, succ
, emfType
,
2437 debugstr_w(description
), out_metafile
);
2439 if(!ref
|| !metafile
|| !out_metafile
|| emfType
< EmfTypeEmfOnly
|| emfType
> EmfTypeEmfPlusDual
)
2440 return InvalidParameter
;
2444 *out_metafile
= NULL
;
2447 FIXME("not implemented\n");
2449 return NotImplemented
;
2452 GpStatus WINGDIPAPI
GdipEmfToWmfBits(HENHMETAFILE hemf
, UINT cbData16
,
2453 LPBYTE pData16
, INT iMapMode
, INT eFlags
)
2455 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf
, cbData16
, pData16
, iMapMode
, eFlags
);
2456 return NotImplemented
;
2459 GpStatus WINGDIPAPI
GdipRecordMetafileFileName(GDIPCONST WCHAR
* fileName
,
2460 HDC hdc
, EmfType type
, GDIPCONST GpRectF
*pFrameRect
,
2461 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
,
2462 GpMetafile
**metafile
)
2464 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
2465 frameUnit
, debugstr_w(desc
), metafile
);
2467 return NotImplemented
;
2470 GpStatus WINGDIPAPI
GdipRecordMetafileFileNameI(GDIPCONST WCHAR
* fileName
, HDC hdc
, EmfType type
,
2471 GDIPCONST GpRect
*pFrameRect
, MetafileFrameUnit frameUnit
,
2472 GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
2474 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
2475 frameUnit
, debugstr_w(desc
), metafile
);
2477 return NotImplemented
;
2480 /*****************************************************************************
2481 * GdipConvertToEmfPlusToFile [GDIPLUS.@]
2484 GpStatus WINGDIPAPI
GdipConvertToEmfPlusToFile(const GpGraphics
* refGraphics
,
2485 GpMetafile
* metafile
, BOOL
* conversionSuccess
,
2486 const WCHAR
* filename
, EmfType emfType
,
2487 const WCHAR
* description
, GpMetafile
** out_metafile
)
2489 FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics
, metafile
, conversionSuccess
, filename
, emfType
, description
, out_metafile
);
2490 return NotImplemented
;
2493 static GpStatus
METAFILE_CreateCompressedImageStream(GpImage
*image
, IStream
**stream
, DWORD
*size
)
2502 hr
= CreateStreamOnHGlobal(NULL
, TRUE
, stream
);
2503 if (FAILED(hr
)) return hresult_to_status(hr
);
2505 stat
= encode_image_png(image
, *stream
, NULL
);
2508 IStream_Release(*stream
);
2512 hr
= IStream_Stat(*stream
, &statstg
, 1);
2515 IStream_Release(*stream
);
2516 return hresult_to_status(hr
);
2518 *size
= statstg
.cbSize
.u
.LowPart
;
2521 hr
= IStream_Seek(*stream
, zero
, STREAM_SEEK_SET
, NULL
);
2524 IStream_Release(*stream
);
2525 return hresult_to_status(hr
);
2531 static GpStatus
METAFILE_FillEmfPlusBitmap(EmfPlusBitmap
*record
, IStream
*stream
, DWORD size
)
2538 record
->PixelFormat
= 0;
2539 record
->Type
= BitmapDataTypeCompressed
;
2541 hr
= IStream_Read(stream
, record
->BitmapData
, size
, NULL
);
2542 if (FAILED(hr
)) return hresult_to_status(hr
);
2546 static GpStatus
METAFILE_AddImageObject(GpMetafile
*metafile
, GpImage
*image
, DWORD
*id
)
2548 EmfPlusObject
*object_record
;
2554 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
2557 if (image
->type
== ImageTypeBitmap
)
2562 stat
= METAFILE_CreateCompressedImageStream(image
, &stream
, &size
);
2563 if (stat
!= Ok
) return stat
;
2564 aligned_size
= (size
+ 3) & ~3;
2566 stat
= METAFILE_AllocateRecord(metafile
,
2567 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image
.ImageData
.bitmap
.BitmapData
[aligned_size
]),
2568 (void**)&object_record
);
2571 IStream_Release(stream
);
2574 memset(object_record
->ObjectData
.image
.ImageData
.bitmap
.BitmapData
+ size
, 0, aligned_size
- size
);
2576 *id
= METAFILE_AddObjectId(metafile
);
2577 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
2578 object_record
->Header
.Flags
= *id
| ObjectTypeImage
<< 8;
2579 object_record
->ObjectData
.image
.Version
= VERSION_MAGIC2
;
2580 object_record
->ObjectData
.image
.Type
= ImageDataTypeBitmap
;
2582 stat
= METAFILE_FillEmfPlusBitmap(&object_record
->ObjectData
.image
.ImageData
.bitmap
, stream
, size
);
2583 IStream_Release(stream
);
2584 if (stat
!= Ok
) METAFILE_RemoveLastRecord(metafile
, &object_record
->Header
);
2587 else if (image
->type
== ImageTypeMetafile
)
2589 HENHMETAFILE hemf
= ((GpMetafile
*)image
)->hemf
;
2590 EmfPlusMetafile
*metafile_record
;
2592 if (!hemf
) return InvalidParameter
;
2594 size
= GetEnhMetaFileBits(hemf
, 0, NULL
);
2595 if (!size
) return GenericError
;
2597 stat
= METAFILE_AllocateRecord(metafile
,
2598 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image
.ImageData
.metafile
.MetafileData
[size
]),
2599 (void**)&object_record
);
2600 if (stat
!= Ok
) return stat
;
2602 *id
= METAFILE_AddObjectId(metafile
);
2603 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
2604 object_record
->Header
.Flags
= *id
| ObjectTypeImage
<< 8;
2605 object_record
->ObjectData
.image
.Version
= VERSION_MAGIC2
;
2606 object_record
->ObjectData
.image
.Type
= ImageDataTypeMetafile
;
2607 metafile_record
= &object_record
->ObjectData
.image
.ImageData
.metafile
;
2608 metafile_record
->Type
= ((GpMetafile
*)image
)->metafile_type
;
2609 metafile_record
->MetafileDataSize
= size
;
2610 if (GetEnhMetaFileBits(hemf
, size
, metafile_record
->MetafileData
) != size
)
2612 METAFILE_RemoveLastRecord(metafile
, &object_record
->Header
);
2613 return GenericError
;
2619 FIXME("not supported image type (%d)\n", image
->type
);
2620 return NotImplemented
;
2624 static GpStatus
METAFILE_AddImageAttributesObject(GpMetafile
*metafile
, const GpImageAttributes
*attrs
, DWORD
*id
)
2626 EmfPlusObject
*object_record
;
2627 EmfPlusImageAttributes
*attrs_record
;
2632 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
2638 stat
= METAFILE_AllocateRecord(metafile
,
2639 FIELD_OFFSET(EmfPlusObject
, ObjectData
.image_attributes
) + sizeof(EmfPlusImageAttributes
),
2640 (void**)&object_record
);
2641 if (stat
!= Ok
) return stat
;
2643 *id
= METAFILE_AddObjectId(metafile
);
2644 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
2645 object_record
->Header
.Flags
= *id
| (ObjectTypeImageAttributes
<< 8);
2646 attrs_record
= &object_record
->ObjectData
.image_attributes
;
2647 attrs_record
->Version
= VERSION_MAGIC2
;
2648 attrs_record
->Reserved1
= 0;
2649 attrs_record
->WrapMode
= attrs
->wrap
;
2650 attrs_record
->ClampColor
.Blue
= attrs
->outside_color
& 0xff;
2651 attrs_record
->ClampColor
.Green
= (attrs
->outside_color
>> 8) & 0xff;
2652 attrs_record
->ClampColor
.Red
= (attrs
->outside_color
>> 16) & 0xff;
2653 attrs_record
->ClampColor
.Alpha
= attrs
->outside_color
>> 24;
2654 attrs_record
->ObjectClamp
= attrs
->clamp
;
2655 attrs_record
->Reserved2
= 0;
2659 GpStatus
METAFILE_DrawImagePointsRect(GpMetafile
*metafile
, GpImage
*image
,
2660 GDIPCONST GpPointF
*points
, INT count
, REAL srcx
, REAL srcy
, REAL srcwidth
,
2661 REAL srcheight
, GpUnit srcUnit
, GDIPCONST GpImageAttributes
* imageAttributes
,
2662 DrawImageAbort callback
, VOID
*callbackData
)
2664 EmfPlusDrawImagePoints
*draw_image_record
;
2665 DWORD image_id
, attributes_id
;
2668 if (count
!= 3) return InvalidParameter
;
2670 if (metafile
->metafile_type
== MetafileTypeEmf
)
2672 FIXME("MetafileTypeEmf metafiles not supported\n");
2673 return NotImplemented
;
2676 FIXME("semi-stub\n");
2678 if (!imageAttributes
)
2680 stat
= METAFILE_AddImageObject(metafile
, image
, &image_id
);
2682 else if (image
->type
== ImageTypeBitmap
)
2684 INT width
= ((GpBitmap
*)image
)->width
;
2685 INT height
= ((GpBitmap
*)image
)->height
;
2686 GpGraphics
*graphics
;
2689 stat
= GdipCreateBitmapFromScan0(width
, height
,
2690 0, PixelFormat32bppARGB
, NULL
, &bitmap
);
2691 if (stat
!= Ok
) return stat
;
2693 stat
= GdipGetImageGraphicsContext((GpImage
*)bitmap
, &graphics
);
2696 GdipDisposeImage((GpImage
*)bitmap
);
2700 stat
= GdipDrawImageRectRectI(graphics
, image
, 0, 0, width
, height
,
2701 0, 0, width
, height
, UnitPixel
, imageAttributes
, NULL
, NULL
);
2702 GdipDeleteGraphics(graphics
);
2705 GdipDisposeImage((GpImage
*)bitmap
);
2709 stat
= METAFILE_AddImageObject(metafile
, (GpImage
*)bitmap
, &image_id
);
2710 GdipDisposeImage((GpImage
*)bitmap
);
2714 FIXME("imageAttributes not supported (image type %d)\n", image
->type
);
2715 return NotImplemented
;
2717 if (stat
!= Ok
) return stat
;
2719 stat
= METAFILE_AddImageAttributesObject(metafile
, imageAttributes
, &attributes_id
);
2720 if (stat
!= Ok
) return stat
;
2722 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusDrawImagePoints
), (void**)&draw_image_record
);
2723 if (stat
!= Ok
) return stat
;
2724 draw_image_record
->Header
.Type
= EmfPlusRecordTypeDrawImagePoints
;
2725 draw_image_record
->Header
.Flags
= image_id
;
2726 draw_image_record
->ImageAttributesID
= attributes_id
;
2727 draw_image_record
->SrcUnit
= UnitPixel
;
2728 draw_image_record
->SrcRect
.X
= units_to_pixels(srcx
, srcUnit
, metafile
->image
.xres
);
2729 draw_image_record
->SrcRect
.Y
= units_to_pixels(srcy
, srcUnit
, metafile
->image
.yres
);
2730 draw_image_record
->SrcRect
.Width
= units_to_pixels(srcwidth
, srcUnit
, metafile
->image
.xres
);
2731 draw_image_record
->SrcRect
.Height
= units_to_pixels(srcheight
, srcUnit
, metafile
->image
.yres
);
2732 draw_image_record
->count
= 3;
2733 draw_image_record
->PointData
[0].pointF
.X
= points
[0].X
;
2734 draw_image_record
->PointData
[0].pointF
.Y
= points
[0].Y
;
2735 draw_image_record
->PointData
[1].pointF
.X
= points
[1].X
;
2736 draw_image_record
->PointData
[1].pointF
.Y
= points
[1].Y
;
2737 draw_image_record
->PointData
[2].pointF
.X
= points
[2].X
;
2738 draw_image_record
->PointData
[2].pointF
.Y
= points
[2].Y
;
2739 METAFILE_WriteRecords(metafile
);
2743 GpStatus
METAFILE_AddSimpleProperty(GpMetafile
*metafile
, SHORT prop
, SHORT val
)
2745 EmfPlusRecordHeader
*record
;
2748 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
2751 stat
= METAFILE_AllocateRecord(metafile
, sizeof(*record
), (void**)&record
);
2752 if (stat
!= Ok
) return stat
;
2754 record
->Type
= prop
;
2755 record
->Flags
= val
;
2757 METAFILE_WriteRecords(metafile
);
2761 static GpStatus
METAFILE_AddPathObject(GpMetafile
*metafile
, GpPath
*path
, DWORD
*id
)
2763 EmfPlusObject
*object_record
;
2768 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
2771 size
= write_path_data(path
, NULL
);
2772 stat
= METAFILE_AllocateRecord(metafile
,
2773 FIELD_OFFSET(EmfPlusObject
, ObjectData
.path
) + size
,
2774 (void**)&object_record
);
2775 if (stat
!= Ok
) return stat
;
2777 *id
= METAFILE_AddObjectId(metafile
);
2778 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
2779 object_record
->Header
.Flags
= *id
| ObjectTypePath
<< 8;
2780 write_path_data(path
, &object_record
->ObjectData
.path
);
2784 static GpStatus
METAFILE_PrepareBrushData(GpBrush
*brush
, DWORD
*size
)
2786 if (brush
->bt
== BrushTypeSolidColor
)
2788 *size
= FIELD_OFFSET(EmfPlusBrush
, BrushData
.solid
) + sizeof(EmfPlusSolidBrushData
);
2792 FIXME("unsupported brush type: %d\n", brush
->bt
);
2793 return NotImplemented
;
2796 static void METAFILE_FillBrushData(GpBrush
*brush
, EmfPlusBrush
*data
)
2798 if (brush
->bt
== BrushTypeSolidColor
)
2800 GpSolidFill
*solid
= (GpSolidFill
*)brush
;
2802 data
->Version
= VERSION_MAGIC2
;
2803 data
->Type
= solid
->brush
.bt
;
2804 data
->BrushData
.solid
.SolidColor
.Blue
= solid
->color
& 0xff;
2805 data
->BrushData
.solid
.SolidColor
.Green
= (solid
->color
>> 8) & 0xff;
2806 data
->BrushData
.solid
.SolidColor
.Red
= (solid
->color
>> 16) & 0xff;
2807 data
->BrushData
.solid
.SolidColor
.Alpha
= solid
->color
>> 24;
2811 static GpStatus
METAFILE_AddPenObject(GpMetafile
*metafile
, GpPen
*pen
, DWORD
*id
)
2813 DWORD i
, data_flags
, pen_data_size
, brush_size
;
2814 EmfPlusObject
*object_record
;
2815 EmfPlusPenData
*pen_data
;
2820 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
2824 pen_data_size
= FIELD_OFFSET(EmfPlusPenData
, OptionalData
);
2826 GdipIsMatrixIdentity(&pen
->transform
, &result
);
2829 data_flags
|= PenDataTransform
;
2830 pen_data_size
+= sizeof(EmfPlusTransformMatrix
);
2832 if (pen
->startcap
!= LineCapFlat
)
2834 data_flags
|= PenDataStartCap
;
2835 pen_data_size
+= sizeof(DWORD
);
2837 if (pen
->endcap
!= LineCapFlat
)
2839 data_flags
|= PenDataEndCap
;
2840 pen_data_size
+= sizeof(DWORD
);
2842 if (pen
->join
!= LineJoinMiter
)
2844 data_flags
|= PenDataJoin
;
2845 pen_data_size
+= sizeof(DWORD
);
2847 if (pen
->miterlimit
!= 10.0)
2849 data_flags
|= PenDataMiterLimit
;
2850 pen_data_size
+= sizeof(REAL
);
2852 if (pen
->style
!= GP_DEFAULT_PENSTYLE
)
2854 data_flags
|= PenDataLineStyle
;
2855 pen_data_size
+= sizeof(DWORD
);
2857 if (pen
->dashcap
!= DashCapFlat
)
2859 data_flags
|= PenDataDashedLineCap
;
2860 pen_data_size
+= sizeof(DWORD
);
2862 data_flags
|= PenDataDashedLineOffset
;
2863 pen_data_size
+= sizeof(REAL
);
2866 data_flags
|= PenDataDashedLine
;
2867 pen_data_size
+= sizeof(DWORD
) + pen
->numdashes
*sizeof(REAL
);
2869 if (pen
->align
!= PenAlignmentCenter
)
2871 data_flags
|= PenDataNonCenter
;
2872 pen_data_size
+= sizeof(DWORD
);
2874 /* TODO: Add support for PenDataCompoundLine */
2875 if (pen
->customstart
)
2877 FIXME("ignoring custom start cup\n");
2881 FIXME("ignoring custom end cup\n");
2884 stat
= METAFILE_PrepareBrushData(pen
->brush
, &brush_size
);
2885 if (stat
!= Ok
) return stat
;
2887 stat
= METAFILE_AllocateRecord(metafile
,
2888 FIELD_OFFSET(EmfPlusObject
, ObjectData
.pen
.data
) + pen_data_size
+ brush_size
,
2889 (void**)&object_record
);
2890 if (stat
!= Ok
) return stat
;
2892 *id
= METAFILE_AddObjectId(metafile
);
2893 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
2894 object_record
->Header
.Flags
= *id
| ObjectTypePen
<< 8;
2895 object_record
->ObjectData
.pen
.Version
= VERSION_MAGIC2
;
2896 object_record
->ObjectData
.pen
.Type
= 0;
2898 pen_data
= (EmfPlusPenData
*)object_record
->ObjectData
.pen
.data
;
2899 pen_data
->PenDataFlags
= data_flags
;
2900 pen_data
->PenUnit
= pen
->unit
;
2901 pen_data
->PenWidth
= pen
->width
;
2904 if (data_flags
& PenDataTransform
)
2906 EmfPlusTransformMatrix
*m
= (EmfPlusTransformMatrix
*)(pen_data
->OptionalData
+ i
);
2907 memcpy(m
, &pen
->transform
, sizeof(*m
));
2908 i
+= sizeof(EmfPlusTransformMatrix
);
2910 if (data_flags
& PenDataStartCap
)
2912 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->startcap
;
2915 if (data_flags
& PenDataEndCap
)
2917 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->endcap
;
2920 if (data_flags
& PenDataJoin
)
2922 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->join
;
2925 if (data_flags
& PenDataMiterLimit
)
2927 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->miterlimit
;
2930 if (data_flags
& PenDataLineStyle
)
2932 switch (pen
->style
& PS_STYLE_MASK
)
2934 case PS_SOLID
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleSolid
; break;
2935 case PS_DASH
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDash
; break;
2936 case PS_DOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDot
; break;
2937 case PS_DASHDOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDashDot
; break;
2938 case PS_DASHDOTDOT
: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleDashDotDot
; break;
2939 default: *(DWORD
*)(pen_data
->OptionalData
+ i
) = LineStyleCustom
; break;
2943 if (data_flags
& PenDataDashedLineCap
)
2945 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->dashcap
;
2948 if (data_flags
& PenDataDashedLineOffset
)
2950 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->offset
;
2953 if (data_flags
& PenDataDashedLine
)
2957 *(DWORD
*)(pen_data
->OptionalData
+ i
) = pen
->numdashes
;
2960 for (j
=0; j
<pen
->numdashes
; j
++)
2962 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->dashes
[j
];
2966 if (data_flags
& PenDataNonCenter
)
2968 *(REAL
*)(pen_data
->OptionalData
+ i
) = pen
->align
;
2972 METAFILE_FillBrushData(pen
->brush
,
2973 (EmfPlusBrush
*)(object_record
->ObjectData
.pen
.data
+ pen_data_size
));
2977 GpStatus
METAFILE_DrawPath(GpMetafile
*metafile
, GpPen
*pen
, GpPath
*path
)
2979 EmfPlusDrawPath
*draw_path_record
;
2984 if (metafile
->metafile_type
== MetafileTypeEmf
)
2987 return NotImplemented
;
2990 stat
= METAFILE_AddPenObject(metafile
, pen
, &pen_id
);
2991 if (stat
!= Ok
) return stat
;
2993 stat
= METAFILE_AddPathObject(metafile
, path
, &path_id
);
2994 if (stat
!= Ok
) return stat
;
2996 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusDrawPath
), (void**)&draw_path_record
);
2997 if (stat
!= Ok
) return stat
;
2998 draw_path_record
->Header
.Type
= EmfPlusRecordTypeDrawPath
;
2999 draw_path_record
->Header
.Flags
= path_id
;
3000 draw_path_record
->PenId
= pen_id
;
3002 METAFILE_WriteRecords(metafile
);
3006 static GpStatus
METAFILE_AddBrushObject(GpMetafile
*metafile
, GpBrush
*brush
, DWORD
*id
)
3008 EmfPlusObject
*object_record
;
3013 if (metafile
->metafile_type
!= MetafileTypeEmfPlusOnly
&& metafile
->metafile_type
!= MetafileTypeEmfPlusDual
)
3016 stat
= METAFILE_PrepareBrushData(brush
, &size
);
3017 if (stat
!= Ok
) return stat
;
3019 stat
= METAFILE_AllocateRecord(metafile
,
3020 FIELD_OFFSET(EmfPlusObject
, ObjectData
) + size
, (void**)&object_record
);
3021 if (stat
!= Ok
) return stat
;
3023 *id
= METAFILE_AddObjectId(metafile
);
3024 object_record
->Header
.Type
= EmfPlusRecordTypeObject
;
3025 object_record
->Header
.Flags
= *id
| ObjectTypeBrush
<< 8;
3026 METAFILE_FillBrushData(brush
, &object_record
->ObjectData
.brush
);
3030 GpStatus
METAFILE_FillPath(GpMetafile
*metafile
, GpBrush
*brush
, GpPath
*path
)
3032 EmfPlusFillPath
*fill_path_record
;
3033 DWORD brush_id
= -1, path_id
;
3037 if (metafile
->metafile_type
== MetafileTypeEmf
)
3040 return NotImplemented
;
3043 inline_color
= brush
->bt
== BrushTypeSolidColor
;
3046 stat
= METAFILE_AddBrushObject(metafile
, brush
, &brush_id
);
3047 if (stat
!= Ok
) return stat
;
3050 stat
= METAFILE_AddPathObject(metafile
, path
, &path_id
);
3051 if (stat
!= Ok
) return stat
;
3053 stat
= METAFILE_AllocateRecord(metafile
,
3054 sizeof(EmfPlusFillPath
), (void**)&fill_path_record
);
3055 if (stat
!= Ok
) return stat
;
3056 fill_path_record
->Header
.Type
= EmfPlusRecordTypeFillPath
;
3059 fill_path_record
->Header
.Flags
= 0x8000 | path_id
;
3060 fill_path_record
->data
.Color
.Blue
= ((GpSolidFill
*)brush
)->color
& 0xff;
3061 fill_path_record
->data
.Color
.Green
= (((GpSolidFill
*)brush
)->color
>> 8) & 0xff;
3062 fill_path_record
->data
.Color
.Red
= (((GpSolidFill
*)brush
)->color
>> 16) & 0xff;
3063 fill_path_record
->data
.Color
.Alpha
= ((GpSolidFill
*)brush
)->color
>> 24;
3067 fill_path_record
->Header
.Flags
= path_id
;
3068 fill_path_record
->data
.BrushId
= brush_id
;
3071 METAFILE_WriteRecords(metafile
);