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 EmfPlusClear
62 EmfPlusRecordHeader Header
;
66 typedef struct EmfPlusFillRects
68 EmfPlusRecordHeader Header
;
73 typedef struct EmfPlusSetPageTransform
75 EmfPlusRecordHeader Header
;
77 } EmfPlusSetPageTransform
;
79 typedef struct EmfPlusRect
87 typedef struct EmfPlusScaleWorldTransform
89 EmfPlusRecordHeader Header
;
92 } EmfPlusScaleWorldTransform
;
94 typedef struct EmfPlusMultiplyWorldTransform
96 EmfPlusRecordHeader Header
;
98 } EmfPlusMultiplyWorldTransform
;
100 typedef struct EmfPlusRotateWorldTransform
102 EmfPlusRecordHeader Header
;
104 } EmfPlusRotateWorldTransform
;
106 static GpStatus
METAFILE_AllocateRecord(GpMetafile
*metafile
, DWORD size
, void **result
)
109 EmfPlusRecordHeader
*record
;
111 if (!metafile
->comment_data_size
)
113 DWORD data_size
= max(256, size
* 2 + 4);
114 metafile
->comment_data
= heap_alloc_zero(data_size
);
116 if (!metafile
->comment_data
)
119 memcpy(metafile
->comment_data
, "EMF+", 4);
121 metafile
->comment_data_size
= data_size
;
122 metafile
->comment_data_length
= 4;
125 size_needed
= size
+ metafile
->comment_data_length
;
127 if (size_needed
> metafile
->comment_data_size
)
129 DWORD data_size
= size_needed
* 2;
130 BYTE
*new_data
= heap_alloc_zero(data_size
);
135 memcpy(new_data
, metafile
->comment_data
, metafile
->comment_data_length
);
137 metafile
->comment_data_size
= data_size
;
138 heap_free(metafile
->comment_data
);
139 metafile
->comment_data
= new_data
;
142 *result
= metafile
->comment_data
+ metafile
->comment_data_length
;
143 metafile
->comment_data_length
+= size
;
145 record
= (EmfPlusRecordHeader
*)*result
;
147 record
->DataSize
= size
- sizeof(EmfPlusRecordHeader
);
152 static void METAFILE_WriteRecords(GpMetafile
*metafile
)
154 if (metafile
->comment_data_length
> 4)
156 GdiComment(metafile
->record_dc
, metafile
->comment_data_length
, metafile
->comment_data
);
157 metafile
->comment_data_length
= 4;
161 static GpStatus
METAFILE_WriteHeader(GpMetafile
*metafile
, HDC hdc
)
165 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
167 EmfPlusHeader
*header
;
169 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusHeader
), (void**)&header
);
173 header
->Header
.Type
= EmfPlusRecordTypeHeader
;
175 if (metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
176 header
->Header
.Flags
= 1;
178 header
->Header
.Flags
= 0;
180 header
->Version
= 0xDBC01002;
182 if (GetDeviceCaps(hdc
, TECHNOLOGY
) == DT_RASDISPLAY
)
183 header
->EmfPlusFlags
= 1;
185 header
->EmfPlusFlags
= 0;
187 header
->LogicalDpiX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
188 header
->LogicalDpiY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
190 METAFILE_WriteRecords(metafile
);
196 static GpStatus
METAFILE_WriteEndOfFile(GpMetafile
*metafile
)
200 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
202 EmfPlusRecordHeader
*record
;
204 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
208 record
->Type
= EmfPlusRecordTypeEndOfFile
;
211 METAFILE_WriteRecords(metafile
);
217 GpStatus WINGDIPAPI
GdipRecordMetafile(HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
218 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
222 REAL framerect_factor_x
, framerect_factor_y
;
226 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
228 if (!hdc
|| type
< EmfTypeEmfOnly
|| type
> EmfTypeEmfPlusDual
|| !metafile
)
229 return InvalidParameter
;
231 dpix
= (REAL
)GetDeviceCaps(hdc
, HORZRES
) / GetDeviceCaps(hdc
, HORZSIZE
) * 25.4;
232 dpiy
= (REAL
)GetDeviceCaps(hdc
, VERTRES
) / GetDeviceCaps(hdc
, VERTSIZE
) * 25.4;
238 case MetafileFrameUnitPixel
:
239 framerect_factor_x
= 2540.0 / dpix
;
240 framerect_factor_y
= 2540.0 / dpiy
;
242 case MetafileFrameUnitPoint
:
243 framerect_factor_x
= framerect_factor_y
= 2540.0 / 72.0;
245 case MetafileFrameUnitInch
:
246 framerect_factor_x
= framerect_factor_y
= 2540.0;
248 case MetafileFrameUnitDocument
:
249 framerect_factor_x
= framerect_factor_y
= 2540.0 / 300.0;
251 case MetafileFrameUnitMillimeter
:
252 framerect_factor_x
= framerect_factor_y
= 100.0;
254 case MetafileFrameUnitGdi
:
255 framerect_factor_x
= framerect_factor_y
= 1.0;
258 return InvalidParameter
;
261 rc
.left
= framerect_factor_x
* frameRect
->X
;
262 rc
.top
= framerect_factor_y
* frameRect
->Y
;
263 rc
.right
= rc
.left
+ framerect_factor_x
* frameRect
->Width
;
264 rc
.bottom
= rc
.top
+ framerect_factor_y
* frameRect
->Height
;
271 record_dc
= CreateEnhMetaFileW(hdc
, NULL
, lprc
, desc
);
276 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
279 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
283 (*metafile
)->image
.type
= ImageTypeMetafile
;
284 (*metafile
)->image
.picture
= NULL
;
285 (*metafile
)->image
.flags
= ImageFlagsNone
;
286 (*metafile
)->image
.palette
= NULL
;
287 (*metafile
)->image
.xres
= dpix
;
288 (*metafile
)->image
.yres
= dpiy
;
289 (*metafile
)->bounds
.X
= (*metafile
)->bounds
.Y
= 0.0;
290 (*metafile
)->bounds
.Width
= (*metafile
)->bounds
.Height
= 1.0;
291 (*metafile
)->unit
= UnitPixel
;
292 (*metafile
)->metafile_type
= type
;
293 (*metafile
)->record_dc
= record_dc
;
294 (*metafile
)->comment_data
= NULL
;
295 (*metafile
)->comment_data_size
= 0;
296 (*metafile
)->comment_data_length
= 0;
297 (*metafile
)->hemf
= NULL
;
301 (*metafile
)->auto_frame
= TRUE
;
302 (*metafile
)->auto_frame_min
.X
= 0;
303 (*metafile
)->auto_frame_min
.Y
= 0;
304 (*metafile
)->auto_frame_max
.X
= -1;
305 (*metafile
)->auto_frame_max
.Y
= -1;
308 stat
= METAFILE_WriteHeader(*metafile
, hdc
);
312 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
313 heap_free(*metafile
);
321 /*****************************************************************************
322 * GdipRecordMetafileI [GDIPLUS.@]
324 GpStatus WINGDIPAPI
GdipRecordMetafileI(HDC hdc
, EmfType type
, GDIPCONST GpRect
*frameRect
,
325 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
327 GpRectF frameRectF
, *pFrameRectF
;
329 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
333 frameRectF
.X
= frameRect
->X
;
334 frameRectF
.Y
= frameRect
->Y
;
335 frameRectF
.Width
= frameRect
->Width
;
336 frameRectF
.Height
= frameRect
->Height
;
337 pFrameRectF
= &frameRectF
;
342 return GdipRecordMetafile(hdc
, type
, pFrameRectF
, frameUnit
, desc
, metafile
);
345 GpStatus WINGDIPAPI
GdipRecordMetafileStream(IStream
*stream
, HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
346 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
350 TRACE("(%p %p %d %p %d %p %p)\n", stream
, hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
353 return InvalidParameter
;
355 stat
= GdipRecordMetafile(hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
359 (*metafile
)->record_stream
= stream
;
360 IStream_AddRef(stream
);
366 static void METAFILE_AdjustFrame(GpMetafile
* metafile
, const GpPointF
*points
,
371 if (!metafile
->auto_frame
|| !num_points
)
374 if (metafile
->auto_frame_max
.X
< metafile
->auto_frame_min
.X
)
375 metafile
->auto_frame_max
= metafile
->auto_frame_min
= points
[0];
377 for (i
=0; i
<num_points
; i
++)
379 if (points
[i
].X
< metafile
->auto_frame_min
.X
)
380 metafile
->auto_frame_min
.X
= points
[i
].X
;
381 if (points
[i
].X
> metafile
->auto_frame_max
.X
)
382 metafile
->auto_frame_max
.X
= points
[i
].X
;
383 if (points
[i
].Y
< metafile
->auto_frame_min
.Y
)
384 metafile
->auto_frame_min
.Y
= points
[i
].Y
;
385 if (points
[i
].Y
> metafile
->auto_frame_max
.Y
)
386 metafile
->auto_frame_max
.Y
= points
[i
].Y
;
390 GpStatus
METAFILE_GetGraphicsContext(GpMetafile
* metafile
, GpGraphics
**result
)
394 if (!metafile
->record_dc
|| metafile
->record_graphics
)
395 return InvalidParameter
;
397 stat
= graphics_from_image((GpImage
*)metafile
, &metafile
->record_graphics
);
401 *result
= metafile
->record_graphics
;
402 metafile
->record_graphics
->xres
= 96.0;
403 metafile
->record_graphics
->yres
= 96.0;
409 GpStatus
METAFILE_GetDC(GpMetafile
* metafile
, HDC
*hdc
)
411 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
413 EmfPlusRecordHeader
*record
;
416 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
420 record
->Type
= EmfPlusRecordTypeGetDC
;
423 METAFILE_WriteRecords(metafile
);
426 *hdc
= metafile
->record_dc
;
431 GpStatus
METAFILE_GraphicsClear(GpMetafile
* metafile
, ARGB color
)
433 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
435 EmfPlusClear
*record
;
438 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusClear
), (void**)&record
);
442 record
->Header
.Type
= EmfPlusRecordTypeClear
;
443 record
->Header
.Flags
= 0;
444 record
->Color
= color
;
446 METAFILE_WriteRecords(metafile
);
452 static BOOL
is_integer_rect(const GpRectF
*rect
)
454 SHORT x
, y
, width
, height
;
458 height
= rect
->Height
;
459 if (rect
->X
!= (REAL
)x
|| rect
->Y
!= (REAL
)y
||
460 rect
->Width
!= (REAL
)width
|| rect
->Height
!= (REAL
)height
)
465 GpStatus
METAFILE_FillRectangles(GpMetafile
* metafile
, GpBrush
* brush
,
466 GDIPCONST GpRectF
* rects
, INT count
)
468 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
470 EmfPlusFillRects
*record
;
472 BOOL integer_rects
= TRUE
;
477 if (brush
->bt
== BrushTypeSolidColor
)
480 brushid
= ((GpSolidFill
*)brush
)->color
;
484 FIXME("brush serialization not implemented\n");
485 return NotImplemented
;
488 for (i
=0; i
<count
; i
++)
490 if (!is_integer_rect(&rects
[i
]))
492 integer_rects
= FALSE
;
500 stat
= METAFILE_AllocateRecord(metafile
,
501 sizeof(EmfPlusFillRects
) + count
* (integer_rects
? sizeof(EmfPlusRect
) : sizeof(GpRectF
)),
506 record
->Header
.Type
= EmfPlusRecordTypeFillRects
;
507 record
->Header
.Flags
= flags
;
508 record
->BrushID
= brushid
;
509 record
->Count
= count
;
513 EmfPlusRect
*record_rects
= (EmfPlusRect
*)(record
+1);
514 for (i
=0; i
<count
; i
++)
516 record_rects
[i
].X
= (SHORT
)rects
[i
].X
;
517 record_rects
[i
].Y
= (SHORT
)rects
[i
].Y
;
518 record_rects
[i
].Width
= (SHORT
)rects
[i
].Width
;
519 record_rects
[i
].Height
= (SHORT
)rects
[i
].Height
;
523 memcpy(record
+1, rects
, sizeof(GpRectF
) * count
);
525 METAFILE_WriteRecords(metafile
);
528 if (metafile
->auto_frame
)
533 for (i
=0; i
<count
; i
++)
535 corners
[0].X
= rects
[i
].X
;
536 corners
[0].Y
= rects
[i
].Y
;
537 corners
[1].X
= rects
[i
].X
+ rects
[i
].Width
;
538 corners
[1].Y
= rects
[i
].Y
;
539 corners
[2].X
= rects
[i
].X
;
540 corners
[2].Y
= rects
[i
].Y
+ rects
[i
].Height
;
541 corners
[3].X
= rects
[i
].X
+ rects
[i
].Width
;
542 corners
[3].Y
= rects
[i
].Y
+ rects
[i
].Height
;
544 GdipTransformPoints(metafile
->record_graphics
, CoordinateSpaceDevice
,
545 CoordinateSpaceWorld
, corners
, 4);
547 METAFILE_AdjustFrame(metafile
, corners
, 4);
554 GpStatus
METAFILE_SetPageTransform(GpMetafile
* metafile
, GpUnit unit
, REAL scale
)
556 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
558 EmfPlusSetPageTransform
*record
;
561 stat
= METAFILE_AllocateRecord(metafile
,
562 sizeof(EmfPlusSetPageTransform
),
567 record
->Header
.Type
= EmfPlusRecordTypeSetPageTransform
;
568 record
->Header
.Flags
= unit
;
569 record
->PageScale
= scale
;
571 METAFILE_WriteRecords(metafile
);
577 GpStatus
METAFILE_ScaleWorldTransform(GpMetafile
* metafile
, REAL sx
, REAL sy
, MatrixOrder order
)
579 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
581 EmfPlusScaleWorldTransform
*record
;
584 stat
= METAFILE_AllocateRecord(metafile
,
585 sizeof(EmfPlusScaleWorldTransform
),
590 record
->Header
.Type
= EmfPlusRecordTypeScaleWorldTransform
;
591 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
595 METAFILE_WriteRecords(metafile
);
601 GpStatus
METAFILE_MultiplyWorldTransform(GpMetafile
* metafile
, GDIPCONST GpMatrix
* matrix
, MatrixOrder order
)
603 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
605 EmfPlusMultiplyWorldTransform
*record
;
608 stat
= METAFILE_AllocateRecord(metafile
,
609 sizeof(EmfPlusMultiplyWorldTransform
),
614 record
->Header
.Type
= EmfPlusRecordTypeMultiplyWorldTransform
;
615 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
616 memcpy(record
->MatrixData
, matrix
->matrix
, sizeof(record
->MatrixData
));
618 METAFILE_WriteRecords(metafile
);
624 GpStatus
METAFILE_RotateWorldTransform(GpMetafile
* metafile
, REAL angle
, MatrixOrder order
)
626 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
628 EmfPlusRotateWorldTransform
*record
;
631 stat
= METAFILE_AllocateRecord(metafile
,
632 sizeof(EmfPlusRotateWorldTransform
),
637 record
->Header
.Type
= EmfPlusRecordTypeRotateWorldTransform
;
638 record
->Header
.Flags
= (order
== MatrixOrderAppend
? 0x2000 : 0);
639 record
->Angle
= angle
;
641 METAFILE_WriteRecords(metafile
);
647 GpStatus
METAFILE_ResetWorldTransform(GpMetafile
* metafile
)
649 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
651 EmfPlusRecordHeader
*record
;
654 stat
= METAFILE_AllocateRecord(metafile
,
655 sizeof(EmfPlusRecordHeader
),
660 record
->Type
= EmfPlusRecordTypeResetWorldTransform
;
663 METAFILE_WriteRecords(metafile
);
669 GpStatus
METAFILE_ReleaseDC(GpMetafile
* metafile
, HDC hdc
)
671 if (hdc
!= metafile
->record_dc
)
672 return InvalidParameter
;
677 GpStatus
METAFILE_GraphicsDeleted(GpMetafile
* metafile
)
681 stat
= METAFILE_WriteEndOfFile(metafile
);
682 metafile
->record_graphics
= NULL
;
684 metafile
->hemf
= CloseEnhMetaFile(metafile
->record_dc
);
685 metafile
->record_dc
= NULL
;
687 heap_free(metafile
->comment_data
);
688 metafile
->comment_data
= NULL
;
689 metafile
->comment_data_size
= 0;
693 MetafileHeader header
;
695 stat
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, &header
);
696 if (stat
== Ok
&& metafile
->auto_frame
&&
697 metafile
->auto_frame_max
.X
>= metafile
->auto_frame_min
.X
)
699 RECTL bounds_rc
, gdi_bounds_rc
;
700 REAL x_scale
= 2540.0 / header
.DpiX
;
701 REAL y_scale
= 2540.0 / header
.DpiY
;
705 bounds_rc
.left
= floorf(metafile
->auto_frame_min
.X
* x_scale
);
706 bounds_rc
.top
= floorf(metafile
->auto_frame_min
.Y
* y_scale
);
707 bounds_rc
.right
= ceilf(metafile
->auto_frame_max
.X
* x_scale
);
708 bounds_rc
.bottom
= ceilf(metafile
->auto_frame_max
.Y
* y_scale
);
710 gdi_bounds_rc
= header
.EmfHeader
.rclBounds
;
711 if (gdi_bounds_rc
.right
> gdi_bounds_rc
.left
&& gdi_bounds_rc
.bottom
> gdi_bounds_rc
.top
)
713 bounds_rc
.left
= min(bounds_rc
.left
, gdi_bounds_rc
.left
);
714 bounds_rc
.top
= min(bounds_rc
.top
, gdi_bounds_rc
.top
);
715 bounds_rc
.right
= max(bounds_rc
.right
, gdi_bounds_rc
.right
);
716 bounds_rc
.bottom
= max(bounds_rc
.bottom
, gdi_bounds_rc
.bottom
);
719 buffer_size
= GetEnhMetaFileBits(metafile
->hemf
, 0, NULL
);
720 buffer
= heap_alloc(buffer_size
);
723 HENHMETAFILE new_hemf
;
725 GetEnhMetaFileBits(metafile
->hemf
, buffer_size
, buffer
);
727 ((ENHMETAHEADER
*)buffer
)->rclFrame
= bounds_rc
;
729 new_hemf
= SetEnhMetaFileBits(buffer_size
, buffer
);
733 DeleteEnhMetaFile(metafile
->hemf
);
734 metafile
->hemf
= new_hemf
;
745 stat
= GdipGetMetafileHeaderFromEmf(metafile
->hemf
, &header
);
749 metafile
->bounds
.X
= header
.X
;
750 metafile
->bounds
.Y
= header
.Y
;
751 metafile
->bounds
.Width
= header
.Width
;
752 metafile
->bounds
.Height
= header
.Height
;
756 if (stat
== Ok
&& metafile
->record_stream
)
761 buffer_size
= GetEnhMetaFileBits(metafile
->hemf
, 0, NULL
);
763 buffer
= heap_alloc(buffer_size
);
768 GetEnhMetaFileBits(metafile
->hemf
, buffer_size
, buffer
);
770 hr
= IStream_Write(metafile
->record_stream
, buffer
, buffer_size
, NULL
);
773 stat
= hresult_to_status(hr
);
781 if (metafile
->record_stream
)
783 IStream_Release(metafile
->record_stream
);
784 metafile
->record_stream
= NULL
;
790 GpStatus WINGDIPAPI
GdipGetHemfFromMetafile(GpMetafile
*metafile
, HENHMETAFILE
*hEmf
)
792 TRACE("(%p,%p)\n", metafile
, hEmf
);
794 if (!metafile
|| !hEmf
|| !metafile
->hemf
)
795 return InvalidParameter
;
797 *hEmf
= metafile
->hemf
;
798 metafile
->hemf
= NULL
;
803 static GpStatus
METAFILE_PlaybackGetDC(GpMetafile
*metafile
)
807 stat
= GdipGetDC(metafile
->playback_graphics
, &metafile
->playback_dc
);
811 /* The result of GdipGetDC always expects device co-ordinates, but the
812 * device co-ordinates of the source metafile do not correspond to
813 * device co-ordinates of the destination. Therefore, we set up the DC
814 * so that the metafile's bounds map to the destination points where we
815 * are drawing this metafile. */
816 SetMapMode(metafile
->playback_dc
, MM_ANISOTROPIC
);
818 SetWindowOrgEx(metafile
->playback_dc
, metafile
->bounds
.X
, metafile
->bounds
.Y
, NULL
);
819 SetWindowExtEx(metafile
->playback_dc
, metafile
->bounds
.Width
, metafile
->bounds
.Height
, NULL
);
821 SetViewportOrgEx(metafile
->playback_dc
, metafile
->playback_points
[0].X
, metafile
->playback_points
[0].Y
, NULL
);
822 SetViewportExtEx(metafile
->playback_dc
,
823 metafile
->playback_points
[1].X
- metafile
->playback_points
[0].X
,
824 metafile
->playback_points
[2].Y
- metafile
->playback_points
[0].Y
, NULL
);
830 static void METAFILE_PlaybackReleaseDC(GpMetafile
*metafile
)
832 if (metafile
->playback_dc
)
834 GdipReleaseDC(metafile
->playback_graphics
, metafile
->playback_dc
);
835 metafile
->playback_dc
= NULL
;
839 static GpStatus
METAFILE_PlaybackUpdateClip(GpMetafile
*metafile
)
841 return GdipCombineRegionRegion(metafile
->playback_graphics
->clip
, metafile
->base_clip
, CombineModeReplace
);
844 static GpStatus
METAFILE_PlaybackUpdateWorldTransform(GpMetafile
*metafile
)
846 GpMatrix
*real_transform
;
849 stat
= GdipCreateMatrix3(&metafile
->src_rect
, metafile
->playback_points
, &real_transform
);
853 REAL scale
= units_to_pixels(1.0, metafile
->page_unit
, 96.0);
855 if (metafile
->page_unit
!= UnitDisplay
)
856 scale
*= metafile
->page_scale
;
858 stat
= GdipScaleMatrix(real_transform
, scale
, scale
, MatrixOrderPrepend
);
861 stat
= GdipMultiplyMatrix(real_transform
, metafile
->world_transform
, MatrixOrderPrepend
);
864 stat
= GdipSetWorldTransform(metafile
->playback_graphics
, real_transform
);
866 GdipDeleteMatrix(real_transform
);
872 GpStatus WINGDIPAPI
GdipPlayMetafileRecord(GDIPCONST GpMetafile
*metafile
,
873 EmfPlusRecordType recordType
, UINT flags
, UINT dataSize
, GDIPCONST BYTE
*data
)
876 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
;
878 TRACE("(%p,%x,%x,%d,%p)\n", metafile
, recordType
, flags
, dataSize
, data
);
880 if (!metafile
|| (dataSize
&& !data
) || !metafile
->playback_graphics
)
881 return InvalidParameter
;
883 if (recordType
>= 1 && recordType
<= 0x7a)
885 /* regular EMF record */
886 if (metafile
->playback_dc
)
888 ENHMETARECORD
*record
;
890 record
= heap_alloc_zero(dataSize
+ 8);
894 record
->iType
= recordType
;
895 record
->nSize
= dataSize
+ 8;
896 memcpy(record
->dParm
, data
, dataSize
);
898 PlayEnhMetaFileRecord(metafile
->playback_dc
, metafile
->handle_table
,
899 record
, metafile
->handle_count
);
909 EmfPlusRecordHeader
*header
= (EmfPlusRecordHeader
*)(data
)-1;
911 METAFILE_PlaybackReleaseDC((GpMetafile
*)metafile
);
915 case EmfPlusRecordTypeHeader
:
916 case EmfPlusRecordTypeEndOfFile
:
918 case EmfPlusRecordTypeGetDC
:
919 METAFILE_PlaybackGetDC((GpMetafile
*)metafile
);
921 case EmfPlusRecordTypeClear
:
923 EmfPlusClear
*record
= (EmfPlusClear
*)header
;
925 return GdipGraphicsClear(metafile
->playback_graphics
, record
->Color
);
927 case EmfPlusRecordTypeFillRects
:
929 EmfPlusFillRects
*record
= (EmfPlusFillRects
*)header
;
930 GpBrush
*brush
, *temp_brush
=NULL
;
931 GpRectF
*rects
, *temp_rects
=NULL
;
933 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
))
934 return InvalidParameter
;
938 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(EmfPlusRect
) * record
->Count
)
939 return InvalidParameter
;
943 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(GpRectF
) * record
->Count
)
944 return InvalidParameter
;
949 stat
= GdipCreateSolidFill((ARGB
)record
->BrushID
, (GpSolidFill
**)&temp_brush
);
954 FIXME("brush deserialization not implemented\n");
955 return NotImplemented
;
962 EmfPlusRect
*int_rects
= (EmfPlusRect
*)(record
+1);
965 rects
= temp_rects
= heap_alloc_zero(sizeof(GpRectF
) * record
->Count
);
968 for (i
=0; i
<record
->Count
; i
++)
970 rects
[i
].X
= int_rects
[i
].X
;
971 rects
[i
].Y
= int_rects
[i
].Y
;
972 rects
[i
].Width
= int_rects
[i
].Width
;
973 rects
[i
].Height
= int_rects
[i
].Height
;
980 rects
= (GpRectF
*)(record
+1);
985 stat
= GdipFillRectangles(metafile
->playback_graphics
, brush
, rects
, record
->Count
);
988 GdipDeleteBrush(temp_brush
);
989 heap_free(temp_rects
);
993 case EmfPlusRecordTypeSetPageTransform
:
995 EmfPlusSetPageTransform
*record
= (EmfPlusSetPageTransform
*)header
;
996 GpUnit unit
= (GpUnit
)flags
;
998 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetPageTransform
))
999 return InvalidParameter
;
1001 real_metafile
->page_unit
= unit
;
1002 real_metafile
->page_scale
= record
->PageScale
;
1004 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
1006 case EmfPlusRecordTypeScaleWorldTransform
:
1008 EmfPlusScaleWorldTransform
*record
= (EmfPlusScaleWorldTransform
*)header
;
1009 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
1011 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusScaleWorldTransform
))
1012 return InvalidParameter
;
1014 GdipScaleMatrix(real_metafile
->world_transform
, record
->Sx
, record
->Sy
, order
);
1016 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
1018 case EmfPlusRecordTypeMultiplyWorldTransform
:
1020 EmfPlusMultiplyWorldTransform
*record
= (EmfPlusMultiplyWorldTransform
*)header
;
1021 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
1024 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusMultiplyWorldTransform
))
1025 return InvalidParameter
;
1027 memcpy(matrix
.matrix
, record
->MatrixData
, sizeof(matrix
.matrix
));
1029 GdipMultiplyMatrix(real_metafile
->world_transform
, &matrix
, order
);
1031 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
1033 case EmfPlusRecordTypeRotateWorldTransform
:
1035 EmfPlusRotateWorldTransform
*record
= (EmfPlusRotateWorldTransform
*)header
;
1036 MatrixOrder order
= (flags
& 0x2000) ? MatrixOrderAppend
: MatrixOrderPrepend
;
1038 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusRotateWorldTransform
))
1039 return InvalidParameter
;
1041 GdipRotateMatrix(real_metafile
->world_transform
, record
->Angle
, order
);
1043 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
1045 case EmfPlusRecordTypeResetWorldTransform
:
1047 GdipSetMatrixElements(real_metafile
->world_transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1049 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
1052 FIXME("Not implemented for record type %x\n", recordType
);
1053 return NotImplemented
;
1060 struct enum_metafile_data
1062 EnumerateMetafileProc callback
;
1063 void *callback_data
;
1064 GpMetafile
*metafile
;
1067 static int CALLBACK
enum_metafile_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
1068 int nObj
, LPARAM lpData
)
1071 struct enum_metafile_data
*data
= (struct enum_metafile_data
*)lpData
;
1074 data
->metafile
->handle_table
= lpHTable
;
1075 data
->metafile
->handle_count
= nObj
;
1077 /* First check for an EMF+ record. */
1078 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
1080 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
1082 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
1086 while (offset
+ sizeof(EmfPlusRecordHeader
) <= comment
->cbData
)
1088 const EmfPlusRecordHeader
*record
= (const EmfPlusRecordHeader
*)&comment
->Data
[offset
];
1090 if (record
->DataSize
)
1091 pStr
= (const BYTE
*)(record
+1);
1095 ret
= data
->callback(record
->Type
, record
->Flags
, record
->DataSize
,
1096 pStr
, data
->callback_data
);
1101 offset
+= record
->Size
;
1108 if (lpEMFR
->nSize
!= 8)
1109 pStr
= (const BYTE
*)lpEMFR
->dParm
;
1113 return data
->callback(lpEMFR
->iType
, 0, lpEMFR
->nSize
-8,
1114 pStr
, data
->callback_data
);
1117 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestPoints(GpGraphics
*graphics
,
1118 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*destPoints
, INT count
,
1119 GDIPCONST GpRectF
*srcRect
, Unit srcUnit
, EnumerateMetafileProc callback
,
1120 VOID
*callbackData
, GDIPCONST GpImageAttributes
*imageAttributes
)
1122 struct enum_metafile_data data
;
1124 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
; /* whoever made this const was joking */
1125 GraphicsContainer state
;
1128 TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics
, metafile
,
1129 destPoints
, count
, srcRect
, srcUnit
, callback
, callbackData
,
1132 if (!graphics
|| !metafile
|| !destPoints
|| count
!= 3 || !srcRect
)
1133 return InvalidParameter
;
1135 if (!metafile
->hemf
)
1136 return InvalidParameter
;
1138 if (metafile
->playback_graphics
)
1141 TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect
), srcUnit
,
1142 debugstr_pointf(&destPoints
[0]), debugstr_pointf(&destPoints
[1]),
1143 debugstr_pointf(&destPoints
[2]));
1145 data
.callback
= callback
;
1146 data
.callback_data
= callbackData
;
1147 data
.metafile
= real_metafile
;
1149 real_metafile
->playback_graphics
= graphics
;
1150 real_metafile
->playback_dc
= NULL
;
1151 real_metafile
->src_rect
= *srcRect
;
1153 memcpy(real_metafile
->playback_points
, destPoints
, sizeof(PointF
) * 3);
1154 stat
= GdipTransformPoints(graphics
, CoordinateSpaceDevice
, CoordinateSpaceWorld
, real_metafile
->playback_points
, 3);
1157 stat
= GdipBeginContainer2(graphics
, &state
);
1161 stat
= GdipSetPageScale(graphics
, 1.0);
1164 stat
= GdipSetPageUnit(graphics
, UnitPixel
);
1167 stat
= GdipResetWorldTransform(graphics
);
1170 stat
= GdipCreateRegion(&real_metafile
->base_clip
);
1173 stat
= GdipGetClip(graphics
, real_metafile
->base_clip
);
1176 stat
= GdipCreatePath(FillModeAlternate
, &dst_path
);
1180 GpPointF clip_points
[4];
1182 clip_points
[0] = real_metafile
->playback_points
[0];
1183 clip_points
[1] = real_metafile
->playback_points
[1];
1184 clip_points
[2].X
= real_metafile
->playback_points
[1].X
+ real_metafile
->playback_points
[2].X
1185 - real_metafile
->playback_points
[0].X
;
1186 clip_points
[2].Y
= real_metafile
->playback_points
[1].Y
+ real_metafile
->playback_points
[2].Y
1187 - real_metafile
->playback_points
[0].Y
;
1188 clip_points
[3] = real_metafile
->playback_points
[2];
1190 stat
= GdipAddPathPolygon(dst_path
, clip_points
, 4);
1193 stat
= GdipCombineRegionPath(real_metafile
->base_clip
, dst_path
, CombineModeIntersect
);
1195 GdipDeletePath(dst_path
);
1199 stat
= GdipCreateMatrix(&real_metafile
->world_transform
);
1203 real_metafile
->page_unit
= UnitDisplay
;
1204 real_metafile
->page_scale
= 1.0;
1205 stat
= METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
1210 stat
= METAFILE_PlaybackUpdateClip(real_metafile
);
1213 if (stat
== Ok
&& (metafile
->metafile_type
== MetafileTypeEmf
||
1214 metafile
->metafile_type
== MetafileTypeWmfPlaceable
||
1215 metafile
->metafile_type
== MetafileTypeWmf
))
1216 stat
= METAFILE_PlaybackGetDC(real_metafile
);
1219 EnumEnhMetaFile(0, metafile
->hemf
, enum_metafile_proc
, &data
, NULL
);
1221 METAFILE_PlaybackReleaseDC(real_metafile
);
1223 GdipDeleteMatrix(real_metafile
->world_transform
);
1224 real_metafile
->world_transform
= NULL
;
1226 GdipDeleteRegion(real_metafile
->base_clip
);
1227 real_metafile
->base_clip
= NULL
;
1229 GdipEndContainer(graphics
, state
);
1232 real_metafile
->playback_graphics
= NULL
;
1237 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRect(GpGraphics
*graphics
,
1238 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRectF
*dest
,
1239 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
1243 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
1245 points
[0].X
= points
[2].X
= dest
->X
;
1246 points
[0].Y
= points
[1].Y
= dest
->Y
;
1247 points
[1].X
= dest
->X
+ dest
->Width
;
1248 points
[2].Y
= dest
->Y
+ dest
->Height
;
1250 return GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, points
, 3,
1251 &metafile
->bounds
, metafile
->unit
, callback
, cb_data
, attrs
);
1254 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRectI(GpGraphics
*graphics
,
1255 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRect
*dest
,
1256 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
1260 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
1264 destf
.Width
= dest
->Width
;
1265 destf
.Height
= dest
->Height
;
1267 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
1270 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPoint(GpGraphics
*graphics
,
1271 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*dest
,
1272 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
1276 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
1280 destf
.Width
= units_to_pixels(metafile
->bounds
.Width
, metafile
->unit
, metafile
->image
.xres
);
1281 destf
.Height
= units_to_pixels(metafile
->bounds
.Height
, metafile
->unit
, metafile
->image
.yres
);
1283 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
1286 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPointI(GpGraphics
*graphics
,
1287 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPoint
*dest
,
1288 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
1292 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
1297 return GdipEnumerateMetafileDestPoint(graphics
, metafile
, &ptf
, callback
, cb_data
, attrs
);
1300 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromMetafile(GpMetafile
* metafile
,
1301 MetafileHeader
* header
)
1305 TRACE("(%p, %p)\n", metafile
, header
);
1307 if(!metafile
|| !header
)
1308 return InvalidParameter
;
1311 FIXME("not implemented\n");
1313 memset(header
, 0, sizeof(MetafileHeader
));
1318 static int CALLBACK
get_emfplus_header_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
1319 int nObj
, LPARAM lpData
)
1321 EmfPlusHeader
*dst_header
= (EmfPlusHeader
*)lpData
;
1323 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
1325 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
1327 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
1329 const EmfPlusRecordHeader
*header
= (const EmfPlusRecordHeader
*)&comment
->Data
[4];
1331 if (4 + sizeof(EmfPlusHeader
) <= comment
->cbData
&&
1332 header
->Type
== EmfPlusRecordTypeHeader
)
1334 memcpy(dst_header
, header
, sizeof(*dst_header
));
1338 else if (lpEMFR
->iType
== EMR_HEADER
)
1344 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromEmf(HENHMETAFILE hemf
,
1345 MetafileHeader
*header
)
1347 ENHMETAHEADER3 emfheader
;
1348 EmfPlusHeader emfplusheader
;
1349 MetafileType metafile_type
;
1351 TRACE("(%p,%p)\n", hemf
, header
);
1353 if(!hemf
|| !header
)
1354 return InvalidParameter
;
1356 if (GetEnhMetaFileHeader(hemf
, sizeof(emfheader
), (ENHMETAHEADER
*)&emfheader
) == 0)
1357 return GenericError
;
1359 emfplusheader
.Header
.Type
= 0;
1361 EnumEnhMetaFile(NULL
, hemf
, get_emfplus_header_proc
, &emfplusheader
, NULL
);
1363 if (emfplusheader
.Header
.Type
== EmfPlusRecordTypeHeader
)
1365 if ((emfplusheader
.Header
.Flags
& 1) == 1)
1366 metafile_type
= MetafileTypeEmfPlusDual
;
1368 metafile_type
= MetafileTypeEmfPlusOnly
;
1371 metafile_type
= MetafileTypeEmf
;
1373 header
->Type
= metafile_type
;
1374 header
->Size
= emfheader
.nBytes
;
1375 header
->DpiX
= (REAL
)emfheader
.szlDevice
.cx
* 25.4 / emfheader
.szlMillimeters
.cx
;
1376 header
->DpiY
= (REAL
)emfheader
.szlDevice
.cy
* 25.4 / emfheader
.szlMillimeters
.cy
;
1377 header
->X
= gdip_round((REAL
)emfheader
.rclFrame
.left
/ 2540.0 * header
->DpiX
);
1378 header
->Y
= gdip_round((REAL
)emfheader
.rclFrame
.top
/ 2540.0 * header
->DpiY
);
1379 header
->Width
= gdip_round((REAL
)(emfheader
.rclFrame
.right
- emfheader
.rclFrame
.left
) / 2540.0 * header
->DpiX
);
1380 header
->Height
= gdip_round((REAL
)(emfheader
.rclFrame
.bottom
- emfheader
.rclFrame
.top
) / 2540.0 * header
->DpiY
);
1381 header
->EmfHeader
= emfheader
;
1383 if (metafile_type
== MetafileTypeEmfPlusDual
|| metafile_type
== MetafileTypeEmfPlusOnly
)
1385 header
->Version
= emfplusheader
.Version
;
1386 header
->EmfPlusFlags
= emfplusheader
.EmfPlusFlags
;
1387 header
->EmfPlusHeaderSize
= emfplusheader
.Header
.Size
;
1388 header
->LogicalDpiX
= emfplusheader
.LogicalDpiX
;
1389 header
->LogicalDpiY
= emfplusheader
.LogicalDpiY
;
1393 header
->Version
= emfheader
.nVersion
;
1394 header
->EmfPlusFlags
= 0;
1395 header
->EmfPlusHeaderSize
= 0;
1396 header
->LogicalDpiX
= 0;
1397 header
->LogicalDpiY
= 0;
1403 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR
*filename
,
1404 MetafileHeader
*header
)
1408 TRACE("(%s,%p)\n", debugstr_w(filename
), header
);
1410 if(!filename
|| !header
)
1411 return InvalidParameter
;
1414 FIXME("not implemented\n");
1416 memset(header
, 0, sizeof(MetafileHeader
));
1421 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromStream(IStream
*stream
,
1422 MetafileHeader
*header
)
1426 TRACE("(%p,%p)\n", stream
, header
);
1428 if(!stream
|| !header
)
1429 return InvalidParameter
;
1432 FIXME("not implemented\n");
1434 memset(header
, 0, sizeof(MetafileHeader
));
1439 GpStatus WINGDIPAPI
GdipCreateMetafileFromEmf(HENHMETAFILE hemf
, BOOL
delete,
1440 GpMetafile
**metafile
)
1443 MetafileHeader header
;
1445 TRACE("(%p,%i,%p)\n", hemf
, delete, metafile
);
1447 if(!hemf
|| !metafile
)
1448 return InvalidParameter
;
1450 stat
= GdipGetMetafileHeaderFromEmf(hemf
, &header
);
1454 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
1458 (*metafile
)->image
.type
= ImageTypeMetafile
;
1459 (*metafile
)->image
.format
= ImageFormatEMF
;
1460 (*metafile
)->image
.frame_count
= 1;
1461 (*metafile
)->image
.xres
= header
.DpiX
;
1462 (*metafile
)->image
.yres
= header
.DpiY
;
1463 (*metafile
)->bounds
.X
= (REAL
)header
.EmfHeader
.rclFrame
.left
/ 2540.0 * header
.DpiX
;
1464 (*metafile
)->bounds
.Y
= (REAL
)header
.EmfHeader
.rclFrame
.top
/ 2540.0 * header
.DpiY
;
1465 (*metafile
)->bounds
.Width
= (REAL
)(header
.EmfHeader
.rclFrame
.right
- header
.EmfHeader
.rclFrame
.left
)
1466 / 2540.0 * header
.DpiX
;
1467 (*metafile
)->bounds
.Height
= (REAL
)(header
.EmfHeader
.rclFrame
.bottom
- header
.EmfHeader
.rclFrame
.top
)
1468 / 2540.0 * header
.DpiY
;
1469 (*metafile
)->unit
= UnitPixel
;
1470 (*metafile
)->metafile_type
= header
.Type
;
1471 (*metafile
)->hemf
= hemf
;
1472 (*metafile
)->preserve_hemf
= !delete;
1474 TRACE("<-- %p\n", *metafile
);
1479 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmf(HMETAFILE hwmf
, BOOL
delete,
1480 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
1485 GpStatus retval
= Ok
;
1487 TRACE("(%p, %d, %p, %p)\n", hwmf
, delete, placeable
, metafile
);
1489 if(!hwmf
|| !metafile
)
1490 return InvalidParameter
;
1493 read
= GetMetaFileBitsEx(hwmf
, 0, NULL
);
1495 return GenericError
;
1496 copy
= heap_alloc_zero(read
);
1497 GetMetaFileBitsEx(hwmf
, read
, copy
);
1499 hemf
= SetWinMetaFileBits(read
, copy
, NULL
, NULL
);
1502 /* FIXME: We should store and use hwmf instead of converting to hemf */
1503 retval
= GdipCreateMetafileFromEmf(hemf
, TRUE
, metafile
);
1509 (*metafile
)->image
.xres
= (REAL
)placeable
->Inch
;
1510 (*metafile
)->image
.yres
= (REAL
)placeable
->Inch
;
1511 (*metafile
)->bounds
.X
= ((REAL
)placeable
->BoundingBox
.Left
) / ((REAL
)placeable
->Inch
);
1512 (*metafile
)->bounds
.Y
= ((REAL
)placeable
->BoundingBox
.Top
) / ((REAL
)placeable
->Inch
);
1513 (*metafile
)->bounds
.Width
= (REAL
)(placeable
->BoundingBox
.Right
-
1514 placeable
->BoundingBox
.Left
);
1515 (*metafile
)->bounds
.Height
= (REAL
)(placeable
->BoundingBox
.Bottom
-
1516 placeable
->BoundingBox
.Top
);
1517 (*metafile
)->metafile_type
= MetafileTypeWmfPlaceable
;
1520 (*metafile
)->metafile_type
= MetafileTypeWmf
;
1521 (*metafile
)->image
.format
= ImageFormatWMF
;
1523 if (delete) DeleteMetaFile(hwmf
);
1526 DeleteEnhMetaFile(hemf
);
1530 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR
*file
,
1531 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
1533 HMETAFILE hmf
= GetMetaFileW(file
);
1535 TRACE("(%s, %p, %p)\n", debugstr_w(file
), placeable
, metafile
);
1537 if(!hmf
) return InvalidParameter
;
1539 return GdipCreateMetafileFromWmf(hmf
, TRUE
, placeable
, metafile
);
1542 GpStatus WINGDIPAPI
GdipCreateMetafileFromFile(GDIPCONST WCHAR
*file
,
1543 GpMetafile
**metafile
)
1545 FIXME("(%p, %p): stub\n", file
, metafile
);
1546 return NotImplemented
;
1549 GpStatus WINGDIPAPI
GdipCreateMetafileFromStream(IStream
*stream
,
1550 GpMetafile
**metafile
)
1552 FIXME("(%p, %p): stub\n", stream
, metafile
);
1553 return NotImplemented
;
1556 GpStatus WINGDIPAPI
GdipSetMetafileDownLevelRasterizationLimit(GpMetafile
*metafile
,
1559 TRACE("(%p,%u)\n", metafile
, limitDpi
);
1564 GpStatus WINGDIPAPI
GdipConvertToEmfPlus(const GpGraphics
* ref
,
1565 GpMetafile
* metafile
, BOOL
* succ
, EmfType emfType
,
1566 const WCHAR
* description
, GpMetafile
** out_metafile
)
1570 TRACE("(%p,%p,%p,%u,%s,%p)\n", ref
, metafile
, succ
, emfType
,
1571 debugstr_w(description
), out_metafile
);
1573 if(!ref
|| !metafile
|| !out_metafile
|| emfType
< EmfTypeEmfOnly
|| emfType
> EmfTypeEmfPlusDual
)
1574 return InvalidParameter
;
1578 *out_metafile
= NULL
;
1581 FIXME("not implemented\n");
1583 return NotImplemented
;
1586 GpStatus WINGDIPAPI
GdipEmfToWmfBits(HENHMETAFILE hemf
, UINT cbData16
,
1587 LPBYTE pData16
, INT iMapMode
, INT eFlags
)
1589 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf
, cbData16
, pData16
, iMapMode
, eFlags
);
1590 return NotImplemented
;
1593 GpStatus WINGDIPAPI
GdipRecordMetafileFileName(GDIPCONST WCHAR
* fileName
,
1594 HDC hdc
, EmfType type
, GDIPCONST GpRectF
*pFrameRect
,
1595 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
,
1596 GpMetafile
**metafile
)
1598 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
1599 frameUnit
, debugstr_w(desc
), metafile
);
1601 return NotImplemented
;
1604 GpStatus WINGDIPAPI
GdipRecordMetafileFileNameI(GDIPCONST WCHAR
* fileName
, HDC hdc
, EmfType type
,
1605 GDIPCONST GpRect
*pFrameRect
, MetafileFrameUnit frameUnit
,
1606 GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
1608 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
1609 frameUnit
, debugstr_w(desc
), metafile
);
1611 return NotImplemented
;
1614 /*****************************************************************************
1615 * GdipConvertToEmfPlusToFile [GDIPLUS.@]
1618 GpStatus WINGDIPAPI
GdipConvertToEmfPlusToFile(const GpGraphics
* refGraphics
,
1619 GpMetafile
* metafile
, BOOL
* conversionSuccess
,
1620 const WCHAR
* filename
, EmfType emfType
,
1621 const WCHAR
* description
, GpMetafile
** out_metafile
)
1623 FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics
, metafile
, conversionSuccess
, filename
, emfType
, description
, out_metafile
);
1624 return NotImplemented
;