ntoskrnl.exe: Implement ObReferenceObjectByName but only for loaded drivers.
[wine.git] / dlls / gdiplus / metafile.c
blobf0c0bd1d9b05628be176b8652d24e962d49e4558
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 EmfPlusClear
62 EmfPlusRecordHeader Header;
63 DWORD Color;
64 } EmfPlusClear;
66 typedef struct EmfPlusFillRects
68 EmfPlusRecordHeader Header;
69 DWORD BrushID;
70 DWORD Count;
71 } EmfPlusFillRects;
73 typedef struct EmfPlusSetPageTransform
75 EmfPlusRecordHeader Header;
76 REAL PageScale;
77 } EmfPlusSetPageTransform;
79 typedef struct EmfPlusRect
81 SHORT X;
82 SHORT Y;
83 SHORT Width;
84 SHORT Height;
85 } EmfPlusRect;
87 typedef struct EmfPlusScaleWorldTransform
89 EmfPlusRecordHeader Header;
90 REAL Sx;
91 REAL Sy;
92 } EmfPlusScaleWorldTransform;
94 static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result)
96 DWORD size_needed;
97 EmfPlusRecordHeader *record;
99 if (!metafile->comment_data_size)
101 DWORD data_size = max(256, size * 2 + 4);
102 metafile->comment_data = heap_alloc_zero(data_size);
104 if (!metafile->comment_data)
105 return OutOfMemory;
107 memcpy(metafile->comment_data, "EMF+", 4);
109 metafile->comment_data_size = data_size;
110 metafile->comment_data_length = 4;
113 size_needed = size + metafile->comment_data_length;
115 if (size_needed > metafile->comment_data_size)
117 DWORD data_size = size_needed * 2;
118 BYTE *new_data = heap_alloc_zero(data_size);
120 if (!new_data)
121 return OutOfMemory;
123 memcpy(new_data, metafile->comment_data, metafile->comment_data_length);
125 metafile->comment_data_size = data_size;
126 heap_free(metafile->comment_data);
127 metafile->comment_data = new_data;
130 *result = metafile->comment_data + metafile->comment_data_length;
131 metafile->comment_data_length += size;
133 record = (EmfPlusRecordHeader*)*result;
134 record->Size = size;
135 record->DataSize = size - sizeof(EmfPlusRecordHeader);
137 return Ok;
140 static void METAFILE_WriteRecords(GpMetafile *metafile)
142 if (metafile->comment_data_length > 4)
144 GdiComment(metafile->record_dc, metafile->comment_data_length, metafile->comment_data);
145 metafile->comment_data_length = 4;
149 static GpStatus METAFILE_WriteHeader(GpMetafile *metafile, HDC hdc)
151 GpStatus stat;
153 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
155 EmfPlusHeader *header;
157 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusHeader), (void**)&header);
158 if (stat != Ok)
159 return stat;
161 header->Header.Type = EmfPlusRecordTypeHeader;
163 if (metafile->metafile_type == MetafileTypeEmfPlusDual)
164 header->Header.Flags = 1;
165 else
166 header->Header.Flags = 0;
168 header->Version = 0xDBC01002;
170 if (GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY)
171 header->EmfPlusFlags = 1;
172 else
173 header->EmfPlusFlags = 0;
175 header->LogicalDpiX = GetDeviceCaps(hdc, LOGPIXELSX);
176 header->LogicalDpiY = GetDeviceCaps(hdc, LOGPIXELSY);
178 METAFILE_WriteRecords(metafile);
181 return Ok;
184 static GpStatus METAFILE_WriteEndOfFile(GpMetafile *metafile)
186 GpStatus stat;
188 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
190 EmfPlusRecordHeader *record;
192 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusRecordHeader), (void**)&record);
193 if (stat != Ok)
194 return stat;
196 record->Type = EmfPlusRecordTypeEndOfFile;
197 record->Flags = 0;
199 METAFILE_WriteRecords(metafile);
202 return Ok;
205 GpStatus WINGDIPAPI GdipRecordMetafile(HDC hdc, EmfType type, GDIPCONST GpRectF *frameRect,
206 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
208 HDC record_dc;
209 REAL dpix, dpiy;
210 REAL framerect_factor_x, framerect_factor_y;
211 RECT rc, *lprc;
212 GpStatus stat;
214 TRACE("(%p %d %p %d %p %p)\n", hdc, type, frameRect, frameUnit, desc, metafile);
216 if (!hdc || type < EmfTypeEmfOnly || type > EmfTypeEmfPlusDual || !metafile)
217 return InvalidParameter;
219 dpix = (REAL)GetDeviceCaps(hdc, HORZRES) / GetDeviceCaps(hdc, HORZSIZE) * 25.4;
220 dpiy = (REAL)GetDeviceCaps(hdc, VERTRES) / GetDeviceCaps(hdc, VERTSIZE) * 25.4;
222 if (frameRect)
224 switch (frameUnit)
226 case MetafileFrameUnitPixel:
227 framerect_factor_x = 2540.0 / dpix;
228 framerect_factor_y = 2540.0 / dpiy;
229 break;
230 case MetafileFrameUnitPoint:
231 framerect_factor_x = framerect_factor_y = 2540.0 / 72.0;
232 break;
233 case MetafileFrameUnitInch:
234 framerect_factor_x = framerect_factor_y = 2540.0;
235 break;
236 case MetafileFrameUnitDocument:
237 framerect_factor_x = framerect_factor_y = 2540.0 / 300.0;
238 break;
239 case MetafileFrameUnitMillimeter:
240 framerect_factor_x = framerect_factor_y = 100.0;
241 break;
242 case MetafileFrameUnitGdi:
243 framerect_factor_x = framerect_factor_y = 1.0;
244 break;
245 default:
246 return InvalidParameter;
249 rc.left = framerect_factor_x * frameRect->X;
250 rc.top = framerect_factor_y * frameRect->Y;
251 rc.right = rc.left + framerect_factor_x * frameRect->Width;
252 rc.bottom = rc.top + framerect_factor_y * frameRect->Height;
254 lprc = &rc;
256 else
257 lprc = NULL;
259 record_dc = CreateEnhMetaFileW(hdc, NULL, lprc, desc);
261 if (!record_dc)
262 return GenericError;
264 *metafile = heap_alloc_zero(sizeof(GpMetafile));
265 if(!*metafile)
267 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc));
268 return OutOfMemory;
271 (*metafile)->image.type = ImageTypeMetafile;
272 (*metafile)->image.picture = NULL;
273 (*metafile)->image.flags = ImageFlagsNone;
274 (*metafile)->image.palette = NULL;
275 (*metafile)->image.xres = dpix;
276 (*metafile)->image.yres = dpiy;
277 (*metafile)->bounds.X = (*metafile)->bounds.Y = 0.0;
278 (*metafile)->bounds.Width = (*metafile)->bounds.Height = 1.0;
279 (*metafile)->unit = UnitPixel;
280 (*metafile)->metafile_type = type;
281 (*metafile)->record_dc = record_dc;
282 (*metafile)->comment_data = NULL;
283 (*metafile)->comment_data_size = 0;
284 (*metafile)->comment_data_length = 0;
285 (*metafile)->hemf = NULL;
287 if (!frameRect)
289 (*metafile)->auto_frame = TRUE;
290 (*metafile)->auto_frame_min.X = 0;
291 (*metafile)->auto_frame_min.Y = 0;
292 (*metafile)->auto_frame_max.X = -1;
293 (*metafile)->auto_frame_max.Y = -1;
296 stat = METAFILE_WriteHeader(*metafile, hdc);
298 if (stat != Ok)
300 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc));
301 heap_free(*metafile);
302 *metafile = NULL;
303 return OutOfMemory;
306 return stat;
309 /*****************************************************************************
310 * GdipRecordMetafileI [GDIPLUS.@]
312 GpStatus WINGDIPAPI GdipRecordMetafileI(HDC hdc, EmfType type, GDIPCONST GpRect *frameRect,
313 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
315 GpRectF frameRectF, *pFrameRectF;
317 TRACE("(%p %d %p %d %p %p)\n", hdc, type, frameRect, frameUnit, desc, metafile);
319 if (frameRect)
321 frameRectF.X = frameRect->X;
322 frameRectF.Y = frameRect->Y;
323 frameRectF.Width = frameRect->Width;
324 frameRectF.Height = frameRect->Height;
325 pFrameRectF = &frameRectF;
327 else
328 pFrameRectF = NULL;
330 return GdipRecordMetafile(hdc, type, pFrameRectF, frameUnit, desc, metafile);
333 GpStatus WINGDIPAPI GdipRecordMetafileStream(IStream *stream, HDC hdc, EmfType type, GDIPCONST GpRectF *frameRect,
334 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
336 GpStatus stat;
338 TRACE("(%p %p %d %p %d %p %p)\n", stream, hdc, type, frameRect, frameUnit, desc, metafile);
340 if (!stream)
341 return InvalidParameter;
343 stat = GdipRecordMetafile(hdc, type, frameRect, frameUnit, desc, metafile);
345 if (stat == Ok)
347 (*metafile)->record_stream = stream;
348 IStream_AddRef(stream);
351 return stat;
354 static void METAFILE_AdjustFrame(GpMetafile* metafile, const GpPointF *points,
355 UINT num_points)
357 int i;
359 if (!metafile->auto_frame || !num_points)
360 return;
362 if (metafile->auto_frame_max.X < metafile->auto_frame_min.X)
363 metafile->auto_frame_max = metafile->auto_frame_min = points[0];
365 for (i=0; i<num_points; i++)
367 if (points[i].X < metafile->auto_frame_min.X)
368 metafile->auto_frame_min.X = points[i].X;
369 if (points[i].X > metafile->auto_frame_max.X)
370 metafile->auto_frame_max.X = points[i].X;
371 if (points[i].Y < metafile->auto_frame_min.Y)
372 metafile->auto_frame_min.Y = points[i].Y;
373 if (points[i].Y > metafile->auto_frame_max.Y)
374 metafile->auto_frame_max.Y = points[i].Y;
378 GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result)
380 GpStatus stat;
382 if (!metafile->record_dc || metafile->record_graphics)
383 return InvalidParameter;
385 stat = graphics_from_image((GpImage*)metafile, &metafile->record_graphics);
387 if (stat == Ok)
389 *result = metafile->record_graphics;
390 metafile->record_graphics->xres = 96.0;
391 metafile->record_graphics->yres = 96.0;
394 return stat;
397 GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc)
399 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
401 EmfPlusRecordHeader *record;
402 GpStatus stat;
404 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusRecordHeader), (void**)&record);
405 if (stat != Ok)
406 return stat;
408 record->Type = EmfPlusRecordTypeGetDC;
409 record->Flags = 0;
411 METAFILE_WriteRecords(metafile);
414 *hdc = metafile->record_dc;
416 return Ok;
419 GpStatus METAFILE_GraphicsClear(GpMetafile* metafile, ARGB color)
421 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
423 EmfPlusClear *record;
424 GpStatus stat;
426 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusClear), (void**)&record);
427 if (stat != Ok)
428 return stat;
430 record->Header.Type = EmfPlusRecordTypeClear;
431 record->Header.Flags = 0;
432 record->Color = color;
434 METAFILE_WriteRecords(metafile);
437 return Ok;
440 static BOOL is_integer_rect(const GpRectF *rect)
442 SHORT x, y, width, height;
443 x = rect->X;
444 y = rect->Y;
445 width = rect->Width;
446 height = rect->Height;
447 if (rect->X != (REAL)x || rect->Y != (REAL)y ||
448 rect->Width != (REAL)width || rect->Height != (REAL)height)
449 return FALSE;
450 return TRUE;
453 GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush,
454 GDIPCONST GpRectF* rects, INT count)
456 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
458 EmfPlusFillRects *record;
459 GpStatus stat;
460 BOOL integer_rects = TRUE;
461 int i;
462 DWORD brushid;
463 int flags = 0;
465 if (brush->bt == BrushTypeSolidColor)
467 flags |= 0x8000;
468 brushid = ((GpSolidFill*)brush)->color;
470 else
472 FIXME("brush serialization not implemented\n");
473 return NotImplemented;
476 for (i=0; i<count; i++)
478 if (!is_integer_rect(&rects[i]))
480 integer_rects = FALSE;
481 break;
485 if (integer_rects)
486 flags |= 0x4000;
488 stat = METAFILE_AllocateRecord(metafile,
489 sizeof(EmfPlusFillRects) + count * (integer_rects ? sizeof(EmfPlusRect) : sizeof(GpRectF)),
490 (void**)&record);
491 if (stat != Ok)
492 return stat;
494 record->Header.Type = EmfPlusRecordTypeFillRects;
495 record->Header.Flags = flags;
496 record->BrushID = brushid;
497 record->Count = count;
499 if (integer_rects)
501 EmfPlusRect *record_rects = (EmfPlusRect*)(record+1);
502 for (i=0; i<count; i++)
504 record_rects[i].X = (SHORT)rects[i].X;
505 record_rects[i].Y = (SHORT)rects[i].Y;
506 record_rects[i].Width = (SHORT)rects[i].Width;
507 record_rects[i].Height = (SHORT)rects[i].Height;
510 else
511 memcpy(record+1, rects, sizeof(GpRectF) * count);
513 METAFILE_WriteRecords(metafile);
516 if (metafile->auto_frame)
518 GpPointF corners[4];
519 int i;
521 for (i=0; i<count; i++)
523 corners[0].X = rects[i].X;
524 corners[0].Y = rects[i].Y;
525 corners[1].X = rects[i].X + rects[i].Width;
526 corners[1].Y = rects[i].Y;
527 corners[2].X = rects[i].X;
528 corners[2].Y = rects[i].Y + rects[i].Height;
529 corners[3].X = rects[i].X + rects[i].Width;
530 corners[3].Y = rects[i].Y + rects[i].Height;
532 GdipTransformPoints(metafile->record_graphics, CoordinateSpaceDevice,
533 CoordinateSpaceWorld, corners, 4);
535 METAFILE_AdjustFrame(metafile, corners, 4);
539 return Ok;
542 GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale)
544 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
546 EmfPlusSetPageTransform *record;
547 GpStatus stat;
549 stat = METAFILE_AllocateRecord(metafile,
550 sizeof(EmfPlusSetPageTransform),
551 (void**)&record);
552 if (stat != Ok)
553 return stat;
555 record->Header.Type = EmfPlusRecordTypeSetPageTransform;
556 record->Header.Flags = unit;
557 record->PageScale = scale;
559 METAFILE_WriteRecords(metafile);
562 return Ok;
565 GpStatus METAFILE_ScaleWorldTransform(GpMetafile* metafile, REAL sx, REAL sy, MatrixOrder order)
567 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
569 EmfPlusScaleWorldTransform *record;
570 GpStatus stat;
572 stat = METAFILE_AllocateRecord(metafile,
573 sizeof(EmfPlusScaleWorldTransform),
574 (void**)&record);
575 if (stat != Ok)
576 return stat;
578 record->Header.Type = EmfPlusRecordTypeScaleWorldTransform;
579 record->Header.Flags = (order == MatrixOrderAppend ? 4 : 0);
580 record->Sx = sx;
581 record->Sy = sy;
583 METAFILE_WriteRecords(metafile);
586 return Ok;
589 GpStatus METAFILE_ResetWorldTransform(GpMetafile* metafile)
591 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
593 EmfPlusRecordHeader *record;
594 GpStatus stat;
596 stat = METAFILE_AllocateRecord(metafile,
597 sizeof(EmfPlusRecordHeader),
598 (void**)&record);
599 if (stat != Ok)
600 return stat;
602 record->Type = EmfPlusRecordTypeResetWorldTransform;
603 record->Flags = 0;
605 METAFILE_WriteRecords(metafile);
608 return Ok;
611 GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc)
613 if (hdc != metafile->record_dc)
614 return InvalidParameter;
616 return Ok;
619 GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile)
621 GpStatus stat;
623 stat = METAFILE_WriteEndOfFile(metafile);
624 metafile->record_graphics = NULL;
626 metafile->hemf = CloseEnhMetaFile(metafile->record_dc);
627 metafile->record_dc = NULL;
629 heap_free(metafile->comment_data);
630 metafile->comment_data = NULL;
631 metafile->comment_data_size = 0;
633 if (stat == Ok)
635 MetafileHeader header;
637 stat = GdipGetMetafileHeaderFromEmf(metafile->hemf, &header);
638 if (stat == Ok && metafile->auto_frame &&
639 metafile->auto_frame_max.X >= metafile->auto_frame_min.X)
641 RECTL bounds_rc, gdi_bounds_rc;
642 REAL x_scale = 2540.0 / header.DpiX;
643 REAL y_scale = 2540.0 / header.DpiY;
644 BYTE* buffer;
645 UINT buffer_size;
647 bounds_rc.left = floorf(metafile->auto_frame_min.X * x_scale);
648 bounds_rc.top = floorf(metafile->auto_frame_min.Y * y_scale);
649 bounds_rc.right = ceilf(metafile->auto_frame_max.X * x_scale);
650 bounds_rc.bottom = ceilf(metafile->auto_frame_max.Y * y_scale);
652 gdi_bounds_rc = header.EmfHeader.rclBounds;
653 if (gdi_bounds_rc.right > gdi_bounds_rc.left && gdi_bounds_rc.bottom > gdi_bounds_rc.top)
655 bounds_rc.left = min(bounds_rc.left, gdi_bounds_rc.left);
656 bounds_rc.top = min(bounds_rc.top, gdi_bounds_rc.top);
657 bounds_rc.right = max(bounds_rc.right, gdi_bounds_rc.right);
658 bounds_rc.bottom = max(bounds_rc.bottom, gdi_bounds_rc.bottom);
661 buffer_size = GetEnhMetaFileBits(metafile->hemf, 0, NULL);
662 buffer = heap_alloc(buffer_size);
663 if (buffer)
665 HENHMETAFILE new_hemf;
667 GetEnhMetaFileBits(metafile->hemf, buffer_size, buffer);
669 ((ENHMETAHEADER*)buffer)->rclFrame = bounds_rc;
671 new_hemf = SetEnhMetaFileBits(buffer_size, buffer);
673 if (new_hemf)
675 DeleteEnhMetaFile(metafile->hemf);
676 metafile->hemf = new_hemf;
678 else
679 stat = OutOfMemory;
681 heap_free(buffer);
683 else
684 stat = OutOfMemory;
686 if (stat == Ok)
687 stat = GdipGetMetafileHeaderFromEmf(metafile->hemf, &header);
689 if (stat == Ok)
691 metafile->bounds.X = header.X;
692 metafile->bounds.Y = header.Y;
693 metafile->bounds.Width = header.Width;
694 metafile->bounds.Height = header.Height;
698 if (stat == Ok && metafile->record_stream)
700 BYTE *buffer;
701 UINT buffer_size;
703 buffer_size = GetEnhMetaFileBits(metafile->hemf, 0, NULL);
705 buffer = heap_alloc(buffer_size);
706 if (buffer)
708 HRESULT hr;
710 GetEnhMetaFileBits(metafile->hemf, buffer_size, buffer);
712 hr = IStream_Write(metafile->record_stream, buffer, buffer_size, NULL);
714 if (FAILED(hr))
715 stat = hresult_to_status(hr);
717 heap_free(buffer);
719 else
720 stat = OutOfMemory;
723 if (metafile->record_stream)
725 IStream_Release(metafile->record_stream);
726 metafile->record_stream = NULL;
729 return stat;
732 GpStatus WINGDIPAPI GdipGetHemfFromMetafile(GpMetafile *metafile, HENHMETAFILE *hEmf)
734 TRACE("(%p,%p)\n", metafile, hEmf);
736 if (!metafile || !hEmf || !metafile->hemf)
737 return InvalidParameter;
739 *hEmf = metafile->hemf;
740 metafile->hemf = NULL;
742 return Ok;
745 static GpStatus METAFILE_PlaybackGetDC(GpMetafile *metafile)
747 GpStatus stat = Ok;
749 stat = GdipGetDC(metafile->playback_graphics, &metafile->playback_dc);
751 if (stat == Ok)
753 /* The result of GdipGetDC always expects device co-ordinates, but the
754 * device co-ordinates of the source metafile do not correspond to
755 * device co-ordinates of the destination. Therefore, we set up the DC
756 * so that the metafile's bounds map to the destination points where we
757 * are drawing this metafile. */
758 SetMapMode(metafile->playback_dc, MM_ANISOTROPIC);
760 SetWindowOrgEx(metafile->playback_dc, metafile->bounds.X, metafile->bounds.Y, NULL);
761 SetWindowExtEx(metafile->playback_dc, metafile->bounds.Width, metafile->bounds.Height, NULL);
763 SetViewportOrgEx(metafile->playback_dc, metafile->playback_points[0].X, metafile->playback_points[0].Y, NULL);
764 SetViewportExtEx(metafile->playback_dc,
765 metafile->playback_points[1].X - metafile->playback_points[0].X,
766 metafile->playback_points[2].Y - metafile->playback_points[0].Y, NULL);
769 return stat;
772 static void METAFILE_PlaybackReleaseDC(GpMetafile *metafile)
774 if (metafile->playback_dc)
776 GdipReleaseDC(metafile->playback_graphics, metafile->playback_dc);
777 metafile->playback_dc = NULL;
781 static GpStatus METAFILE_PlaybackUpdateClip(GpMetafile *metafile)
783 return GdipCombineRegionRegion(metafile->playback_graphics->clip, metafile->base_clip, CombineModeReplace);
786 static GpStatus METAFILE_PlaybackUpdateWorldTransform(GpMetafile *metafile)
788 GpMatrix *real_transform;
789 GpStatus stat;
791 stat = GdipCreateMatrix3(&metafile->src_rect, metafile->playback_points, &real_transform);
793 if (stat == Ok)
795 REAL scale = units_to_pixels(1.0, metafile->page_unit, 96.0);
797 if (metafile->page_unit != UnitDisplay)
798 scale *= metafile->page_scale;
800 stat = GdipScaleMatrix(real_transform, scale, scale, MatrixOrderPrepend);
802 if (stat == Ok)
803 stat = GdipMultiplyMatrix(real_transform, metafile->world_transform, MatrixOrderPrepend);
805 if (stat == Ok)
806 stat = GdipSetWorldTransform(metafile->playback_graphics, real_transform);
808 GdipDeleteMatrix(real_transform);
811 return stat;
814 GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
815 EmfPlusRecordType recordType, UINT flags, UINT dataSize, GDIPCONST BYTE *data)
817 GpStatus stat;
818 GpMetafile *real_metafile = (GpMetafile*)metafile;
820 TRACE("(%p,%x,%x,%d,%p)\n", metafile, recordType, flags, dataSize, data);
822 if (!metafile || (dataSize && !data) || !metafile->playback_graphics)
823 return InvalidParameter;
825 if (recordType >= 1 && recordType <= 0x7a)
827 /* regular EMF record */
828 if (metafile->playback_dc)
830 ENHMETARECORD *record;
832 record = heap_alloc_zero(dataSize + 8);
834 if (record)
836 record->iType = recordType;
837 record->nSize = dataSize + 8;
838 memcpy(record->dParm, data, dataSize);
840 PlayEnhMetaFileRecord(metafile->playback_dc, metafile->handle_table,
841 record, metafile->handle_count);
843 heap_free(record);
845 else
846 return OutOfMemory;
849 else
851 EmfPlusRecordHeader *header = (EmfPlusRecordHeader*)(data)-1;
853 METAFILE_PlaybackReleaseDC((GpMetafile*)metafile);
855 switch(recordType)
857 case EmfPlusRecordTypeHeader:
858 case EmfPlusRecordTypeEndOfFile:
859 break;
860 case EmfPlusRecordTypeGetDC:
861 METAFILE_PlaybackGetDC((GpMetafile*)metafile);
862 break;
863 case EmfPlusRecordTypeClear:
865 EmfPlusClear *record = (EmfPlusClear*)header;
867 return GdipGraphicsClear(metafile->playback_graphics, record->Color);
869 case EmfPlusRecordTypeFillRects:
871 EmfPlusFillRects *record = (EmfPlusFillRects*)header;
872 GpBrush *brush, *temp_brush=NULL;
873 GpRectF *rects, *temp_rects=NULL;
875 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects))
876 return InvalidParameter;
878 if (flags & 0x4000)
880 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(EmfPlusRect) * record->Count)
881 return InvalidParameter;
883 else
885 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(GpRectF) * record->Count)
886 return InvalidParameter;
889 if (flags & 0x8000)
891 stat = GdipCreateSolidFill((ARGB)record->BrushID, (GpSolidFill**)&temp_brush);
892 brush = temp_brush;
894 else
896 FIXME("brush deserialization not implemented\n");
897 return NotImplemented;
900 if (stat == Ok)
902 if (flags & 0x4000)
904 EmfPlusRect *int_rects = (EmfPlusRect*)(record+1);
905 int i;
907 rects = temp_rects = heap_alloc_zero(sizeof(GpRectF) * record->Count);
908 if (rects)
910 for (i=0; i<record->Count; i++)
912 rects[i].X = int_rects[i].X;
913 rects[i].Y = int_rects[i].Y;
914 rects[i].Width = int_rects[i].Width;
915 rects[i].Height = int_rects[i].Height;
918 else
919 stat = OutOfMemory;
921 else
922 rects = (GpRectF*)(record+1);
925 if (stat == Ok)
927 stat = GdipFillRectangles(metafile->playback_graphics, brush, rects, record->Count);
930 GdipDeleteBrush(temp_brush);
931 heap_free(temp_rects);
933 return stat;
935 case EmfPlusRecordTypeSetPageTransform:
937 EmfPlusSetPageTransform *record = (EmfPlusSetPageTransform*)header;
938 GpUnit unit = (GpUnit)flags;
940 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusSetPageTransform))
941 return InvalidParameter;
943 real_metafile->page_unit = unit;
944 real_metafile->page_scale = record->PageScale;
946 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
948 case EmfPlusRecordTypeScaleWorldTransform:
950 EmfPlusScaleWorldTransform *record = (EmfPlusScaleWorldTransform*)header;
951 MatrixOrder order = (flags & 0x4) ? MatrixOrderAppend : MatrixOrderPrepend;
953 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusScaleWorldTransform))
954 return InvalidParameter;
956 GdipScaleMatrix(real_metafile->world_transform, record->Sx, record->Sy, order);
958 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
960 case EmfPlusRecordTypeResetWorldTransform:
962 GdipSetMatrixElements(real_metafile->world_transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
964 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
966 default:
967 FIXME("Not implemented for record type %x\n", recordType);
968 return NotImplemented;
972 return Ok;
975 struct enum_metafile_data
977 EnumerateMetafileProc callback;
978 void *callback_data;
979 GpMetafile *metafile;
982 static int CALLBACK enum_metafile_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR,
983 int nObj, LPARAM lpData)
985 BOOL ret;
986 struct enum_metafile_data *data = (struct enum_metafile_data*)lpData;
987 const BYTE* pStr;
989 data->metafile->handle_table = lpHTable;
990 data->metafile->handle_count = nObj;
992 /* First check for an EMF+ record. */
993 if (lpEMFR->iType == EMR_GDICOMMENT)
995 const EMRGDICOMMENT *comment = (const EMRGDICOMMENT*)lpEMFR;
997 if (comment->cbData >= 4 && memcmp(comment->Data, "EMF+", 4) == 0)
999 int offset = 4;
1001 while (offset + sizeof(EmfPlusRecordHeader) <= comment->cbData)
1003 const EmfPlusRecordHeader *record = (const EmfPlusRecordHeader*)&comment->Data[offset];
1005 if (record->DataSize)
1006 pStr = (const BYTE*)(record+1);
1007 else
1008 pStr = NULL;
1010 ret = data->callback(record->Type, record->Flags, record->DataSize,
1011 pStr, data->callback_data);
1013 if (!ret)
1014 return 0;
1016 offset += record->Size;
1019 return 1;
1023 if (lpEMFR->nSize != 8)
1024 pStr = (const BYTE*)lpEMFR->dParm;
1025 else
1026 pStr = NULL;
1028 return data->callback(lpEMFR->iType, 0, lpEMFR->nSize-8,
1029 pStr, data->callback_data);
1032 GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics,
1033 GDIPCONST GpMetafile *metafile, GDIPCONST GpPointF *destPoints, INT count,
1034 GDIPCONST GpRectF *srcRect, Unit srcUnit, EnumerateMetafileProc callback,
1035 VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes)
1037 struct enum_metafile_data data;
1038 GpStatus stat;
1039 GpMetafile *real_metafile = (GpMetafile*)metafile; /* whoever made this const was joking */
1040 GraphicsContainer state;
1041 GpPath *dst_path;
1043 TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics, metafile,
1044 destPoints, count, srcRect, srcUnit, callback, callbackData,
1045 imageAttributes);
1047 if (!graphics || !metafile || !destPoints || count != 3 || !srcRect)
1048 return InvalidParameter;
1050 if (!metafile->hemf)
1051 return InvalidParameter;
1053 if (metafile->playback_graphics)
1054 return ObjectBusy;
1056 TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect), srcUnit,
1057 debugstr_pointf(&destPoints[0]), debugstr_pointf(&destPoints[1]),
1058 debugstr_pointf(&destPoints[2]));
1060 data.callback = callback;
1061 data.callback_data = callbackData;
1062 data.metafile = real_metafile;
1064 real_metafile->playback_graphics = graphics;
1065 real_metafile->playback_dc = NULL;
1066 real_metafile->src_rect = *srcRect;
1068 memcpy(real_metafile->playback_points, destPoints, sizeof(PointF) * 3);
1069 stat = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, real_metafile->playback_points, 3);
1071 if (stat == Ok)
1072 stat = GdipBeginContainer2(graphics, &state);
1074 if (stat == Ok)
1076 stat = GdipSetPageScale(graphics, 1.0);
1078 if (stat == Ok)
1079 stat = GdipSetPageUnit(graphics, UnitPixel);
1081 if (stat == Ok)
1082 stat = GdipResetWorldTransform(graphics);
1084 if (stat == Ok)
1085 stat = GdipCreateRegion(&real_metafile->base_clip);
1087 if (stat == Ok)
1088 stat = GdipGetClip(graphics, real_metafile->base_clip);
1090 if (stat == Ok)
1091 stat = GdipCreatePath(FillModeAlternate, &dst_path);
1093 if (stat == Ok)
1095 GpPointF clip_points[4];
1097 clip_points[0] = real_metafile->playback_points[0];
1098 clip_points[1] = real_metafile->playback_points[1];
1099 clip_points[2].X = real_metafile->playback_points[1].X + real_metafile->playback_points[2].X
1100 - real_metafile->playback_points[0].X;
1101 clip_points[2].Y = real_metafile->playback_points[1].Y + real_metafile->playback_points[2].Y
1102 - real_metafile->playback_points[0].Y;
1103 clip_points[3] = real_metafile->playback_points[2];
1105 stat = GdipAddPathPolygon(dst_path, clip_points, 4);
1107 if (stat == Ok)
1108 stat = GdipCombineRegionPath(real_metafile->base_clip, dst_path, CombineModeIntersect);
1110 GdipDeletePath(dst_path);
1113 if (stat == Ok)
1114 stat = GdipCreateMatrix(&real_metafile->world_transform);
1116 if (stat == Ok)
1118 real_metafile->page_unit = UnitDisplay;
1119 real_metafile->page_scale = 1.0;
1120 stat = METAFILE_PlaybackUpdateWorldTransform(real_metafile);
1123 if (stat == Ok)
1125 stat = METAFILE_PlaybackUpdateClip(real_metafile);
1128 if (stat == Ok && (metafile->metafile_type == MetafileTypeEmf ||
1129 metafile->metafile_type == MetafileTypeWmfPlaceable ||
1130 metafile->metafile_type == MetafileTypeWmf))
1131 stat = METAFILE_PlaybackGetDC(real_metafile);
1133 if (stat == Ok)
1134 EnumEnhMetaFile(0, metafile->hemf, enum_metafile_proc, &data, NULL);
1136 METAFILE_PlaybackReleaseDC(real_metafile);
1138 GdipDeleteMatrix(real_metafile->world_transform);
1139 real_metafile->world_transform = NULL;
1141 GdipDeleteRegion(real_metafile->base_clip);
1142 real_metafile->base_clip = NULL;
1144 GdipEndContainer(graphics, state);
1147 real_metafile->playback_graphics = NULL;
1149 return stat;
1152 GpStatus WINGDIPAPI GdipEnumerateMetafileDestRect(GpGraphics *graphics,
1153 GDIPCONST GpMetafile *metafile, GDIPCONST GpRectF *dest,
1154 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
1156 GpPointF points[3];
1158 if (!graphics || !metafile || !dest) return InvalidParameter;
1160 points[0].X = points[2].X = dest->X;
1161 points[0].Y = points[1].Y = dest->Y;
1162 points[1].X = dest->X + dest->Width;
1163 points[2].Y = dest->Y + dest->Height;
1165 return GdipEnumerateMetafileSrcRectDestPoints(graphics, metafile, points, 3,
1166 &metafile->bounds, metafile->unit, callback, cb_data, attrs);
1169 GpStatus WINGDIPAPI GdipEnumerateMetafileDestRectI(GpGraphics *graphics,
1170 GDIPCONST GpMetafile *metafile, GDIPCONST GpRect *dest,
1171 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
1173 GpRectF destf;
1175 if (!graphics || !metafile || !dest) return InvalidParameter;
1177 destf.X = dest->X;
1178 destf.Y = dest->Y;
1179 destf.Width = dest->Width;
1180 destf.Height = dest->Height;
1182 return GdipEnumerateMetafileDestRect(graphics, metafile, &destf, callback, cb_data, attrs);
1185 GpStatus WINGDIPAPI GdipEnumerateMetafileDestPoint(GpGraphics *graphics,
1186 GDIPCONST GpMetafile *metafile, GDIPCONST GpPointF *dest,
1187 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
1189 GpRectF destf;
1191 if (!graphics || !metafile || !dest) return InvalidParameter;
1193 destf.X = dest->X;
1194 destf.Y = dest->Y;
1195 destf.Width = units_to_pixels(metafile->bounds.Width, metafile->unit, metafile->image.xres);
1196 destf.Height = units_to_pixels(metafile->bounds.Height, metafile->unit, metafile->image.yres);
1198 return GdipEnumerateMetafileDestRect(graphics, metafile, &destf, callback, cb_data, attrs);
1201 GpStatus WINGDIPAPI GdipEnumerateMetafileDestPointI(GpGraphics *graphics,
1202 GDIPCONST GpMetafile *metafile, GDIPCONST GpPoint *dest,
1203 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
1205 GpPointF ptf;
1207 if (!graphics || !metafile || !dest) return InvalidParameter;
1209 ptf.X = dest->X;
1210 ptf.Y = dest->Y;
1212 return GdipEnumerateMetafileDestPoint(graphics, metafile, &ptf, callback, cb_data, attrs);
1215 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
1216 MetafileHeader * header)
1218 static int calls;
1220 TRACE("(%p, %p)\n", metafile, header);
1222 if(!metafile || !header)
1223 return InvalidParameter;
1225 if(!(calls++))
1226 FIXME("not implemented\n");
1228 memset(header, 0, sizeof(MetafileHeader));
1230 return Ok;
1233 static int CALLBACK get_emfplus_header_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR,
1234 int nObj, LPARAM lpData)
1236 EmfPlusHeader *dst_header = (EmfPlusHeader*)lpData;
1238 if (lpEMFR->iType == EMR_GDICOMMENT)
1240 const EMRGDICOMMENT *comment = (const EMRGDICOMMENT*)lpEMFR;
1242 if (comment->cbData >= 4 && memcmp(comment->Data, "EMF+", 4) == 0)
1244 const EmfPlusRecordHeader *header = (const EmfPlusRecordHeader*)&comment->Data[4];
1246 if (4 + sizeof(EmfPlusHeader) <= comment->cbData &&
1247 header->Type == EmfPlusRecordTypeHeader)
1249 memcpy(dst_header, header, sizeof(*dst_header));
1253 else if (lpEMFR->iType == EMR_HEADER)
1254 return TRUE;
1256 return FALSE;
1259 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromEmf(HENHMETAFILE hemf,
1260 MetafileHeader *header)
1262 ENHMETAHEADER3 emfheader;
1263 EmfPlusHeader emfplusheader;
1264 MetafileType metafile_type;
1266 TRACE("(%p,%p)\n", hemf, header);
1268 if(!hemf || !header)
1269 return InvalidParameter;
1271 if (GetEnhMetaFileHeader(hemf, sizeof(emfheader), (ENHMETAHEADER*)&emfheader) == 0)
1272 return GenericError;
1274 emfplusheader.Header.Type = 0;
1276 EnumEnhMetaFile(NULL, hemf, get_emfplus_header_proc, &emfplusheader, NULL);
1278 if (emfplusheader.Header.Type == EmfPlusRecordTypeHeader)
1280 if ((emfplusheader.Header.Flags & 1) == 1)
1281 metafile_type = MetafileTypeEmfPlusDual;
1282 else
1283 metafile_type = MetafileTypeEmfPlusOnly;
1285 else
1286 metafile_type = MetafileTypeEmf;
1288 header->Type = metafile_type;
1289 header->Size = emfheader.nBytes;
1290 header->DpiX = (REAL)emfheader.szlDevice.cx * 25.4 / emfheader.szlMillimeters.cx;
1291 header->DpiY = (REAL)emfheader.szlDevice.cy * 25.4 / emfheader.szlMillimeters.cy;
1292 header->X = gdip_round((REAL)emfheader.rclFrame.left / 2540.0 * header->DpiX);
1293 header->Y = gdip_round((REAL)emfheader.rclFrame.top / 2540.0 * header->DpiY);
1294 header->Width = gdip_round((REAL)(emfheader.rclFrame.right - emfheader.rclFrame.left) / 2540.0 * header->DpiX);
1295 header->Height = gdip_round((REAL)(emfheader.rclFrame.bottom - emfheader.rclFrame.top) / 2540.0 * header->DpiY);
1296 header->EmfHeader = emfheader;
1298 if (metafile_type == MetafileTypeEmfPlusDual || metafile_type == MetafileTypeEmfPlusOnly)
1300 header->Version = emfplusheader.Version;
1301 header->EmfPlusFlags = emfplusheader.EmfPlusFlags;
1302 header->EmfPlusHeaderSize = emfplusheader.Header.Size;
1303 header->LogicalDpiX = emfplusheader.LogicalDpiX;
1304 header->LogicalDpiY = emfplusheader.LogicalDpiY;
1306 else
1308 header->Version = emfheader.nVersion;
1309 header->EmfPlusFlags = 0;
1310 header->EmfPlusHeaderSize = 0;
1311 header->LogicalDpiX = 0;
1312 header->LogicalDpiY = 0;
1315 return Ok;
1318 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR *filename,
1319 MetafileHeader *header)
1321 static int calls;
1323 TRACE("(%s,%p)\n", debugstr_w(filename), header);
1325 if(!filename || !header)
1326 return InvalidParameter;
1328 if(!(calls++))
1329 FIXME("not implemented\n");
1331 memset(header, 0, sizeof(MetafileHeader));
1333 return Ok;
1336 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromStream(IStream *stream,
1337 MetafileHeader *header)
1339 static int calls;
1341 TRACE("(%p,%p)\n", stream, header);
1343 if(!stream || !header)
1344 return InvalidParameter;
1346 if(!(calls++))
1347 FIXME("not implemented\n");
1349 memset(header, 0, sizeof(MetafileHeader));
1351 return Ok;
1354 GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete,
1355 GpMetafile **metafile)
1357 GpStatus stat;
1358 MetafileHeader header;
1360 TRACE("(%p,%i,%p)\n", hemf, delete, metafile);
1362 if(!hemf || !metafile)
1363 return InvalidParameter;
1365 stat = GdipGetMetafileHeaderFromEmf(hemf, &header);
1366 if (stat != Ok)
1367 return stat;
1369 *metafile = heap_alloc_zero(sizeof(GpMetafile));
1370 if (!*metafile)
1371 return OutOfMemory;
1373 (*metafile)->image.type = ImageTypeMetafile;
1374 (*metafile)->image.format = ImageFormatEMF;
1375 (*metafile)->image.frame_count = 1;
1376 (*metafile)->image.xres = header.DpiX;
1377 (*metafile)->image.yres = header.DpiY;
1378 (*metafile)->bounds.X = (REAL)header.EmfHeader.rclFrame.left / 2540.0 * header.DpiX;
1379 (*metafile)->bounds.Y = (REAL)header.EmfHeader.rclFrame.top / 2540.0 * header.DpiY;
1380 (*metafile)->bounds.Width = (REAL)(header.EmfHeader.rclFrame.right - header.EmfHeader.rclFrame.left)
1381 / 2540.0 * header.DpiX;
1382 (*metafile)->bounds.Height = (REAL)(header.EmfHeader.rclFrame.bottom - header.EmfHeader.rclFrame.top)
1383 / 2540.0 * header.DpiY;
1384 (*metafile)->unit = UnitPixel;
1385 (*metafile)->metafile_type = header.Type;
1386 (*metafile)->hemf = hemf;
1387 (*metafile)->preserve_hemf = !delete;
1389 TRACE("<-- %p\n", *metafile);
1391 return Ok;
1394 GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
1395 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
1397 UINT read;
1398 BYTE *copy;
1399 HENHMETAFILE hemf;
1400 GpStatus retval = Ok;
1402 TRACE("(%p, %d, %p, %p)\n", hwmf, delete, placeable, metafile);
1404 if(!hwmf || !metafile)
1405 return InvalidParameter;
1407 *metafile = NULL;
1408 read = GetMetaFileBitsEx(hwmf, 0, NULL);
1409 if(!read)
1410 return GenericError;
1411 copy = heap_alloc_zero(read);
1412 GetMetaFileBitsEx(hwmf, read, copy);
1414 hemf = SetWinMetaFileBits(read, copy, NULL, NULL);
1415 heap_free(copy);
1417 /* FIXME: We should store and use hwmf instead of converting to hemf */
1418 retval = GdipCreateMetafileFromEmf(hemf, TRUE, metafile);
1420 if (retval == Ok)
1422 if (placeable)
1424 (*metafile)->image.xres = (REAL)placeable->Inch;
1425 (*metafile)->image.yres = (REAL)placeable->Inch;
1426 (*metafile)->bounds.X = ((REAL)placeable->BoundingBox.Left) / ((REAL)placeable->Inch);
1427 (*metafile)->bounds.Y = ((REAL)placeable->BoundingBox.Top) / ((REAL)placeable->Inch);
1428 (*metafile)->bounds.Width = (REAL)(placeable->BoundingBox.Right -
1429 placeable->BoundingBox.Left);
1430 (*metafile)->bounds.Height = (REAL)(placeable->BoundingBox.Bottom -
1431 placeable->BoundingBox.Top);
1432 (*metafile)->metafile_type = MetafileTypeWmfPlaceable;
1434 else
1435 (*metafile)->metafile_type = MetafileTypeWmf;
1436 (*metafile)->image.format = ImageFormatWMF;
1438 if (delete) DeleteMetaFile(hwmf);
1440 else
1441 DeleteEnhMetaFile(hemf);
1442 return retval;
1445 GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file,
1446 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
1448 HMETAFILE hmf = GetMetaFileW(file);
1450 TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile);
1452 if(!hmf) return InvalidParameter;
1454 return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile);
1457 GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file,
1458 GpMetafile **metafile)
1460 FIXME("(%p, %p): stub\n", file, metafile);
1461 return NotImplemented;
1464 GpStatus WINGDIPAPI GdipCreateMetafileFromStream(IStream *stream,
1465 GpMetafile **metafile)
1467 FIXME("(%p, %p): stub\n", stream, metafile);
1468 return NotImplemented;
1471 GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile *metafile,
1472 UINT limitDpi)
1474 TRACE("(%p,%u)\n", metafile, limitDpi);
1476 return Ok;
1479 GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
1480 GpMetafile* metafile, BOOL* succ, EmfType emfType,
1481 const WCHAR* description, GpMetafile** out_metafile)
1483 static int calls;
1485 TRACE("(%p,%p,%p,%u,%s,%p)\n", ref, metafile, succ, emfType,
1486 debugstr_w(description), out_metafile);
1488 if(!ref || !metafile || !out_metafile || emfType < EmfTypeEmfOnly || emfType > EmfTypeEmfPlusDual)
1489 return InvalidParameter;
1491 if(succ)
1492 *succ = FALSE;
1493 *out_metafile = NULL;
1495 if(!(calls++))
1496 FIXME("not implemented\n");
1498 return NotImplemented;
1501 GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE hemf, UINT cbData16,
1502 LPBYTE pData16, INT iMapMode, INT eFlags)
1504 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf, cbData16, pData16, iMapMode, eFlags);
1505 return NotImplemented;
1508 GpStatus WINGDIPAPI GdipRecordMetafileFileName(GDIPCONST WCHAR* fileName,
1509 HDC hdc, EmfType type, GDIPCONST GpRectF *pFrameRect,
1510 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc,
1511 GpMetafile **metafile)
1513 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
1514 frameUnit, debugstr_w(desc), metafile);
1516 return NotImplemented;
1519 GpStatus WINGDIPAPI GdipRecordMetafileFileNameI(GDIPCONST WCHAR* fileName, HDC hdc, EmfType type,
1520 GDIPCONST GpRect *pFrameRect, MetafileFrameUnit frameUnit,
1521 GDIPCONST WCHAR *desc, GpMetafile **metafile)
1523 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
1524 frameUnit, debugstr_w(desc), metafile);
1526 return NotImplemented;
1529 /*****************************************************************************
1530 * GdipConvertToEmfPlusToFile [GDIPLUS.@]
1533 GpStatus WINGDIPAPI GdipConvertToEmfPlusToFile(const GpGraphics* refGraphics,
1534 GpMetafile* metafile, BOOL* conversionSuccess,
1535 const WCHAR* filename, EmfType emfType,
1536 const WCHAR* description, GpMetafile** out_metafile)
1538 FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics, metafile, conversionSuccess, filename, emfType, description, out_metafile);
1539 return NotImplemented;