inetcomm/tests: Return interface pointer for test stream.
[wine.git] / dlls / gdiplus / metafile.c
blobd5b1b14a407c552ffebcdda4212f53333dcba466
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 #define NONAMELESSUNION
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "wine/unicode.h"
29 #define COBJMACROS
30 #include "objbase.h"
31 #include "ocidl.h"
32 #include "olectl.h"
33 #include "ole2.h"
35 #include "winreg.h"
36 #include "shlwapi.h"
38 #include "gdiplus.h"
39 #include "gdiplus_private.h"
40 #include "wine/debug.h"
41 #include "wine/list.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
45 typedef struct EmfPlusRecordHeader
47 WORD Type;
48 WORD Flags;
49 DWORD Size;
50 DWORD DataSize;
51 } EmfPlusRecordHeader;
53 typedef struct EmfPlusHeader
55 EmfPlusRecordHeader Header;
56 DWORD Version;
57 DWORD EmfPlusFlags;
58 DWORD LogicalDpiX;
59 DWORD LogicalDpiY;
60 } EmfPlusHeader;
62 typedef struct EmfPlusClear
64 EmfPlusRecordHeader Header;
65 DWORD Color;
66 } EmfPlusClear;
68 typedef struct EmfPlusFillRects
70 EmfPlusRecordHeader Header;
71 DWORD BrushID;
72 DWORD Count;
73 } EmfPlusFillRects;
75 typedef struct EmfPlusSetClipRect
77 EmfPlusRecordHeader Header;
78 GpRectF ClipRect;
79 } EmfPlusSetClipRect;
81 typedef struct EmfPlusSetPageTransform
83 EmfPlusRecordHeader Header;
84 REAL PageScale;
85 } EmfPlusSetPageTransform;
87 typedef struct EmfPlusRect
89 SHORT X;
90 SHORT Y;
91 SHORT Width;
92 SHORT Height;
93 } EmfPlusRect;
95 typedef struct EmfPlusSetWorldTransform
97 EmfPlusRecordHeader Header;
98 REAL MatrixData[6];
99 } EmfPlusSetWorldTransform;
101 typedef struct EmfPlusScaleWorldTransform
103 EmfPlusRecordHeader Header;
104 REAL Sx;
105 REAL Sy;
106 } EmfPlusScaleWorldTransform;
108 typedef struct EmfPlusMultiplyWorldTransform
110 EmfPlusRecordHeader Header;
111 REAL MatrixData[6];
112 } EmfPlusMultiplyWorldTransform;
114 typedef struct EmfPlusRotateWorldTransform
116 EmfPlusRecordHeader Header;
117 REAL Angle;
118 } EmfPlusRotateWorldTransform;
120 typedef struct EmfPlusTranslateWorldTransform
122 EmfPlusRecordHeader Header;
123 REAL dx;
124 REAL dy;
125 } EmfPlusTranslateWorldTransform;
127 typedef struct EmfPlusBeginContainer
129 EmfPlusRecordHeader Header;
130 GpRectF DestRect;
131 GpRectF SrcRect;
132 DWORD StackIndex;
133 } EmfPlusBeginContainer;
135 typedef struct EmfPlusContainerRecord
137 EmfPlusRecordHeader Header;
138 DWORD StackIndex;
139 } EmfPlusContainerRecord;
141 enum container_type
143 BEGIN_CONTAINER,
144 SAVE_GRAPHICS
147 typedef struct container
149 struct list entry;
150 DWORD id;
151 enum container_type type;
152 GraphicsContainer state;
153 GpMatrix world_transform;
154 GpUnit page_unit;
155 REAL page_scale;
156 GpRegion *clip;
157 } container;
159 static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result)
161 DWORD size_needed;
162 EmfPlusRecordHeader *record;
164 if (!metafile->comment_data_size)
166 DWORD data_size = max(256, size * 2 + 4);
167 metafile->comment_data = heap_alloc_zero(data_size);
169 if (!metafile->comment_data)
170 return OutOfMemory;
172 memcpy(metafile->comment_data, "EMF+", 4);
174 metafile->comment_data_size = data_size;
175 metafile->comment_data_length = 4;
178 size_needed = size + metafile->comment_data_length;
180 if (size_needed > metafile->comment_data_size)
182 DWORD data_size = size_needed * 2;
183 BYTE *new_data = heap_alloc_zero(data_size);
185 if (!new_data)
186 return OutOfMemory;
188 memcpy(new_data, metafile->comment_data, metafile->comment_data_length);
190 metafile->comment_data_size = data_size;
191 heap_free(metafile->comment_data);
192 metafile->comment_data = new_data;
195 *result = metafile->comment_data + metafile->comment_data_length;
196 metafile->comment_data_length += size;
198 record = (EmfPlusRecordHeader*)*result;
199 record->Size = size;
200 record->DataSize = size - sizeof(EmfPlusRecordHeader);
202 return Ok;
205 static void METAFILE_WriteRecords(GpMetafile *metafile)
207 if (metafile->comment_data_length > 4)
209 GdiComment(metafile->record_dc, metafile->comment_data_length, metafile->comment_data);
210 metafile->comment_data_length = 4;
214 static GpStatus METAFILE_WriteHeader(GpMetafile *metafile, HDC hdc)
216 GpStatus stat;
218 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
220 EmfPlusHeader *header;
222 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusHeader), (void**)&header);
223 if (stat != Ok)
224 return stat;
226 header->Header.Type = EmfPlusRecordTypeHeader;
228 if (metafile->metafile_type == MetafileTypeEmfPlusDual)
229 header->Header.Flags = 1;
230 else
231 header->Header.Flags = 0;
233 header->Version = 0xDBC01002;
235 if (GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY)
236 header->EmfPlusFlags = 1;
237 else
238 header->EmfPlusFlags = 0;
240 header->LogicalDpiX = GetDeviceCaps(hdc, LOGPIXELSX);
241 header->LogicalDpiY = GetDeviceCaps(hdc, LOGPIXELSY);
243 METAFILE_WriteRecords(metafile);
246 return Ok;
249 static GpStatus METAFILE_WriteEndOfFile(GpMetafile *metafile)
251 GpStatus stat;
253 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
255 EmfPlusRecordHeader *record;
257 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusRecordHeader), (void**)&record);
258 if (stat != Ok)
259 return stat;
261 record->Type = EmfPlusRecordTypeEndOfFile;
262 record->Flags = 0;
264 METAFILE_WriteRecords(metafile);
267 return Ok;
270 GpStatus WINGDIPAPI GdipRecordMetafile(HDC hdc, EmfType type, GDIPCONST GpRectF *frameRect,
271 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
273 HDC record_dc;
274 REAL dpix, dpiy;
275 REAL framerect_factor_x, framerect_factor_y;
276 RECT rc, *lprc;
277 GpStatus stat;
279 TRACE("(%p %d %p %d %p %p)\n", hdc, type, frameRect, frameUnit, desc, metafile);
281 if (!hdc || type < EmfTypeEmfOnly || type > EmfTypeEmfPlusDual || !metafile)
282 return InvalidParameter;
284 dpix = (REAL)GetDeviceCaps(hdc, HORZRES) / GetDeviceCaps(hdc, HORZSIZE) * 25.4;
285 dpiy = (REAL)GetDeviceCaps(hdc, VERTRES) / GetDeviceCaps(hdc, VERTSIZE) * 25.4;
287 if (frameRect)
289 switch (frameUnit)
291 case MetafileFrameUnitPixel:
292 framerect_factor_x = 2540.0 / dpix;
293 framerect_factor_y = 2540.0 / dpiy;
294 break;
295 case MetafileFrameUnitPoint:
296 framerect_factor_x = framerect_factor_y = 2540.0 / 72.0;
297 break;
298 case MetafileFrameUnitInch:
299 framerect_factor_x = framerect_factor_y = 2540.0;
300 break;
301 case MetafileFrameUnitDocument:
302 framerect_factor_x = framerect_factor_y = 2540.0 / 300.0;
303 break;
304 case MetafileFrameUnitMillimeter:
305 framerect_factor_x = framerect_factor_y = 100.0;
306 break;
307 case MetafileFrameUnitGdi:
308 framerect_factor_x = framerect_factor_y = 1.0;
309 break;
310 default:
311 return InvalidParameter;
314 rc.left = framerect_factor_x * frameRect->X;
315 rc.top = framerect_factor_y * frameRect->Y;
316 rc.right = rc.left + framerect_factor_x * frameRect->Width;
317 rc.bottom = rc.top + framerect_factor_y * frameRect->Height;
319 lprc = &rc;
321 else
322 lprc = NULL;
324 record_dc = CreateEnhMetaFileW(hdc, NULL, lprc, desc);
326 if (!record_dc)
327 return GenericError;
329 *metafile = heap_alloc_zero(sizeof(GpMetafile));
330 if(!*metafile)
332 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc));
333 return OutOfMemory;
336 (*metafile)->image.type = ImageTypeMetafile;
337 (*metafile)->image.flags = ImageFlagsNone;
338 (*metafile)->image.palette = NULL;
339 (*metafile)->image.xres = dpix;
340 (*metafile)->image.yres = dpiy;
341 (*metafile)->bounds.X = (*metafile)->bounds.Y = 0.0;
342 (*metafile)->bounds.Width = (*metafile)->bounds.Height = 1.0;
343 (*metafile)->unit = UnitPixel;
344 (*metafile)->metafile_type = type;
345 (*metafile)->record_dc = record_dc;
346 (*metafile)->comment_data = NULL;
347 (*metafile)->comment_data_size = 0;
348 (*metafile)->comment_data_length = 0;
349 (*metafile)->hemf = NULL;
350 list_init(&(*metafile)->containers);
352 if (!frameRect)
354 (*metafile)->auto_frame = TRUE;
355 (*metafile)->auto_frame_min.X = 0;
356 (*metafile)->auto_frame_min.Y = 0;
357 (*metafile)->auto_frame_max.X = -1;
358 (*metafile)->auto_frame_max.Y = -1;
361 stat = METAFILE_WriteHeader(*metafile, hdc);
363 if (stat != Ok)
365 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc));
366 heap_free(*metafile);
367 *metafile = NULL;
368 return OutOfMemory;
371 return stat;
374 /*****************************************************************************
375 * GdipRecordMetafileI [GDIPLUS.@]
377 GpStatus WINGDIPAPI GdipRecordMetafileI(HDC hdc, EmfType type, GDIPCONST GpRect *frameRect,
378 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
380 GpRectF frameRectF, *pFrameRectF;
382 TRACE("(%p %d %p %d %p %p)\n", hdc, type, frameRect, frameUnit, desc, metafile);
384 if (frameRect)
386 frameRectF.X = frameRect->X;
387 frameRectF.Y = frameRect->Y;
388 frameRectF.Width = frameRect->Width;
389 frameRectF.Height = frameRect->Height;
390 pFrameRectF = &frameRectF;
392 else
393 pFrameRectF = NULL;
395 return GdipRecordMetafile(hdc, type, pFrameRectF, frameUnit, desc, metafile);
398 GpStatus WINGDIPAPI GdipRecordMetafileStream(IStream *stream, HDC hdc, EmfType type, GDIPCONST GpRectF *frameRect,
399 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
401 GpStatus stat;
403 TRACE("(%p %p %d %p %d %p %p)\n", stream, hdc, type, frameRect, frameUnit, desc, metafile);
405 if (!stream)
406 return InvalidParameter;
408 stat = GdipRecordMetafile(hdc, type, frameRect, frameUnit, desc, metafile);
410 if (stat == Ok)
412 (*metafile)->record_stream = stream;
413 IStream_AddRef(stream);
416 return stat;
419 static void METAFILE_AdjustFrame(GpMetafile* metafile, const GpPointF *points,
420 UINT num_points)
422 int i;
424 if (!metafile->auto_frame || !num_points)
425 return;
427 if (metafile->auto_frame_max.X < metafile->auto_frame_min.X)
428 metafile->auto_frame_max = metafile->auto_frame_min = points[0];
430 for (i=0; i<num_points; i++)
432 if (points[i].X < metafile->auto_frame_min.X)
433 metafile->auto_frame_min.X = points[i].X;
434 if (points[i].X > metafile->auto_frame_max.X)
435 metafile->auto_frame_max.X = points[i].X;
436 if (points[i].Y < metafile->auto_frame_min.Y)
437 metafile->auto_frame_min.Y = points[i].Y;
438 if (points[i].Y > metafile->auto_frame_max.Y)
439 metafile->auto_frame_max.Y = points[i].Y;
443 GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result)
445 GpStatus stat;
447 if (!metafile->record_dc || metafile->record_graphics)
448 return InvalidParameter;
450 stat = graphics_from_image((GpImage*)metafile, &metafile->record_graphics);
452 if (stat == Ok)
454 *result = metafile->record_graphics;
455 metafile->record_graphics->xres = 96.0;
456 metafile->record_graphics->yres = 96.0;
459 return stat;
462 GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc)
464 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
466 EmfPlusRecordHeader *record;
467 GpStatus stat;
469 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusRecordHeader), (void**)&record);
470 if (stat != Ok)
471 return stat;
473 record->Type = EmfPlusRecordTypeGetDC;
474 record->Flags = 0;
476 METAFILE_WriteRecords(metafile);
479 *hdc = metafile->record_dc;
481 return Ok;
484 GpStatus METAFILE_GraphicsClear(GpMetafile* metafile, ARGB color)
486 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
488 EmfPlusClear *record;
489 GpStatus stat;
491 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusClear), (void**)&record);
492 if (stat != Ok)
493 return stat;
495 record->Header.Type = EmfPlusRecordTypeClear;
496 record->Header.Flags = 0;
497 record->Color = color;
499 METAFILE_WriteRecords(metafile);
502 return Ok;
505 static BOOL is_integer_rect(const GpRectF *rect)
507 SHORT x, y, width, height;
508 x = rect->X;
509 y = rect->Y;
510 width = rect->Width;
511 height = rect->Height;
512 if (rect->X != (REAL)x || rect->Y != (REAL)y ||
513 rect->Width != (REAL)width || rect->Height != (REAL)height)
514 return FALSE;
515 return TRUE;
518 GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush,
519 GDIPCONST GpRectF* rects, INT count)
521 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
523 EmfPlusFillRects *record;
524 GpStatus stat;
525 BOOL integer_rects = TRUE;
526 int i;
527 DWORD brushid;
528 int flags = 0;
530 if (brush->bt == BrushTypeSolidColor)
532 flags |= 0x8000;
533 brushid = ((GpSolidFill*)brush)->color;
535 else
537 FIXME("brush serialization not implemented\n");
538 return NotImplemented;
541 for (i=0; i<count; i++)
543 if (!is_integer_rect(&rects[i]))
545 integer_rects = FALSE;
546 break;
550 if (integer_rects)
551 flags |= 0x4000;
553 stat = METAFILE_AllocateRecord(metafile,
554 sizeof(EmfPlusFillRects) + count * (integer_rects ? sizeof(EmfPlusRect) : sizeof(GpRectF)),
555 (void**)&record);
556 if (stat != Ok)
557 return stat;
559 record->Header.Type = EmfPlusRecordTypeFillRects;
560 record->Header.Flags = flags;
561 record->BrushID = brushid;
562 record->Count = count;
564 if (integer_rects)
566 EmfPlusRect *record_rects = (EmfPlusRect*)(record+1);
567 for (i=0; i<count; i++)
569 record_rects[i].X = (SHORT)rects[i].X;
570 record_rects[i].Y = (SHORT)rects[i].Y;
571 record_rects[i].Width = (SHORT)rects[i].Width;
572 record_rects[i].Height = (SHORT)rects[i].Height;
575 else
576 memcpy(record+1, rects, sizeof(GpRectF) * count);
578 METAFILE_WriteRecords(metafile);
581 if (metafile->auto_frame)
583 GpPointF corners[4];
584 int i;
586 for (i=0; i<count; i++)
588 corners[0].X = rects[i].X;
589 corners[0].Y = rects[i].Y;
590 corners[1].X = rects[i].X + rects[i].Width;
591 corners[1].Y = rects[i].Y;
592 corners[2].X = rects[i].X;
593 corners[2].Y = rects[i].Y + rects[i].Height;
594 corners[3].X = rects[i].X + rects[i].Width;
595 corners[3].Y = rects[i].Y + rects[i].Height;
597 GdipTransformPoints(metafile->record_graphics, CoordinateSpaceDevice,
598 CoordinateSpaceWorld, corners, 4);
600 METAFILE_AdjustFrame(metafile, corners, 4);
604 return Ok;
607 GpStatus METAFILE_SetClipRect(GpMetafile* metafile, REAL x, REAL y, REAL width, REAL height, CombineMode mode)
609 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
611 EmfPlusSetClipRect *record;
612 GpStatus stat;
614 stat = METAFILE_AllocateRecord(metafile,
615 sizeof(EmfPlusSetClipRect),
616 (void**)&record);
617 if (stat != Ok)
618 return stat;
620 record->Header.Type = EmfPlusRecordTypeSetClipRect;
621 record->Header.Flags = (mode & 0xf) << 8;
622 record->ClipRect.X = x;
623 record->ClipRect.Y = y;
624 record->ClipRect.Width = width;
625 record->ClipRect.Height = height;
627 METAFILE_WriteRecords(metafile);
630 return Ok;
633 GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale)
635 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
637 EmfPlusSetPageTransform *record;
638 GpStatus stat;
640 stat = METAFILE_AllocateRecord(metafile,
641 sizeof(EmfPlusSetPageTransform),
642 (void**)&record);
643 if (stat != Ok)
644 return stat;
646 record->Header.Type = EmfPlusRecordTypeSetPageTransform;
647 record->Header.Flags = unit;
648 record->PageScale = scale;
650 METAFILE_WriteRecords(metafile);
653 return Ok;
656 GpStatus METAFILE_SetWorldTransform(GpMetafile* metafile, GDIPCONST GpMatrix* transform)
658 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
660 EmfPlusSetWorldTransform *record;
661 GpStatus stat;
663 stat = METAFILE_AllocateRecord(metafile,
664 sizeof(EmfPlusSetWorldTransform),
665 (void**)&record);
666 if (stat != Ok)
667 return stat;
669 record->Header.Type = EmfPlusRecordTypeSetWorldTransform;
670 record->Header.Flags = 0;
671 memcpy(record->MatrixData, transform->matrix, sizeof(record->MatrixData));
673 METAFILE_WriteRecords(metafile);
676 return Ok;
679 GpStatus METAFILE_ScaleWorldTransform(GpMetafile* metafile, REAL sx, REAL sy, MatrixOrder order)
681 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
683 EmfPlusScaleWorldTransform *record;
684 GpStatus stat;
686 stat = METAFILE_AllocateRecord(metafile,
687 sizeof(EmfPlusScaleWorldTransform),
688 (void**)&record);
689 if (stat != Ok)
690 return stat;
692 record->Header.Type = EmfPlusRecordTypeScaleWorldTransform;
693 record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0);
694 record->Sx = sx;
695 record->Sy = sy;
697 METAFILE_WriteRecords(metafile);
700 return Ok;
703 GpStatus METAFILE_MultiplyWorldTransform(GpMetafile* metafile, GDIPCONST GpMatrix* matrix, MatrixOrder order)
705 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
707 EmfPlusMultiplyWorldTransform *record;
708 GpStatus stat;
710 stat = METAFILE_AllocateRecord(metafile,
711 sizeof(EmfPlusMultiplyWorldTransform),
712 (void**)&record);
713 if (stat != Ok)
714 return stat;
716 record->Header.Type = EmfPlusRecordTypeMultiplyWorldTransform;
717 record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0);
718 memcpy(record->MatrixData, matrix->matrix, sizeof(record->MatrixData));
720 METAFILE_WriteRecords(metafile);
723 return Ok;
726 GpStatus METAFILE_RotateWorldTransform(GpMetafile* metafile, REAL angle, MatrixOrder order)
728 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
730 EmfPlusRotateWorldTransform *record;
731 GpStatus stat;
733 stat = METAFILE_AllocateRecord(metafile,
734 sizeof(EmfPlusRotateWorldTransform),
735 (void**)&record);
736 if (stat != Ok)
737 return stat;
739 record->Header.Type = EmfPlusRecordTypeRotateWorldTransform;
740 record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0);
741 record->Angle = angle;
743 METAFILE_WriteRecords(metafile);
746 return Ok;
749 GpStatus METAFILE_TranslateWorldTransform(GpMetafile* metafile, REAL dx, REAL dy, MatrixOrder order)
751 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
753 EmfPlusTranslateWorldTransform *record;
754 GpStatus stat;
756 stat = METAFILE_AllocateRecord(metafile,
757 sizeof(EmfPlusTranslateWorldTransform),
758 (void**)&record);
759 if (stat != Ok)
760 return stat;
762 record->Header.Type = EmfPlusRecordTypeTranslateWorldTransform;
763 record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0);
764 record->dx = dx;
765 record->dy = dy;
767 METAFILE_WriteRecords(metafile);
770 return Ok;
773 GpStatus METAFILE_ResetWorldTransform(GpMetafile* metafile)
775 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
777 EmfPlusRecordHeader *record;
778 GpStatus stat;
780 stat = METAFILE_AllocateRecord(metafile,
781 sizeof(EmfPlusRecordHeader),
782 (void**)&record);
783 if (stat != Ok)
784 return stat;
786 record->Type = EmfPlusRecordTypeResetWorldTransform;
787 record->Flags = 0;
789 METAFILE_WriteRecords(metafile);
792 return Ok;
795 GpStatus METAFILE_BeginContainer(GpMetafile* metafile, GDIPCONST GpRectF *dstrect,
796 GDIPCONST GpRectF *srcrect, GpUnit unit, DWORD StackIndex)
798 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
800 EmfPlusBeginContainer *record;
801 GpStatus stat;
803 stat = METAFILE_AllocateRecord(metafile, sizeof(*record), (void**)&record);
804 if (stat != Ok)
805 return stat;
807 record->Header.Type = EmfPlusRecordTypeBeginContainer;
808 record->Header.Flags = unit & 0xff;
809 record->DestRect = *dstrect;
810 record->SrcRect = *srcrect;
811 record->StackIndex = StackIndex;
813 METAFILE_WriteRecords(metafile);
816 return Ok;
819 GpStatus METAFILE_BeginContainerNoParams(GpMetafile* metafile, DWORD StackIndex)
821 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
823 EmfPlusContainerRecord *record;
824 GpStatus stat;
826 stat = METAFILE_AllocateRecord(metafile,
827 sizeof(EmfPlusContainerRecord),
828 (void**)&record);
829 if (stat != Ok)
830 return stat;
832 record->Header.Type = EmfPlusRecordTypeBeginContainerNoParams;
833 record->Header.Flags = 0;
834 record->StackIndex = StackIndex;
836 METAFILE_WriteRecords(metafile);
839 return Ok;
842 GpStatus METAFILE_EndContainer(GpMetafile* metafile, DWORD StackIndex)
844 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
846 EmfPlusContainerRecord *record;
847 GpStatus stat;
849 stat = METAFILE_AllocateRecord(metafile,
850 sizeof(EmfPlusContainerRecord),
851 (void**)&record);
852 if (stat != Ok)
853 return stat;
855 record->Header.Type = EmfPlusRecordTypeEndContainer;
856 record->Header.Flags = 0;
857 record->StackIndex = StackIndex;
859 METAFILE_WriteRecords(metafile);
862 return Ok;
865 GpStatus METAFILE_SaveGraphics(GpMetafile* metafile, DWORD StackIndex)
867 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
869 EmfPlusContainerRecord *record;
870 GpStatus stat;
872 stat = METAFILE_AllocateRecord(metafile,
873 sizeof(EmfPlusContainerRecord),
874 (void**)&record);
875 if (stat != Ok)
876 return stat;
878 record->Header.Type = EmfPlusRecordTypeSave;
879 record->Header.Flags = 0;
880 record->StackIndex = StackIndex;
882 METAFILE_WriteRecords(metafile);
885 return Ok;
888 GpStatus METAFILE_RestoreGraphics(GpMetafile* metafile, DWORD StackIndex)
890 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
892 EmfPlusContainerRecord *record;
893 GpStatus stat;
895 stat = METAFILE_AllocateRecord(metafile,
896 sizeof(EmfPlusContainerRecord),
897 (void**)&record);
898 if (stat != Ok)
899 return stat;
901 record->Header.Type = EmfPlusRecordTypeRestore;
902 record->Header.Flags = 0;
903 record->StackIndex = StackIndex;
905 METAFILE_WriteRecords(metafile);
908 return Ok;
911 GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc)
913 if (hdc != metafile->record_dc)
914 return InvalidParameter;
916 return Ok;
919 GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile)
921 GpStatus stat;
923 stat = METAFILE_WriteEndOfFile(metafile);
924 metafile->record_graphics = NULL;
926 metafile->hemf = CloseEnhMetaFile(metafile->record_dc);
927 metafile->record_dc = NULL;
929 heap_free(metafile->comment_data);
930 metafile->comment_data = NULL;
931 metafile->comment_data_size = 0;
933 if (stat == Ok)
935 MetafileHeader header;
937 stat = GdipGetMetafileHeaderFromEmf(metafile->hemf, &header);
938 if (stat == Ok && metafile->auto_frame &&
939 metafile->auto_frame_max.X >= metafile->auto_frame_min.X)
941 RECTL bounds_rc, gdi_bounds_rc;
942 REAL x_scale = 2540.0 / header.DpiX;
943 REAL y_scale = 2540.0 / header.DpiY;
944 BYTE* buffer;
945 UINT buffer_size;
947 bounds_rc.left = floorf(metafile->auto_frame_min.X * x_scale);
948 bounds_rc.top = floorf(metafile->auto_frame_min.Y * y_scale);
949 bounds_rc.right = ceilf(metafile->auto_frame_max.X * x_scale);
950 bounds_rc.bottom = ceilf(metafile->auto_frame_max.Y * y_scale);
952 gdi_bounds_rc = header.u.EmfHeader.rclBounds;
953 if (gdi_bounds_rc.right > gdi_bounds_rc.left && gdi_bounds_rc.bottom > gdi_bounds_rc.top)
955 bounds_rc.left = min(bounds_rc.left, gdi_bounds_rc.left);
956 bounds_rc.top = min(bounds_rc.top, gdi_bounds_rc.top);
957 bounds_rc.right = max(bounds_rc.right, gdi_bounds_rc.right);
958 bounds_rc.bottom = max(bounds_rc.bottom, gdi_bounds_rc.bottom);
961 buffer_size = GetEnhMetaFileBits(metafile->hemf, 0, NULL);
962 buffer = heap_alloc(buffer_size);
963 if (buffer)
965 HENHMETAFILE new_hemf;
967 GetEnhMetaFileBits(metafile->hemf, buffer_size, buffer);
969 ((ENHMETAHEADER*)buffer)->rclFrame = bounds_rc;
971 new_hemf = SetEnhMetaFileBits(buffer_size, buffer);
973 if (new_hemf)
975 DeleteEnhMetaFile(metafile->hemf);
976 metafile->hemf = new_hemf;
978 else
979 stat = OutOfMemory;
981 heap_free(buffer);
983 else
984 stat = OutOfMemory;
986 if (stat == Ok)
987 stat = GdipGetMetafileHeaderFromEmf(metafile->hemf, &header);
989 if (stat == Ok)
991 metafile->bounds.X = header.X;
992 metafile->bounds.Y = header.Y;
993 metafile->bounds.Width = header.Width;
994 metafile->bounds.Height = header.Height;
998 if (stat == Ok && metafile->record_stream)
1000 BYTE *buffer;
1001 UINT buffer_size;
1003 buffer_size = GetEnhMetaFileBits(metafile->hemf, 0, NULL);
1005 buffer = heap_alloc(buffer_size);
1006 if (buffer)
1008 HRESULT hr;
1010 GetEnhMetaFileBits(metafile->hemf, buffer_size, buffer);
1012 hr = IStream_Write(metafile->record_stream, buffer, buffer_size, NULL);
1014 if (FAILED(hr))
1015 stat = hresult_to_status(hr);
1017 heap_free(buffer);
1019 else
1020 stat = OutOfMemory;
1023 if (metafile->record_stream)
1025 IStream_Release(metafile->record_stream);
1026 metafile->record_stream = NULL;
1029 return stat;
1032 GpStatus WINGDIPAPI GdipGetHemfFromMetafile(GpMetafile *metafile, HENHMETAFILE *hEmf)
1034 TRACE("(%p,%p)\n", metafile, hEmf);
1036 if (!metafile || !hEmf || !metafile->hemf)
1037 return InvalidParameter;
1039 *hEmf = metafile->hemf;
1040 metafile->hemf = NULL;
1042 return Ok;
1045 static void METAFILE_GetFinalGdiTransform(const GpMetafile *metafile, XFORM *result)
1047 const GpRectF *rect;
1048 const GpPointF *pt;
1050 /* This transforms metafile device space to output points. */
1051 rect = &metafile->src_rect;
1052 pt = metafile->playback_points;
1053 result->eM11 = (pt[1].X - pt[0].X) / rect->Width;
1054 result->eM21 = (pt[2].X - pt[0].X) / rect->Height;
1055 result->eDx = pt[0].X - result->eM11 * rect->X - result->eM21 * rect->Y;
1056 result->eM12 = (pt[1].Y - pt[0].Y) / rect->Width;
1057 result->eM22 = (pt[2].Y - pt[0].Y) / rect->Height;
1058 result->eDy = pt[0].Y - result->eM12 * rect->X - result->eM22 * rect->Y;
1061 static GpStatus METAFILE_PlaybackUpdateGdiTransform(GpMetafile *metafile)
1063 XFORM combined, final;
1065 METAFILE_GetFinalGdiTransform(metafile, &final);
1067 CombineTransform(&combined, &metafile->gdiworldtransform, &final);
1069 SetGraphicsMode(metafile->playback_dc, GM_ADVANCED);
1070 SetWorldTransform(metafile->playback_dc, &combined);
1072 return Ok;
1075 static GpStatus METAFILE_PlaybackGetDC(GpMetafile *metafile)
1077 GpStatus stat = Ok;
1079 stat = GdipGetDC(metafile->playback_graphics, &metafile->playback_dc);
1081 if (stat == Ok)
1083 static const XFORM identity = {1, 0, 0, 1, 0, 0};
1085 metafile->gdiworldtransform = identity;
1086 METAFILE_PlaybackUpdateGdiTransform(metafile);
1089 return stat;
1092 static void METAFILE_PlaybackReleaseDC(GpMetafile *metafile)
1094 if (metafile->playback_dc)
1096 GdipReleaseDC(metafile->playback_graphics, metafile->playback_dc);
1097 metafile->playback_dc = NULL;
1101 static GpStatus METAFILE_PlaybackUpdateClip(GpMetafile *metafile)
1103 GpStatus stat;
1104 stat = GdipCombineRegionRegion(metafile->playback_graphics->clip, metafile->base_clip, CombineModeReplace);
1105 if (stat == Ok)
1106 stat = GdipCombineRegionRegion(metafile->playback_graphics->clip, metafile->clip, CombineModeIntersect);
1107 return stat;
1110 static GpStatus METAFILE_PlaybackUpdateWorldTransform(GpMetafile *metafile)
1112 GpMatrix *real_transform;
1113 GpStatus stat;
1115 stat = GdipCreateMatrix3(&metafile->src_rect, metafile->playback_points, &real_transform);
1117 if (stat == Ok)
1119 REAL scale = units_to_pixels(1.0, metafile->page_unit, 96.0);
1121 if (metafile->page_unit != UnitDisplay)
1122 scale *= metafile->page_scale;
1124 stat = GdipScaleMatrix(real_transform, scale, scale, MatrixOrderPrepend);
1126 if (stat == Ok)
1127 stat = GdipMultiplyMatrix(real_transform, metafile->world_transform, MatrixOrderPrepend);
1129 if (stat == Ok)
1130 stat = GdipSetWorldTransform(metafile->playback_graphics, real_transform);
1132 GdipDeleteMatrix(real_transform);
1135 return stat;
1138 GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
1139 EmfPlusRecordType recordType, UINT flags, UINT dataSize, GDIPCONST BYTE *data)
1141 GpStatus stat;
1142 GpMetafile *real_metafile = (GpMetafile*)metafile;
1144 TRACE("(%p,%x,%x,%d,%p)\n", metafile, recordType, flags, dataSize, data);
1146 if (!metafile || (dataSize && !data) || !metafile->playback_graphics)
1147 return InvalidParameter;
1149 if (recordType >= 1 && recordType <= 0x7a)
1151 /* regular EMF record */
1152 if (metafile->playback_dc)
1154 ENHMETARECORD *record;
1156 switch (recordType)
1158 case EMR_SETMAPMODE:
1159 case EMR_SAVEDC:
1160 case EMR_RESTOREDC:
1161 case EMR_SETWINDOWORGEX:
1162 case EMR_SETWINDOWEXTEX:
1163 case EMR_SETVIEWPORTORGEX:
1164 case EMR_SETVIEWPORTEXTEX:
1165 case EMR_SCALEVIEWPORTEXTEX:
1166 case EMR_SCALEWINDOWEXTEX:
1167 case EMR_MODIFYWORLDTRANSFORM:
1168 FIXME("not implemented for record type %x\n", recordType);
1169 break;
1170 case EMR_SETWORLDTRANSFORM:
1172 const XFORM* xform = (void*)data;
1173 real_metafile->gdiworldtransform = *xform;
1174 METAFILE_PlaybackUpdateGdiTransform(real_metafile);
1175 break;
1177 case EMR_EXTSELECTCLIPRGN:
1179 DWORD rgndatasize = *(DWORD*)data;
1180 DWORD mode = *(DWORD*)(data + 4);
1181 const RGNDATA *rgndata = (const RGNDATA*)(data + 8);
1182 HRGN hrgn = NULL;
1184 if (dataSize > 8)
1186 XFORM final;
1188 METAFILE_GetFinalGdiTransform(metafile, &final);
1190 hrgn = ExtCreateRegion(&final, rgndatasize, rgndata);
1193 ExtSelectClipRgn(metafile->playback_dc, hrgn, mode);
1195 DeleteObject(hrgn);
1197 return Ok;
1199 default:
1200 break;
1203 record = heap_alloc_zero(dataSize + 8);
1205 if (record)
1207 record->iType = recordType;
1208 record->nSize = dataSize + 8;
1209 memcpy(record->dParm, data, dataSize);
1211 PlayEnhMetaFileRecord(metafile->playback_dc, metafile->handle_table,
1212 record, metafile->handle_count);
1214 heap_free(record);
1216 else
1217 return OutOfMemory;
1220 else
1222 EmfPlusRecordHeader *header = (EmfPlusRecordHeader*)(data)-1;
1224 METAFILE_PlaybackReleaseDC((GpMetafile*)metafile);
1226 switch(recordType)
1228 case EmfPlusRecordTypeHeader:
1229 case EmfPlusRecordTypeEndOfFile:
1230 break;
1231 case EmfPlusRecordTypeGetDC:
1232 METAFILE_PlaybackGetDC((GpMetafile*)metafile);
1233 break;
1234 case EmfPlusRecordTypeClear:
1236 EmfPlusClear *record = (EmfPlusClear*)header;
1238 return GdipGraphicsClear(metafile->playback_graphics, record->Color);
1240 case EmfPlusRecordTypeFillRects:
1242 EmfPlusFillRects *record = (EmfPlusFillRects*)header;
1243 GpBrush *brush, *temp_brush=NULL;
1244 GpRectF *rects, *temp_rects=NULL;
1246 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects))
1247 return InvalidParameter;
1249 if (flags & 0x4000)
1251 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(EmfPlusRect) * record->Count)
1252 return InvalidParameter;
1254 else
1256 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(GpRectF) * record->Count)
1257 return InvalidParameter;
1260 if (flags & 0x8000)
1262 stat = GdipCreateSolidFill((ARGB)record->BrushID, (GpSolidFill**)&temp_brush);
1263 brush = temp_brush;
1265 else
1267 FIXME("brush deserialization not implemented\n");
1268 return NotImplemented;
1271 if (stat == Ok)
1273 if (flags & 0x4000)
1275 EmfPlusRect *int_rects = (EmfPlusRect*)(record+1);
1276 int i;
1278 rects = temp_rects = heap_alloc_zero(sizeof(GpRectF) * record->Count);
1279 if (rects)
1281 for (i=0; i<record->Count; i++)
1283 rects[i].X = int_rects[i].X;
1284 rects[i].Y = int_rects[i].Y;
1285 rects[i].Width = int_rects[i].Width;
1286 rects[i].Height = int_rects[i].Height;
1289 else
1290 stat = OutOfMemory;
1292 else
1293 rects = (GpRectF*)(record+1);
1296 if (stat == Ok)
1298 stat = GdipFillRectangles(metafile->playback_graphics, brush, rects, record->Count);
1301 GdipDeleteBrush(temp_brush);
1302 heap_free(temp_rects);
1304 return stat;
1306 case EmfPlusRecordTypeSetClipRect:
1308 EmfPlusSetClipRect *record = (EmfPlusSetClipRect*)header;
1309 CombineMode mode = (CombineMode)((flags >> 8) & 0xf);
1310 GpRegion *region;
1311 GpMatrix world_to_device;
1313 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(*record))
1314 return InvalidParameter;
1316 stat = GdipCreateRegionRect(&record->ClipRect, &region);
1318 if (stat == Ok)
1320 get_graphics_transform(real_metafile->playback_graphics,
1321 CoordinateSpaceDevice, CoordinateSpaceWorld, &world_to_device);
1323 GdipTransformRegion(region, &world_to_device);
1325 GdipCombineRegionRegion(real_metafile->clip, region, mode);
1327 GdipDeleteRegion(region);
1330 return METAFILE_PlaybackUpdateClip(real_metafile);
1332 case EmfPlusRecordTypeSetPageTransform:
1334 EmfPlusSetPageTransform *record = (EmfPlusSetPageTransform*)header;
1335 GpUnit unit = (GpUnit)flags;
1337 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusSetPageTransform))
1338 return InvalidParameter;
1340 real_metafile->page_unit = unit;
1341 real_metafile->page_scale = record->PageScale;
1343 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
1345 case EmfPlusRecordTypeSetWorldTransform:
1347 EmfPlusSetWorldTransform *record = (EmfPlusSetWorldTransform*)header;
1349 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusSetWorldTransform))
1350 return InvalidParameter;
1352 memcpy(real_metafile->world_transform->matrix, record->MatrixData, sizeof(record->MatrixData));
1354 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
1356 case EmfPlusRecordTypeScaleWorldTransform:
1358 EmfPlusScaleWorldTransform *record = (EmfPlusScaleWorldTransform*)header;
1359 MatrixOrder order = (flags & 0x2000) ? MatrixOrderAppend : MatrixOrderPrepend;
1361 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusScaleWorldTransform))
1362 return InvalidParameter;
1364 GdipScaleMatrix(real_metafile->world_transform, record->Sx, record->Sy, order);
1366 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
1368 case EmfPlusRecordTypeMultiplyWorldTransform:
1370 EmfPlusMultiplyWorldTransform *record = (EmfPlusMultiplyWorldTransform*)header;
1371 MatrixOrder order = (flags & 0x2000) ? MatrixOrderAppend : MatrixOrderPrepend;
1372 GpMatrix matrix;
1374 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusMultiplyWorldTransform))
1375 return InvalidParameter;
1377 memcpy(matrix.matrix, record->MatrixData, sizeof(matrix.matrix));
1379 GdipMultiplyMatrix(real_metafile->world_transform, &matrix, order);
1381 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
1383 case EmfPlusRecordTypeRotateWorldTransform:
1385 EmfPlusRotateWorldTransform *record = (EmfPlusRotateWorldTransform*)header;
1386 MatrixOrder order = (flags & 0x2000) ? MatrixOrderAppend : MatrixOrderPrepend;
1388 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusRotateWorldTransform))
1389 return InvalidParameter;
1391 GdipRotateMatrix(real_metafile->world_transform, record->Angle, order);
1393 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
1395 case EmfPlusRecordTypeTranslateWorldTransform:
1397 EmfPlusTranslateWorldTransform *record = (EmfPlusTranslateWorldTransform*)header;
1398 MatrixOrder order = (flags & 0x2000) ? MatrixOrderAppend : MatrixOrderPrepend;
1400 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusTranslateWorldTransform))
1401 return InvalidParameter;
1403 GdipTranslateMatrix(real_metafile->world_transform, record->dx, record->dy, order);
1405 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
1407 case EmfPlusRecordTypeResetWorldTransform:
1409 GdipSetMatrixElements(real_metafile->world_transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1411 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
1413 case EmfPlusRecordTypeBeginContainer:
1415 EmfPlusBeginContainer *record = (EmfPlusBeginContainer*)header;
1416 container* cont;
1417 GpUnit unit;
1418 REAL scale_x, scale_y;
1419 GpRectF scaled_srcrect;
1420 GpMatrix transform;
1422 cont = heap_alloc_zero(sizeof(*cont));
1423 if (!cont)
1424 return OutOfMemory;
1426 stat = GdipCloneRegion(metafile->clip, &cont->clip);
1427 if (stat != Ok)
1429 heap_free(cont);
1430 return stat;
1433 stat = GdipBeginContainer2(metafile->playback_graphics, &cont->state);
1435 if (stat != Ok)
1437 GdipDeleteRegion(cont->clip);
1438 heap_free(cont);
1439 return stat;
1442 cont->id = record->StackIndex;
1443 cont->type = BEGIN_CONTAINER;
1444 cont->world_transform = *metafile->world_transform;
1445 cont->page_unit = metafile->page_unit;
1446 cont->page_scale = metafile->page_scale;
1447 list_add_head(&real_metafile->containers, &cont->entry);
1449 unit = record->Header.Flags & 0xff;
1451 scale_x = units_to_pixels(1.0, unit, metafile->image.xres);
1452 scale_y = units_to_pixels(1.0, unit, metafile->image.yres);
1454 scaled_srcrect.X = scale_x * record->SrcRect.X;
1455 scaled_srcrect.Y = scale_y * record->SrcRect.Y;
1456 scaled_srcrect.Width = scale_x * record->SrcRect.Width;
1457 scaled_srcrect.Height = scale_y * record->SrcRect.Height;
1459 transform.matrix[0] = record->DestRect.Width / scaled_srcrect.Width;
1460 transform.matrix[1] = 0.0;
1461 transform.matrix[2] = 0.0;
1462 transform.matrix[3] = record->DestRect.Height / scaled_srcrect.Height;
1463 transform.matrix[4] = record->DestRect.X - scaled_srcrect.X;
1464 transform.matrix[5] = record->DestRect.Y - scaled_srcrect.Y;
1466 GdipMultiplyMatrix(real_metafile->world_transform, &transform, MatrixOrderPrepend);
1468 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
1470 case EmfPlusRecordTypeBeginContainerNoParams:
1471 case EmfPlusRecordTypeSave:
1473 EmfPlusContainerRecord *record = (EmfPlusContainerRecord*)header;
1474 container* cont;
1476 cont = heap_alloc_zero(sizeof(*cont));
1477 if (!cont)
1478 return OutOfMemory;
1480 stat = GdipCloneRegion(metafile->clip, &cont->clip);
1481 if (stat != Ok)
1483 heap_free(cont);
1484 return stat;
1487 if (recordType == EmfPlusRecordTypeBeginContainerNoParams)
1488 stat = GdipBeginContainer2(metafile->playback_graphics, &cont->state);
1489 else
1490 stat = GdipSaveGraphics(metafile->playback_graphics, &cont->state);
1492 if (stat != Ok)
1494 GdipDeleteRegion(cont->clip);
1495 heap_free(cont);
1496 return stat;
1499 cont->id = record->StackIndex;
1500 if (recordType == EmfPlusRecordTypeBeginContainerNoParams)
1501 cont->type = BEGIN_CONTAINER;
1502 else
1503 cont->type = SAVE_GRAPHICS;
1504 cont->world_transform = *metafile->world_transform;
1505 cont->page_unit = metafile->page_unit;
1506 cont->page_scale = metafile->page_scale;
1507 list_add_head(&real_metafile->containers, &cont->entry);
1509 break;
1511 case EmfPlusRecordTypeEndContainer:
1512 case EmfPlusRecordTypeRestore:
1514 EmfPlusContainerRecord *record = (EmfPlusContainerRecord*)header;
1515 container* cont;
1516 enum container_type type;
1517 BOOL found=FALSE;
1519 if (recordType == EmfPlusRecordTypeEndContainer)
1520 type = BEGIN_CONTAINER;
1521 else
1522 type = SAVE_GRAPHICS;
1524 LIST_FOR_EACH_ENTRY(cont, &real_metafile->containers, container, entry)
1526 if (cont->id == record->StackIndex && cont->type == type)
1528 found = TRUE;
1529 break;
1533 if (found)
1535 container* cont2;
1537 /* pop any newer items on the stack */
1538 while ((cont2 = LIST_ENTRY(list_head(&real_metafile->containers), container, entry)) != cont)
1540 list_remove(&cont2->entry);
1541 GdipDeleteRegion(cont2->clip);
1542 heap_free(cont2);
1545 if (type == BEGIN_CONTAINER)
1546 GdipEndContainer(real_metafile->playback_graphics, cont->state);
1547 else
1548 GdipRestoreGraphics(real_metafile->playback_graphics, cont->state);
1550 *real_metafile->world_transform = cont->world_transform;
1551 real_metafile->page_unit = cont->page_unit;
1552 real_metafile->page_scale = cont->page_scale;
1553 GdipCombineRegionRegion(real_metafile->clip, cont->clip, CombineModeReplace);
1555 list_remove(&cont->entry);
1556 GdipDeleteRegion(cont->clip);
1557 heap_free(cont);
1560 break;
1562 default:
1563 FIXME("Not implemented for record type %x\n", recordType);
1564 return NotImplemented;
1568 return Ok;
1571 struct enum_metafile_data
1573 EnumerateMetafileProc callback;
1574 void *callback_data;
1575 GpMetafile *metafile;
1578 static int CALLBACK enum_metafile_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR,
1579 int nObj, LPARAM lpData)
1581 BOOL ret;
1582 struct enum_metafile_data *data = (struct enum_metafile_data*)lpData;
1583 const BYTE* pStr;
1585 data->metafile->handle_table = lpHTable;
1586 data->metafile->handle_count = nObj;
1588 /* First check for an EMF+ record. */
1589 if (lpEMFR->iType == EMR_GDICOMMENT)
1591 const EMRGDICOMMENT *comment = (const EMRGDICOMMENT*)lpEMFR;
1593 if (comment->cbData >= 4 && memcmp(comment->Data, "EMF+", 4) == 0)
1595 int offset = 4;
1597 while (offset + sizeof(EmfPlusRecordHeader) <= comment->cbData)
1599 const EmfPlusRecordHeader *record = (const EmfPlusRecordHeader*)&comment->Data[offset];
1601 if (record->DataSize)
1602 pStr = (const BYTE*)(record+1);
1603 else
1604 pStr = NULL;
1606 ret = data->callback(record->Type, record->Flags, record->DataSize,
1607 pStr, data->callback_data);
1609 if (!ret)
1610 return 0;
1612 offset += record->Size;
1615 return 1;
1619 if (lpEMFR->nSize != 8)
1620 pStr = (const BYTE*)lpEMFR->dParm;
1621 else
1622 pStr = NULL;
1624 return data->callback(lpEMFR->iType, 0, lpEMFR->nSize-8,
1625 pStr, data->callback_data);
1628 GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics,
1629 GDIPCONST GpMetafile *metafile, GDIPCONST GpPointF *destPoints, INT count,
1630 GDIPCONST GpRectF *srcRect, Unit srcUnit, EnumerateMetafileProc callback,
1631 VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes)
1633 struct enum_metafile_data data;
1634 GpStatus stat;
1635 GpMetafile *real_metafile = (GpMetafile*)metafile; /* whoever made this const was joking */
1636 GraphicsContainer state;
1637 GpPath *dst_path;
1639 TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics, metafile,
1640 destPoints, count, srcRect, srcUnit, callback, callbackData,
1641 imageAttributes);
1643 if (!graphics || !metafile || !destPoints || count != 3 || !srcRect)
1644 return InvalidParameter;
1646 if (!metafile->hemf)
1647 return InvalidParameter;
1649 if (metafile->playback_graphics)
1650 return ObjectBusy;
1652 TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect), srcUnit,
1653 debugstr_pointf(&destPoints[0]), debugstr_pointf(&destPoints[1]),
1654 debugstr_pointf(&destPoints[2]));
1656 data.callback = callback;
1657 data.callback_data = callbackData;
1658 data.metafile = real_metafile;
1660 real_metafile->playback_graphics = graphics;
1661 real_metafile->playback_dc = NULL;
1662 real_metafile->src_rect = *srcRect;
1664 memcpy(real_metafile->playback_points, destPoints, sizeof(PointF) * 3);
1665 stat = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, real_metafile->playback_points, 3);
1667 if (stat == Ok)
1668 stat = GdipBeginContainer2(graphics, &state);
1670 if (stat == Ok)
1672 stat = GdipSetPageScale(graphics, 1.0);
1674 if (stat == Ok)
1675 stat = GdipSetPageUnit(graphics, UnitPixel);
1677 if (stat == Ok)
1678 stat = GdipResetWorldTransform(graphics);
1680 if (stat == Ok)
1681 stat = GdipCreateRegion(&real_metafile->base_clip);
1683 if (stat == Ok)
1684 stat = GdipGetClip(graphics, real_metafile->base_clip);
1686 if (stat == Ok)
1687 stat = GdipCreateRegion(&real_metafile->clip);
1689 if (stat == Ok)
1690 stat = GdipCreatePath(FillModeAlternate, &dst_path);
1692 if (stat == Ok)
1694 GpPointF clip_points[4];
1696 clip_points[0] = real_metafile->playback_points[0];
1697 clip_points[1] = real_metafile->playback_points[1];
1698 clip_points[2].X = real_metafile->playback_points[1].X + real_metafile->playback_points[2].X
1699 - real_metafile->playback_points[0].X;
1700 clip_points[2].Y = real_metafile->playback_points[1].Y + real_metafile->playback_points[2].Y
1701 - real_metafile->playback_points[0].Y;
1702 clip_points[3] = real_metafile->playback_points[2];
1704 stat = GdipAddPathPolygon(dst_path, clip_points, 4);
1706 if (stat == Ok)
1707 stat = GdipCombineRegionPath(real_metafile->base_clip, dst_path, CombineModeIntersect);
1709 GdipDeletePath(dst_path);
1712 if (stat == Ok)
1713 stat = GdipCreateMatrix(&real_metafile->world_transform);
1715 if (stat == Ok)
1717 real_metafile->page_unit = UnitDisplay;
1718 real_metafile->page_scale = 1.0;
1719 stat = METAFILE_PlaybackUpdateWorldTransform(real_metafile);
1722 if (stat == Ok)
1724 stat = METAFILE_PlaybackUpdateClip(real_metafile);
1727 if (stat == Ok && (metafile->metafile_type == MetafileTypeEmf ||
1728 metafile->metafile_type == MetafileTypeWmfPlaceable ||
1729 metafile->metafile_type == MetafileTypeWmf))
1730 stat = METAFILE_PlaybackGetDC(real_metafile);
1732 if (stat == Ok)
1733 EnumEnhMetaFile(0, metafile->hemf, enum_metafile_proc, &data, NULL);
1735 METAFILE_PlaybackReleaseDC(real_metafile);
1737 GdipDeleteMatrix(real_metafile->world_transform);
1738 real_metafile->world_transform = NULL;
1740 GdipDeleteRegion(real_metafile->base_clip);
1741 real_metafile->base_clip = NULL;
1743 GdipDeleteRegion(real_metafile->clip);
1744 real_metafile->clip = NULL;
1746 while (list_head(&real_metafile->containers))
1748 container* cont = LIST_ENTRY(list_head(&real_metafile->containers), container, entry);
1749 list_remove(&cont->entry);
1750 GdipDeleteRegion(cont->clip);
1751 heap_free(cont);
1754 GdipEndContainer(graphics, state);
1757 real_metafile->playback_graphics = NULL;
1759 return stat;
1762 GpStatus WINGDIPAPI GdipEnumerateMetafileDestRect(GpGraphics *graphics,
1763 GDIPCONST GpMetafile *metafile, GDIPCONST GpRectF *dest,
1764 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
1766 GpPointF points[3];
1768 if (!graphics || !metafile || !dest) return InvalidParameter;
1770 points[0].X = points[2].X = dest->X;
1771 points[0].Y = points[1].Y = dest->Y;
1772 points[1].X = dest->X + dest->Width;
1773 points[2].Y = dest->Y + dest->Height;
1775 return GdipEnumerateMetafileSrcRectDestPoints(graphics, metafile, points, 3,
1776 &metafile->bounds, metafile->unit, callback, cb_data, attrs);
1779 GpStatus WINGDIPAPI GdipEnumerateMetafileDestRectI(GpGraphics *graphics,
1780 GDIPCONST GpMetafile *metafile, GDIPCONST GpRect *dest,
1781 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
1783 GpRectF destf;
1785 if (!graphics || !metafile || !dest) return InvalidParameter;
1787 destf.X = dest->X;
1788 destf.Y = dest->Y;
1789 destf.Width = dest->Width;
1790 destf.Height = dest->Height;
1792 return GdipEnumerateMetafileDestRect(graphics, metafile, &destf, callback, cb_data, attrs);
1795 GpStatus WINGDIPAPI GdipEnumerateMetafileDestPoint(GpGraphics *graphics,
1796 GDIPCONST GpMetafile *metafile, GDIPCONST GpPointF *dest,
1797 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
1799 GpRectF destf;
1801 if (!graphics || !metafile || !dest) return InvalidParameter;
1803 destf.X = dest->X;
1804 destf.Y = dest->Y;
1805 destf.Width = units_to_pixels(metafile->bounds.Width, metafile->unit, metafile->image.xres);
1806 destf.Height = units_to_pixels(metafile->bounds.Height, metafile->unit, metafile->image.yres);
1808 return GdipEnumerateMetafileDestRect(graphics, metafile, &destf, callback, cb_data, attrs);
1811 GpStatus WINGDIPAPI GdipEnumerateMetafileDestPointI(GpGraphics *graphics,
1812 GDIPCONST GpMetafile *metafile, GDIPCONST GpPoint *dest,
1813 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
1815 GpPointF ptf;
1817 if (!graphics || !metafile || !dest) return InvalidParameter;
1819 ptf.X = dest->X;
1820 ptf.Y = dest->Y;
1822 return GdipEnumerateMetafileDestPoint(graphics, metafile, &ptf, callback, cb_data, attrs);
1825 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
1826 MetafileHeader * header)
1828 GpStatus status;
1830 TRACE("(%p, %p)\n", metafile, header);
1832 if(!metafile || !header)
1833 return InvalidParameter;
1835 if (metafile->hemf)
1837 status = GdipGetMetafileHeaderFromEmf(metafile->hemf, header);
1838 if (status != Ok) return status;
1840 else
1842 memset(header, 0, sizeof(*header));
1843 header->Version = 0xdbc01002;
1846 header->Type = metafile->metafile_type;
1847 header->DpiX = metafile->image.xres;
1848 header->DpiY = metafile->image.yres;
1849 header->Width = gdip_round(metafile->bounds.Width);
1850 header->Height = gdip_round(metafile->bounds.Height);
1852 return Ok;
1855 static int CALLBACK get_emfplus_header_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR,
1856 int nObj, LPARAM lpData)
1858 EmfPlusHeader *dst_header = (EmfPlusHeader*)lpData;
1860 if (lpEMFR->iType == EMR_GDICOMMENT)
1862 const EMRGDICOMMENT *comment = (const EMRGDICOMMENT*)lpEMFR;
1864 if (comment->cbData >= 4 && memcmp(comment->Data, "EMF+", 4) == 0)
1866 const EmfPlusRecordHeader *header = (const EmfPlusRecordHeader*)&comment->Data[4];
1868 if (4 + sizeof(EmfPlusHeader) <= comment->cbData &&
1869 header->Type == EmfPlusRecordTypeHeader)
1871 memcpy(dst_header, header, sizeof(*dst_header));
1875 else if (lpEMFR->iType == EMR_HEADER)
1876 return TRUE;
1878 return FALSE;
1881 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromEmf(HENHMETAFILE hemf,
1882 MetafileHeader *header)
1884 ENHMETAHEADER3 emfheader;
1885 EmfPlusHeader emfplusheader;
1886 MetafileType metafile_type;
1888 TRACE("(%p,%p)\n", hemf, header);
1890 if(!hemf || !header)
1891 return InvalidParameter;
1893 if (GetEnhMetaFileHeader(hemf, sizeof(emfheader), (ENHMETAHEADER*)&emfheader) == 0)
1894 return GenericError;
1896 emfplusheader.Header.Type = 0;
1898 EnumEnhMetaFile(NULL, hemf, get_emfplus_header_proc, &emfplusheader, NULL);
1900 if (emfplusheader.Header.Type == EmfPlusRecordTypeHeader)
1902 if ((emfplusheader.Header.Flags & 1) == 1)
1903 metafile_type = MetafileTypeEmfPlusDual;
1904 else
1905 metafile_type = MetafileTypeEmfPlusOnly;
1907 else
1908 metafile_type = MetafileTypeEmf;
1910 header->Type = metafile_type;
1911 header->Size = emfheader.nBytes;
1912 header->DpiX = (REAL)emfheader.szlDevice.cx * 25.4 / emfheader.szlMillimeters.cx;
1913 header->DpiY = (REAL)emfheader.szlDevice.cy * 25.4 / emfheader.szlMillimeters.cy;
1914 header->X = gdip_round((REAL)emfheader.rclFrame.left / 2540.0 * header->DpiX);
1915 header->Y = gdip_round((REAL)emfheader.rclFrame.top / 2540.0 * header->DpiY);
1916 header->Width = gdip_round((REAL)(emfheader.rclFrame.right - emfheader.rclFrame.left) / 2540.0 * header->DpiX);
1917 header->Height = gdip_round((REAL)(emfheader.rclFrame.bottom - emfheader.rclFrame.top) / 2540.0 * header->DpiY);
1918 header->u.EmfHeader = emfheader;
1920 if (metafile_type == MetafileTypeEmfPlusDual || metafile_type == MetafileTypeEmfPlusOnly)
1922 header->Version = emfplusheader.Version;
1923 header->EmfPlusFlags = emfplusheader.EmfPlusFlags;
1924 header->EmfPlusHeaderSize = emfplusheader.Header.Size;
1925 header->LogicalDpiX = emfplusheader.LogicalDpiX;
1926 header->LogicalDpiY = emfplusheader.LogicalDpiY;
1928 else
1930 header->Version = emfheader.nVersion;
1931 header->EmfPlusFlags = 0;
1932 header->EmfPlusHeaderSize = 0;
1933 header->LogicalDpiX = 0;
1934 header->LogicalDpiY = 0;
1937 return Ok;
1940 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromWmf(HMETAFILE hwmf,
1941 GDIPCONST WmfPlaceableFileHeader *placeable, MetafileHeader *header)
1943 GpStatus status;
1944 GpMetafile *metafile;
1946 TRACE("(%p,%p,%p)\n", hwmf, placeable, header);
1948 status = GdipCreateMetafileFromWmf(hwmf, FALSE, placeable, &metafile);
1949 if (status == Ok)
1951 status = GdipGetMetafileHeaderFromMetafile(metafile, header);
1952 GdipDisposeImage(&metafile->image);
1954 return status;
1957 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR *filename,
1958 MetafileHeader *header)
1960 GpStatus status;
1961 GpMetafile *metafile;
1963 TRACE("(%s,%p)\n", debugstr_w(filename), header);
1965 if (!filename || !header)
1966 return InvalidParameter;
1968 status = GdipCreateMetafileFromFile(filename, &metafile);
1969 if (status == Ok)
1971 status = GdipGetMetafileHeaderFromMetafile(metafile, header);
1972 GdipDisposeImage(&metafile->image);
1974 return status;
1977 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromStream(IStream *stream,
1978 MetafileHeader *header)
1980 GpStatus status;
1981 GpMetafile *metafile;
1983 TRACE("(%p,%p)\n", stream, header);
1985 if (!stream || !header)
1986 return InvalidParameter;
1988 status = GdipCreateMetafileFromStream(stream, &metafile);
1989 if (status == Ok)
1991 status = GdipGetMetafileHeaderFromMetafile(metafile, header);
1992 GdipDisposeImage(&metafile->image);
1994 return status;
1997 GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete,
1998 GpMetafile **metafile)
2000 GpStatus stat;
2001 MetafileHeader header;
2003 TRACE("(%p,%i,%p)\n", hemf, delete, metafile);
2005 if(!hemf || !metafile)
2006 return InvalidParameter;
2008 stat = GdipGetMetafileHeaderFromEmf(hemf, &header);
2009 if (stat != Ok)
2010 return stat;
2012 *metafile = heap_alloc_zero(sizeof(GpMetafile));
2013 if (!*metafile)
2014 return OutOfMemory;
2016 (*metafile)->image.type = ImageTypeMetafile;
2017 (*metafile)->image.format = ImageFormatEMF;
2018 (*metafile)->image.frame_count = 1;
2019 (*metafile)->image.xres = header.DpiX;
2020 (*metafile)->image.yres = header.DpiY;
2021 (*metafile)->bounds.X = (REAL)header.u.EmfHeader.rclFrame.left / 2540.0 * header.DpiX;
2022 (*metafile)->bounds.Y = (REAL)header.u.EmfHeader.rclFrame.top / 2540.0 * header.DpiY;
2023 (*metafile)->bounds.Width = (REAL)(header.u.EmfHeader.rclFrame.right - header.u.EmfHeader.rclFrame.left)
2024 / 2540.0 * header.DpiX;
2025 (*metafile)->bounds.Height = (REAL)(header.u.EmfHeader.rclFrame.bottom - header.u.EmfHeader.rclFrame.top)
2026 / 2540.0 * header.DpiY;
2027 (*metafile)->unit = UnitPixel;
2028 (*metafile)->metafile_type = header.Type;
2029 (*metafile)->hemf = hemf;
2030 (*metafile)->preserve_hemf = !delete;
2031 list_init(&(*metafile)->containers);
2033 TRACE("<-- %p\n", *metafile);
2035 return Ok;
2038 GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
2039 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
2041 UINT read;
2042 BYTE *copy;
2043 HENHMETAFILE hemf;
2044 GpStatus retval = Ok;
2046 TRACE("(%p, %d, %p, %p)\n", hwmf, delete, placeable, metafile);
2048 if(!hwmf || !metafile)
2049 return InvalidParameter;
2051 *metafile = NULL;
2052 read = GetMetaFileBitsEx(hwmf, 0, NULL);
2053 if(!read)
2054 return GenericError;
2055 copy = heap_alloc_zero(read);
2056 GetMetaFileBitsEx(hwmf, read, copy);
2058 hemf = SetWinMetaFileBits(read, copy, NULL, NULL);
2059 heap_free(copy);
2061 /* FIXME: We should store and use hwmf instead of converting to hemf */
2062 retval = GdipCreateMetafileFromEmf(hemf, TRUE, metafile);
2064 if (retval == Ok)
2066 if (placeable)
2068 (*metafile)->image.xres = (REAL)placeable->Inch;
2069 (*metafile)->image.yres = (REAL)placeable->Inch;
2070 (*metafile)->bounds.X = ((REAL)placeable->BoundingBox.Left) / ((REAL)placeable->Inch);
2071 (*metafile)->bounds.Y = ((REAL)placeable->BoundingBox.Top) / ((REAL)placeable->Inch);
2072 (*metafile)->bounds.Width = (REAL)(placeable->BoundingBox.Right -
2073 placeable->BoundingBox.Left);
2074 (*metafile)->bounds.Height = (REAL)(placeable->BoundingBox.Bottom -
2075 placeable->BoundingBox.Top);
2076 (*metafile)->metafile_type = MetafileTypeWmfPlaceable;
2078 else
2079 (*metafile)->metafile_type = MetafileTypeWmf;
2080 (*metafile)->image.format = ImageFormatWMF;
2082 if (delete) DeleteMetaFile(hwmf);
2084 else
2085 DeleteEnhMetaFile(hemf);
2086 return retval;
2089 GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file,
2090 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
2092 HMETAFILE hmf = GetMetaFileW(file);
2094 TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile);
2096 if(!hmf) return InvalidParameter;
2098 return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile);
2101 GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file,
2102 GpMetafile **metafile)
2104 GpStatus status;
2105 IStream *stream;
2107 TRACE("(%p, %p)\n", file, metafile);
2109 if (!file || !metafile) return InvalidParameter;
2111 *metafile = NULL;
2113 status = GdipCreateStreamOnFile(file, GENERIC_READ, &stream);
2114 if (status == Ok)
2116 status = GdipCreateMetafileFromStream(stream, metafile);
2117 IStream_Release(stream);
2119 return status;
2122 GpStatus WINGDIPAPI GdipCreateMetafileFromStream(IStream *stream,
2123 GpMetafile **metafile)
2125 GpStatus stat;
2127 TRACE("%p %p\n", stream, metafile);
2129 stat = GdipLoadImageFromStream(stream, (GpImage **)metafile);
2130 if (stat != Ok) return stat;
2132 if ((*metafile)->image.type != ImageTypeMetafile)
2134 GdipDisposeImage(&(*metafile)->image);
2135 *metafile = NULL;
2136 return GenericError;
2139 return Ok;
2142 GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile *metafile,
2143 UINT limitDpi)
2145 TRACE("(%p,%u)\n", metafile, limitDpi);
2147 return Ok;
2150 GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
2151 GpMetafile* metafile, BOOL* succ, EmfType emfType,
2152 const WCHAR* description, GpMetafile** out_metafile)
2154 static int calls;
2156 TRACE("(%p,%p,%p,%u,%s,%p)\n", ref, metafile, succ, emfType,
2157 debugstr_w(description), out_metafile);
2159 if(!ref || !metafile || !out_metafile || emfType < EmfTypeEmfOnly || emfType > EmfTypeEmfPlusDual)
2160 return InvalidParameter;
2162 if(succ)
2163 *succ = FALSE;
2164 *out_metafile = NULL;
2166 if(!(calls++))
2167 FIXME("not implemented\n");
2169 return NotImplemented;
2172 GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE hemf, UINT cbData16,
2173 LPBYTE pData16, INT iMapMode, INT eFlags)
2175 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf, cbData16, pData16, iMapMode, eFlags);
2176 return NotImplemented;
2179 GpStatus WINGDIPAPI GdipRecordMetafileFileName(GDIPCONST WCHAR* fileName,
2180 HDC hdc, EmfType type, GDIPCONST GpRectF *pFrameRect,
2181 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc,
2182 GpMetafile **metafile)
2184 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
2185 frameUnit, debugstr_w(desc), metafile);
2187 return NotImplemented;
2190 GpStatus WINGDIPAPI GdipRecordMetafileFileNameI(GDIPCONST WCHAR* fileName, HDC hdc, EmfType type,
2191 GDIPCONST GpRect *pFrameRect, MetafileFrameUnit frameUnit,
2192 GDIPCONST WCHAR *desc, GpMetafile **metafile)
2194 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
2195 frameUnit, debugstr_w(desc), metafile);
2197 return NotImplemented;
2200 /*****************************************************************************
2201 * GdipConvertToEmfPlusToFile [GDIPLUS.@]
2204 GpStatus WINGDIPAPI GdipConvertToEmfPlusToFile(const GpGraphics* refGraphics,
2205 GpMetafile* metafile, BOOL* conversionSuccess,
2206 const WCHAR* filename, EmfType emfType,
2207 const WCHAR* description, GpMetafile** out_metafile)
2209 FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics, metafile, conversionSuccess, filename, emfType, description, out_metafile);
2210 return NotImplemented;