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
25 #include "wine/unicode.h"
37 #include "gdiplus_private.h"
38 #include "wine/debug.h"
39 #include "wine/list.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus
);
43 typedef struct EmfPlusRecordHeader
49 } EmfPlusRecordHeader
;
51 typedef struct EmfPlusHeader
53 EmfPlusRecordHeader Header
;
60 typedef struct EmfPlusFillRects
62 EmfPlusRecordHeader Header
;
67 typedef struct EmfPlusRect
75 static GpStatus
METAFILE_AllocateRecord(GpMetafile
*metafile
, DWORD size
, void **result
)
78 EmfPlusRecordHeader
*record
;
80 if (!metafile
->comment_data_size
)
82 DWORD data_size
= max(256, size
* 2 + 4);
83 metafile
->comment_data
= GdipAlloc(data_size
);
85 if (!metafile
->comment_data
)
88 memcpy(metafile
->comment_data
, "EMF+", 4);
90 metafile
->comment_data_size
= data_size
;
91 metafile
->comment_data_length
= 4;
94 size_needed
= size
+ metafile
->comment_data_length
;
96 if (size_needed
> metafile
->comment_data_size
)
98 DWORD data_size
= size_needed
* 2;
99 BYTE
*new_data
= GdipAlloc(data_size
);
104 memcpy(new_data
, metafile
->comment_data
, metafile
->comment_data_length
);
106 metafile
->comment_data_size
= data_size
;
107 GdipFree(metafile
->comment_data
);
108 metafile
->comment_data
= new_data
;
111 *result
= metafile
->comment_data
+ metafile
->comment_data_length
;
112 metafile
->comment_data_length
+= size
;
114 record
= (EmfPlusRecordHeader
*)*result
;
116 record
->DataSize
= size
- sizeof(EmfPlusRecordHeader
);
121 static void METAFILE_WriteRecords(GpMetafile
*metafile
)
123 if (metafile
->comment_data_length
> 4)
125 GdiComment(metafile
->record_dc
, metafile
->comment_data_length
, metafile
->comment_data
);
126 metafile
->comment_data_length
= 4;
130 static GpStatus
METAFILE_WriteHeader(GpMetafile
*metafile
, HDC hdc
)
134 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
136 EmfPlusHeader
*header
;
138 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusHeader
), (void**)&header
);
142 header
->Header
.Type
= EmfPlusRecordTypeHeader
;
144 if (metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
145 header
->Header
.Flags
= 1;
147 header
->Header
.Flags
= 0;
149 header
->Version
= 0xDBC01002;
151 if (GetDeviceCaps(hdc
, TECHNOLOGY
) == DT_RASDISPLAY
)
152 header
->EmfPlusFlags
= 1;
154 header
->EmfPlusFlags
= 0;
156 header
->LogicalDpiX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
157 header
->LogicalDpiY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
159 METAFILE_WriteRecords(metafile
);
165 static GpStatus
METAFILE_WriteEndOfFile(GpMetafile
*metafile
)
169 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
171 EmfPlusRecordHeader
*record
;
173 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
177 record
->Type
= EmfPlusRecordTypeEndOfFile
;
180 METAFILE_WriteRecords(metafile
);
186 GpStatus WINGDIPAPI
GdipRecordMetafile(HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
187 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
190 REAL framerect_factor_x
, framerect_factor_y
;
194 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
196 if (!hdc
|| type
< EmfTypeEmfOnly
|| type
> EmfTypeEmfPlusDual
|| !metafile
)
197 return InvalidParameter
;
201 FIXME("not implemented for NULL rect\n");
202 return NotImplemented
;
207 case MetafileFrameUnitPixel
:
208 framerect_factor_x
= 2540.0 / GetDeviceCaps(hdc
, LOGPIXELSX
);
209 framerect_factor_y
= 2540.0 / GetDeviceCaps(hdc
, LOGPIXELSY
);
211 case MetafileFrameUnitPoint
:
212 framerect_factor_x
= framerect_factor_y
= 2540.0 / 72.0;
214 case MetafileFrameUnitInch
:
215 framerect_factor_x
= framerect_factor_y
= 2540.0;
217 case MetafileFrameUnitDocument
:
218 framerect_factor_x
= framerect_factor_y
= 2540.0 / 300.0;
220 case MetafileFrameUnitMillimeter
:
221 framerect_factor_x
= framerect_factor_y
= 100.0;
223 case MetafileFrameUnitGdi
:
224 framerect_factor_x
= framerect_factor_y
= 1.0;
227 return InvalidParameter
;
230 rc
.left
= framerect_factor_x
* frameRect
->X
;
231 rc
.top
= framerect_factor_y
* frameRect
->Y
;
232 rc
.right
= rc
.left
+ framerect_factor_x
* frameRect
->Width
;
233 rc
.bottom
= rc
.top
+ framerect_factor_y
* frameRect
->Height
;
235 record_dc
= CreateEnhMetaFileW(hdc
, NULL
, &rc
, desc
);
240 *metafile
= GdipAlloc(sizeof(GpMetafile
));
243 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
247 (*metafile
)->image
.type
= ImageTypeMetafile
;
248 (*metafile
)->image
.picture
= NULL
;
249 (*metafile
)->image
.flags
= ImageFlagsNone
;
250 (*metafile
)->image
.palette
= NULL
;
251 (*metafile
)->bounds
= *frameRect
;
252 (*metafile
)->unit
= frameUnit
;
253 (*metafile
)->metafile_type
= type
;
254 (*metafile
)->record_dc
= record_dc
;
255 (*metafile
)->comment_data
= NULL
;
256 (*metafile
)->comment_data_size
= 0;
257 (*metafile
)->comment_data_length
= 0;
258 (*metafile
)->hemf
= NULL
;
260 stat
= METAFILE_WriteHeader(*metafile
, hdc
);
264 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
273 /*****************************************************************************
274 * GdipRecordMetafileI [GDIPLUS.@]
276 GpStatus WINGDIPAPI
GdipRecordMetafileI(HDC hdc
, EmfType type
, GDIPCONST GpRect
*frameRect
,
277 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
279 GpRectF frameRectF
, *pFrameRectF
;
281 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
285 frameRectF
.X
= frameRect
->X
;
286 frameRectF
.Y
= frameRect
->Y
;
287 frameRectF
.Width
= frameRect
->Width
;
288 frameRectF
.Height
= frameRect
->Height
;
289 pFrameRectF
= &frameRectF
;
294 return GdipRecordMetafile(hdc
, type
, pFrameRectF
, frameUnit
, desc
, metafile
);
297 GpStatus
METAFILE_GetGraphicsContext(GpMetafile
* metafile
, GpGraphics
**result
)
301 if (!metafile
->record_dc
|| metafile
->record_graphics
)
302 return InvalidParameter
;
304 stat
= graphics_from_image((GpImage
*)metafile
, &metafile
->record_graphics
);
307 *result
= metafile
->record_graphics
;
312 GpStatus
METAFILE_GetDC(GpMetafile
* metafile
, HDC
*hdc
)
314 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
316 EmfPlusRecordHeader
*record
;
319 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
323 record
->Type
= EmfPlusRecordTypeGetDC
;
326 METAFILE_WriteRecords(metafile
);
329 *hdc
= metafile
->record_dc
;
334 static BOOL
is_integer_rect(const GpRectF
*rect
)
336 SHORT x
, y
, width
, height
;
340 height
= rect
->Height
;
341 if (rect
->X
!= (REAL
)x
|| rect
->Y
!= (REAL
)y
||
342 rect
->Width
!= (REAL
)width
|| rect
->Height
!= (REAL
)height
)
347 GpStatus
METAFILE_FillRectangles(GpMetafile
* metafile
, GpBrush
* brush
,
348 GDIPCONST GpRectF
* rects
, INT count
)
350 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
352 EmfPlusFillRects
*record
;
354 BOOL integer_rects
=1;
359 if (brush
->bt
== BrushTypeSolidColor
)
362 brushid
= ((GpSolidFill
*)brush
)->color
;
366 FIXME("brush serialization not implemented\n");
367 return NotImplemented
;
370 for (i
=0; i
<count
; i
++)
372 if (!is_integer_rect(&rects
[i
]))
382 stat
= METAFILE_AllocateRecord(metafile
,
383 sizeof(EmfPlusFillRects
) + count
* (integer_rects
? sizeof(EmfPlusRect
) : sizeof(GpRectF
)),
388 record
->Header
.Type
= EmfPlusRecordTypeFillRects
;
389 record
->Header
.Flags
= flags
;
390 record
->BrushID
= brushid
;
391 record
->Count
= count
;
395 EmfPlusRect
*record_rects
= (EmfPlusRect
*)(record
+1);
396 for (i
=0; i
<count
; i
++)
398 record_rects
[i
].X
= (SHORT
)rects
[i
].X
;
399 record_rects
[i
].Y
= (SHORT
)rects
[i
].Y
;
400 record_rects
[i
].Width
= (SHORT
)rects
[i
].Width
;
401 record_rects
[i
].Height
= (SHORT
)rects
[i
].Height
;
405 memcpy(record
+1, rects
, sizeof(GpRectF
) * count
);
407 METAFILE_WriteRecords(metafile
);
413 GpStatus
METAFILE_ReleaseDC(GpMetafile
* metafile
, HDC hdc
)
415 if (hdc
!= metafile
->record_dc
)
416 return InvalidParameter
;
421 GpStatus
METAFILE_GraphicsDeleted(GpMetafile
* metafile
)
425 stat
= METAFILE_WriteEndOfFile(metafile
);
426 metafile
->record_graphics
= NULL
;
428 metafile
->hemf
= CloseEnhMetaFile(metafile
->record_dc
);
429 metafile
->record_dc
= NULL
;
431 GdipFree(metafile
->comment_data
);
432 metafile
->comment_data
= NULL
;
433 metafile
->comment_data_size
= 0;
438 GpStatus WINGDIPAPI
GdipGetHemfFromMetafile(GpMetafile
*metafile
, HENHMETAFILE
*hEmf
)
440 TRACE("(%p,%p)\n", metafile
, hEmf
);
442 if (!metafile
|| !hEmf
|| !metafile
->hemf
)
443 return InvalidParameter
;
445 *hEmf
= metafile
->hemf
;
446 metafile
->hemf
= NULL
;
451 static GpStatus
METAFILE_PlaybackGetDC(GpMetafile
*metafile
)
455 stat
= GdipGetDC(metafile
->playback_graphics
, &metafile
->playback_dc
);
459 /* The result of GdipGetDC always expects device co-ordinates, but the
460 * device co-ordinates of the source metafile do not correspond to
461 * device co-ordinates of the destination. Therefore, we set up the DC
462 * so that the metafile's bounds map to the destination points where we
463 * are drawing this metafile. */
464 SetMapMode(metafile
->playback_dc
, MM_ANISOTROPIC
);
466 SetWindowOrgEx(metafile
->playback_dc
, metafile
->bounds
.X
, metafile
->bounds
.Y
, NULL
);
467 SetWindowExtEx(metafile
->playback_dc
, metafile
->bounds
.Width
, metafile
->bounds
.Height
, NULL
);
469 SetViewportOrgEx(metafile
->playback_dc
, metafile
->playback_points
[0].X
, metafile
->playback_points
[0].Y
, NULL
);
470 SetViewportExtEx(metafile
->playback_dc
,
471 metafile
->playback_points
[1].X
- metafile
->playback_points
[0].X
,
472 metafile
->playback_points
[2].Y
- metafile
->playback_points
[0].Y
, NULL
);
478 static void METAFILE_PlaybackReleaseDC(GpMetafile
*metafile
)
480 if (metafile
->playback_dc
)
482 GdipReleaseDC(metafile
->playback_graphics
, metafile
->playback_dc
);
483 metafile
->playback_dc
= NULL
;
487 static GpStatus
METAFILE_PlaybackUpdateWorldTransform(GpMetafile
*metafile
)
489 GpMatrix
*real_transform
;
492 stat
= GdipCreateMatrix3(&metafile
->src_rect
, metafile
->playback_points
, &real_transform
);
496 /* FIXME: Prepend page transform. */
498 stat
= GdipMultiplyMatrix(real_transform
, metafile
->world_transform
, MatrixOrderPrepend
);
501 stat
= GdipSetWorldTransform(metafile
->playback_graphics
, real_transform
);
503 GdipDeleteMatrix(real_transform
);
509 GpStatus WINGDIPAPI
GdipPlayMetafileRecord(GDIPCONST GpMetafile
*metafile
,
510 EmfPlusRecordType recordType
, UINT flags
, UINT dataSize
, GDIPCONST BYTE
*data
)
514 TRACE("(%p,%x,%x,%d,%p)\n", metafile
, recordType
, flags
, dataSize
, data
);
516 if (!metafile
|| (dataSize
&& !data
) || !metafile
->playback_graphics
)
517 return InvalidParameter
;
519 if (recordType
>= 1 && recordType
<= 0x7a)
521 /* regular EMF record */
522 if (metafile
->playback_dc
)
524 ENHMETARECORD
*record
;
526 record
= GdipAlloc(dataSize
+ 8);
530 record
->iType
= recordType
;
531 record
->nSize
= dataSize
+ 8;
532 memcpy(record
->dParm
, data
, dataSize
);
534 PlayEnhMetaFileRecord(metafile
->playback_dc
, metafile
->handle_table
,
535 record
, metafile
->handle_count
);
545 EmfPlusRecordHeader
*header
= (EmfPlusRecordHeader
*)(data
)-1;
547 METAFILE_PlaybackReleaseDC((GpMetafile
*)metafile
);
551 case EmfPlusRecordTypeHeader
:
552 case EmfPlusRecordTypeEndOfFile
:
554 case EmfPlusRecordTypeGetDC
:
555 METAFILE_PlaybackGetDC((GpMetafile
*)metafile
);
557 case EmfPlusRecordTypeFillRects
:
559 EmfPlusFillRects
*record
= (EmfPlusFillRects
*)header
;
560 GpBrush
*brush
, *temp_brush
=NULL
;
561 GpRectF
*rects
, *temp_rects
=NULL
;
563 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
))
564 return InvalidParameter
;
568 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(EmfPlusRect
) * record
->Count
)
569 return InvalidParameter
;
573 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(GpRectF
) * record
->Count
)
574 return InvalidParameter
;
579 stat
= GdipCreateSolidFill((ARGB
)record
->BrushID
, (GpSolidFill
**)&temp_brush
);
584 FIXME("brush deserialization not implemented\n");
585 return NotImplemented
;
592 EmfPlusRect
*int_rects
= (EmfPlusRect
*)(record
+1);
595 rects
= temp_rects
= GdipAlloc(sizeof(GpRectF
) * record
->Count
);
598 for (i
=0; i
<record
->Count
; i
++)
600 rects
[i
].X
= int_rects
[i
].X
;
601 rects
[i
].Y
= int_rects
[i
].Y
;
602 rects
[i
].Width
= int_rects
[i
].Width
;
603 rects
[i
].Height
= int_rects
[i
].Height
;
610 rects
= (GpRectF
*)(record
+1);
615 stat
= GdipFillRectangles(metafile
->playback_graphics
, brush
, rects
, record
->Count
);
618 GdipDeleteBrush(temp_brush
);
619 GdipFree(temp_rects
);
624 FIXME("Not implemented for record type %x\n", recordType
);
625 return NotImplemented
;
632 struct enum_metafile_data
634 EnumerateMetafileProc callback
;
636 GpMetafile
*metafile
;
639 static int CALLBACK
enum_metafile_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
640 int nObj
, LPARAM lpData
)
643 struct enum_metafile_data
*data
= (struct enum_metafile_data
*)lpData
;
646 data
->metafile
->handle_table
= lpHTable
;
647 data
->metafile
->handle_count
= nObj
;
649 /* First check for an EMF+ record. */
650 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
652 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
654 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
658 while (offset
+ sizeof(EmfPlusRecordHeader
) <= comment
->cbData
)
660 const EmfPlusRecordHeader
*record
= (const EmfPlusRecordHeader
*)&comment
->Data
[offset
];
662 if (record
->DataSize
)
663 pStr
= (const BYTE
*)(record
+1);
667 ret
= data
->callback(record
->Type
, record
->Flags
, record
->DataSize
,
668 pStr
, data
->callback_data
);
673 offset
+= record
->Size
;
680 if (lpEMFR
->nSize
!= 8)
681 pStr
= (const BYTE
*)lpEMFR
->dParm
;
685 return data
->callback(lpEMFR
->iType
, 0, lpEMFR
->nSize
-8,
686 pStr
, data
->callback_data
);
689 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestPoints(GpGraphics
*graphics
,
690 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*destPoints
, INT count
,
691 GDIPCONST GpRectF
*srcRect
, Unit srcUnit
, EnumerateMetafileProc callback
,
692 VOID
*callbackData
, GDIPCONST GpImageAttributes
*imageAttributes
)
694 struct enum_metafile_data data
;
696 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
; /* whoever made this const was joking */
697 GraphicsContainer state
;
699 TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics
, metafile
,
700 destPoints
, count
, srcRect
, srcUnit
, callback
, callbackData
,
703 if (!graphics
|| !metafile
|| !destPoints
|| count
!= 3 || !srcRect
)
704 return InvalidParameter
;
707 return InvalidParameter
;
709 if (metafile
->playback_graphics
)
712 TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect
), srcUnit
,
713 debugstr_pointf(&destPoints
[0]), debugstr_pointf(&destPoints
[1]),
714 debugstr_pointf(&destPoints
[2]));
716 data
.callback
= callback
;
717 data
.callback_data
= callbackData
;
718 data
.metafile
= real_metafile
;
720 real_metafile
->playback_graphics
= graphics
;
721 real_metafile
->playback_dc
= NULL
;
722 real_metafile
->src_rect
= *srcRect
;
724 memcpy(real_metafile
->playback_points
, destPoints
, sizeof(PointF
) * 3);
725 stat
= GdipTransformPoints(graphics
, CoordinateSpaceDevice
, CoordinateSpaceWorld
, real_metafile
->playback_points
, 3);
728 stat
= GdipBeginContainer2(graphics
, &state
);
732 stat
= GdipSetPageScale(graphics
, 1.0);
735 stat
= GdipSetPageUnit(graphics
, UnitPixel
);
738 stat
= GdipCreateMatrix(&real_metafile
->world_transform
);
742 real_metafile
->page_unit
= UnitPixel
; /* FIXME: Use frame unit here? */
743 real_metafile
->page_scale
= 1.0;
744 stat
= METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
747 if (stat
== Ok
&& (metafile
->metafile_type
== MetafileTypeEmf
||
748 metafile
->metafile_type
== MetafileTypeWmfPlaceable
||
749 metafile
->metafile_type
== MetafileTypeWmf
))
750 stat
= METAFILE_PlaybackGetDC(real_metafile
);
753 EnumEnhMetaFile(0, metafile
->hemf
, enum_metafile_proc
, &data
, NULL
);
755 METAFILE_PlaybackReleaseDC(real_metafile
);
757 GdipDeleteMatrix(real_metafile
->world_transform
);
758 real_metafile
->world_transform
= NULL
;
760 GdipEndContainer(graphics
, state
);
763 real_metafile
->playback_graphics
= NULL
;
768 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRect(GpGraphics
*graphics
,
769 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRectF
*dest
,
770 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
774 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
776 points
[0].X
= points
[2].X
= dest
->X
;
777 points
[0].Y
= points
[1].Y
= dest
->Y
;
778 points
[1].X
= dest
->X
+ dest
->Width
;
779 points
[2].Y
= dest
->Y
+ dest
->Height
;
781 return GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, points
, 3,
782 &metafile
->bounds
, metafile
->unit
, callback
, cb_data
, attrs
);
785 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRectI(GpGraphics
*graphics
,
786 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRect
*dest
,
787 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
791 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
795 destf
.Width
= dest
->Width
;
796 destf
.Height
= dest
->Height
;
798 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
801 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPoint(GpGraphics
*graphics
,
802 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*dest
,
803 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
807 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
811 destf
.Width
= units_to_pixels(metafile
->bounds
.Width
, metafile
->unit
, metafile
->image
.xres
);
812 destf
.Height
= units_to_pixels(metafile
->bounds
.Height
, metafile
->unit
, metafile
->image
.yres
);
814 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
817 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPointI(GpGraphics
*graphics
,
818 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPoint
*dest
,
819 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
823 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
828 return GdipEnumerateMetafileDestPoint(graphics
, metafile
, &ptf
, callback
, cb_data
, attrs
);
831 static int CALLBACK
get_metafile_type_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
832 int nObj
, LPARAM lpData
)
834 MetafileType
*result
= (MetafileType
*)lpData
;
836 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
838 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
840 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
842 const EmfPlusRecordHeader
*header
= (const EmfPlusRecordHeader
*)&comment
->Data
[4];
844 if (4 + sizeof(EmfPlusRecordHeader
) <= comment
->cbData
&&
845 header
->Type
== EmfPlusRecordTypeHeader
)
847 if ((header
->Flags
& 1) == 1)
848 *result
= MetafileTypeEmfPlusDual
;
850 *result
= MetafileTypeEmfPlusOnly
;
854 *result
= MetafileTypeEmf
;
857 *result
= MetafileTypeEmf
;
862 MetafileType
METAFILE_GetEmfType(HENHMETAFILE hemf
)
864 MetafileType result
= MetafileTypeInvalid
;
865 EnumEnhMetaFile(NULL
, hemf
, get_metafile_type_proc
, &result
, NULL
);