gdiplus: Mark the Graphics object as busy before freeing it.
[wine/multimedia.git] / dlls / gdiplus / metafile.c
bloba79bfc3007a2e8a5eeb8e8d72fcb67ef8834236f
1 /*
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
19 #include <stdarg.h>
20 #include <math.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wingdi.h"
25 #include "wine/unicode.h"
27 #define COBJMACROS
28 #include "objbase.h"
29 #include "ocidl.h"
30 #include "olectl.h"
31 #include "ole2.h"
33 #include "winreg.h"
34 #include "shlwapi.h"
36 #include "gdiplus.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
45 WORD Type;
46 WORD Flags;
47 DWORD Size;
48 DWORD DataSize;
49 } EmfPlusRecordHeader;
51 typedef struct EmfPlusHeader
53 EmfPlusRecordHeader Header;
54 DWORD Version;
55 DWORD EmfPlusFlags;
56 DWORD LogicalDpiX;
57 DWORD LogicalDpiY;
58 } EmfPlusHeader;
60 typedef struct EmfPlusFillRects
62 EmfPlusRecordHeader Header;
63 DWORD BrushID;
64 DWORD Count;
65 } EmfPlusFillRects;
67 typedef struct EmfPlusRect
69 SHORT X;
70 SHORT Y;
71 SHORT Width;
72 SHORT Height;
73 } EmfPlusRect;
75 static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result)
77 DWORD size_needed;
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)
86 return OutOfMemory;
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);
101 if (!new_data)
102 return OutOfMemory;
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;
115 record->Size = size;
116 record->DataSize = size - sizeof(EmfPlusRecordHeader);
118 return Ok;
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)
132 GpStatus stat;
134 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
136 EmfPlusHeader *header;
138 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusHeader), (void**)&header);
139 if (stat != Ok)
140 return stat;
142 header->Header.Type = EmfPlusRecordTypeHeader;
144 if (metafile->metafile_type == MetafileTypeEmfPlusDual)
145 header->Header.Flags = 1;
146 else
147 header->Header.Flags = 0;
149 header->Version = 0xDBC01002;
151 if (GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY)
152 header->EmfPlusFlags = 1;
153 else
154 header->EmfPlusFlags = 0;
156 header->LogicalDpiX = GetDeviceCaps(hdc, LOGPIXELSX);
157 header->LogicalDpiY = GetDeviceCaps(hdc, LOGPIXELSY);
159 METAFILE_WriteRecords(metafile);
162 return Ok;
165 static GpStatus METAFILE_WriteEndOfFile(GpMetafile *metafile)
167 GpStatus stat;
169 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
171 EmfPlusRecordHeader *record;
173 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusRecordHeader), (void**)&record);
174 if (stat != Ok)
175 return stat;
177 record->Type = EmfPlusRecordTypeEndOfFile;
178 record->Flags = 0;
180 METAFILE_WriteRecords(metafile);
183 return Ok;
186 GpStatus WINGDIPAPI GdipRecordMetafile(HDC hdc, EmfType type, GDIPCONST GpRectF *frameRect,
187 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
189 HDC record_dc;
190 REAL framerect_factor_x, framerect_factor_y;
191 RECT rc;
192 GpStatus stat;
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;
199 if (!frameRect)
201 FIXME("not implemented for NULL rect\n");
202 return NotImplemented;
205 switch (frameUnit)
207 case MetafileFrameUnitPixel:
208 framerect_factor_x = 2540.0 / GetDeviceCaps(hdc, LOGPIXELSX);
209 framerect_factor_y = 2540.0 / GetDeviceCaps(hdc, LOGPIXELSY);
210 break;
211 case MetafileFrameUnitPoint:
212 framerect_factor_x = framerect_factor_y = 2540.0 / 72.0;
213 break;
214 case MetafileFrameUnitInch:
215 framerect_factor_x = framerect_factor_y = 2540.0;
216 break;
217 case MetafileFrameUnitDocument:
218 framerect_factor_x = framerect_factor_y = 2540.0 / 300.0;
219 break;
220 case MetafileFrameUnitMillimeter:
221 framerect_factor_x = framerect_factor_y = 100.0;
222 break;
223 case MetafileFrameUnitGdi:
224 framerect_factor_x = framerect_factor_y = 1.0;
225 break;
226 default:
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);
237 if (!record_dc)
238 return GenericError;
240 *metafile = GdipAlloc(sizeof(GpMetafile));
241 if(!*metafile)
243 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc));
244 return OutOfMemory;
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);
262 if (stat != Ok)
264 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc));
265 GdipFree(*metafile);
266 *metafile = NULL;
267 return OutOfMemory;
270 return stat;
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);
283 if (frameRect)
285 frameRectF.X = frameRect->X;
286 frameRectF.Y = frameRect->Y;
287 frameRectF.Width = frameRect->Width;
288 frameRectF.Height = frameRect->Height;
289 pFrameRectF = &frameRectF;
291 else
292 pFrameRectF = NULL;
294 return GdipRecordMetafile(hdc, type, pFrameRectF, frameUnit, desc, metafile);
297 GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result)
299 GpStatus stat;
301 if (!metafile->record_dc || metafile->record_graphics)
302 return InvalidParameter;
304 stat = graphics_from_image((GpImage*)metafile, &metafile->record_graphics);
306 if (stat == Ok)
307 *result = metafile->record_graphics;
309 return stat;
312 GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc)
314 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
316 EmfPlusRecordHeader *record;
317 GpStatus stat;
319 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusRecordHeader), (void**)&record);
320 if (stat != Ok)
321 return stat;
323 record->Type = EmfPlusRecordTypeGetDC;
324 record->Flags = 0;
326 METAFILE_WriteRecords(metafile);
329 *hdc = metafile->record_dc;
331 return Ok;
334 static BOOL is_integer_rect(const GpRectF *rect)
336 SHORT x, y, width, height;
337 x = rect->X;
338 y = rect->Y;
339 width = rect->Width;
340 height = rect->Height;
341 if (rect->X != (REAL)x || rect->Y != (REAL)y ||
342 rect->Width != (REAL)width || rect->Height != (REAL)height)
343 return FALSE;
344 return TRUE;
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;
353 GpStatus stat;
354 BOOL integer_rects=1;
355 int i;
356 DWORD brushid;
357 int flags = 0;
359 if (brush->bt == BrushTypeSolidColor)
361 flags |= 0x8000;
362 brushid = ((GpSolidFill*)brush)->color;
364 else
366 FIXME("brush serialization not implemented\n");
367 return NotImplemented;
370 for (i=0; i<count; i++)
372 if (!is_integer_rect(&rects[i]))
374 integer_rects = 0;
375 break;
379 if (integer_rects)
380 flags |= 0x4000;
382 stat = METAFILE_AllocateRecord(metafile,
383 sizeof(EmfPlusFillRects) + count * (integer_rects ? sizeof(EmfPlusRect) : sizeof(GpRectF)),
384 (void**)&record);
385 if (stat != Ok)
386 return stat;
388 record->Header.Type = EmfPlusRecordTypeFillRects;
389 record->Header.Flags = flags;
390 record->BrushID = brushid;
391 record->Count = count;
393 if (integer_rects)
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;
404 else
405 memcpy(record+1, rects, sizeof(GpRectF) * count);
407 METAFILE_WriteRecords(metafile);
410 return Ok;
413 GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc)
415 if (hdc != metafile->record_dc)
416 return InvalidParameter;
418 return Ok;
421 GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile)
423 GpStatus stat;
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;
435 return stat;
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;
448 return Ok;
451 static GpStatus METAFILE_PlaybackGetDC(GpMetafile *metafile)
453 GpStatus stat = Ok;
455 stat = GdipGetDC(metafile->playback_graphics, &metafile->playback_dc);
457 if (stat == Ok)
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);
475 return stat;
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;
490 GpStatus stat;
492 stat = GdipCreateMatrix3(&metafile->src_rect, metafile->playback_points, &real_transform);
494 if (stat == Ok)
496 /* FIXME: Prepend page transform. */
498 stat = GdipMultiplyMatrix(real_transform, metafile->world_transform, MatrixOrderPrepend);
500 if (stat == Ok)
501 stat = GdipSetWorldTransform(metafile->playback_graphics, real_transform);
503 GdipDeleteMatrix(real_transform);
506 return stat;
509 GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
510 EmfPlusRecordType recordType, UINT flags, UINT dataSize, GDIPCONST BYTE *data)
512 GpStatus stat;
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);
528 if (record)
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);
537 GdipFree(record);
539 else
540 return OutOfMemory;
543 else
545 EmfPlusRecordHeader *header = (EmfPlusRecordHeader*)(data)-1;
547 METAFILE_PlaybackReleaseDC((GpMetafile*)metafile);
549 switch(recordType)
551 case EmfPlusRecordTypeHeader:
552 case EmfPlusRecordTypeEndOfFile:
553 break;
554 case EmfPlusRecordTypeGetDC:
555 METAFILE_PlaybackGetDC((GpMetafile*)metafile);
556 break;
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;
566 if (flags & 0x4000)
568 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(EmfPlusRect) * record->Count)
569 return InvalidParameter;
571 else
573 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(GpRectF) * record->Count)
574 return InvalidParameter;
577 if (flags & 0x8000)
579 stat = GdipCreateSolidFill((ARGB)record->BrushID, (GpSolidFill**)&temp_brush);
580 brush = temp_brush;
582 else
584 FIXME("brush deserialization not implemented\n");
585 return NotImplemented;
588 if (stat == Ok)
590 if (flags & 0x4000)
592 EmfPlusRect *int_rects = (EmfPlusRect*)(record+1);
593 int i;
595 rects = temp_rects = GdipAlloc(sizeof(GpRectF) * record->Count);
596 if (rects)
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;
606 else
607 stat = OutOfMemory;
609 else
610 rects = (GpRectF*)(record+1);
613 if (stat == Ok)
615 stat = GdipFillRectangles(metafile->playback_graphics, brush, rects, record->Count);
618 GdipDeleteBrush(temp_brush);
619 GdipFree(temp_rects);
621 return stat;
623 default:
624 FIXME("Not implemented for record type %x\n", recordType);
625 return NotImplemented;
629 return Ok;
632 struct enum_metafile_data
634 EnumerateMetafileProc callback;
635 void *callback_data;
636 GpMetafile *metafile;
639 static int CALLBACK enum_metafile_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR,
640 int nObj, LPARAM lpData)
642 BOOL ret;
643 struct enum_metafile_data *data = (struct enum_metafile_data*)lpData;
644 const BYTE* pStr;
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)
656 int offset = 4;
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);
664 else
665 pStr = NULL;
667 ret = data->callback(record->Type, record->Flags, record->DataSize,
668 pStr, data->callback_data);
670 if (!ret)
671 return 0;
673 offset += record->Size;
676 return 1;
680 if (lpEMFR->nSize != 8)
681 pStr = (const BYTE*)lpEMFR->dParm;
682 else
683 pStr = NULL;
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;
695 GpStatus stat;
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,
701 imageAttributes);
703 if (!graphics || !metafile || !destPoints || count != 3 || !srcRect)
704 return InvalidParameter;
706 if (!metafile->hemf)
707 return InvalidParameter;
709 if (metafile->playback_graphics)
710 return ObjectBusy;
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);
727 if (stat == Ok)
728 stat = GdipBeginContainer2(graphics, &state);
730 if (stat == Ok)
732 stat = GdipSetPageScale(graphics, 1.0);
734 if (stat == Ok)
735 stat = GdipSetPageUnit(graphics, UnitPixel);
737 if (stat == Ok)
738 stat = GdipCreateMatrix(&real_metafile->world_transform);
740 if (stat == Ok)
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);
752 if (stat == Ok)
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;
765 return stat;
768 GpStatus WINGDIPAPI GdipEnumerateMetafileDestRect(GpGraphics *graphics,
769 GDIPCONST GpMetafile *metafile, GDIPCONST GpRectF *dest,
770 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
772 GpPointF points[3];
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)
789 GpRectF destf;
791 if (!graphics || !metafile || !dest) return InvalidParameter;
793 destf.X = dest->X;
794 destf.Y = dest->Y;
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)
805 GpRectF destf;
807 if (!graphics || !metafile || !dest) return InvalidParameter;
809 destf.X = dest->X;
810 destf.Y = dest->Y;
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)
821 GpPointF ptf;
823 if (!graphics || !metafile || !dest) return InvalidParameter;
825 ptf.X = dest->X;
826 ptf.Y = dest->Y;
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;
849 else
850 *result = MetafileTypeEmfPlusOnly;
853 else
854 *result = MetafileTypeEmf;
856 else
857 *result = MetafileTypeEmf;
859 return FALSE;
862 MetafileType METAFILE_GetEmfType(HENHMETAFILE hemf)
864 MetafileType result = MetafileTypeInvalid;
865 EnumEnhMetaFile(NULL, hemf, get_metafile_type_proc, &result, NULL);
866 return result;