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 EmfPlusSetPageTransform
69 EmfPlusRecordHeader Header
;
71 } EmfPlusSetPageTransform
;
73 typedef struct EmfPlusRect
81 static GpStatus
METAFILE_AllocateRecord(GpMetafile
*metafile
, DWORD size
, void **result
)
84 EmfPlusRecordHeader
*record
;
86 if (!metafile
->comment_data_size
)
88 DWORD data_size
= max(256, size
* 2 + 4);
89 metafile
->comment_data
= heap_alloc_zero(data_size
);
91 if (!metafile
->comment_data
)
94 memcpy(metafile
->comment_data
, "EMF+", 4);
96 metafile
->comment_data_size
= data_size
;
97 metafile
->comment_data_length
= 4;
100 size_needed
= size
+ metafile
->comment_data_length
;
102 if (size_needed
> metafile
->comment_data_size
)
104 DWORD data_size
= size_needed
* 2;
105 BYTE
*new_data
= heap_alloc_zero(data_size
);
110 memcpy(new_data
, metafile
->comment_data
, metafile
->comment_data_length
);
112 metafile
->comment_data_size
= data_size
;
113 heap_free(metafile
->comment_data
);
114 metafile
->comment_data
= new_data
;
117 *result
= metafile
->comment_data
+ metafile
->comment_data_length
;
118 metafile
->comment_data_length
+= size
;
120 record
= (EmfPlusRecordHeader
*)*result
;
122 record
->DataSize
= size
- sizeof(EmfPlusRecordHeader
);
127 static void METAFILE_WriteRecords(GpMetafile
*metafile
)
129 if (metafile
->comment_data_length
> 4)
131 GdiComment(metafile
->record_dc
, metafile
->comment_data_length
, metafile
->comment_data
);
132 metafile
->comment_data_length
= 4;
136 static GpStatus
METAFILE_WriteHeader(GpMetafile
*metafile
, HDC hdc
)
140 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
142 EmfPlusHeader
*header
;
144 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusHeader
), (void**)&header
);
148 header
->Header
.Type
= EmfPlusRecordTypeHeader
;
150 if (metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
151 header
->Header
.Flags
= 1;
153 header
->Header
.Flags
= 0;
155 header
->Version
= 0xDBC01002;
157 if (GetDeviceCaps(hdc
, TECHNOLOGY
) == DT_RASDISPLAY
)
158 header
->EmfPlusFlags
= 1;
160 header
->EmfPlusFlags
= 0;
162 header
->LogicalDpiX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
163 header
->LogicalDpiY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
165 METAFILE_WriteRecords(metafile
);
171 static GpStatus
METAFILE_WriteEndOfFile(GpMetafile
*metafile
)
175 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
177 EmfPlusRecordHeader
*record
;
179 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
183 record
->Type
= EmfPlusRecordTypeEndOfFile
;
186 METAFILE_WriteRecords(metafile
);
192 GpStatus WINGDIPAPI
GdipRecordMetafile(HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
193 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
197 REAL framerect_factor_x
, framerect_factor_y
;
201 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
203 if (!hdc
|| type
< EmfTypeEmfOnly
|| type
> EmfTypeEmfPlusDual
|| !metafile
)
204 return InvalidParameter
;
208 FIXME("not implemented for NULL rect\n");
209 return NotImplemented
;
212 dpix
= (REAL
)GetDeviceCaps(hdc
, HORZRES
) / GetDeviceCaps(hdc
, HORZSIZE
) * 25.4;
213 dpiy
= (REAL
)GetDeviceCaps(hdc
, VERTRES
) / GetDeviceCaps(hdc
, VERTSIZE
) * 25.4;
217 case MetafileFrameUnitPixel
:
218 framerect_factor_x
= 2540.0 / dpix
;
219 framerect_factor_y
= 2540.0 / dpiy
;
221 case MetafileFrameUnitPoint
:
222 framerect_factor_x
= framerect_factor_y
= 2540.0 / 72.0;
224 case MetafileFrameUnitInch
:
225 framerect_factor_x
= framerect_factor_y
= 2540.0;
227 case MetafileFrameUnitDocument
:
228 framerect_factor_x
= framerect_factor_y
= 2540.0 / 300.0;
230 case MetafileFrameUnitMillimeter
:
231 framerect_factor_x
= framerect_factor_y
= 100.0;
233 case MetafileFrameUnitGdi
:
234 framerect_factor_x
= framerect_factor_y
= 1.0;
237 return InvalidParameter
;
240 rc
.left
= framerect_factor_x
* frameRect
->X
;
241 rc
.top
= framerect_factor_y
* frameRect
->Y
;
242 rc
.right
= rc
.left
+ framerect_factor_x
* frameRect
->Width
;
243 rc
.bottom
= rc
.top
+ framerect_factor_y
* frameRect
->Height
;
245 record_dc
= CreateEnhMetaFileW(hdc
, NULL
, &rc
, desc
);
250 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
253 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
257 (*metafile
)->image
.type
= ImageTypeMetafile
;
258 (*metafile
)->image
.picture
= NULL
;
259 (*metafile
)->image
.flags
= ImageFlagsNone
;
260 (*metafile
)->image
.palette
= NULL
;
261 (*metafile
)->image
.xres
= dpix
;
262 (*metafile
)->image
.yres
= dpiy
;
263 (*metafile
)->bounds
= *frameRect
;
264 (*metafile
)->unit
= frameUnit
;
265 (*metafile
)->metafile_type
= type
;
266 (*metafile
)->record_dc
= record_dc
;
267 (*metafile
)->comment_data
= NULL
;
268 (*metafile
)->comment_data_size
= 0;
269 (*metafile
)->comment_data_length
= 0;
270 (*metafile
)->hemf
= NULL
;
272 stat
= METAFILE_WriteHeader(*metafile
, hdc
);
276 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
277 heap_free(*metafile
);
285 /*****************************************************************************
286 * GdipRecordMetafileI [GDIPLUS.@]
288 GpStatus WINGDIPAPI
GdipRecordMetafileI(HDC hdc
, EmfType type
, GDIPCONST GpRect
*frameRect
,
289 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
291 GpRectF frameRectF
, *pFrameRectF
;
293 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
297 frameRectF
.X
= frameRect
->X
;
298 frameRectF
.Y
= frameRect
->Y
;
299 frameRectF
.Width
= frameRect
->Width
;
300 frameRectF
.Height
= frameRect
->Height
;
301 pFrameRectF
= &frameRectF
;
306 return GdipRecordMetafile(hdc
, type
, pFrameRectF
, frameUnit
, desc
, metafile
);
309 GpStatus
METAFILE_GetGraphicsContext(GpMetafile
* metafile
, GpGraphics
**result
)
313 if (!metafile
->record_dc
|| metafile
->record_graphics
)
314 return InvalidParameter
;
316 stat
= graphics_from_image((GpImage
*)metafile
, &metafile
->record_graphics
);
320 *result
= metafile
->record_graphics
;
321 metafile
->record_graphics
->xres
= 96.0;
322 metafile
->record_graphics
->yres
= 96.0;
328 GpStatus
METAFILE_GetDC(GpMetafile
* metafile
, HDC
*hdc
)
330 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
332 EmfPlusRecordHeader
*record
;
335 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
339 record
->Type
= EmfPlusRecordTypeGetDC
;
342 METAFILE_WriteRecords(metafile
);
345 *hdc
= metafile
->record_dc
;
350 static BOOL
is_integer_rect(const GpRectF
*rect
)
352 SHORT x
, y
, width
, height
;
356 height
= rect
->Height
;
357 if (rect
->X
!= (REAL
)x
|| rect
->Y
!= (REAL
)y
||
358 rect
->Width
!= (REAL
)width
|| rect
->Height
!= (REAL
)height
)
363 GpStatus
METAFILE_FillRectangles(GpMetafile
* metafile
, GpBrush
* brush
,
364 GDIPCONST GpRectF
* rects
, INT count
)
366 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
368 EmfPlusFillRects
*record
;
370 BOOL integer_rects
= TRUE
;
375 if (brush
->bt
== BrushTypeSolidColor
)
378 brushid
= ((GpSolidFill
*)brush
)->color
;
382 FIXME("brush serialization not implemented\n");
383 return NotImplemented
;
386 for (i
=0; i
<count
; i
++)
388 if (!is_integer_rect(&rects
[i
]))
390 integer_rects
= FALSE
;
398 stat
= METAFILE_AllocateRecord(metafile
,
399 sizeof(EmfPlusFillRects
) + count
* (integer_rects
? sizeof(EmfPlusRect
) : sizeof(GpRectF
)),
404 record
->Header
.Type
= EmfPlusRecordTypeFillRects
;
405 record
->Header
.Flags
= flags
;
406 record
->BrushID
= brushid
;
407 record
->Count
= count
;
411 EmfPlusRect
*record_rects
= (EmfPlusRect
*)(record
+1);
412 for (i
=0; i
<count
; i
++)
414 record_rects
[i
].X
= (SHORT
)rects
[i
].X
;
415 record_rects
[i
].Y
= (SHORT
)rects
[i
].Y
;
416 record_rects
[i
].Width
= (SHORT
)rects
[i
].Width
;
417 record_rects
[i
].Height
= (SHORT
)rects
[i
].Height
;
421 memcpy(record
+1, rects
, sizeof(GpRectF
) * count
);
423 METAFILE_WriteRecords(metafile
);
429 GpStatus
METAFILE_SetPageTransform(GpMetafile
* metafile
, GpUnit unit
, REAL scale
)
431 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
433 EmfPlusSetPageTransform
*record
;
436 stat
= METAFILE_AllocateRecord(metafile
,
437 sizeof(EmfPlusSetPageTransform
),
442 record
->Header
.Type
= EmfPlusRecordTypeSetPageTransform
;
443 record
->Header
.Flags
= unit
;
444 record
->PageScale
= scale
;
446 METAFILE_WriteRecords(metafile
);
452 GpStatus
METAFILE_ReleaseDC(GpMetafile
* metafile
, HDC hdc
)
454 if (hdc
!= metafile
->record_dc
)
455 return InvalidParameter
;
460 GpStatus
METAFILE_GraphicsDeleted(GpMetafile
* metafile
)
464 stat
= METAFILE_WriteEndOfFile(metafile
);
465 metafile
->record_graphics
= NULL
;
467 metafile
->hemf
= CloseEnhMetaFile(metafile
->record_dc
);
468 metafile
->record_dc
= NULL
;
470 heap_free(metafile
->comment_data
);
471 metafile
->comment_data
= NULL
;
472 metafile
->comment_data_size
= 0;
477 GpStatus WINGDIPAPI
GdipGetHemfFromMetafile(GpMetafile
*metafile
, HENHMETAFILE
*hEmf
)
479 TRACE("(%p,%p)\n", metafile
, hEmf
);
481 if (!metafile
|| !hEmf
|| !metafile
->hemf
)
482 return InvalidParameter
;
484 *hEmf
= metafile
->hemf
;
485 metafile
->hemf
= NULL
;
490 static GpStatus
METAFILE_PlaybackGetDC(GpMetafile
*metafile
)
494 stat
= GdipGetDC(metafile
->playback_graphics
, &metafile
->playback_dc
);
498 /* The result of GdipGetDC always expects device co-ordinates, but the
499 * device co-ordinates of the source metafile do not correspond to
500 * device co-ordinates of the destination. Therefore, we set up the DC
501 * so that the metafile's bounds map to the destination points where we
502 * are drawing this metafile. */
503 SetMapMode(metafile
->playback_dc
, MM_ANISOTROPIC
);
505 SetWindowOrgEx(metafile
->playback_dc
, metafile
->bounds
.X
, metafile
->bounds
.Y
, NULL
);
506 SetWindowExtEx(metafile
->playback_dc
, metafile
->bounds
.Width
, metafile
->bounds
.Height
, NULL
);
508 SetViewportOrgEx(metafile
->playback_dc
, metafile
->playback_points
[0].X
, metafile
->playback_points
[0].Y
, NULL
);
509 SetViewportExtEx(metafile
->playback_dc
,
510 metafile
->playback_points
[1].X
- metafile
->playback_points
[0].X
,
511 metafile
->playback_points
[2].Y
- metafile
->playback_points
[0].Y
, NULL
);
517 static void METAFILE_PlaybackReleaseDC(GpMetafile
*metafile
)
519 if (metafile
->playback_dc
)
521 GdipReleaseDC(metafile
->playback_graphics
, metafile
->playback_dc
);
522 metafile
->playback_dc
= NULL
;
526 static GpStatus
METAFILE_PlaybackUpdateWorldTransform(GpMetafile
*metafile
)
528 GpMatrix
*real_transform
;
531 stat
= GdipCreateMatrix3(&metafile
->src_rect
, metafile
->playback_points
, &real_transform
);
535 REAL scale
= units_to_pixels(1.0, metafile
->page_unit
, 96.0);
537 if (metafile
->page_unit
!= UnitDisplay
)
538 scale
*= metafile
->page_scale
;
540 stat
= GdipScaleMatrix(real_transform
, scale
, scale
, MatrixOrderPrepend
);
543 stat
= GdipMultiplyMatrix(real_transform
, metafile
->world_transform
, MatrixOrderPrepend
);
546 stat
= GdipSetWorldTransform(metafile
->playback_graphics
, real_transform
);
548 GdipDeleteMatrix(real_transform
);
554 GpStatus WINGDIPAPI
GdipPlayMetafileRecord(GDIPCONST GpMetafile
*metafile
,
555 EmfPlusRecordType recordType
, UINT flags
, UINT dataSize
, GDIPCONST BYTE
*data
)
558 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
;
560 TRACE("(%p,%x,%x,%d,%p)\n", metafile
, recordType
, flags
, dataSize
, data
);
562 if (!metafile
|| (dataSize
&& !data
) || !metafile
->playback_graphics
)
563 return InvalidParameter
;
565 if (recordType
>= 1 && recordType
<= 0x7a)
567 /* regular EMF record */
568 if (metafile
->playback_dc
)
570 ENHMETARECORD
*record
;
572 record
= heap_alloc_zero(dataSize
+ 8);
576 record
->iType
= recordType
;
577 record
->nSize
= dataSize
+ 8;
578 memcpy(record
->dParm
, data
, dataSize
);
580 PlayEnhMetaFileRecord(metafile
->playback_dc
, metafile
->handle_table
,
581 record
, metafile
->handle_count
);
591 EmfPlusRecordHeader
*header
= (EmfPlusRecordHeader
*)(data
)-1;
593 METAFILE_PlaybackReleaseDC((GpMetafile
*)metafile
);
597 case EmfPlusRecordTypeHeader
:
598 case EmfPlusRecordTypeEndOfFile
:
600 case EmfPlusRecordTypeGetDC
:
601 METAFILE_PlaybackGetDC((GpMetafile
*)metafile
);
603 case EmfPlusRecordTypeFillRects
:
605 EmfPlusFillRects
*record
= (EmfPlusFillRects
*)header
;
606 GpBrush
*brush
, *temp_brush
=NULL
;
607 GpRectF
*rects
, *temp_rects
=NULL
;
609 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
))
610 return InvalidParameter
;
614 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(EmfPlusRect
) * record
->Count
)
615 return InvalidParameter
;
619 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(GpRectF
) * record
->Count
)
620 return InvalidParameter
;
625 stat
= GdipCreateSolidFill((ARGB
)record
->BrushID
, (GpSolidFill
**)&temp_brush
);
630 FIXME("brush deserialization not implemented\n");
631 return NotImplemented
;
638 EmfPlusRect
*int_rects
= (EmfPlusRect
*)(record
+1);
641 rects
= temp_rects
= heap_alloc_zero(sizeof(GpRectF
) * record
->Count
);
644 for (i
=0; i
<record
->Count
; i
++)
646 rects
[i
].X
= int_rects
[i
].X
;
647 rects
[i
].Y
= int_rects
[i
].Y
;
648 rects
[i
].Width
= int_rects
[i
].Width
;
649 rects
[i
].Height
= int_rects
[i
].Height
;
656 rects
= (GpRectF
*)(record
+1);
661 stat
= GdipFillRectangles(metafile
->playback_graphics
, brush
, rects
, record
->Count
);
664 GdipDeleteBrush(temp_brush
);
665 heap_free(temp_rects
);
669 case EmfPlusRecordTypeSetPageTransform
:
671 EmfPlusSetPageTransform
*record
= (EmfPlusSetPageTransform
*)header
;
672 GpUnit unit
= (GpUnit
)flags
;
674 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetPageTransform
))
675 return InvalidParameter
;
677 real_metafile
->page_unit
= unit
;
678 real_metafile
->page_scale
= record
->PageScale
;
680 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
683 FIXME("Not implemented for record type %x\n", recordType
);
684 return NotImplemented
;
691 struct enum_metafile_data
693 EnumerateMetafileProc callback
;
695 GpMetafile
*metafile
;
698 static int CALLBACK
enum_metafile_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
699 int nObj
, LPARAM lpData
)
702 struct enum_metafile_data
*data
= (struct enum_metafile_data
*)lpData
;
705 data
->metafile
->handle_table
= lpHTable
;
706 data
->metafile
->handle_count
= nObj
;
708 /* First check for an EMF+ record. */
709 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
711 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
713 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
717 while (offset
+ sizeof(EmfPlusRecordHeader
) <= comment
->cbData
)
719 const EmfPlusRecordHeader
*record
= (const EmfPlusRecordHeader
*)&comment
->Data
[offset
];
721 if (record
->DataSize
)
722 pStr
= (const BYTE
*)(record
+1);
726 ret
= data
->callback(record
->Type
, record
->Flags
, record
->DataSize
,
727 pStr
, data
->callback_data
);
732 offset
+= record
->Size
;
739 if (lpEMFR
->nSize
!= 8)
740 pStr
= (const BYTE
*)lpEMFR
->dParm
;
744 return data
->callback(lpEMFR
->iType
, 0, lpEMFR
->nSize
-8,
745 pStr
, data
->callback_data
);
748 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestPoints(GpGraphics
*graphics
,
749 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*destPoints
, INT count
,
750 GDIPCONST GpRectF
*srcRect
, Unit srcUnit
, EnumerateMetafileProc callback
,
751 VOID
*callbackData
, GDIPCONST GpImageAttributes
*imageAttributes
)
753 struct enum_metafile_data data
;
755 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
; /* whoever made this const was joking */
756 GraphicsContainer state
;
758 TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics
, metafile
,
759 destPoints
, count
, srcRect
, srcUnit
, callback
, callbackData
,
762 if (!graphics
|| !metafile
|| !destPoints
|| count
!= 3 || !srcRect
)
763 return InvalidParameter
;
766 return InvalidParameter
;
768 if (metafile
->playback_graphics
)
771 TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect
), srcUnit
,
772 debugstr_pointf(&destPoints
[0]), debugstr_pointf(&destPoints
[1]),
773 debugstr_pointf(&destPoints
[2]));
775 data
.callback
= callback
;
776 data
.callback_data
= callbackData
;
777 data
.metafile
= real_metafile
;
779 real_metafile
->playback_graphics
= graphics
;
780 real_metafile
->playback_dc
= NULL
;
781 real_metafile
->src_rect
= *srcRect
;
783 memcpy(real_metafile
->playback_points
, destPoints
, sizeof(PointF
) * 3);
784 stat
= GdipTransformPoints(graphics
, CoordinateSpaceDevice
, CoordinateSpaceWorld
, real_metafile
->playback_points
, 3);
787 stat
= GdipBeginContainer2(graphics
, &state
);
791 stat
= GdipSetPageScale(graphics
, 1.0);
794 stat
= GdipSetPageUnit(graphics
, UnitPixel
);
797 stat
= GdipCreateMatrix(&real_metafile
->world_transform
);
801 real_metafile
->page_unit
= UnitDisplay
;
802 real_metafile
->page_scale
= 1.0;
803 stat
= METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
806 if (stat
== Ok
&& (metafile
->metafile_type
== MetafileTypeEmf
||
807 metafile
->metafile_type
== MetafileTypeWmfPlaceable
||
808 metafile
->metafile_type
== MetafileTypeWmf
))
809 stat
= METAFILE_PlaybackGetDC(real_metafile
);
812 EnumEnhMetaFile(0, metafile
->hemf
, enum_metafile_proc
, &data
, NULL
);
814 METAFILE_PlaybackReleaseDC(real_metafile
);
816 GdipDeleteMatrix(real_metafile
->world_transform
);
817 real_metafile
->world_transform
= NULL
;
819 GdipEndContainer(graphics
, state
);
822 real_metafile
->playback_graphics
= NULL
;
827 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRect(GpGraphics
*graphics
,
828 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRectF
*dest
,
829 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
833 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
835 points
[0].X
= points
[2].X
= dest
->X
;
836 points
[0].Y
= points
[1].Y
= dest
->Y
;
837 points
[1].X
= dest
->X
+ dest
->Width
;
838 points
[2].Y
= dest
->Y
+ dest
->Height
;
840 return GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, points
, 3,
841 &metafile
->bounds
, metafile
->unit
, callback
, cb_data
, attrs
);
844 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRectI(GpGraphics
*graphics
,
845 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRect
*dest
,
846 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
850 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
854 destf
.Width
= dest
->Width
;
855 destf
.Height
= dest
->Height
;
857 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
860 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPoint(GpGraphics
*graphics
,
861 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*dest
,
862 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
866 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
870 destf
.Width
= units_to_pixels(metafile
->bounds
.Width
, metafile
->unit
, metafile
->image
.xres
);
871 destf
.Height
= units_to_pixels(metafile
->bounds
.Height
, metafile
->unit
, metafile
->image
.yres
);
873 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
876 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPointI(GpGraphics
*graphics
,
877 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPoint
*dest
,
878 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
882 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
887 return GdipEnumerateMetafileDestPoint(graphics
, metafile
, &ptf
, callback
, cb_data
, attrs
);
890 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromMetafile(GpMetafile
* metafile
,
891 MetafileHeader
* header
)
895 TRACE("(%p, %p)\n", metafile
, header
);
897 if(!metafile
|| !header
)
898 return InvalidParameter
;
901 FIXME("not implemented\n");
903 memset(header
, 0, sizeof(MetafileHeader
));
908 static int CALLBACK
get_emfplus_header_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
909 int nObj
, LPARAM lpData
)
911 EmfPlusHeader
*dst_header
= (EmfPlusHeader
*)lpData
;
913 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
915 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
917 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
919 const EmfPlusRecordHeader
*header
= (const EmfPlusRecordHeader
*)&comment
->Data
[4];
921 if (4 + sizeof(EmfPlusHeader
) <= comment
->cbData
&&
922 header
->Type
== EmfPlusRecordTypeHeader
)
924 memcpy(dst_header
, header
, sizeof(*dst_header
));
928 else if (lpEMFR
->iType
== EMR_HEADER
)
934 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromEmf(HENHMETAFILE hemf
,
935 MetafileHeader
*header
)
937 ENHMETAHEADER3 emfheader
;
938 EmfPlusHeader emfplusheader
;
939 MetafileType metafile_type
;
941 TRACE("(%p,%p)\n", hemf
, header
);
944 return InvalidParameter
;
946 if (GetEnhMetaFileHeader(hemf
, sizeof(emfheader
), (ENHMETAHEADER
*)&emfheader
) == 0)
949 emfplusheader
.Header
.Type
= 0;
951 EnumEnhMetaFile(NULL
, hemf
, get_emfplus_header_proc
, &emfplusheader
, NULL
);
953 if (emfplusheader
.Header
.Type
== EmfPlusRecordTypeHeader
)
955 if ((emfplusheader
.Header
.Flags
& 1) == 1)
956 metafile_type
= MetafileTypeEmfPlusDual
;
958 metafile_type
= MetafileTypeEmfPlusOnly
;
961 metafile_type
= MetafileTypeEmf
;
963 header
->Type
= metafile_type
;
964 header
->Size
= emfheader
.nBytes
;
965 header
->DpiX
= (REAL
)emfheader
.szlDevice
.cx
* 25.4 / emfheader
.szlMillimeters
.cx
;
966 header
->DpiY
= (REAL
)emfheader
.szlDevice
.cy
* 25.4 / emfheader
.szlMillimeters
.cy
;
967 header
->X
= gdip_round((REAL
)emfheader
.rclFrame
.left
/ 2540.0 * header
->DpiX
);
968 header
->Y
= gdip_round((REAL
)emfheader
.rclFrame
.top
/ 2540.0 * header
->DpiY
);
969 header
->Width
= gdip_round((REAL
)(emfheader
.rclFrame
.right
- emfheader
.rclFrame
.left
) / 2540.0 * header
->DpiX
);
970 header
->Height
= gdip_round((REAL
)(emfheader
.rclFrame
.bottom
- emfheader
.rclFrame
.top
) / 2540.0 * header
->DpiY
);
971 header
->EmfHeader
= emfheader
;
973 if (metafile_type
== MetafileTypeEmfPlusDual
|| metafile_type
== MetafileTypeEmfPlusOnly
)
975 header
->Version
= emfplusheader
.Version
;
976 header
->EmfPlusFlags
= emfplusheader
.EmfPlusFlags
;
977 header
->EmfPlusHeaderSize
= emfplusheader
.Header
.Size
;
978 header
->LogicalDpiX
= emfplusheader
.LogicalDpiX
;
979 header
->LogicalDpiY
= emfplusheader
.LogicalDpiY
;
983 header
->Version
= emfheader
.nVersion
;
984 header
->EmfPlusFlags
= 0;
985 header
->EmfPlusHeaderSize
= 0;
986 header
->LogicalDpiX
= 0;
987 header
->LogicalDpiY
= 0;
993 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR
*filename
,
994 MetafileHeader
*header
)
998 TRACE("(%s,%p)\n", debugstr_w(filename
), header
);
1000 if(!filename
|| !header
)
1001 return InvalidParameter
;
1004 FIXME("not implemented\n");
1006 memset(header
, 0, sizeof(MetafileHeader
));
1011 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromStream(IStream
*stream
,
1012 MetafileHeader
*header
)
1016 TRACE("(%p,%p)\n", stream
, header
);
1018 if(!stream
|| !header
)
1019 return InvalidParameter
;
1022 FIXME("not implemented\n");
1024 memset(header
, 0, sizeof(MetafileHeader
));
1029 GpStatus WINGDIPAPI
GdipCreateMetafileFromEmf(HENHMETAFILE hemf
, BOOL
delete,
1030 GpMetafile
**metafile
)
1033 MetafileHeader header
;
1035 TRACE("(%p,%i,%p)\n", hemf
, delete, metafile
);
1037 if(!hemf
|| !metafile
)
1038 return InvalidParameter
;
1040 stat
= GdipGetMetafileHeaderFromEmf(hemf
, &header
);
1044 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
1048 (*metafile
)->image
.type
= ImageTypeMetafile
;
1049 (*metafile
)->image
.format
= ImageFormatEMF
;
1050 (*metafile
)->image
.frame_count
= 1;
1051 (*metafile
)->image
.xres
= header
.DpiX
;
1052 (*metafile
)->image
.yres
= header
.DpiY
;
1053 (*metafile
)->bounds
.X
= (REAL
)header
.EmfHeader
.rclFrame
.left
/ 2540.0 * header
.DpiX
;
1054 (*metafile
)->bounds
.Y
= (REAL
)header
.EmfHeader
.rclFrame
.top
/ 2540.0 * header
.DpiY
;
1055 (*metafile
)->bounds
.Width
= (REAL
)(header
.EmfHeader
.rclFrame
.right
- header
.EmfHeader
.rclFrame
.left
)
1056 / 2540.0 * header
.DpiX
;
1057 (*metafile
)->bounds
.Height
= (REAL
)(header
.EmfHeader
.rclFrame
.bottom
- header
.EmfHeader
.rclFrame
.top
)
1058 / 2540.0 * header
.DpiY
;
1059 (*metafile
)->unit
= UnitPixel
;
1060 (*metafile
)->metafile_type
= header
.Type
;
1061 (*metafile
)->hemf
= hemf
;
1062 (*metafile
)->preserve_hemf
= !delete;
1064 TRACE("<-- %p\n", *metafile
);
1069 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmf(HMETAFILE hwmf
, BOOL
delete,
1070 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
1075 GpStatus retval
= Ok
;
1077 TRACE("(%p, %d, %p, %p)\n", hwmf
, delete, placeable
, metafile
);
1079 if(!hwmf
|| !metafile
)
1080 return InvalidParameter
;
1083 read
= GetMetaFileBitsEx(hwmf
, 0, NULL
);
1085 return GenericError
;
1086 copy
= heap_alloc_zero(read
);
1087 GetMetaFileBitsEx(hwmf
, read
, copy
);
1089 hemf
= SetWinMetaFileBits(read
, copy
, NULL
, NULL
);
1092 /* FIXME: We should store and use hwmf instead of converting to hemf */
1093 retval
= GdipCreateMetafileFromEmf(hemf
, TRUE
, metafile
);
1099 (*metafile
)->image
.xres
= (REAL
)placeable
->Inch
;
1100 (*metafile
)->image
.yres
= (REAL
)placeable
->Inch
;
1101 (*metafile
)->bounds
.X
= ((REAL
)placeable
->BoundingBox
.Left
) / ((REAL
)placeable
->Inch
);
1102 (*metafile
)->bounds
.Y
= ((REAL
)placeable
->BoundingBox
.Top
) / ((REAL
)placeable
->Inch
);
1103 (*metafile
)->bounds
.Width
= (REAL
)(placeable
->BoundingBox
.Right
-
1104 placeable
->BoundingBox
.Left
);
1105 (*metafile
)->bounds
.Height
= (REAL
)(placeable
->BoundingBox
.Bottom
-
1106 placeable
->BoundingBox
.Top
);
1107 (*metafile
)->metafile_type
= MetafileTypeWmfPlaceable
;
1110 (*metafile
)->metafile_type
= MetafileTypeWmf
;
1111 (*metafile
)->image
.format
= ImageFormatWMF
;
1113 if (delete) DeleteMetaFile(hwmf
);
1116 DeleteEnhMetaFile(hemf
);
1120 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR
*file
,
1121 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
1123 HMETAFILE hmf
= GetMetaFileW(file
);
1125 TRACE("(%s, %p, %p)\n", debugstr_w(file
), placeable
, metafile
);
1127 if(!hmf
) return InvalidParameter
;
1129 return GdipCreateMetafileFromWmf(hmf
, TRUE
, placeable
, metafile
);
1132 GpStatus WINGDIPAPI
GdipCreateMetafileFromFile(GDIPCONST WCHAR
*file
,
1133 GpMetafile
**metafile
)
1135 FIXME("(%p, %p): stub\n", file
, metafile
);
1136 return NotImplemented
;
1139 GpStatus WINGDIPAPI
GdipCreateMetafileFromStream(IStream
*stream
,
1140 GpMetafile
**metafile
)
1142 FIXME("(%p, %p): stub\n", stream
, metafile
);
1143 return NotImplemented
;
1146 GpStatus WINGDIPAPI
GdipSetMetafileDownLevelRasterizationLimit(GpMetafile
*metafile
,
1149 TRACE("(%p,%u)\n", metafile
, limitDpi
);
1154 GpStatus WINGDIPAPI
GdipConvertToEmfPlus(const GpGraphics
* ref
,
1155 GpMetafile
* metafile
, BOOL
* succ
, EmfType emfType
,
1156 const WCHAR
* description
, GpMetafile
** out_metafile
)
1160 TRACE("(%p,%p,%p,%u,%s,%p)\n", ref
, metafile
, succ
, emfType
,
1161 debugstr_w(description
), out_metafile
);
1163 if(!ref
|| !metafile
|| !out_metafile
|| emfType
< EmfTypeEmfOnly
|| emfType
> EmfTypeEmfPlusDual
)
1164 return InvalidParameter
;
1168 *out_metafile
= NULL
;
1171 FIXME("not implemented\n");
1173 return NotImplemented
;
1176 GpStatus WINGDIPAPI
GdipEmfToWmfBits(HENHMETAFILE hemf
, UINT cbData16
,
1177 LPBYTE pData16
, INT iMapMode
, INT eFlags
)
1179 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf
, cbData16
, pData16
, iMapMode
, eFlags
);
1180 return NotImplemented
;
1183 GpStatus WINGDIPAPI
GdipRecordMetafileFileName(GDIPCONST WCHAR
* fileName
,
1184 HDC hdc
, EmfType type
, GDIPCONST GpRectF
*pFrameRect
,
1185 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
,
1186 GpMetafile
**metafile
)
1188 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
1189 frameUnit
, debugstr_w(desc
), metafile
);
1191 return NotImplemented
;
1194 GpStatus WINGDIPAPI
GdipRecordMetafileFileNameI(GDIPCONST WCHAR
* fileName
, HDC hdc
, EmfType type
,
1195 GDIPCONST GpRect
*pFrameRect
, MetafileFrameUnit frameUnit
,
1196 GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
1198 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
1199 frameUnit
, debugstr_w(desc
), metafile
);
1201 return NotImplemented
;
1204 /*****************************************************************************
1205 * GdipConvertToEmfPlusToFile [GDIPLUS.@]
1208 GpStatus WINGDIPAPI
GdipConvertToEmfPlusToFile(const GpGraphics
* refGraphics
,
1209 GpMetafile
* metafile
, BOOL
* conversionSuccess
,
1210 const WCHAR
* filename
, EmfType emfType
,
1211 const WCHAR
* description
, GpMetafile
** out_metafile
)
1213 FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics
, metafile
, conversionSuccess
, filename
, emfType
, description
, out_metafile
);
1214 return NotImplemented
;