wined3d: Introduce R10G10B10X2 vertex formats for D3D8/9.
[wine.git] / dlls / gdiplus / metafile.c
blob022af38c21c428675b08843f076ab060c71e0cd2
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 static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result)
89 DWORD size_needed;
90 EmfPlusRecordHeader *record;
92 if (!metafile->comment_data_size)
94 DWORD data_size = max(256, size * 2 + 4);
95 metafile->comment_data = heap_alloc_zero(data_size);
97 if (!metafile->comment_data)
98 return OutOfMemory;
100 memcpy(metafile->comment_data, "EMF+", 4);
102 metafile->comment_data_size = data_size;
103 metafile->comment_data_length = 4;
106 size_needed = size + metafile->comment_data_length;
108 if (size_needed > metafile->comment_data_size)
110 DWORD data_size = size_needed * 2;
111 BYTE *new_data = heap_alloc_zero(data_size);
113 if (!new_data)
114 return OutOfMemory;
116 memcpy(new_data, metafile->comment_data, metafile->comment_data_length);
118 metafile->comment_data_size = data_size;
119 heap_free(metafile->comment_data);
120 metafile->comment_data = new_data;
123 *result = metafile->comment_data + metafile->comment_data_length;
124 metafile->comment_data_length += size;
126 record = (EmfPlusRecordHeader*)*result;
127 record->Size = size;
128 record->DataSize = size - sizeof(EmfPlusRecordHeader);
130 return Ok;
133 static void METAFILE_WriteRecords(GpMetafile *metafile)
135 if (metafile->comment_data_length > 4)
137 GdiComment(metafile->record_dc, metafile->comment_data_length, metafile->comment_data);
138 metafile->comment_data_length = 4;
142 static GpStatus METAFILE_WriteHeader(GpMetafile *metafile, HDC hdc)
144 GpStatus stat;
146 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
148 EmfPlusHeader *header;
150 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusHeader), (void**)&header);
151 if (stat != Ok)
152 return stat;
154 header->Header.Type = EmfPlusRecordTypeHeader;
156 if (metafile->metafile_type == MetafileTypeEmfPlusDual)
157 header->Header.Flags = 1;
158 else
159 header->Header.Flags = 0;
161 header->Version = 0xDBC01002;
163 if (GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY)
164 header->EmfPlusFlags = 1;
165 else
166 header->EmfPlusFlags = 0;
168 header->LogicalDpiX = GetDeviceCaps(hdc, LOGPIXELSX);
169 header->LogicalDpiY = GetDeviceCaps(hdc, LOGPIXELSY);
171 METAFILE_WriteRecords(metafile);
174 return Ok;
177 static GpStatus METAFILE_WriteEndOfFile(GpMetafile *metafile)
179 GpStatus stat;
181 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
183 EmfPlusRecordHeader *record;
185 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusRecordHeader), (void**)&record);
186 if (stat != Ok)
187 return stat;
189 record->Type = EmfPlusRecordTypeEndOfFile;
190 record->Flags = 0;
192 METAFILE_WriteRecords(metafile);
195 return Ok;
198 GpStatus WINGDIPAPI GdipRecordMetafile(HDC hdc, EmfType type, GDIPCONST GpRectF *frameRect,
199 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
201 HDC record_dc;
202 REAL dpix, dpiy;
203 REAL framerect_factor_x, framerect_factor_y;
204 RECT rc, *lprc;
205 GpStatus stat;
207 TRACE("(%p %d %p %d %p %p)\n", hdc, type, frameRect, frameUnit, desc, metafile);
209 if (!hdc || type < EmfTypeEmfOnly || type > EmfTypeEmfPlusDual || !metafile)
210 return InvalidParameter;
212 dpix = (REAL)GetDeviceCaps(hdc, HORZRES) / GetDeviceCaps(hdc, HORZSIZE) * 25.4;
213 dpiy = (REAL)GetDeviceCaps(hdc, VERTRES) / GetDeviceCaps(hdc, VERTSIZE) * 25.4;
215 if (frameRect)
217 switch (frameUnit)
219 case MetafileFrameUnitPixel:
220 framerect_factor_x = 2540.0 / dpix;
221 framerect_factor_y = 2540.0 / dpiy;
222 break;
223 case MetafileFrameUnitPoint:
224 framerect_factor_x = framerect_factor_y = 2540.0 / 72.0;
225 break;
226 case MetafileFrameUnitInch:
227 framerect_factor_x = framerect_factor_y = 2540.0;
228 break;
229 case MetafileFrameUnitDocument:
230 framerect_factor_x = framerect_factor_y = 2540.0 / 300.0;
231 break;
232 case MetafileFrameUnitMillimeter:
233 framerect_factor_x = framerect_factor_y = 100.0;
234 break;
235 case MetafileFrameUnitGdi:
236 framerect_factor_x = framerect_factor_y = 1.0;
237 break;
238 default:
239 return InvalidParameter;
242 rc.left = framerect_factor_x * frameRect->X;
243 rc.top = framerect_factor_y * frameRect->Y;
244 rc.right = rc.left + framerect_factor_x * frameRect->Width;
245 rc.bottom = rc.top + framerect_factor_y * frameRect->Height;
247 lprc = &rc;
249 else
250 lprc = NULL;
252 record_dc = CreateEnhMetaFileW(hdc, NULL, lprc, desc);
254 if (!record_dc)
255 return GenericError;
257 *metafile = heap_alloc_zero(sizeof(GpMetafile));
258 if(!*metafile)
260 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc));
261 return OutOfMemory;
264 (*metafile)->image.type = ImageTypeMetafile;
265 (*metafile)->image.picture = NULL;
266 (*metafile)->image.flags = ImageFlagsNone;
267 (*metafile)->image.palette = NULL;
268 (*metafile)->image.xres = dpix;
269 (*metafile)->image.yres = dpiy;
270 (*metafile)->bounds.X = (*metafile)->bounds.Y = 0.0;
271 (*metafile)->bounds.Width = (*metafile)->bounds.Height = 1.0;
272 (*metafile)->unit = UnitPixel;
273 (*metafile)->metafile_type = type;
274 (*metafile)->record_dc = record_dc;
275 (*metafile)->comment_data = NULL;
276 (*metafile)->comment_data_size = 0;
277 (*metafile)->comment_data_length = 0;
278 (*metafile)->hemf = NULL;
280 if (!frameRect)
282 (*metafile)->auto_frame = TRUE;
283 (*metafile)->auto_frame_min.X = 0;
284 (*metafile)->auto_frame_min.Y = 0;
285 (*metafile)->auto_frame_max.X = -1;
286 (*metafile)->auto_frame_max.Y = -1;
289 stat = METAFILE_WriteHeader(*metafile, hdc);
291 if (stat != Ok)
293 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc));
294 heap_free(*metafile);
295 *metafile = NULL;
296 return OutOfMemory;
299 return stat;
302 /*****************************************************************************
303 * GdipRecordMetafileI [GDIPLUS.@]
305 GpStatus WINGDIPAPI GdipRecordMetafileI(HDC hdc, EmfType type, GDIPCONST GpRect *frameRect,
306 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
308 GpRectF frameRectF, *pFrameRectF;
310 TRACE("(%p %d %p %d %p %p)\n", hdc, type, frameRect, frameUnit, desc, metafile);
312 if (frameRect)
314 frameRectF.X = frameRect->X;
315 frameRectF.Y = frameRect->Y;
316 frameRectF.Width = frameRect->Width;
317 frameRectF.Height = frameRect->Height;
318 pFrameRectF = &frameRectF;
320 else
321 pFrameRectF = NULL;
323 return GdipRecordMetafile(hdc, type, pFrameRectF, frameUnit, desc, metafile);
326 GpStatus WINGDIPAPI GdipRecordMetafileStream(IStream *stream, HDC hdc, EmfType type, GDIPCONST GpRectF *frameRect,
327 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
329 GpStatus stat;
331 TRACE("(%p %p %d %p %d %p %p)\n", stream, hdc, type, frameRect, frameUnit, desc, metafile);
333 if (!stream)
334 return InvalidParameter;
336 stat = GdipRecordMetafile(hdc, type, frameRect, frameUnit, desc, metafile);
338 if (stat == Ok)
340 (*metafile)->record_stream = stream;
341 IStream_AddRef(stream);
344 return stat;
347 static void METAFILE_AdjustFrame(GpMetafile* metafile, const GpPointF *points,
348 UINT num_points)
350 int i;
352 if (!metafile->auto_frame || !num_points)
353 return;
355 if (metafile->auto_frame_max.X < metafile->auto_frame_min.X)
356 metafile->auto_frame_max = metafile->auto_frame_min = points[0];
358 for (i=0; i<num_points; i++)
360 if (points[i].X < metafile->auto_frame_min.X)
361 metafile->auto_frame_min.X = points[i].X;
362 if (points[i].X > metafile->auto_frame_max.X)
363 metafile->auto_frame_max.X = points[i].X;
364 if (points[i].Y < metafile->auto_frame_min.Y)
365 metafile->auto_frame_min.Y = points[i].Y;
366 if (points[i].Y > metafile->auto_frame_max.Y)
367 metafile->auto_frame_max.Y = points[i].Y;
371 GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result)
373 GpStatus stat;
375 if (!metafile->record_dc || metafile->record_graphics)
376 return InvalidParameter;
378 stat = graphics_from_image((GpImage*)metafile, &metafile->record_graphics);
380 if (stat == Ok)
382 *result = metafile->record_graphics;
383 metafile->record_graphics->xres = 96.0;
384 metafile->record_graphics->yres = 96.0;
387 return stat;
390 GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc)
392 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
394 EmfPlusRecordHeader *record;
395 GpStatus stat;
397 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusRecordHeader), (void**)&record);
398 if (stat != Ok)
399 return stat;
401 record->Type = EmfPlusRecordTypeGetDC;
402 record->Flags = 0;
404 METAFILE_WriteRecords(metafile);
407 *hdc = metafile->record_dc;
409 return Ok;
412 GpStatus METAFILE_GraphicsClear(GpMetafile* metafile, ARGB color)
414 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
416 EmfPlusClear *record;
417 GpStatus stat;
419 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusClear), (void**)&record);
420 if (stat != Ok)
421 return stat;
423 record->Header.Type = EmfPlusRecordTypeClear;
424 record->Header.Flags = 0;
425 record->Color = color;
427 METAFILE_WriteRecords(metafile);
430 return Ok;
433 static BOOL is_integer_rect(const GpRectF *rect)
435 SHORT x, y, width, height;
436 x = rect->X;
437 y = rect->Y;
438 width = rect->Width;
439 height = rect->Height;
440 if (rect->X != (REAL)x || rect->Y != (REAL)y ||
441 rect->Width != (REAL)width || rect->Height != (REAL)height)
442 return FALSE;
443 return TRUE;
446 GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush,
447 GDIPCONST GpRectF* rects, INT count)
449 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
451 EmfPlusFillRects *record;
452 GpStatus stat;
453 BOOL integer_rects = TRUE;
454 int i;
455 DWORD brushid;
456 int flags = 0;
458 if (brush->bt == BrushTypeSolidColor)
460 flags |= 0x8000;
461 brushid = ((GpSolidFill*)brush)->color;
463 else
465 FIXME("brush serialization not implemented\n");
466 return NotImplemented;
469 for (i=0; i<count; i++)
471 if (!is_integer_rect(&rects[i]))
473 integer_rects = FALSE;
474 break;
478 if (integer_rects)
479 flags |= 0x4000;
481 stat = METAFILE_AllocateRecord(metafile,
482 sizeof(EmfPlusFillRects) + count * (integer_rects ? sizeof(EmfPlusRect) : sizeof(GpRectF)),
483 (void**)&record);
484 if (stat != Ok)
485 return stat;
487 record->Header.Type = EmfPlusRecordTypeFillRects;
488 record->Header.Flags = flags;
489 record->BrushID = brushid;
490 record->Count = count;
492 if (integer_rects)
494 EmfPlusRect *record_rects = (EmfPlusRect*)(record+1);
495 for (i=0; i<count; i++)
497 record_rects[i].X = (SHORT)rects[i].X;
498 record_rects[i].Y = (SHORT)rects[i].Y;
499 record_rects[i].Width = (SHORT)rects[i].Width;
500 record_rects[i].Height = (SHORT)rects[i].Height;
503 else
504 memcpy(record+1, rects, sizeof(GpRectF) * count);
506 METAFILE_WriteRecords(metafile);
509 if (metafile->auto_frame)
511 GpPointF corners[4];
512 int i;
514 for (i=0; i<count; i++)
516 corners[0].X = rects[i].X;
517 corners[0].Y = rects[i].Y;
518 corners[1].X = rects[i].X + rects[i].Width;
519 corners[1].Y = rects[i].Y;
520 corners[2].X = rects[i].X;
521 corners[2].Y = rects[i].Y + rects[i].Height;
522 corners[3].X = rects[i].X + rects[i].Width;
523 corners[3].Y = rects[i].Y + rects[i].Height;
525 GdipTransformPoints(metafile->record_graphics, CoordinateSpaceDevice,
526 CoordinateSpaceWorld, corners, 4);
528 METAFILE_AdjustFrame(metafile, corners, 4);
532 return Ok;
535 GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale)
537 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
539 EmfPlusSetPageTransform *record;
540 GpStatus stat;
542 stat = METAFILE_AllocateRecord(metafile,
543 sizeof(EmfPlusSetPageTransform),
544 (void**)&record);
545 if (stat != Ok)
546 return stat;
548 record->Header.Type = EmfPlusRecordTypeSetPageTransform;
549 record->Header.Flags = unit;
550 record->PageScale = scale;
552 METAFILE_WriteRecords(metafile);
555 return Ok;
558 GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc)
560 if (hdc != metafile->record_dc)
561 return InvalidParameter;
563 return Ok;
566 GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile)
568 GpStatus stat;
570 stat = METAFILE_WriteEndOfFile(metafile);
571 metafile->record_graphics = NULL;
573 metafile->hemf = CloseEnhMetaFile(metafile->record_dc);
574 metafile->record_dc = NULL;
576 heap_free(metafile->comment_data);
577 metafile->comment_data = NULL;
578 metafile->comment_data_size = 0;
580 if (stat == Ok)
582 MetafileHeader header;
584 stat = GdipGetMetafileHeaderFromEmf(metafile->hemf, &header);
585 if (stat == Ok && metafile->auto_frame &&
586 metafile->auto_frame_max.X >= metafile->auto_frame_min.X)
588 RECTL bounds_rc, gdi_bounds_rc;
589 REAL x_scale = 2540.0 / header.DpiX;
590 REAL y_scale = 2540.0 / header.DpiY;
591 BYTE* buffer;
592 UINT buffer_size;
594 bounds_rc.left = floorf(metafile->auto_frame_min.X * x_scale);
595 bounds_rc.top = floorf(metafile->auto_frame_min.Y * y_scale);
596 bounds_rc.right = ceilf(metafile->auto_frame_max.X * x_scale);
597 bounds_rc.bottom = ceilf(metafile->auto_frame_max.Y * y_scale);
599 gdi_bounds_rc = header.EmfHeader.rclBounds;
600 if (gdi_bounds_rc.right > gdi_bounds_rc.left && gdi_bounds_rc.bottom > gdi_bounds_rc.top)
602 bounds_rc.left = min(bounds_rc.left, gdi_bounds_rc.left);
603 bounds_rc.top = min(bounds_rc.top, gdi_bounds_rc.top);
604 bounds_rc.right = max(bounds_rc.right, gdi_bounds_rc.right);
605 bounds_rc.bottom = max(bounds_rc.bottom, gdi_bounds_rc.bottom);
608 buffer_size = GetEnhMetaFileBits(metafile->hemf, 0, NULL);
609 buffer = heap_alloc(buffer_size);
610 if (buffer)
612 HENHMETAFILE new_hemf;
614 GetEnhMetaFileBits(metafile->hemf, buffer_size, buffer);
616 ((ENHMETAHEADER*)buffer)->rclFrame = bounds_rc;
618 new_hemf = SetEnhMetaFileBits(buffer_size, buffer);
620 if (new_hemf)
622 DeleteEnhMetaFile(metafile->hemf);
623 metafile->hemf = new_hemf;
625 else
626 stat = OutOfMemory;
628 heap_free(buffer);
630 else
631 stat = OutOfMemory;
633 if (stat == Ok)
634 stat = GdipGetMetafileHeaderFromEmf(metafile->hemf, &header);
636 if (stat == Ok)
638 metafile->bounds.X = header.X;
639 metafile->bounds.Y = header.Y;
640 metafile->bounds.Width = header.Width;
641 metafile->bounds.Height = header.Height;
645 if (stat == Ok && metafile->record_stream)
647 BYTE *buffer;
648 UINT buffer_size;
650 buffer_size = GetEnhMetaFileBits(metafile->hemf, 0, NULL);
652 buffer = heap_alloc(buffer_size);
653 if (buffer)
655 HRESULT hr;
657 GetEnhMetaFileBits(metafile->hemf, buffer_size, buffer);
659 hr = IStream_Write(metafile->record_stream, buffer, buffer_size, NULL);
661 if (FAILED(hr))
662 stat = hresult_to_status(hr);
664 heap_free(buffer);
666 else
667 stat = OutOfMemory;
670 if (metafile->record_stream)
672 IStream_Release(metafile->record_stream);
673 metafile->record_stream = NULL;
676 return stat;
679 GpStatus WINGDIPAPI GdipGetHemfFromMetafile(GpMetafile *metafile, HENHMETAFILE *hEmf)
681 TRACE("(%p,%p)\n", metafile, hEmf);
683 if (!metafile || !hEmf || !metafile->hemf)
684 return InvalidParameter;
686 *hEmf = metafile->hemf;
687 metafile->hemf = NULL;
689 return Ok;
692 static GpStatus METAFILE_PlaybackGetDC(GpMetafile *metafile)
694 GpStatus stat = Ok;
696 stat = GdipGetDC(metafile->playback_graphics, &metafile->playback_dc);
698 if (stat == Ok)
700 /* The result of GdipGetDC always expects device co-ordinates, but the
701 * device co-ordinates of the source metafile do not correspond to
702 * device co-ordinates of the destination. Therefore, we set up the DC
703 * so that the metafile's bounds map to the destination points where we
704 * are drawing this metafile. */
705 SetMapMode(metafile->playback_dc, MM_ANISOTROPIC);
707 SetWindowOrgEx(metafile->playback_dc, metafile->bounds.X, metafile->bounds.Y, NULL);
708 SetWindowExtEx(metafile->playback_dc, metafile->bounds.Width, metafile->bounds.Height, NULL);
710 SetViewportOrgEx(metafile->playback_dc, metafile->playback_points[0].X, metafile->playback_points[0].Y, NULL);
711 SetViewportExtEx(metafile->playback_dc,
712 metafile->playback_points[1].X - metafile->playback_points[0].X,
713 metafile->playback_points[2].Y - metafile->playback_points[0].Y, NULL);
716 return stat;
719 static void METAFILE_PlaybackReleaseDC(GpMetafile *metafile)
721 if (metafile->playback_dc)
723 GdipReleaseDC(metafile->playback_graphics, metafile->playback_dc);
724 metafile->playback_dc = NULL;
728 static GpStatus METAFILE_PlaybackUpdateClip(GpMetafile *metafile)
730 return GdipCombineRegionRegion(metafile->playback_graphics->clip, metafile->base_clip, CombineModeReplace);
733 static GpStatus METAFILE_PlaybackUpdateWorldTransform(GpMetafile *metafile)
735 GpMatrix *real_transform;
736 GpStatus stat;
738 stat = GdipCreateMatrix3(&metafile->src_rect, metafile->playback_points, &real_transform);
740 if (stat == Ok)
742 REAL scale = units_to_pixels(1.0, metafile->page_unit, 96.0);
744 if (metafile->page_unit != UnitDisplay)
745 scale *= metafile->page_scale;
747 stat = GdipScaleMatrix(real_transform, scale, scale, MatrixOrderPrepend);
749 if (stat == Ok)
750 stat = GdipMultiplyMatrix(real_transform, metafile->world_transform, MatrixOrderPrepend);
752 if (stat == Ok)
753 stat = GdipSetWorldTransform(metafile->playback_graphics, real_transform);
755 GdipDeleteMatrix(real_transform);
758 return stat;
761 GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
762 EmfPlusRecordType recordType, UINT flags, UINT dataSize, GDIPCONST BYTE *data)
764 GpStatus stat;
765 GpMetafile *real_metafile = (GpMetafile*)metafile;
767 TRACE("(%p,%x,%x,%d,%p)\n", metafile, recordType, flags, dataSize, data);
769 if (!metafile || (dataSize && !data) || !metafile->playback_graphics)
770 return InvalidParameter;
772 if (recordType >= 1 && recordType <= 0x7a)
774 /* regular EMF record */
775 if (metafile->playback_dc)
777 ENHMETARECORD *record;
779 record = heap_alloc_zero(dataSize + 8);
781 if (record)
783 record->iType = recordType;
784 record->nSize = dataSize + 8;
785 memcpy(record->dParm, data, dataSize);
787 PlayEnhMetaFileRecord(metafile->playback_dc, metafile->handle_table,
788 record, metafile->handle_count);
790 heap_free(record);
792 else
793 return OutOfMemory;
796 else
798 EmfPlusRecordHeader *header = (EmfPlusRecordHeader*)(data)-1;
800 METAFILE_PlaybackReleaseDC((GpMetafile*)metafile);
802 switch(recordType)
804 case EmfPlusRecordTypeHeader:
805 case EmfPlusRecordTypeEndOfFile:
806 break;
807 case EmfPlusRecordTypeGetDC:
808 METAFILE_PlaybackGetDC((GpMetafile*)metafile);
809 break;
810 case EmfPlusRecordTypeClear:
812 EmfPlusClear *record = (EmfPlusClear*)header;
814 return GdipGraphicsClear(metafile->playback_graphics, record->Color);
816 case EmfPlusRecordTypeFillRects:
818 EmfPlusFillRects *record = (EmfPlusFillRects*)header;
819 GpBrush *brush, *temp_brush=NULL;
820 GpRectF *rects, *temp_rects=NULL;
822 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects))
823 return InvalidParameter;
825 if (flags & 0x4000)
827 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(EmfPlusRect) * record->Count)
828 return InvalidParameter;
830 else
832 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(GpRectF) * record->Count)
833 return InvalidParameter;
836 if (flags & 0x8000)
838 stat = GdipCreateSolidFill((ARGB)record->BrushID, (GpSolidFill**)&temp_brush);
839 brush = temp_brush;
841 else
843 FIXME("brush deserialization not implemented\n");
844 return NotImplemented;
847 if (stat == Ok)
849 if (flags & 0x4000)
851 EmfPlusRect *int_rects = (EmfPlusRect*)(record+1);
852 int i;
854 rects = temp_rects = heap_alloc_zero(sizeof(GpRectF) * record->Count);
855 if (rects)
857 for (i=0; i<record->Count; i++)
859 rects[i].X = int_rects[i].X;
860 rects[i].Y = int_rects[i].Y;
861 rects[i].Width = int_rects[i].Width;
862 rects[i].Height = int_rects[i].Height;
865 else
866 stat = OutOfMemory;
868 else
869 rects = (GpRectF*)(record+1);
872 if (stat == Ok)
874 stat = GdipFillRectangles(metafile->playback_graphics, brush, rects, record->Count);
877 GdipDeleteBrush(temp_brush);
878 heap_free(temp_rects);
880 return stat;
882 case EmfPlusRecordTypeSetPageTransform:
884 EmfPlusSetPageTransform *record = (EmfPlusSetPageTransform*)header;
885 GpUnit unit = (GpUnit)flags;
887 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusSetPageTransform))
888 return InvalidParameter;
890 real_metafile->page_unit = unit;
891 real_metafile->page_scale = record->PageScale;
893 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
895 default:
896 FIXME("Not implemented for record type %x\n", recordType);
897 return NotImplemented;
901 return Ok;
904 struct enum_metafile_data
906 EnumerateMetafileProc callback;
907 void *callback_data;
908 GpMetafile *metafile;
911 static int CALLBACK enum_metafile_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR,
912 int nObj, LPARAM lpData)
914 BOOL ret;
915 struct enum_metafile_data *data = (struct enum_metafile_data*)lpData;
916 const BYTE* pStr;
918 data->metafile->handle_table = lpHTable;
919 data->metafile->handle_count = nObj;
921 /* First check for an EMF+ record. */
922 if (lpEMFR->iType == EMR_GDICOMMENT)
924 const EMRGDICOMMENT *comment = (const EMRGDICOMMENT*)lpEMFR;
926 if (comment->cbData >= 4 && memcmp(comment->Data, "EMF+", 4) == 0)
928 int offset = 4;
930 while (offset + sizeof(EmfPlusRecordHeader) <= comment->cbData)
932 const EmfPlusRecordHeader *record = (const EmfPlusRecordHeader*)&comment->Data[offset];
934 if (record->DataSize)
935 pStr = (const BYTE*)(record+1);
936 else
937 pStr = NULL;
939 ret = data->callback(record->Type, record->Flags, record->DataSize,
940 pStr, data->callback_data);
942 if (!ret)
943 return 0;
945 offset += record->Size;
948 return 1;
952 if (lpEMFR->nSize != 8)
953 pStr = (const BYTE*)lpEMFR->dParm;
954 else
955 pStr = NULL;
957 return data->callback(lpEMFR->iType, 0, lpEMFR->nSize-8,
958 pStr, data->callback_data);
961 GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics,
962 GDIPCONST GpMetafile *metafile, GDIPCONST GpPointF *destPoints, INT count,
963 GDIPCONST GpRectF *srcRect, Unit srcUnit, EnumerateMetafileProc callback,
964 VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes)
966 struct enum_metafile_data data;
967 GpStatus stat;
968 GpMetafile *real_metafile = (GpMetafile*)metafile; /* whoever made this const was joking */
969 GraphicsContainer state;
970 GpPath *dst_path;
972 TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics, metafile,
973 destPoints, count, srcRect, srcUnit, callback, callbackData,
974 imageAttributes);
976 if (!graphics || !metafile || !destPoints || count != 3 || !srcRect)
977 return InvalidParameter;
979 if (!metafile->hemf)
980 return InvalidParameter;
982 if (metafile->playback_graphics)
983 return ObjectBusy;
985 TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect), srcUnit,
986 debugstr_pointf(&destPoints[0]), debugstr_pointf(&destPoints[1]),
987 debugstr_pointf(&destPoints[2]));
989 data.callback = callback;
990 data.callback_data = callbackData;
991 data.metafile = real_metafile;
993 real_metafile->playback_graphics = graphics;
994 real_metafile->playback_dc = NULL;
995 real_metafile->src_rect = *srcRect;
997 memcpy(real_metafile->playback_points, destPoints, sizeof(PointF) * 3);
998 stat = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, real_metafile->playback_points, 3);
1000 if (stat == Ok)
1001 stat = GdipBeginContainer2(graphics, &state);
1003 if (stat == Ok)
1005 stat = GdipSetPageScale(graphics, 1.0);
1007 if (stat == Ok)
1008 stat = GdipSetPageUnit(graphics, UnitPixel);
1010 if (stat == Ok)
1011 stat = GdipResetWorldTransform(graphics);
1013 if (stat == Ok)
1014 stat = GdipCreateRegion(&real_metafile->base_clip);
1016 if (stat == Ok)
1017 stat = GdipGetClip(graphics, real_metafile->base_clip);
1019 if (stat == Ok)
1020 stat = GdipCreatePath(FillModeAlternate, &dst_path);
1022 if (stat == Ok)
1024 GpPointF clip_points[4];
1026 clip_points[0] = real_metafile->playback_points[0];
1027 clip_points[1] = real_metafile->playback_points[1];
1028 clip_points[2].X = real_metafile->playback_points[1].X + real_metafile->playback_points[2].X
1029 - real_metafile->playback_points[0].X;
1030 clip_points[2].Y = real_metafile->playback_points[1].Y + real_metafile->playback_points[2].Y
1031 - real_metafile->playback_points[0].Y;
1032 clip_points[3] = real_metafile->playback_points[2];
1034 stat = GdipAddPathPolygon(dst_path, clip_points, 4);
1036 if (stat == Ok)
1037 stat = GdipCombineRegionPath(real_metafile->base_clip, dst_path, CombineModeIntersect);
1039 GdipDeletePath(dst_path);
1042 if (stat == Ok)
1043 stat = GdipCreateMatrix(&real_metafile->world_transform);
1045 if (stat == Ok)
1047 real_metafile->page_unit = UnitDisplay;
1048 real_metafile->page_scale = 1.0;
1049 stat = METAFILE_PlaybackUpdateWorldTransform(real_metafile);
1052 if (stat == Ok)
1054 stat = METAFILE_PlaybackUpdateClip(real_metafile);
1057 if (stat == Ok && (metafile->metafile_type == MetafileTypeEmf ||
1058 metafile->metafile_type == MetafileTypeWmfPlaceable ||
1059 metafile->metafile_type == MetafileTypeWmf))
1060 stat = METAFILE_PlaybackGetDC(real_metafile);
1062 if (stat == Ok)
1063 EnumEnhMetaFile(0, metafile->hemf, enum_metafile_proc, &data, NULL);
1065 METAFILE_PlaybackReleaseDC(real_metafile);
1067 GdipDeleteMatrix(real_metafile->world_transform);
1068 real_metafile->world_transform = NULL;
1070 GdipDeleteRegion(real_metafile->base_clip);
1071 real_metafile->base_clip = NULL;
1073 GdipEndContainer(graphics, state);
1076 real_metafile->playback_graphics = NULL;
1078 return stat;
1081 GpStatus WINGDIPAPI GdipEnumerateMetafileDestRect(GpGraphics *graphics,
1082 GDIPCONST GpMetafile *metafile, GDIPCONST GpRectF *dest,
1083 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
1085 GpPointF points[3];
1087 if (!graphics || !metafile || !dest) return InvalidParameter;
1089 points[0].X = points[2].X = dest->X;
1090 points[0].Y = points[1].Y = dest->Y;
1091 points[1].X = dest->X + dest->Width;
1092 points[2].Y = dest->Y + dest->Height;
1094 return GdipEnumerateMetafileSrcRectDestPoints(graphics, metafile, points, 3,
1095 &metafile->bounds, metafile->unit, callback, cb_data, attrs);
1098 GpStatus WINGDIPAPI GdipEnumerateMetafileDestRectI(GpGraphics *graphics,
1099 GDIPCONST GpMetafile *metafile, GDIPCONST GpRect *dest,
1100 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
1102 GpRectF destf;
1104 if (!graphics || !metafile || !dest) return InvalidParameter;
1106 destf.X = dest->X;
1107 destf.Y = dest->Y;
1108 destf.Width = dest->Width;
1109 destf.Height = dest->Height;
1111 return GdipEnumerateMetafileDestRect(graphics, metafile, &destf, callback, cb_data, attrs);
1114 GpStatus WINGDIPAPI GdipEnumerateMetafileDestPoint(GpGraphics *graphics,
1115 GDIPCONST GpMetafile *metafile, GDIPCONST GpPointF *dest,
1116 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
1118 GpRectF destf;
1120 if (!graphics || !metafile || !dest) return InvalidParameter;
1122 destf.X = dest->X;
1123 destf.Y = dest->Y;
1124 destf.Width = units_to_pixels(metafile->bounds.Width, metafile->unit, metafile->image.xres);
1125 destf.Height = units_to_pixels(metafile->bounds.Height, metafile->unit, metafile->image.yres);
1127 return GdipEnumerateMetafileDestRect(graphics, metafile, &destf, callback, cb_data, attrs);
1130 GpStatus WINGDIPAPI GdipEnumerateMetafileDestPointI(GpGraphics *graphics,
1131 GDIPCONST GpMetafile *metafile, GDIPCONST GpPoint *dest,
1132 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
1134 GpPointF ptf;
1136 if (!graphics || !metafile || !dest) return InvalidParameter;
1138 ptf.X = dest->X;
1139 ptf.Y = dest->Y;
1141 return GdipEnumerateMetafileDestPoint(graphics, metafile, &ptf, callback, cb_data, attrs);
1144 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
1145 MetafileHeader * header)
1147 static int calls;
1149 TRACE("(%p, %p)\n", metafile, header);
1151 if(!metafile || !header)
1152 return InvalidParameter;
1154 if(!(calls++))
1155 FIXME("not implemented\n");
1157 memset(header, 0, sizeof(MetafileHeader));
1159 return Ok;
1162 static int CALLBACK get_emfplus_header_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR,
1163 int nObj, LPARAM lpData)
1165 EmfPlusHeader *dst_header = (EmfPlusHeader*)lpData;
1167 if (lpEMFR->iType == EMR_GDICOMMENT)
1169 const EMRGDICOMMENT *comment = (const EMRGDICOMMENT*)lpEMFR;
1171 if (comment->cbData >= 4 && memcmp(comment->Data, "EMF+", 4) == 0)
1173 const EmfPlusRecordHeader *header = (const EmfPlusRecordHeader*)&comment->Data[4];
1175 if (4 + sizeof(EmfPlusHeader) <= comment->cbData &&
1176 header->Type == EmfPlusRecordTypeHeader)
1178 memcpy(dst_header, header, sizeof(*dst_header));
1182 else if (lpEMFR->iType == EMR_HEADER)
1183 return TRUE;
1185 return FALSE;
1188 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromEmf(HENHMETAFILE hemf,
1189 MetafileHeader *header)
1191 ENHMETAHEADER3 emfheader;
1192 EmfPlusHeader emfplusheader;
1193 MetafileType metafile_type;
1195 TRACE("(%p,%p)\n", hemf, header);
1197 if(!hemf || !header)
1198 return InvalidParameter;
1200 if (GetEnhMetaFileHeader(hemf, sizeof(emfheader), (ENHMETAHEADER*)&emfheader) == 0)
1201 return GenericError;
1203 emfplusheader.Header.Type = 0;
1205 EnumEnhMetaFile(NULL, hemf, get_emfplus_header_proc, &emfplusheader, NULL);
1207 if (emfplusheader.Header.Type == EmfPlusRecordTypeHeader)
1209 if ((emfplusheader.Header.Flags & 1) == 1)
1210 metafile_type = MetafileTypeEmfPlusDual;
1211 else
1212 metafile_type = MetafileTypeEmfPlusOnly;
1214 else
1215 metafile_type = MetafileTypeEmf;
1217 header->Type = metafile_type;
1218 header->Size = emfheader.nBytes;
1219 header->DpiX = (REAL)emfheader.szlDevice.cx * 25.4 / emfheader.szlMillimeters.cx;
1220 header->DpiY = (REAL)emfheader.szlDevice.cy * 25.4 / emfheader.szlMillimeters.cy;
1221 header->X = gdip_round((REAL)emfheader.rclFrame.left / 2540.0 * header->DpiX);
1222 header->Y = gdip_round((REAL)emfheader.rclFrame.top / 2540.0 * header->DpiY);
1223 header->Width = gdip_round((REAL)(emfheader.rclFrame.right - emfheader.rclFrame.left) / 2540.0 * header->DpiX);
1224 header->Height = gdip_round((REAL)(emfheader.rclFrame.bottom - emfheader.rclFrame.top) / 2540.0 * header->DpiY);
1225 header->EmfHeader = emfheader;
1227 if (metafile_type == MetafileTypeEmfPlusDual || metafile_type == MetafileTypeEmfPlusOnly)
1229 header->Version = emfplusheader.Version;
1230 header->EmfPlusFlags = emfplusheader.EmfPlusFlags;
1231 header->EmfPlusHeaderSize = emfplusheader.Header.Size;
1232 header->LogicalDpiX = emfplusheader.LogicalDpiX;
1233 header->LogicalDpiY = emfplusheader.LogicalDpiY;
1235 else
1237 header->Version = emfheader.nVersion;
1238 header->EmfPlusFlags = 0;
1239 header->EmfPlusHeaderSize = 0;
1240 header->LogicalDpiX = 0;
1241 header->LogicalDpiY = 0;
1244 return Ok;
1247 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR *filename,
1248 MetafileHeader *header)
1250 static int calls;
1252 TRACE("(%s,%p)\n", debugstr_w(filename), header);
1254 if(!filename || !header)
1255 return InvalidParameter;
1257 if(!(calls++))
1258 FIXME("not implemented\n");
1260 memset(header, 0, sizeof(MetafileHeader));
1262 return Ok;
1265 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromStream(IStream *stream,
1266 MetafileHeader *header)
1268 static int calls;
1270 TRACE("(%p,%p)\n", stream, header);
1272 if(!stream || !header)
1273 return InvalidParameter;
1275 if(!(calls++))
1276 FIXME("not implemented\n");
1278 memset(header, 0, sizeof(MetafileHeader));
1280 return Ok;
1283 GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete,
1284 GpMetafile **metafile)
1286 GpStatus stat;
1287 MetafileHeader header;
1289 TRACE("(%p,%i,%p)\n", hemf, delete, metafile);
1291 if(!hemf || !metafile)
1292 return InvalidParameter;
1294 stat = GdipGetMetafileHeaderFromEmf(hemf, &header);
1295 if (stat != Ok)
1296 return stat;
1298 *metafile = heap_alloc_zero(sizeof(GpMetafile));
1299 if (!*metafile)
1300 return OutOfMemory;
1302 (*metafile)->image.type = ImageTypeMetafile;
1303 (*metafile)->image.format = ImageFormatEMF;
1304 (*metafile)->image.frame_count = 1;
1305 (*metafile)->image.xres = header.DpiX;
1306 (*metafile)->image.yres = header.DpiY;
1307 (*metafile)->bounds.X = (REAL)header.EmfHeader.rclFrame.left / 2540.0 * header.DpiX;
1308 (*metafile)->bounds.Y = (REAL)header.EmfHeader.rclFrame.top / 2540.0 * header.DpiY;
1309 (*metafile)->bounds.Width = (REAL)(header.EmfHeader.rclFrame.right - header.EmfHeader.rclFrame.left)
1310 / 2540.0 * header.DpiX;
1311 (*metafile)->bounds.Height = (REAL)(header.EmfHeader.rclFrame.bottom - header.EmfHeader.rclFrame.top)
1312 / 2540.0 * header.DpiY;
1313 (*metafile)->unit = UnitPixel;
1314 (*metafile)->metafile_type = header.Type;
1315 (*metafile)->hemf = hemf;
1316 (*metafile)->preserve_hemf = !delete;
1318 TRACE("<-- %p\n", *metafile);
1320 return Ok;
1323 GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
1324 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
1326 UINT read;
1327 BYTE *copy;
1328 HENHMETAFILE hemf;
1329 GpStatus retval = Ok;
1331 TRACE("(%p, %d, %p, %p)\n", hwmf, delete, placeable, metafile);
1333 if(!hwmf || !metafile)
1334 return InvalidParameter;
1336 *metafile = NULL;
1337 read = GetMetaFileBitsEx(hwmf, 0, NULL);
1338 if(!read)
1339 return GenericError;
1340 copy = heap_alloc_zero(read);
1341 GetMetaFileBitsEx(hwmf, read, copy);
1343 hemf = SetWinMetaFileBits(read, copy, NULL, NULL);
1344 heap_free(copy);
1346 /* FIXME: We should store and use hwmf instead of converting to hemf */
1347 retval = GdipCreateMetafileFromEmf(hemf, TRUE, metafile);
1349 if (retval == Ok)
1351 if (placeable)
1353 (*metafile)->image.xres = (REAL)placeable->Inch;
1354 (*metafile)->image.yres = (REAL)placeable->Inch;
1355 (*metafile)->bounds.X = ((REAL)placeable->BoundingBox.Left) / ((REAL)placeable->Inch);
1356 (*metafile)->bounds.Y = ((REAL)placeable->BoundingBox.Top) / ((REAL)placeable->Inch);
1357 (*metafile)->bounds.Width = (REAL)(placeable->BoundingBox.Right -
1358 placeable->BoundingBox.Left);
1359 (*metafile)->bounds.Height = (REAL)(placeable->BoundingBox.Bottom -
1360 placeable->BoundingBox.Top);
1361 (*metafile)->metafile_type = MetafileTypeWmfPlaceable;
1363 else
1364 (*metafile)->metafile_type = MetafileTypeWmf;
1365 (*metafile)->image.format = ImageFormatWMF;
1367 if (delete) DeleteMetaFile(hwmf);
1369 else
1370 DeleteEnhMetaFile(hemf);
1371 return retval;
1374 GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file,
1375 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
1377 HMETAFILE hmf = GetMetaFileW(file);
1379 TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile);
1381 if(!hmf) return InvalidParameter;
1383 return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile);
1386 GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file,
1387 GpMetafile **metafile)
1389 FIXME("(%p, %p): stub\n", file, metafile);
1390 return NotImplemented;
1393 GpStatus WINGDIPAPI GdipCreateMetafileFromStream(IStream *stream,
1394 GpMetafile **metafile)
1396 FIXME("(%p, %p): stub\n", stream, metafile);
1397 return NotImplemented;
1400 GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile *metafile,
1401 UINT limitDpi)
1403 TRACE("(%p,%u)\n", metafile, limitDpi);
1405 return Ok;
1408 GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
1409 GpMetafile* metafile, BOOL* succ, EmfType emfType,
1410 const WCHAR* description, GpMetafile** out_metafile)
1412 static int calls;
1414 TRACE("(%p,%p,%p,%u,%s,%p)\n", ref, metafile, succ, emfType,
1415 debugstr_w(description), out_metafile);
1417 if(!ref || !metafile || !out_metafile || emfType < EmfTypeEmfOnly || emfType > EmfTypeEmfPlusDual)
1418 return InvalidParameter;
1420 if(succ)
1421 *succ = FALSE;
1422 *out_metafile = NULL;
1424 if(!(calls++))
1425 FIXME("not implemented\n");
1427 return NotImplemented;
1430 GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE hemf, UINT cbData16,
1431 LPBYTE pData16, INT iMapMode, INT eFlags)
1433 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf, cbData16, pData16, iMapMode, eFlags);
1434 return NotImplemented;
1437 GpStatus WINGDIPAPI GdipRecordMetafileFileName(GDIPCONST WCHAR* fileName,
1438 HDC hdc, EmfType type, GDIPCONST GpRectF *pFrameRect,
1439 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc,
1440 GpMetafile **metafile)
1442 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
1443 frameUnit, debugstr_w(desc), metafile);
1445 return NotImplemented;
1448 GpStatus WINGDIPAPI GdipRecordMetafileFileNameI(GDIPCONST WCHAR* fileName, HDC hdc, EmfType type,
1449 GDIPCONST GpRect *pFrameRect, MetafileFrameUnit frameUnit,
1450 GDIPCONST WCHAR *desc, GpMetafile **metafile)
1452 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
1453 frameUnit, debugstr_w(desc), metafile);
1455 return NotImplemented;
1458 /*****************************************************************************
1459 * GdipConvertToEmfPlusToFile [GDIPLUS.@]
1462 GpStatus WINGDIPAPI GdipConvertToEmfPlusToFile(const GpGraphics* refGraphics,
1463 GpMetafile* metafile, BOOL* conversionSuccess,
1464 const WCHAR* filename, EmfType emfType,
1465 const WCHAR* description, GpMetafile** out_metafile)
1467 FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics, metafile, conversionSuccess, filename, emfType, description, out_metafile);
1468 return NotImplemented;