gdiplus/metafile: Added support for EmfPlusFont objects.
[wine.git] / dlls / gdiplus / metafile.c
blobb67f5654aeec32d27ecdd7a049b76ed174be62df
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>
21 #include <assert.h>
23 #define NONAMELESSUNION
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "wine/unicode.h"
30 #define COBJMACROS
31 #include "objbase.h"
32 #include "ocidl.h"
33 #include "olectl.h"
34 #include "ole2.h"
36 #include "winreg.h"
37 #include "shlwapi.h"
39 #include "gdiplus.h"
40 #include "gdiplus_private.h"
41 #include "wine/debug.h"
42 #include "wine/list.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
46 HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**);
48 typedef struct EmfPlusARGB
50 BYTE Blue;
51 BYTE Green;
52 BYTE Red;
53 BYTE Alpha;
54 } EmfPlusARGB;
56 typedef struct EmfPlusRecordHeader
58 WORD Type;
59 WORD Flags;
60 DWORD Size;
61 DWORD DataSize;
62 } EmfPlusRecordHeader;
64 typedef struct EmfPlusHeader
66 EmfPlusRecordHeader Header;
67 DWORD Version;
68 DWORD EmfPlusFlags;
69 DWORD LogicalDpiX;
70 DWORD LogicalDpiY;
71 } EmfPlusHeader;
73 typedef struct EmfPlusClear
75 EmfPlusRecordHeader Header;
76 DWORD Color;
77 } EmfPlusClear;
79 typedef struct EmfPlusFillRects
81 EmfPlusRecordHeader Header;
82 DWORD BrushID;
83 DWORD Count;
84 } EmfPlusFillRects;
86 typedef struct EmfPlusSetClipRect
88 EmfPlusRecordHeader Header;
89 GpRectF ClipRect;
90 } EmfPlusSetClipRect;
92 typedef struct EmfPlusSetPageTransform
94 EmfPlusRecordHeader Header;
95 REAL PageScale;
96 } EmfPlusSetPageTransform;
98 typedef struct EmfPlusRect
100 SHORT X;
101 SHORT Y;
102 SHORT Width;
103 SHORT Height;
104 } EmfPlusRect;
106 typedef struct EmfPlusSetWorldTransform
108 EmfPlusRecordHeader Header;
109 REAL MatrixData[6];
110 } EmfPlusSetWorldTransform;
112 typedef struct EmfPlusScaleWorldTransform
114 EmfPlusRecordHeader Header;
115 REAL Sx;
116 REAL Sy;
117 } EmfPlusScaleWorldTransform;
119 typedef struct EmfPlusMultiplyWorldTransform
121 EmfPlusRecordHeader Header;
122 REAL MatrixData[6];
123 } EmfPlusMultiplyWorldTransform;
125 typedef struct EmfPlusRotateWorldTransform
127 EmfPlusRecordHeader Header;
128 REAL Angle;
129 } EmfPlusRotateWorldTransform;
131 typedef struct EmfPlusTranslateWorldTransform
133 EmfPlusRecordHeader Header;
134 REAL dx;
135 REAL dy;
136 } EmfPlusTranslateWorldTransform;
138 typedef struct EmfPlusBeginContainer
140 EmfPlusRecordHeader Header;
141 GpRectF DestRect;
142 GpRectF SrcRect;
143 DWORD StackIndex;
144 } EmfPlusBeginContainer;
146 typedef struct EmfPlusContainerRecord
148 EmfPlusRecordHeader Header;
149 DWORD StackIndex;
150 } EmfPlusContainerRecord;
152 enum container_type
154 BEGIN_CONTAINER,
155 SAVE_GRAPHICS
158 typedef struct container
160 struct list entry;
161 DWORD id;
162 enum container_type type;
163 GraphicsContainer state;
164 GpMatrix world_transform;
165 GpUnit page_unit;
166 REAL page_scale;
167 GpRegion *clip;
168 } container;
170 enum PenDataFlags
172 PenDataTransform = 0x0001,
173 PenDataStartCap = 0x0002,
174 PenDataEndCap = 0x0004,
175 PenDataJoin = 0x0008,
176 PenDataMiterLimit = 0x0010,
177 PenDataLineStyle = 0x0020,
178 PenDataDashedLineCap = 0x0040,
179 PenDataDashedLineOffset = 0x0080,
180 PenDataDashedLine = 0x0100,
181 PenDataNonCenter = 0x0200,
182 PenDataCompoundLine = 0x0400,
183 PenDataCustomStartCap = 0x0800,
184 PenDataCustomEndCap = 0x1000
187 typedef struct EmfPlusTransformMatrix
189 REAL TransformMatrix[6];
190 } EmfPlusTransformMatrix;
192 enum LineStyle
194 LineStyleSolid,
195 LineStyleDash,
196 LineStyleDot,
197 LineStyleDashDot,
198 LineStyleDashDotDot,
199 LineStyleCustom
202 typedef struct EmfPlusPenData
204 DWORD PenDataFlags;
205 DWORD PenUnit;
206 REAL PenWidth;
207 BYTE OptionalData[1];
208 } EmfPlusPenData;
210 typedef struct EmfPlusSolidBrushData
212 EmfPlusARGB SolidColor;
213 } EmfPlusSolidBrushData;
215 typedef struct EmfPlusBrush
217 DWORD Version;
218 DWORD Type;
219 union {
220 EmfPlusSolidBrushData solid;
221 } BrushData;
222 } EmfPlusBrush;
224 typedef struct EmfPlusPen
226 DWORD Version;
227 DWORD Type;
228 /* EmfPlusPenData */
229 /* EmfPlusBrush */
230 BYTE data[1];
231 } EmfPlusPen;
233 typedef struct EmfPlusPath
235 DWORD Version;
236 DWORD PathPointCount;
237 DWORD PathPointFlags;
238 /* PathPoints[] */
239 /* PathPointTypes[] */
240 /* AlignmentPadding */
241 BYTE data[1];
242 } EmfPlusPath;
244 typedef struct EmfPlusRegion
246 DWORD Version;
247 DWORD RegionNodeCount;
248 BYTE RegionNode[1];
249 } EmfPlusRegion;
251 typedef struct EmfPlusPalette
253 DWORD PaletteStyleFlags;
254 DWORD PaletteCount;
255 BYTE PaletteEntries[1];
256 } EmfPlusPalette;
258 typedef enum
260 BitmapDataTypePixel,
261 BitmapDataTypeCompressed,
262 } BitmapDataType;
264 typedef struct EmfPlusBitmap
266 DWORD Width;
267 DWORD Height;
268 DWORD Stride;
269 DWORD PixelFormat;
270 DWORD Type;
271 BYTE BitmapData[1];
272 } EmfPlusBitmap;
274 typedef struct EmfPlusMetafile
276 DWORD Type;
277 DWORD MetafileDataSize;
278 BYTE MetafileData[1];
279 } EmfPlusMetafile;
281 typedef enum ImageDataType
283 ImageDataTypeUnknown,
284 ImageDataTypeBitmap,
285 ImageDataTypeMetafile,
286 } ImageDataType;
288 typedef struct EmfPlusImage
290 DWORD Version;
291 ImageDataType Type;
292 union
294 EmfPlusBitmap bitmap;
295 EmfPlusMetafile metafile;
296 } ImageData;
297 } EmfPlusImage;
299 typedef struct EmfPlusImageAttributes
301 DWORD Version;
302 DWORD Reserved1;
303 DWORD WrapMode;
304 EmfPlusARGB ClampColor;
305 DWORD ObjectClamp;
306 DWORD Reserved2;
307 } EmfPlusImageAttributes;
309 typedef struct EmfPlusObject
311 EmfPlusRecordHeader Header;
312 union
314 EmfPlusBrush brush;
315 EmfPlusPen pen;
316 EmfPlusPath path;
317 EmfPlusRegion region;
318 EmfPlusImage image;
319 EmfPlusImageAttributes image_attributes;
320 } ObjectData;
321 } EmfPlusObject;
323 typedef struct EmfPlusRectF
325 float X;
326 float Y;
327 float Width;
328 float Height;
329 } EmfPlusRectF;
331 typedef struct EmfPlusPointR7
333 BYTE X;
334 BYTE Y;
335 } EmfPlusPointR7;
337 typedef struct EmfPlusPoint
339 short X;
340 short Y;
341 } EmfPlusPoint;
343 typedef struct EmfPlusPointF
345 float X;
346 float Y;
347 } EmfPlusPointF;
349 typedef struct EmfPlusDrawImagePoints
351 EmfPlusRecordHeader Header;
352 DWORD ImageAttributesID;
353 DWORD SrcUnit;
354 EmfPlusRectF SrcRect;
355 DWORD count;
356 union
358 EmfPlusPointR7 pointsR[3];
359 EmfPlusPoint points[3];
360 EmfPlusPointF pointsF[3];
361 } PointData;
362 } EmfPlusDrawImagePoints;
364 typedef struct EmfPlusDrawPath
366 EmfPlusRecordHeader Header;
367 DWORD PenId;
368 } EmfPlusDrawPath;
370 typedef struct EmfPlusFillPath
372 EmfPlusRecordHeader Header;
373 union
375 DWORD BrushId;
376 EmfPlusARGB Color;
377 } data;
378 } EmfPlusFillPath;
380 typedef struct EmfPlusFont
382 DWORD Version;
383 float EmSize;
384 DWORD SizeUnit;
385 DWORD FontStyleFlags;
386 DWORD Reserved;
387 DWORD Length;
388 WCHAR FamilyName[1];
389 } EmfPlusFont;
391 static void metafile_free_object_table_entry(GpMetafile *metafile, BYTE id)
393 struct emfplus_object *object = &metafile->objtable[id];
395 switch (object->type)
397 case ObjectTypeInvalid:
398 break;
399 case ObjectTypeBrush:
400 GdipDeleteBrush(object->u.brush);
401 break;
402 case ObjectTypePath:
403 GdipDeletePath(object->u.path);
404 break;
405 case ObjectTypeImage:
406 GdipDisposeImage(object->u.image);
407 break;
408 case ObjectTypeFont:
409 GdipDeleteFont(object->u.font);
410 break;
411 case ObjectTypeImageAttributes:
412 GdipDisposeImageAttributes(object->u.image_attributes);
413 break;
414 default:
415 FIXME("not implemented for object type %u.\n", object->type);
416 return;
419 object->type = ObjectTypeInvalid;
420 object->u.object = NULL;
423 void METAFILE_Free(GpMetafile *metafile)
425 unsigned int i;
427 heap_free(metafile->comment_data);
428 DeleteEnhMetaFile(CloseEnhMetaFile(metafile->record_dc));
429 if (!metafile->preserve_hemf)
430 DeleteEnhMetaFile(metafile->hemf);
431 if (metafile->record_graphics)
433 WARN("metafile closed while recording\n");
434 /* not sure what to do here; for now just prevent the graphics from functioning or using this object */
435 metafile->record_graphics->image = NULL;
436 metafile->record_graphics->busy = TRUE;
439 if (metafile->record_stream)
440 IStream_Release(metafile->record_stream);
442 for (i = 0; i < sizeof(metafile->objtable)/sizeof(metafile->objtable[0]); i++)
443 metafile_free_object_table_entry(metafile, i);
446 static DWORD METAFILE_AddObjectId(GpMetafile *metafile)
448 return (metafile->next_object_id++) % EmfPlusObjectTableSize;
451 static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result)
453 DWORD size_needed;
454 EmfPlusRecordHeader *record;
456 if (!metafile->comment_data_size)
458 DWORD data_size = max(256, size * 2 + 4);
459 metafile->comment_data = heap_alloc_zero(data_size);
461 if (!metafile->comment_data)
462 return OutOfMemory;
464 memcpy(metafile->comment_data, "EMF+", 4);
466 metafile->comment_data_size = data_size;
467 metafile->comment_data_length = 4;
470 size_needed = size + metafile->comment_data_length;
472 if (size_needed > metafile->comment_data_size)
474 DWORD data_size = size_needed * 2;
475 BYTE *new_data = heap_alloc_zero(data_size);
477 if (!new_data)
478 return OutOfMemory;
480 memcpy(new_data, metafile->comment_data, metafile->comment_data_length);
482 metafile->comment_data_size = data_size;
483 heap_free(metafile->comment_data);
484 metafile->comment_data = new_data;
487 *result = metafile->comment_data + metafile->comment_data_length;
488 metafile->comment_data_length += size;
490 record = (EmfPlusRecordHeader*)*result;
491 record->Size = size;
492 record->DataSize = size - sizeof(EmfPlusRecordHeader);
494 return Ok;
497 static void METAFILE_RemoveLastRecord(GpMetafile *metafile, EmfPlusRecordHeader *record)
499 assert(metafile->comment_data + metafile->comment_data_length == (BYTE*)record + record->Size);
500 metafile->comment_data_length -= record->Size;
503 static void METAFILE_WriteRecords(GpMetafile *metafile)
505 if (metafile->comment_data_length > 4)
507 GdiComment(metafile->record_dc, metafile->comment_data_length, metafile->comment_data);
508 metafile->comment_data_length = 4;
512 static GpStatus METAFILE_WriteHeader(GpMetafile *metafile, HDC hdc)
514 GpStatus stat;
516 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
518 EmfPlusHeader *header;
520 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusHeader), (void**)&header);
521 if (stat != Ok)
522 return stat;
524 header->Header.Type = EmfPlusRecordTypeHeader;
526 if (metafile->metafile_type == MetafileTypeEmfPlusDual)
527 header->Header.Flags = 1;
528 else
529 header->Header.Flags = 0;
531 header->Version = VERSION_MAGIC2;
533 if (GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY)
534 header->EmfPlusFlags = 1;
535 else
536 header->EmfPlusFlags = 0;
538 header->LogicalDpiX = GetDeviceCaps(hdc, LOGPIXELSX);
539 header->LogicalDpiY = GetDeviceCaps(hdc, LOGPIXELSY);
541 METAFILE_WriteRecords(metafile);
544 return Ok;
547 static GpStatus METAFILE_WriteEndOfFile(GpMetafile *metafile)
549 GpStatus stat;
551 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
553 EmfPlusRecordHeader *record;
555 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusRecordHeader), (void**)&record);
556 if (stat != Ok)
557 return stat;
559 record->Type = EmfPlusRecordTypeEndOfFile;
560 record->Flags = 0;
562 METAFILE_WriteRecords(metafile);
565 return Ok;
568 GpStatus WINGDIPAPI GdipRecordMetafile(HDC hdc, EmfType type, GDIPCONST GpRectF *frameRect,
569 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
571 HDC record_dc;
572 REAL dpix, dpiy;
573 REAL framerect_factor_x, framerect_factor_y;
574 RECT rc, *lprc;
575 GpStatus stat;
577 TRACE("(%p %d %p %d %p %p)\n", hdc, type, frameRect, frameUnit, desc, metafile);
579 if (!hdc || type < EmfTypeEmfOnly || type > EmfTypeEmfPlusDual || !metafile)
580 return InvalidParameter;
582 dpix = (REAL)GetDeviceCaps(hdc, HORZRES) / GetDeviceCaps(hdc, HORZSIZE) * 25.4;
583 dpiy = (REAL)GetDeviceCaps(hdc, VERTRES) / GetDeviceCaps(hdc, VERTSIZE) * 25.4;
585 if (frameRect)
587 switch (frameUnit)
589 case MetafileFrameUnitPixel:
590 framerect_factor_x = 2540.0 / dpix;
591 framerect_factor_y = 2540.0 / dpiy;
592 break;
593 case MetafileFrameUnitPoint:
594 framerect_factor_x = framerect_factor_y = 2540.0 / 72.0;
595 break;
596 case MetafileFrameUnitInch:
597 framerect_factor_x = framerect_factor_y = 2540.0;
598 break;
599 case MetafileFrameUnitDocument:
600 framerect_factor_x = framerect_factor_y = 2540.0 / 300.0;
601 break;
602 case MetafileFrameUnitMillimeter:
603 framerect_factor_x = framerect_factor_y = 100.0;
604 break;
605 case MetafileFrameUnitGdi:
606 framerect_factor_x = framerect_factor_y = 1.0;
607 break;
608 default:
609 return InvalidParameter;
612 rc.left = framerect_factor_x * frameRect->X;
613 rc.top = framerect_factor_y * frameRect->Y;
614 rc.right = rc.left + framerect_factor_x * frameRect->Width;
615 rc.bottom = rc.top + framerect_factor_y * frameRect->Height;
617 lprc = &rc;
619 else
620 lprc = NULL;
622 record_dc = CreateEnhMetaFileW(hdc, NULL, lprc, desc);
624 if (!record_dc)
625 return GenericError;
627 *metafile = heap_alloc_zero(sizeof(GpMetafile));
628 if(!*metafile)
630 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc));
631 return OutOfMemory;
634 (*metafile)->image.type = ImageTypeMetafile;
635 (*metafile)->image.flags = ImageFlagsNone;
636 (*metafile)->image.palette = NULL;
637 (*metafile)->image.xres = dpix;
638 (*metafile)->image.yres = dpiy;
639 (*metafile)->bounds.X = (*metafile)->bounds.Y = 0.0;
640 (*metafile)->bounds.Width = (*metafile)->bounds.Height = 1.0;
641 (*metafile)->unit = UnitPixel;
642 (*metafile)->metafile_type = type;
643 (*metafile)->record_dc = record_dc;
644 (*metafile)->comment_data = NULL;
645 (*metafile)->comment_data_size = 0;
646 (*metafile)->comment_data_length = 0;
647 (*metafile)->hemf = NULL;
648 list_init(&(*metafile)->containers);
650 if (!frameRect)
652 (*metafile)->auto_frame = TRUE;
653 (*metafile)->auto_frame_min.X = 0;
654 (*metafile)->auto_frame_min.Y = 0;
655 (*metafile)->auto_frame_max.X = -1;
656 (*metafile)->auto_frame_max.Y = -1;
659 stat = METAFILE_WriteHeader(*metafile, hdc);
661 if (stat != Ok)
663 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc));
664 heap_free(*metafile);
665 *metafile = NULL;
666 return OutOfMemory;
669 return stat;
672 /*****************************************************************************
673 * GdipRecordMetafileI [GDIPLUS.@]
675 GpStatus WINGDIPAPI GdipRecordMetafileI(HDC hdc, EmfType type, GDIPCONST GpRect *frameRect,
676 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
678 GpRectF frameRectF, *pFrameRectF;
680 TRACE("(%p %d %p %d %p %p)\n", hdc, type, frameRect, frameUnit, desc, metafile);
682 if (frameRect)
684 frameRectF.X = frameRect->X;
685 frameRectF.Y = frameRect->Y;
686 frameRectF.Width = frameRect->Width;
687 frameRectF.Height = frameRect->Height;
688 pFrameRectF = &frameRectF;
690 else
691 pFrameRectF = NULL;
693 return GdipRecordMetafile(hdc, type, pFrameRectF, frameUnit, desc, metafile);
696 GpStatus WINGDIPAPI GdipRecordMetafileStream(IStream *stream, HDC hdc, EmfType type, GDIPCONST GpRectF *frameRect,
697 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
699 GpStatus stat;
701 TRACE("(%p %p %d %p %d %p %p)\n", stream, hdc, type, frameRect, frameUnit, desc, metafile);
703 if (!stream)
704 return InvalidParameter;
706 stat = GdipRecordMetafile(hdc, type, frameRect, frameUnit, desc, metafile);
708 if (stat == Ok)
710 (*metafile)->record_stream = stream;
711 IStream_AddRef(stream);
714 return stat;
717 static void METAFILE_AdjustFrame(GpMetafile* metafile, const GpPointF *points,
718 UINT num_points)
720 int i;
722 if (!metafile->auto_frame || !num_points)
723 return;
725 if (metafile->auto_frame_max.X < metafile->auto_frame_min.X)
726 metafile->auto_frame_max = metafile->auto_frame_min = points[0];
728 for (i=0; i<num_points; i++)
730 if (points[i].X < metafile->auto_frame_min.X)
731 metafile->auto_frame_min.X = points[i].X;
732 if (points[i].X > metafile->auto_frame_max.X)
733 metafile->auto_frame_max.X = points[i].X;
734 if (points[i].Y < metafile->auto_frame_min.Y)
735 metafile->auto_frame_min.Y = points[i].Y;
736 if (points[i].Y > metafile->auto_frame_max.Y)
737 metafile->auto_frame_max.Y = points[i].Y;
741 GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result)
743 GpStatus stat;
745 if (!metafile->record_dc || metafile->record_graphics)
746 return InvalidParameter;
748 stat = graphics_from_image((GpImage*)metafile, &metafile->record_graphics);
750 if (stat == Ok)
752 *result = metafile->record_graphics;
753 metafile->record_graphics->xres = 96.0;
754 metafile->record_graphics->yres = 96.0;
757 return stat;
760 GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc)
762 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
764 EmfPlusRecordHeader *record;
765 GpStatus stat;
767 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusRecordHeader), (void**)&record);
768 if (stat != Ok)
769 return stat;
771 record->Type = EmfPlusRecordTypeGetDC;
772 record->Flags = 0;
774 METAFILE_WriteRecords(metafile);
777 *hdc = metafile->record_dc;
779 return Ok;
782 GpStatus METAFILE_GraphicsClear(GpMetafile* metafile, ARGB color)
784 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
786 EmfPlusClear *record;
787 GpStatus stat;
789 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusClear), (void**)&record);
790 if (stat != Ok)
791 return stat;
793 record->Header.Type = EmfPlusRecordTypeClear;
794 record->Header.Flags = 0;
795 record->Color = color;
797 METAFILE_WriteRecords(metafile);
800 return Ok;
803 static BOOL is_integer_rect(const GpRectF *rect)
805 SHORT x, y, width, height;
806 x = rect->X;
807 y = rect->Y;
808 width = rect->Width;
809 height = rect->Height;
810 if (rect->X != (REAL)x || rect->Y != (REAL)y ||
811 rect->Width != (REAL)width || rect->Height != (REAL)height)
812 return FALSE;
813 return TRUE;
816 GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush,
817 GDIPCONST GpRectF* rects, INT count)
819 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
821 EmfPlusFillRects *record;
822 GpStatus stat;
823 BOOL integer_rects = TRUE;
824 int i;
825 DWORD brushid;
826 int flags = 0;
828 if (brush->bt == BrushTypeSolidColor)
830 flags |= 0x8000;
831 brushid = ((GpSolidFill*)brush)->color;
833 else
835 FIXME("brush serialization not implemented\n");
836 return NotImplemented;
839 for (i=0; i<count; i++)
841 if (!is_integer_rect(&rects[i]))
843 integer_rects = FALSE;
844 break;
848 if (integer_rects)
849 flags |= 0x4000;
851 stat = METAFILE_AllocateRecord(metafile,
852 sizeof(EmfPlusFillRects) + count * (integer_rects ? sizeof(EmfPlusRect) : sizeof(GpRectF)),
853 (void**)&record);
854 if (stat != Ok)
855 return stat;
857 record->Header.Type = EmfPlusRecordTypeFillRects;
858 record->Header.Flags = flags;
859 record->BrushID = brushid;
860 record->Count = count;
862 if (integer_rects)
864 EmfPlusRect *record_rects = (EmfPlusRect*)(record+1);
865 for (i=0; i<count; i++)
867 record_rects[i].X = (SHORT)rects[i].X;
868 record_rects[i].Y = (SHORT)rects[i].Y;
869 record_rects[i].Width = (SHORT)rects[i].Width;
870 record_rects[i].Height = (SHORT)rects[i].Height;
873 else
874 memcpy(record+1, rects, sizeof(GpRectF) * count);
876 METAFILE_WriteRecords(metafile);
879 if (metafile->auto_frame)
881 GpPointF corners[4];
882 int i;
884 for (i=0; i<count; i++)
886 corners[0].X = rects[i].X;
887 corners[0].Y = rects[i].Y;
888 corners[1].X = rects[i].X + rects[i].Width;
889 corners[1].Y = rects[i].Y;
890 corners[2].X = rects[i].X;
891 corners[2].Y = rects[i].Y + rects[i].Height;
892 corners[3].X = rects[i].X + rects[i].Width;
893 corners[3].Y = rects[i].Y + rects[i].Height;
895 GdipTransformPoints(metafile->record_graphics, CoordinateSpaceDevice,
896 CoordinateSpaceWorld, corners, 4);
898 METAFILE_AdjustFrame(metafile, corners, 4);
902 return Ok;
905 GpStatus METAFILE_SetClipRect(GpMetafile* metafile, REAL x, REAL y, REAL width, REAL height, CombineMode mode)
907 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
909 EmfPlusSetClipRect *record;
910 GpStatus stat;
912 stat = METAFILE_AllocateRecord(metafile,
913 sizeof(EmfPlusSetClipRect),
914 (void**)&record);
915 if (stat != Ok)
916 return stat;
918 record->Header.Type = EmfPlusRecordTypeSetClipRect;
919 record->Header.Flags = (mode & 0xf) << 8;
920 record->ClipRect.X = x;
921 record->ClipRect.Y = y;
922 record->ClipRect.Width = width;
923 record->ClipRect.Height = height;
925 METAFILE_WriteRecords(metafile);
928 return Ok;
931 static GpStatus METAFILE_AddRegionObject(GpMetafile *metafile, GpRegion *region, DWORD *id)
933 EmfPlusObject *object_record;
934 DWORD size;
935 GpStatus stat;
937 *id = -1;
938 if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
939 return Ok;
941 size = write_region_data(region, NULL);
942 stat = METAFILE_AllocateRecord(metafile,
943 FIELD_OFFSET(EmfPlusObject, ObjectData.region) + size, (void**)&object_record);
944 if (stat != Ok) return stat;
946 *id = METAFILE_AddObjectId(metafile);
947 object_record->Header.Type = EmfPlusRecordTypeObject;
948 object_record->Header.Flags = *id | ObjectTypeRegion << 8;
949 write_region_data(region, &object_record->ObjectData.region);
950 return Ok;
953 GpStatus METAFILE_SetClipRegion(GpMetafile* metafile, GpRegion* region, CombineMode mode)
955 EmfPlusRecordHeader *record;
956 DWORD region_id;
957 GpStatus stat;
959 if (metafile->metafile_type == MetafileTypeEmf)
961 FIXME("stub!\n");
962 return NotImplemented;
965 stat = METAFILE_AddRegionObject(metafile, region, &region_id);
966 if (stat != Ok) return stat;
968 stat = METAFILE_AllocateRecord(metafile, sizeof(*record), (void**)&record);
969 if (stat != Ok) return stat;
971 record->Type = EmfPlusRecordTypeSetClipRegion;
972 record->Flags = region_id | mode << 8;
974 METAFILE_WriteRecords(metafile);
975 return Ok;
978 GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale)
980 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
982 EmfPlusSetPageTransform *record;
983 GpStatus stat;
985 stat = METAFILE_AllocateRecord(metafile,
986 sizeof(EmfPlusSetPageTransform),
987 (void**)&record);
988 if (stat != Ok)
989 return stat;
991 record->Header.Type = EmfPlusRecordTypeSetPageTransform;
992 record->Header.Flags = unit;
993 record->PageScale = scale;
995 METAFILE_WriteRecords(metafile);
998 return Ok;
1001 GpStatus METAFILE_SetWorldTransform(GpMetafile* metafile, GDIPCONST GpMatrix* transform)
1003 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1005 EmfPlusSetWorldTransform *record;
1006 GpStatus stat;
1008 stat = METAFILE_AllocateRecord(metafile,
1009 sizeof(EmfPlusSetWorldTransform),
1010 (void**)&record);
1011 if (stat != Ok)
1012 return stat;
1014 record->Header.Type = EmfPlusRecordTypeSetWorldTransform;
1015 record->Header.Flags = 0;
1016 memcpy(record->MatrixData, transform->matrix, sizeof(record->MatrixData));
1018 METAFILE_WriteRecords(metafile);
1021 return Ok;
1024 GpStatus METAFILE_ScaleWorldTransform(GpMetafile* metafile, REAL sx, REAL sy, MatrixOrder order)
1026 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1028 EmfPlusScaleWorldTransform *record;
1029 GpStatus stat;
1031 stat = METAFILE_AllocateRecord(metafile,
1032 sizeof(EmfPlusScaleWorldTransform),
1033 (void**)&record);
1034 if (stat != Ok)
1035 return stat;
1037 record->Header.Type = EmfPlusRecordTypeScaleWorldTransform;
1038 record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0);
1039 record->Sx = sx;
1040 record->Sy = sy;
1042 METAFILE_WriteRecords(metafile);
1045 return Ok;
1048 GpStatus METAFILE_MultiplyWorldTransform(GpMetafile* metafile, GDIPCONST GpMatrix* matrix, MatrixOrder order)
1050 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1052 EmfPlusMultiplyWorldTransform *record;
1053 GpStatus stat;
1055 stat = METAFILE_AllocateRecord(metafile,
1056 sizeof(EmfPlusMultiplyWorldTransform),
1057 (void**)&record);
1058 if (stat != Ok)
1059 return stat;
1061 record->Header.Type = EmfPlusRecordTypeMultiplyWorldTransform;
1062 record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0);
1063 memcpy(record->MatrixData, matrix->matrix, sizeof(record->MatrixData));
1065 METAFILE_WriteRecords(metafile);
1068 return Ok;
1071 GpStatus METAFILE_RotateWorldTransform(GpMetafile* metafile, REAL angle, MatrixOrder order)
1073 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1075 EmfPlusRotateWorldTransform *record;
1076 GpStatus stat;
1078 stat = METAFILE_AllocateRecord(metafile,
1079 sizeof(EmfPlusRotateWorldTransform),
1080 (void**)&record);
1081 if (stat != Ok)
1082 return stat;
1084 record->Header.Type = EmfPlusRecordTypeRotateWorldTransform;
1085 record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0);
1086 record->Angle = angle;
1088 METAFILE_WriteRecords(metafile);
1091 return Ok;
1094 GpStatus METAFILE_TranslateWorldTransform(GpMetafile* metafile, REAL dx, REAL dy, MatrixOrder order)
1096 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1098 EmfPlusTranslateWorldTransform *record;
1099 GpStatus stat;
1101 stat = METAFILE_AllocateRecord(metafile,
1102 sizeof(EmfPlusTranslateWorldTransform),
1103 (void**)&record);
1104 if (stat != Ok)
1105 return stat;
1107 record->Header.Type = EmfPlusRecordTypeTranslateWorldTransform;
1108 record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0);
1109 record->dx = dx;
1110 record->dy = dy;
1112 METAFILE_WriteRecords(metafile);
1115 return Ok;
1118 GpStatus METAFILE_ResetWorldTransform(GpMetafile* metafile)
1120 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1122 EmfPlusRecordHeader *record;
1123 GpStatus stat;
1125 stat = METAFILE_AllocateRecord(metafile,
1126 sizeof(EmfPlusRecordHeader),
1127 (void**)&record);
1128 if (stat != Ok)
1129 return stat;
1131 record->Type = EmfPlusRecordTypeResetWorldTransform;
1132 record->Flags = 0;
1134 METAFILE_WriteRecords(metafile);
1137 return Ok;
1140 GpStatus METAFILE_BeginContainer(GpMetafile* metafile, GDIPCONST GpRectF *dstrect,
1141 GDIPCONST GpRectF *srcrect, GpUnit unit, DWORD StackIndex)
1143 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1145 EmfPlusBeginContainer *record;
1146 GpStatus stat;
1148 stat = METAFILE_AllocateRecord(metafile, sizeof(*record), (void**)&record);
1149 if (stat != Ok)
1150 return stat;
1152 record->Header.Type = EmfPlusRecordTypeBeginContainer;
1153 record->Header.Flags = unit & 0xff;
1154 record->DestRect = *dstrect;
1155 record->SrcRect = *srcrect;
1156 record->StackIndex = StackIndex;
1158 METAFILE_WriteRecords(metafile);
1161 return Ok;
1164 GpStatus METAFILE_BeginContainerNoParams(GpMetafile* metafile, DWORD StackIndex)
1166 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1168 EmfPlusContainerRecord *record;
1169 GpStatus stat;
1171 stat = METAFILE_AllocateRecord(metafile,
1172 sizeof(EmfPlusContainerRecord),
1173 (void**)&record);
1174 if (stat != Ok)
1175 return stat;
1177 record->Header.Type = EmfPlusRecordTypeBeginContainerNoParams;
1178 record->Header.Flags = 0;
1179 record->StackIndex = StackIndex;
1181 METAFILE_WriteRecords(metafile);
1184 return Ok;
1187 GpStatus METAFILE_EndContainer(GpMetafile* metafile, DWORD StackIndex)
1189 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1191 EmfPlusContainerRecord *record;
1192 GpStatus stat;
1194 stat = METAFILE_AllocateRecord(metafile,
1195 sizeof(EmfPlusContainerRecord),
1196 (void**)&record);
1197 if (stat != Ok)
1198 return stat;
1200 record->Header.Type = EmfPlusRecordTypeEndContainer;
1201 record->Header.Flags = 0;
1202 record->StackIndex = StackIndex;
1204 METAFILE_WriteRecords(metafile);
1207 return Ok;
1210 GpStatus METAFILE_SaveGraphics(GpMetafile* metafile, DWORD StackIndex)
1212 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1214 EmfPlusContainerRecord *record;
1215 GpStatus stat;
1217 stat = METAFILE_AllocateRecord(metafile,
1218 sizeof(EmfPlusContainerRecord),
1219 (void**)&record);
1220 if (stat != Ok)
1221 return stat;
1223 record->Header.Type = EmfPlusRecordTypeSave;
1224 record->Header.Flags = 0;
1225 record->StackIndex = StackIndex;
1227 METAFILE_WriteRecords(metafile);
1230 return Ok;
1233 GpStatus METAFILE_RestoreGraphics(GpMetafile* metafile, DWORD StackIndex)
1235 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1237 EmfPlusContainerRecord *record;
1238 GpStatus stat;
1240 stat = METAFILE_AllocateRecord(metafile,
1241 sizeof(EmfPlusContainerRecord),
1242 (void**)&record);
1243 if (stat != Ok)
1244 return stat;
1246 record->Header.Type = EmfPlusRecordTypeRestore;
1247 record->Header.Flags = 0;
1248 record->StackIndex = StackIndex;
1250 METAFILE_WriteRecords(metafile);
1253 return Ok;
1256 GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc)
1258 if (hdc != metafile->record_dc)
1259 return InvalidParameter;
1261 return Ok;
1264 GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile)
1266 GpStatus stat;
1268 stat = METAFILE_WriteEndOfFile(metafile);
1269 metafile->record_graphics = NULL;
1271 metafile->hemf = CloseEnhMetaFile(metafile->record_dc);
1272 metafile->record_dc = NULL;
1274 heap_free(metafile->comment_data);
1275 metafile->comment_data = NULL;
1276 metafile->comment_data_size = 0;
1278 if (stat == Ok)
1280 MetafileHeader header;
1282 stat = GdipGetMetafileHeaderFromEmf(metafile->hemf, &header);
1283 if (stat == Ok && metafile->auto_frame &&
1284 metafile->auto_frame_max.X >= metafile->auto_frame_min.X)
1286 RECTL bounds_rc, gdi_bounds_rc;
1287 REAL x_scale = 2540.0 / header.DpiX;
1288 REAL y_scale = 2540.0 / header.DpiY;
1289 BYTE* buffer;
1290 UINT buffer_size;
1292 bounds_rc.left = floorf(metafile->auto_frame_min.X * x_scale);
1293 bounds_rc.top = floorf(metafile->auto_frame_min.Y * y_scale);
1294 bounds_rc.right = ceilf(metafile->auto_frame_max.X * x_scale);
1295 bounds_rc.bottom = ceilf(metafile->auto_frame_max.Y * y_scale);
1297 gdi_bounds_rc = header.u.EmfHeader.rclBounds;
1298 if (gdi_bounds_rc.right > gdi_bounds_rc.left && gdi_bounds_rc.bottom > gdi_bounds_rc.top)
1300 bounds_rc.left = min(bounds_rc.left, gdi_bounds_rc.left);
1301 bounds_rc.top = min(bounds_rc.top, gdi_bounds_rc.top);
1302 bounds_rc.right = max(bounds_rc.right, gdi_bounds_rc.right);
1303 bounds_rc.bottom = max(bounds_rc.bottom, gdi_bounds_rc.bottom);
1306 buffer_size = GetEnhMetaFileBits(metafile->hemf, 0, NULL);
1307 buffer = heap_alloc(buffer_size);
1308 if (buffer)
1310 HENHMETAFILE new_hemf;
1312 GetEnhMetaFileBits(metafile->hemf, buffer_size, buffer);
1314 ((ENHMETAHEADER*)buffer)->rclFrame = bounds_rc;
1316 new_hemf = SetEnhMetaFileBits(buffer_size, buffer);
1318 if (new_hemf)
1320 DeleteEnhMetaFile(metafile->hemf);
1321 metafile->hemf = new_hemf;
1323 else
1324 stat = OutOfMemory;
1326 heap_free(buffer);
1328 else
1329 stat = OutOfMemory;
1331 if (stat == Ok)
1332 stat = GdipGetMetafileHeaderFromEmf(metafile->hemf, &header);
1334 if (stat == Ok)
1336 metafile->bounds.X = header.X;
1337 metafile->bounds.Y = header.Y;
1338 metafile->bounds.Width = header.Width;
1339 metafile->bounds.Height = header.Height;
1343 if (stat == Ok && metafile->record_stream)
1345 BYTE *buffer;
1346 UINT buffer_size;
1348 buffer_size = GetEnhMetaFileBits(metafile->hemf, 0, NULL);
1350 buffer = heap_alloc(buffer_size);
1351 if (buffer)
1353 HRESULT hr;
1355 GetEnhMetaFileBits(metafile->hemf, buffer_size, buffer);
1357 hr = IStream_Write(metafile->record_stream, buffer, buffer_size, NULL);
1359 if (FAILED(hr))
1360 stat = hresult_to_status(hr);
1362 heap_free(buffer);
1364 else
1365 stat = OutOfMemory;
1368 if (metafile->record_stream)
1370 IStream_Release(metafile->record_stream);
1371 metafile->record_stream = NULL;
1374 return stat;
1377 GpStatus WINGDIPAPI GdipGetHemfFromMetafile(GpMetafile *metafile, HENHMETAFILE *hEmf)
1379 TRACE("(%p,%p)\n", metafile, hEmf);
1381 if (!metafile || !hEmf || !metafile->hemf)
1382 return InvalidParameter;
1384 *hEmf = metafile->hemf;
1385 metafile->hemf = NULL;
1387 return Ok;
1390 static void METAFILE_GetFinalGdiTransform(const GpMetafile *metafile, XFORM *result)
1392 const GpRectF *rect;
1393 const GpPointF *pt;
1395 /* This transforms metafile device space to output points. */
1396 rect = &metafile->src_rect;
1397 pt = metafile->playback_points;
1398 result->eM11 = (pt[1].X - pt[0].X) / rect->Width;
1399 result->eM21 = (pt[2].X - pt[0].X) / rect->Height;
1400 result->eDx = pt[0].X - result->eM11 * rect->X - result->eM21 * rect->Y;
1401 result->eM12 = (pt[1].Y - pt[0].Y) / rect->Width;
1402 result->eM22 = (pt[2].Y - pt[0].Y) / rect->Height;
1403 result->eDy = pt[0].Y - result->eM12 * rect->X - result->eM22 * rect->Y;
1406 static GpStatus METAFILE_PlaybackUpdateGdiTransform(GpMetafile *metafile)
1408 XFORM combined, final;
1410 METAFILE_GetFinalGdiTransform(metafile, &final);
1412 CombineTransform(&combined, &metafile->gdiworldtransform, &final);
1414 SetGraphicsMode(metafile->playback_dc, GM_ADVANCED);
1415 SetWorldTransform(metafile->playback_dc, &combined);
1417 return Ok;
1420 static GpStatus METAFILE_PlaybackGetDC(GpMetafile *metafile)
1422 GpStatus stat = Ok;
1424 stat = GdipGetDC(metafile->playback_graphics, &metafile->playback_dc);
1426 if (stat == Ok)
1428 static const XFORM identity = {1, 0, 0, 1, 0, 0};
1430 metafile->gdiworldtransform = identity;
1431 METAFILE_PlaybackUpdateGdiTransform(metafile);
1434 return stat;
1437 static void METAFILE_PlaybackReleaseDC(GpMetafile *metafile)
1439 if (metafile->playback_dc)
1441 GdipReleaseDC(metafile->playback_graphics, metafile->playback_dc);
1442 metafile->playback_dc = NULL;
1446 static GpStatus METAFILE_PlaybackUpdateClip(GpMetafile *metafile)
1448 GpStatus stat;
1449 stat = GdipCombineRegionRegion(metafile->playback_graphics->clip, metafile->base_clip, CombineModeReplace);
1450 if (stat == Ok)
1451 stat = GdipCombineRegionRegion(metafile->playback_graphics->clip, metafile->clip, CombineModeIntersect);
1452 return stat;
1455 static GpStatus METAFILE_PlaybackUpdateWorldTransform(GpMetafile *metafile)
1457 GpMatrix *real_transform;
1458 GpStatus stat;
1460 stat = GdipCreateMatrix3(&metafile->src_rect, metafile->playback_points, &real_transform);
1462 if (stat == Ok)
1464 REAL scale = units_to_pixels(1.0, metafile->page_unit, 96.0);
1466 if (metafile->page_unit != UnitDisplay)
1467 scale *= metafile->page_scale;
1469 stat = GdipScaleMatrix(real_transform, scale, scale, MatrixOrderPrepend);
1471 if (stat == Ok)
1472 stat = GdipMultiplyMatrix(real_transform, metafile->world_transform, MatrixOrderPrepend);
1474 if (stat == Ok)
1475 stat = GdipSetWorldTransform(metafile->playback_graphics, real_transform);
1477 GdipDeleteMatrix(real_transform);
1480 return stat;
1483 static void metafile_set_object_table_entry(GpMetafile *metafile, BYTE id, BYTE type, void *object)
1485 metafile_free_object_table_entry(metafile, id);
1486 metafile->objtable[id].type = type;
1487 metafile->objtable[id].u.object = object;
1490 static GpStatus metafile_deserialize_image(const BYTE *record_data, UINT data_size, GpImage **image)
1492 EmfPlusImage *data = (EmfPlusImage *)record_data;
1493 GpStatus status;
1495 *image = NULL;
1497 if (data_size < FIELD_OFFSET(EmfPlusImage, ImageData))
1498 return InvalidParameter;
1499 data_size -= FIELD_OFFSET(EmfPlusImage, ImageData);
1501 switch (data->Type)
1503 case ImageDataTypeBitmap:
1505 EmfPlusBitmap *bitmapdata = &data->ImageData.bitmap;
1507 if (data_size <= FIELD_OFFSET(EmfPlusBitmap, BitmapData))
1508 return InvalidParameter;
1509 data_size -= FIELD_OFFSET(EmfPlusBitmap, BitmapData);
1511 switch (bitmapdata->Type)
1513 case BitmapDataTypePixel:
1515 ColorPalette *palette;
1516 BYTE *scan0;
1518 if (bitmapdata->PixelFormat & PixelFormatIndexed)
1520 EmfPlusPalette *palette_obj = (EmfPlusPalette *)bitmapdata->BitmapData;
1521 UINT palette_size = FIELD_OFFSET(EmfPlusPalette, PaletteEntries);
1523 if (data_size <= palette_size)
1524 return InvalidParameter;
1525 palette_size += palette_obj->PaletteCount * sizeof(EmfPlusARGB);
1527 if (data_size < palette_size)
1528 return InvalidParameter;
1529 data_size -= palette_size;
1531 palette = (ColorPalette *)bitmapdata->BitmapData;
1532 scan0 = (BYTE *)bitmapdata->BitmapData + palette_size;
1534 else
1536 palette = NULL;
1537 scan0 = bitmapdata->BitmapData;
1540 if (data_size < bitmapdata->Height * bitmapdata->Stride)
1541 return InvalidParameter;
1543 status = GdipCreateBitmapFromScan0(bitmapdata->Width, bitmapdata->Height, bitmapdata->Stride,
1544 bitmapdata->PixelFormat, scan0, (GpBitmap **)image);
1545 if (status == Ok && palette)
1547 status = GdipSetImagePalette(*image, palette);
1548 if (status != Ok)
1550 GdipDisposeImage(*image);
1551 *image = NULL;
1554 break;
1556 case BitmapDataTypeCompressed:
1558 IWICImagingFactory *factory;
1559 IWICStream *stream;
1560 HRESULT hr;
1562 if (WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory) != S_OK)
1563 return GenericError;
1565 hr = IWICImagingFactory_CreateStream(factory, &stream);
1566 IWICImagingFactory_Release(factory);
1567 if (hr != S_OK)
1568 return GenericError;
1570 if (IWICStream_InitializeFromMemory(stream, bitmapdata->BitmapData, data_size) == S_OK)
1571 status = GdipCreateBitmapFromStream((IStream *)stream, (GpBitmap **)image);
1572 else
1573 status = GenericError;
1575 IWICStream_Release(stream);
1576 break;
1578 default:
1579 WARN("Invalid bitmap type %d.\n", bitmapdata->Type);
1580 return InvalidParameter;
1582 break;
1584 default:
1585 FIXME("image type %d not supported.\n", data->Type);
1586 return NotImplemented;
1589 return status;
1592 static GpStatus metafile_deserialize_path(const BYTE *record_data, UINT data_size, GpPath **path)
1594 EmfPlusPath *data = (EmfPlusPath *)record_data;
1595 GpStatus status;
1596 BYTE *types;
1597 UINT size;
1598 DWORD i;
1600 *path = NULL;
1602 if (data_size <= FIELD_OFFSET(EmfPlusPath, data))
1603 return InvalidParameter;
1604 data_size -= FIELD_OFFSET(EmfPlusPath, data);
1606 if (data->PathPointFlags & 0x800) /* R */
1608 FIXME("RLE encoded path data is not supported.\n");
1609 return NotImplemented;
1611 else
1613 if (data->PathPointFlags & 0x4000) /* C */
1614 size = sizeof(EmfPlusPoint);
1615 else
1616 size = sizeof(EmfPlusPointF);
1617 size += sizeof(BYTE); /* EmfPlusPathPointType */
1618 size *= data->PathPointCount;
1621 if (data_size < size)
1622 return InvalidParameter;
1624 status = GdipCreatePath(FillModeAlternate, path);
1625 if (status != Ok)
1626 return status;
1628 (*path)->pathdata.Count = data->PathPointCount;
1629 (*path)->pathdata.Points = GdipAlloc(data->PathPointCount * sizeof(*(*path)->pathdata.Points));
1630 (*path)->pathdata.Types = GdipAlloc(data->PathPointCount * sizeof(*(*path)->pathdata.Types));
1631 (*path)->datalen = (*path)->pathdata.Count;
1633 if (!(*path)->pathdata.Points || !(*path)->pathdata.Types)
1635 GdipDeletePath(*path);
1636 return OutOfMemory;
1639 if (data->PathPointFlags & 0x4000) /* C */
1641 EmfPlusPoint *points = (EmfPlusPoint *)data->data;
1642 for (i = 0; i < data->PathPointCount; i++)
1644 (*path)->pathdata.Points[i].X = points[i].X;
1645 (*path)->pathdata.Points[i].Y = points[i].Y;
1647 types = (BYTE *)(points + i);
1649 else
1651 EmfPlusPointF *points = (EmfPlusPointF *)data->data;
1652 memcpy((*path)->pathdata.Points, points, sizeof(*points) * data->PathPointCount);
1653 types = (BYTE *)(points + data->PathPointCount);
1656 memcpy((*path)->pathdata.Types, types, sizeof(*types) * data->PathPointCount);
1658 return Ok;
1661 static GpStatus metafile_deserialize_brush(const BYTE *record_data, UINT data_size, GpBrush **brush)
1663 static const UINT header_size = FIELD_OFFSET(EmfPlusBrush, BrushData);
1664 EmfPlusBrush *data = (EmfPlusBrush *)record_data;
1665 GpStatus status;
1667 *brush = NULL;
1669 if (data_size < header_size)
1670 return InvalidParameter;
1672 switch (data->Type)
1674 case BrushTypeSolidColor:
1675 if (data_size != header_size + sizeof(EmfPlusSolidBrushData))
1676 return InvalidParameter;
1678 status = GdipCreateSolidFill(*(ARGB *)&data->BrushData.solid.SolidColor, (GpSolidFill **)brush);
1679 break;
1680 default:
1681 FIXME("brush type %u is not supported.\n", data->Type);
1682 return NotImplemented;
1685 return status;
1688 static GpStatus METAFILE_PlaybackObject(GpMetafile *metafile, UINT flags, UINT data_size, const BYTE *record_data)
1690 BYTE type = (flags >> 8) & 0xff;
1691 BYTE id = flags & 0xff;
1692 void *object = NULL;
1693 GpStatus status;
1695 if (type > ObjectTypeMax || id >= EmfPlusObjectTableSize)
1696 return InvalidParameter;
1698 switch (type)
1700 case ObjectTypeBrush:
1701 status = metafile_deserialize_brush(record_data, data_size, (GpBrush **)&object);
1702 break;
1703 case ObjectTypePath:
1704 status = metafile_deserialize_path(record_data, data_size, (GpPath **)&object);
1705 break;
1706 case ObjectTypeImage:
1707 status = metafile_deserialize_image(record_data, data_size, (GpImage **)&object);
1708 break;
1709 case ObjectTypeFont:
1711 EmfPlusFont *data = (EmfPlusFont *)record_data;
1712 GpFontFamily *family;
1713 WCHAR *familyname;
1715 if (data_size <= FIELD_OFFSET(EmfPlusFont, FamilyName))
1716 return InvalidParameter;
1717 data_size -= FIELD_OFFSET(EmfPlusFont, FamilyName);
1719 if (data_size < data->Length * sizeof(WCHAR))
1720 return InvalidParameter;
1722 if (!(familyname = GdipAlloc((data->Length + 1) * sizeof(*familyname))))
1723 return OutOfMemory;
1725 memcpy(familyname, data->FamilyName, data->Length * sizeof(*familyname));
1726 familyname[data->Length] = 0;
1728 status = GdipCreateFontFamilyFromName(familyname, NULL, &family);
1729 GdipFree(familyname);
1730 if (status != Ok)
1731 return InvalidParameter;
1733 status = GdipCreateFont(family, data->EmSize, data->FontStyleFlags, data->SizeUnit, (GpFont **)&object);
1734 GdipDeleteFontFamily(family);
1735 break;
1737 case ObjectTypeImageAttributes:
1739 EmfPlusImageAttributes *data = (EmfPlusImageAttributes *)record_data;
1740 GpImageAttributes *attributes = NULL;
1742 if (data_size != sizeof(*data))
1743 return InvalidParameter;
1745 if ((status = GdipCreateImageAttributes(&attributes)) != Ok)
1746 return status;
1748 status = GdipSetImageAttributesWrapMode(attributes, data->WrapMode, *(DWORD *)&data->ClampColor,
1749 !!data->ObjectClamp);
1750 if (status == Ok)
1751 object = attributes;
1752 else
1753 GdipDisposeImageAttributes(attributes);
1754 break;
1756 default:
1757 FIXME("not implemented for object type %d.\n", type);
1758 return NotImplemented;
1761 if (status == Ok)
1762 metafile_set_object_table_entry(metafile, id, type, object);
1764 return status;
1767 GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
1768 EmfPlusRecordType recordType, UINT flags, UINT dataSize, GDIPCONST BYTE *data)
1770 GpStatus stat;
1771 GpMetafile *real_metafile = (GpMetafile*)metafile;
1773 TRACE("(%p,%x,%x,%d,%p)\n", metafile, recordType, flags, dataSize, data);
1775 if (!metafile || (dataSize && !data) || !metafile->playback_graphics)
1776 return InvalidParameter;
1778 if (recordType >= 1 && recordType <= 0x7a)
1780 /* regular EMF record */
1781 if (metafile->playback_dc)
1783 switch (recordType)
1785 case EMR_SETMAPMODE:
1786 case EMR_SAVEDC:
1787 case EMR_RESTOREDC:
1788 case EMR_SETWINDOWORGEX:
1789 case EMR_SETWINDOWEXTEX:
1790 case EMR_SETVIEWPORTORGEX:
1791 case EMR_SETVIEWPORTEXTEX:
1792 case EMR_SCALEVIEWPORTEXTEX:
1793 case EMR_SCALEWINDOWEXTEX:
1794 case EMR_MODIFYWORLDTRANSFORM:
1795 FIXME("not implemented for record type %x\n", recordType);
1796 break;
1797 case EMR_SETWORLDTRANSFORM:
1799 const XFORM* xform = (void*)data;
1800 real_metafile->gdiworldtransform = *xform;
1801 METAFILE_PlaybackUpdateGdiTransform(real_metafile);
1802 break;
1804 case EMR_EXTSELECTCLIPRGN:
1806 DWORD rgndatasize = *(DWORD*)data;
1807 DWORD mode = *(DWORD*)(data + 4);
1808 const RGNDATA *rgndata = (const RGNDATA*)(data + 8);
1809 HRGN hrgn = NULL;
1811 if (dataSize > 8)
1813 XFORM final;
1815 METAFILE_GetFinalGdiTransform(metafile, &final);
1817 hrgn = ExtCreateRegion(&final, rgndatasize, rgndata);
1820 ExtSelectClipRgn(metafile->playback_dc, hrgn, mode);
1822 DeleteObject(hrgn);
1824 return Ok;
1826 default:
1828 ENHMETARECORD *record = heap_alloc_zero(dataSize + 8);
1830 if (record)
1832 record->iType = recordType;
1833 record->nSize = dataSize + 8;
1834 memcpy(record->dParm, data, dataSize);
1836 if(PlayEnhMetaFileRecord(metafile->playback_dc, metafile->handle_table,
1837 record, metafile->handle_count) == 0)
1838 ERR("PlayEnhMetaFileRecord failed\n");
1840 heap_free(record);
1842 else
1843 return OutOfMemory;
1845 break;
1850 else
1852 EmfPlusRecordHeader *header = (EmfPlusRecordHeader*)(data)-1;
1854 METAFILE_PlaybackReleaseDC((GpMetafile*)metafile);
1856 switch(recordType)
1858 case EmfPlusRecordTypeHeader:
1859 case EmfPlusRecordTypeEndOfFile:
1860 break;
1861 case EmfPlusRecordTypeGetDC:
1862 METAFILE_PlaybackGetDC((GpMetafile*)metafile);
1863 break;
1864 case EmfPlusRecordTypeClear:
1866 EmfPlusClear *record = (EmfPlusClear*)header;
1868 if (dataSize != sizeof(record->Color))
1869 return InvalidParameter;
1871 return GdipGraphicsClear(metafile->playback_graphics, record->Color);
1873 case EmfPlusRecordTypeFillRects:
1875 EmfPlusFillRects *record = (EmfPlusFillRects*)header;
1876 GpBrush *brush, *temp_brush=NULL;
1877 GpRectF *rects, *temp_rects=NULL;
1879 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects))
1880 return InvalidParameter;
1882 if (flags & 0x4000)
1884 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(EmfPlusRect) * record->Count)
1885 return InvalidParameter;
1887 else
1889 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(GpRectF) * record->Count)
1890 return InvalidParameter;
1893 if (flags & 0x8000)
1895 stat = GdipCreateSolidFill((ARGB)record->BrushID, (GpSolidFill**)&temp_brush);
1896 brush = temp_brush;
1898 else
1900 if (record->BrushID >= EmfPlusObjectTableSize ||
1901 real_metafile->objtable[record->BrushID].type != ObjectTypeBrush)
1902 return InvalidParameter;
1904 brush = real_metafile->objtable[record->BrushID].u.brush;
1905 stat = Ok;
1908 if (stat == Ok)
1910 if (flags & 0x4000)
1912 EmfPlusRect *int_rects = (EmfPlusRect*)(record+1);
1913 int i;
1915 rects = temp_rects = heap_alloc_zero(sizeof(GpRectF) * record->Count);
1916 if (rects)
1918 for (i=0; i<record->Count; i++)
1920 rects[i].X = int_rects[i].X;
1921 rects[i].Y = int_rects[i].Y;
1922 rects[i].Width = int_rects[i].Width;
1923 rects[i].Height = int_rects[i].Height;
1926 else
1927 stat = OutOfMemory;
1929 else
1930 rects = (GpRectF*)(record+1);
1933 if (stat == Ok)
1935 stat = GdipFillRectangles(metafile->playback_graphics, brush, rects, record->Count);
1938 GdipDeleteBrush(temp_brush);
1939 heap_free(temp_rects);
1941 return stat;
1943 case EmfPlusRecordTypeSetClipRect:
1945 EmfPlusSetClipRect *record = (EmfPlusSetClipRect*)header;
1946 CombineMode mode = (CombineMode)((flags >> 8) & 0xf);
1947 GpRegion *region;
1948 GpMatrix world_to_device;
1950 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(*record))
1951 return InvalidParameter;
1953 stat = GdipCreateRegionRect(&record->ClipRect, &region);
1955 if (stat == Ok)
1957 get_graphics_transform(real_metafile->playback_graphics,
1958 CoordinateSpaceDevice, CoordinateSpaceWorld, &world_to_device);
1960 GdipTransformRegion(region, &world_to_device);
1962 GdipCombineRegionRegion(real_metafile->clip, region, mode);
1964 GdipDeleteRegion(region);
1967 return METAFILE_PlaybackUpdateClip(real_metafile);
1969 case EmfPlusRecordTypeSetPageTransform:
1971 EmfPlusSetPageTransform *record = (EmfPlusSetPageTransform*)header;
1972 GpUnit unit = (GpUnit)flags;
1974 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusSetPageTransform))
1975 return InvalidParameter;
1977 real_metafile->page_unit = unit;
1978 real_metafile->page_scale = record->PageScale;
1980 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
1982 case EmfPlusRecordTypeSetWorldTransform:
1984 EmfPlusSetWorldTransform *record = (EmfPlusSetWorldTransform*)header;
1986 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusSetWorldTransform))
1987 return InvalidParameter;
1989 memcpy(real_metafile->world_transform->matrix, record->MatrixData, sizeof(record->MatrixData));
1991 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
1993 case EmfPlusRecordTypeScaleWorldTransform:
1995 EmfPlusScaleWorldTransform *record = (EmfPlusScaleWorldTransform*)header;
1996 MatrixOrder order = (flags & 0x2000) ? MatrixOrderAppend : MatrixOrderPrepend;
1998 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusScaleWorldTransform))
1999 return InvalidParameter;
2001 GdipScaleMatrix(real_metafile->world_transform, record->Sx, record->Sy, order);
2003 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
2005 case EmfPlusRecordTypeMultiplyWorldTransform:
2007 EmfPlusMultiplyWorldTransform *record = (EmfPlusMultiplyWorldTransform*)header;
2008 MatrixOrder order = (flags & 0x2000) ? MatrixOrderAppend : MatrixOrderPrepend;
2009 GpMatrix matrix;
2011 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusMultiplyWorldTransform))
2012 return InvalidParameter;
2014 memcpy(matrix.matrix, record->MatrixData, sizeof(matrix.matrix));
2016 GdipMultiplyMatrix(real_metafile->world_transform, &matrix, order);
2018 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
2020 case EmfPlusRecordTypeRotateWorldTransform:
2022 EmfPlusRotateWorldTransform *record = (EmfPlusRotateWorldTransform*)header;
2023 MatrixOrder order = (flags & 0x2000) ? MatrixOrderAppend : MatrixOrderPrepend;
2025 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusRotateWorldTransform))
2026 return InvalidParameter;
2028 GdipRotateMatrix(real_metafile->world_transform, record->Angle, order);
2030 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
2032 case EmfPlusRecordTypeTranslateWorldTransform:
2034 EmfPlusTranslateWorldTransform *record = (EmfPlusTranslateWorldTransform*)header;
2035 MatrixOrder order = (flags & 0x2000) ? MatrixOrderAppend : MatrixOrderPrepend;
2037 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusTranslateWorldTransform))
2038 return InvalidParameter;
2040 GdipTranslateMatrix(real_metafile->world_transform, record->dx, record->dy, order);
2042 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
2044 case EmfPlusRecordTypeResetWorldTransform:
2046 GdipSetMatrixElements(real_metafile->world_transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
2048 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
2050 case EmfPlusRecordTypeBeginContainer:
2052 EmfPlusBeginContainer *record = (EmfPlusBeginContainer*)header;
2053 container* cont;
2054 GpUnit unit;
2055 REAL scale_x, scale_y;
2056 GpRectF scaled_srcrect;
2057 GpMatrix transform;
2059 cont = heap_alloc_zero(sizeof(*cont));
2060 if (!cont)
2061 return OutOfMemory;
2063 stat = GdipCloneRegion(metafile->clip, &cont->clip);
2064 if (stat != Ok)
2066 heap_free(cont);
2067 return stat;
2070 stat = GdipBeginContainer2(metafile->playback_graphics, &cont->state);
2072 if (stat != Ok)
2074 GdipDeleteRegion(cont->clip);
2075 heap_free(cont);
2076 return stat;
2079 cont->id = record->StackIndex;
2080 cont->type = BEGIN_CONTAINER;
2081 cont->world_transform = *metafile->world_transform;
2082 cont->page_unit = metafile->page_unit;
2083 cont->page_scale = metafile->page_scale;
2084 list_add_head(&real_metafile->containers, &cont->entry);
2086 unit = record->Header.Flags & 0xff;
2088 scale_x = units_to_pixels(1.0, unit, metafile->image.xres);
2089 scale_y = units_to_pixels(1.0, unit, metafile->image.yres);
2091 scaled_srcrect.X = scale_x * record->SrcRect.X;
2092 scaled_srcrect.Y = scale_y * record->SrcRect.Y;
2093 scaled_srcrect.Width = scale_x * record->SrcRect.Width;
2094 scaled_srcrect.Height = scale_y * record->SrcRect.Height;
2096 transform.matrix[0] = record->DestRect.Width / scaled_srcrect.Width;
2097 transform.matrix[1] = 0.0;
2098 transform.matrix[2] = 0.0;
2099 transform.matrix[3] = record->DestRect.Height / scaled_srcrect.Height;
2100 transform.matrix[4] = record->DestRect.X - scaled_srcrect.X;
2101 transform.matrix[5] = record->DestRect.Y - scaled_srcrect.Y;
2103 GdipMultiplyMatrix(real_metafile->world_transform, &transform, MatrixOrderPrepend);
2105 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
2107 case EmfPlusRecordTypeBeginContainerNoParams:
2108 case EmfPlusRecordTypeSave:
2110 EmfPlusContainerRecord *record = (EmfPlusContainerRecord*)header;
2111 container* cont;
2113 cont = heap_alloc_zero(sizeof(*cont));
2114 if (!cont)
2115 return OutOfMemory;
2117 stat = GdipCloneRegion(metafile->clip, &cont->clip);
2118 if (stat != Ok)
2120 heap_free(cont);
2121 return stat;
2124 if (recordType == EmfPlusRecordTypeBeginContainerNoParams)
2125 stat = GdipBeginContainer2(metafile->playback_graphics, &cont->state);
2126 else
2127 stat = GdipSaveGraphics(metafile->playback_graphics, &cont->state);
2129 if (stat != Ok)
2131 GdipDeleteRegion(cont->clip);
2132 heap_free(cont);
2133 return stat;
2136 cont->id = record->StackIndex;
2137 if (recordType == EmfPlusRecordTypeBeginContainerNoParams)
2138 cont->type = BEGIN_CONTAINER;
2139 else
2140 cont->type = SAVE_GRAPHICS;
2141 cont->world_transform = *metafile->world_transform;
2142 cont->page_unit = metafile->page_unit;
2143 cont->page_scale = metafile->page_scale;
2144 list_add_head(&real_metafile->containers, &cont->entry);
2146 break;
2148 case EmfPlusRecordTypeEndContainer:
2149 case EmfPlusRecordTypeRestore:
2151 EmfPlusContainerRecord *record = (EmfPlusContainerRecord*)header;
2152 container* cont;
2153 enum container_type type;
2154 BOOL found=FALSE;
2156 if (recordType == EmfPlusRecordTypeEndContainer)
2157 type = BEGIN_CONTAINER;
2158 else
2159 type = SAVE_GRAPHICS;
2161 LIST_FOR_EACH_ENTRY(cont, &real_metafile->containers, container, entry)
2163 if (cont->id == record->StackIndex && cont->type == type)
2165 found = TRUE;
2166 break;
2170 if (found)
2172 container* cont2;
2174 /* pop any newer items on the stack */
2175 while ((cont2 = LIST_ENTRY(list_head(&real_metafile->containers), container, entry)) != cont)
2177 list_remove(&cont2->entry);
2178 GdipDeleteRegion(cont2->clip);
2179 heap_free(cont2);
2182 if (type == BEGIN_CONTAINER)
2183 GdipEndContainer(real_metafile->playback_graphics, cont->state);
2184 else
2185 GdipRestoreGraphics(real_metafile->playback_graphics, cont->state);
2187 *real_metafile->world_transform = cont->world_transform;
2188 real_metafile->page_unit = cont->page_unit;
2189 real_metafile->page_scale = cont->page_scale;
2190 GdipCombineRegionRegion(real_metafile->clip, cont->clip, CombineModeReplace);
2192 list_remove(&cont->entry);
2193 GdipDeleteRegion(cont->clip);
2194 heap_free(cont);
2197 break;
2199 case EmfPlusRecordTypeSetPixelOffsetMode:
2201 return GdipSetPixelOffsetMode(real_metafile->playback_graphics, flags & 0xff);
2203 case EmfPlusRecordTypeSetCompositingQuality:
2205 return GdipSetCompositingQuality(real_metafile->playback_graphics, flags & 0xff);
2207 case EmfPlusRecordTypeSetInterpolationMode:
2209 return GdipSetInterpolationMode(real_metafile->playback_graphics, flags & 0xff);
2211 case EmfPlusRecordTypeSetTextRenderingHint:
2213 return GdipSetTextRenderingHint(real_metafile->playback_graphics, flags & 0xff);
2215 case EmfPlusRecordTypeSetAntiAliasMode:
2217 return GdipSetSmoothingMode(real_metafile->playback_graphics, (flags >> 1) & 0xff);
2219 case EmfPlusRecordTypeObject:
2221 return METAFILE_PlaybackObject(real_metafile, flags, dataSize, data);
2223 case EmfPlusRecordTypeDrawImagePoints:
2225 EmfPlusDrawImagePoints *draw = (EmfPlusDrawImagePoints *)header;
2226 static const UINT fixed_part_size = FIELD_OFFSET(EmfPlusDrawImagePoints, PointData) -
2227 FIELD_OFFSET(EmfPlusDrawImagePoints, ImageAttributesID);
2228 BYTE image = flags & 0xff;
2229 GpPointF points[3];
2230 unsigned int i;
2231 UINT size;
2233 if (image >= EmfPlusObjectTableSize || real_metafile->objtable[image].type != ObjectTypeImage)
2234 return InvalidParameter;
2236 if (dataSize <= fixed_part_size)
2237 return InvalidParameter;
2238 dataSize -= fixed_part_size;
2240 if (draw->ImageAttributesID >= EmfPlusObjectTableSize ||
2241 real_metafile->objtable[draw->ImageAttributesID].type != ObjectTypeImageAttributes)
2242 return InvalidParameter;
2244 if (draw->count != 3)
2245 return InvalidParameter;
2247 if ((flags >> 13) & 1) /* E */
2248 FIXME("image effects are not supported.\n");
2250 if ((flags >> 11) & 1) /* P */
2251 size = sizeof(EmfPlusPointR7) * draw->count;
2252 else if ((flags >> 14) & 1) /* C */
2253 size = sizeof(EmfPlusPoint) * draw->count;
2254 else
2255 size = sizeof(EmfPlusPointF) * draw->count;
2257 if (dataSize != size)
2258 return InvalidParameter;
2260 if ((flags >> 11) & 1) /* P */
2262 points[0].X = draw->PointData.pointsR[0].X;
2263 points[0].Y = draw->PointData.pointsR[0].Y;
2264 for (i = 1; i < 3; i++)
2266 points[i].X = points[i-1].X + draw->PointData.pointsR[i].X;
2267 points[i].Y = points[i-1].Y + draw->PointData.pointsR[i].Y;
2270 else if ((flags >> 14) & 1) /* C */
2272 for (i = 0; i < 3; i++)
2274 points[i].X = draw->PointData.points[i].X;
2275 points[i].Y = draw->PointData.points[i].Y;
2278 else
2279 memcpy(points, draw->PointData.pointsF, sizeof(points));
2281 return GdipDrawImagePointsRect(real_metafile->playback_graphics, real_metafile->objtable[image].u.image,
2282 points, 3, draw->SrcRect.X, draw->SrcRect.Y, draw->SrcRect.Width, draw->SrcRect.Height, draw->SrcUnit,
2283 real_metafile->objtable[draw->ImageAttributesID].u.image_attributes, NULL, NULL);
2285 case EmfPlusRecordTypeFillPath:
2287 EmfPlusFillPath *fill = (EmfPlusFillPath *)header;
2288 GpSolidFill *solidfill = NULL;
2289 BYTE path = flags & 0xff;
2290 GpBrush *brush;
2292 if (path >= EmfPlusObjectTableSize || real_metafile->objtable[path].type != ObjectTypePath)
2293 return InvalidParameter;
2295 if (dataSize != sizeof(fill->data.BrushId))
2296 return InvalidParameter;
2298 if (flags & 0x8000)
2300 stat = GdipCreateSolidFill(*(ARGB *)&fill->data.Color, (GpSolidFill **)&solidfill);
2301 if (stat != Ok)
2302 return stat;
2303 brush = (GpBrush *)solidfill;
2305 else
2307 if (fill->data.BrushId >= EmfPlusObjectTableSize ||
2308 real_metafile->objtable[fill->data.BrushId].type != ObjectTypeBrush)
2309 return InvalidParameter;
2311 brush = real_metafile->objtable[fill->data.BrushId].u.brush;
2314 stat = GdipFillPath(real_metafile->playback_graphics, brush, real_metafile->objtable[path].u.path);
2315 GdipDeleteBrush((GpBrush *)solidfill);
2316 return stat;
2318 default:
2319 FIXME("Not implemented for record type %x\n", recordType);
2320 return NotImplemented;
2324 return Ok;
2327 struct enum_metafile_data
2329 EnumerateMetafileProc callback;
2330 void *callback_data;
2331 GpMetafile *metafile;
2334 static int CALLBACK enum_metafile_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR,
2335 int nObj, LPARAM lpData)
2337 BOOL ret;
2338 struct enum_metafile_data *data = (struct enum_metafile_data*)lpData;
2339 const BYTE* pStr;
2341 data->metafile->handle_table = lpHTable;
2342 data->metafile->handle_count = nObj;
2344 /* First check for an EMF+ record. */
2345 if (lpEMFR->iType == EMR_GDICOMMENT)
2347 const EMRGDICOMMENT *comment = (const EMRGDICOMMENT*)lpEMFR;
2349 if (comment->cbData >= 4 && memcmp(comment->Data, "EMF+", 4) == 0)
2351 int offset = 4;
2353 while (offset + sizeof(EmfPlusRecordHeader) <= comment->cbData)
2355 const EmfPlusRecordHeader *record = (const EmfPlusRecordHeader*)&comment->Data[offset];
2357 if (record->DataSize)
2358 pStr = (const BYTE*)(record+1);
2359 else
2360 pStr = NULL;
2362 ret = data->callback(record->Type, record->Flags, record->DataSize,
2363 pStr, data->callback_data);
2365 if (!ret)
2366 return 0;
2368 offset += record->Size;
2371 return 1;
2375 if (lpEMFR->nSize != 8)
2376 pStr = (const BYTE*)lpEMFR->dParm;
2377 else
2378 pStr = NULL;
2380 return data->callback(lpEMFR->iType, 0, lpEMFR->nSize-8,
2381 pStr, data->callback_data);
2384 GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics,
2385 GDIPCONST GpMetafile *metafile, GDIPCONST GpPointF *destPoints, INT count,
2386 GDIPCONST GpRectF *srcRect, Unit srcUnit, EnumerateMetafileProc callback,
2387 VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes)
2389 struct enum_metafile_data data;
2390 GpStatus stat;
2391 GpMetafile *real_metafile = (GpMetafile*)metafile; /* whoever made this const was joking */
2392 GraphicsContainer state;
2393 GpPath *dst_path;
2395 TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics, metafile,
2396 destPoints, count, srcRect, srcUnit, callback, callbackData,
2397 imageAttributes);
2399 if (!graphics || !metafile || !destPoints || count != 3 || !srcRect)
2400 return InvalidParameter;
2402 if (!metafile->hemf)
2403 return InvalidParameter;
2405 if (metafile->playback_graphics)
2406 return ObjectBusy;
2408 TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect), srcUnit,
2409 debugstr_pointf(&destPoints[0]), debugstr_pointf(&destPoints[1]),
2410 debugstr_pointf(&destPoints[2]));
2412 data.callback = callback;
2413 data.callback_data = callbackData;
2414 data.metafile = real_metafile;
2416 real_metafile->playback_graphics = graphics;
2417 real_metafile->playback_dc = NULL;
2418 real_metafile->src_rect = *srcRect;
2420 memcpy(real_metafile->playback_points, destPoints, sizeof(PointF) * 3);
2421 stat = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, real_metafile->playback_points, 3);
2423 if (stat == Ok)
2424 stat = GdipBeginContainer2(graphics, &state);
2426 if (stat == Ok)
2428 stat = GdipSetPageScale(graphics, 1.0);
2430 if (stat == Ok)
2431 stat = GdipSetPageUnit(graphics, UnitPixel);
2433 if (stat == Ok)
2434 stat = GdipResetWorldTransform(graphics);
2436 if (stat == Ok)
2437 stat = GdipCreateRegion(&real_metafile->base_clip);
2439 if (stat == Ok)
2440 stat = GdipGetClip(graphics, real_metafile->base_clip);
2442 if (stat == Ok)
2443 stat = GdipCreateRegion(&real_metafile->clip);
2445 if (stat == Ok)
2446 stat = GdipCreatePath(FillModeAlternate, &dst_path);
2448 if (stat == Ok)
2450 GpPointF clip_points[4];
2452 clip_points[0] = real_metafile->playback_points[0];
2453 clip_points[1] = real_metafile->playback_points[1];
2454 clip_points[2].X = real_metafile->playback_points[1].X + real_metafile->playback_points[2].X
2455 - real_metafile->playback_points[0].X;
2456 clip_points[2].Y = real_metafile->playback_points[1].Y + real_metafile->playback_points[2].Y
2457 - real_metafile->playback_points[0].Y;
2458 clip_points[3] = real_metafile->playback_points[2];
2460 stat = GdipAddPathPolygon(dst_path, clip_points, 4);
2462 if (stat == Ok)
2463 stat = GdipCombineRegionPath(real_metafile->base_clip, dst_path, CombineModeIntersect);
2465 GdipDeletePath(dst_path);
2468 if (stat == Ok)
2469 stat = GdipCreateMatrix(&real_metafile->world_transform);
2471 if (stat == Ok)
2473 real_metafile->page_unit = UnitDisplay;
2474 real_metafile->page_scale = 1.0;
2475 stat = METAFILE_PlaybackUpdateWorldTransform(real_metafile);
2478 if (stat == Ok)
2480 stat = METAFILE_PlaybackUpdateClip(real_metafile);
2483 if (stat == Ok && (metafile->metafile_type == MetafileTypeEmf ||
2484 metafile->metafile_type == MetafileTypeWmfPlaceable ||
2485 metafile->metafile_type == MetafileTypeWmf))
2486 stat = METAFILE_PlaybackGetDC(real_metafile);
2488 if (stat == Ok)
2489 EnumEnhMetaFile(0, metafile->hemf, enum_metafile_proc, &data, NULL);
2491 METAFILE_PlaybackReleaseDC(real_metafile);
2493 GdipDeleteMatrix(real_metafile->world_transform);
2494 real_metafile->world_transform = NULL;
2496 GdipDeleteRegion(real_metafile->base_clip);
2497 real_metafile->base_clip = NULL;
2499 GdipDeleteRegion(real_metafile->clip);
2500 real_metafile->clip = NULL;
2502 while (list_head(&real_metafile->containers))
2504 container* cont = LIST_ENTRY(list_head(&real_metafile->containers), container, entry);
2505 list_remove(&cont->entry);
2506 GdipDeleteRegion(cont->clip);
2507 heap_free(cont);
2510 GdipEndContainer(graphics, state);
2513 real_metafile->playback_graphics = NULL;
2515 return stat;
2518 GpStatus WINGDIPAPI GdipEnumerateMetafileDestRect(GpGraphics *graphics,
2519 GDIPCONST GpMetafile *metafile, GDIPCONST GpRectF *dest,
2520 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
2522 GpPointF points[3];
2524 if (!graphics || !metafile || !dest) return InvalidParameter;
2526 points[0].X = points[2].X = dest->X;
2527 points[0].Y = points[1].Y = dest->Y;
2528 points[1].X = dest->X + dest->Width;
2529 points[2].Y = dest->Y + dest->Height;
2531 return GdipEnumerateMetafileSrcRectDestPoints(graphics, metafile, points, 3,
2532 &metafile->bounds, metafile->unit, callback, cb_data, attrs);
2535 GpStatus WINGDIPAPI GdipEnumerateMetafileDestRectI(GpGraphics *graphics,
2536 GDIPCONST GpMetafile *metafile, GDIPCONST GpRect *dest,
2537 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
2539 GpRectF destf;
2541 if (!graphics || !metafile || !dest) return InvalidParameter;
2543 destf.X = dest->X;
2544 destf.Y = dest->Y;
2545 destf.Width = dest->Width;
2546 destf.Height = dest->Height;
2548 return GdipEnumerateMetafileDestRect(graphics, metafile, &destf, callback, cb_data, attrs);
2551 GpStatus WINGDIPAPI GdipEnumerateMetafileDestPoint(GpGraphics *graphics,
2552 GDIPCONST GpMetafile *metafile, GDIPCONST GpPointF *dest,
2553 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
2555 GpRectF destf;
2557 if (!graphics || !metafile || !dest) return InvalidParameter;
2559 destf.X = dest->X;
2560 destf.Y = dest->Y;
2561 destf.Width = units_to_pixels(metafile->bounds.Width, metafile->unit, metafile->image.xres);
2562 destf.Height = units_to_pixels(metafile->bounds.Height, metafile->unit, metafile->image.yres);
2564 return GdipEnumerateMetafileDestRect(graphics, metafile, &destf, callback, cb_data, attrs);
2567 GpStatus WINGDIPAPI GdipEnumerateMetafileDestPointI(GpGraphics *graphics,
2568 GDIPCONST GpMetafile *metafile, GDIPCONST GpPoint *dest,
2569 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
2571 GpPointF ptf;
2573 if (!graphics || !metafile || !dest) return InvalidParameter;
2575 ptf.X = dest->X;
2576 ptf.Y = dest->Y;
2578 return GdipEnumerateMetafileDestPoint(graphics, metafile, &ptf, callback, cb_data, attrs);
2581 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
2582 MetafileHeader * header)
2584 GpStatus status;
2586 TRACE("(%p, %p)\n", metafile, header);
2588 if(!metafile || !header)
2589 return InvalidParameter;
2591 if (metafile->hemf)
2593 status = GdipGetMetafileHeaderFromEmf(metafile->hemf, header);
2594 if (status != Ok) return status;
2596 else
2598 memset(header, 0, sizeof(*header));
2599 header->Version = VERSION_MAGIC2;
2602 header->Type = metafile->metafile_type;
2603 header->DpiX = metafile->image.xres;
2604 header->DpiY = metafile->image.yres;
2605 header->Width = gdip_round(metafile->bounds.Width);
2606 header->Height = gdip_round(metafile->bounds.Height);
2608 return Ok;
2611 static int CALLBACK get_emfplus_header_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR,
2612 int nObj, LPARAM lpData)
2614 EmfPlusHeader *dst_header = (EmfPlusHeader*)lpData;
2616 if (lpEMFR->iType == EMR_GDICOMMENT)
2618 const EMRGDICOMMENT *comment = (const EMRGDICOMMENT*)lpEMFR;
2620 if (comment->cbData >= 4 && memcmp(comment->Data, "EMF+", 4) == 0)
2622 const EmfPlusRecordHeader *header = (const EmfPlusRecordHeader*)&comment->Data[4];
2624 if (4 + sizeof(EmfPlusHeader) <= comment->cbData &&
2625 header->Type == EmfPlusRecordTypeHeader)
2627 memcpy(dst_header, header, sizeof(*dst_header));
2631 else if (lpEMFR->iType == EMR_HEADER)
2632 return TRUE;
2634 return FALSE;
2637 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromEmf(HENHMETAFILE hemf,
2638 MetafileHeader *header)
2640 ENHMETAHEADER3 emfheader;
2641 EmfPlusHeader emfplusheader;
2642 MetafileType metafile_type;
2644 TRACE("(%p,%p)\n", hemf, header);
2646 if(!hemf || !header)
2647 return InvalidParameter;
2649 if (GetEnhMetaFileHeader(hemf, sizeof(emfheader), (ENHMETAHEADER*)&emfheader) == 0)
2650 return GenericError;
2652 emfplusheader.Header.Type = 0;
2654 EnumEnhMetaFile(NULL, hemf, get_emfplus_header_proc, &emfplusheader, NULL);
2656 if (emfplusheader.Header.Type == EmfPlusRecordTypeHeader)
2658 if ((emfplusheader.Header.Flags & 1) == 1)
2659 metafile_type = MetafileTypeEmfPlusDual;
2660 else
2661 metafile_type = MetafileTypeEmfPlusOnly;
2663 else
2664 metafile_type = MetafileTypeEmf;
2666 header->Type = metafile_type;
2667 header->Size = emfheader.nBytes;
2668 header->DpiX = (REAL)emfheader.szlDevice.cx * 25.4 / emfheader.szlMillimeters.cx;
2669 header->DpiY = (REAL)emfheader.szlDevice.cy * 25.4 / emfheader.szlMillimeters.cy;
2670 header->X = gdip_round((REAL)emfheader.rclFrame.left / 2540.0 * header->DpiX);
2671 header->Y = gdip_round((REAL)emfheader.rclFrame.top / 2540.0 * header->DpiY);
2672 header->Width = gdip_round((REAL)(emfheader.rclFrame.right - emfheader.rclFrame.left) / 2540.0 * header->DpiX);
2673 header->Height = gdip_round((REAL)(emfheader.rclFrame.bottom - emfheader.rclFrame.top) / 2540.0 * header->DpiY);
2674 header->u.EmfHeader = emfheader;
2676 if (metafile_type == MetafileTypeEmfPlusDual || metafile_type == MetafileTypeEmfPlusOnly)
2678 header->Version = emfplusheader.Version;
2679 header->EmfPlusFlags = emfplusheader.EmfPlusFlags;
2680 header->EmfPlusHeaderSize = emfplusheader.Header.Size;
2681 header->LogicalDpiX = emfplusheader.LogicalDpiX;
2682 header->LogicalDpiY = emfplusheader.LogicalDpiY;
2684 else
2686 header->Version = emfheader.nVersion;
2687 header->EmfPlusFlags = 0;
2688 header->EmfPlusHeaderSize = 0;
2689 header->LogicalDpiX = 0;
2690 header->LogicalDpiY = 0;
2693 return Ok;
2696 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromWmf(HMETAFILE hwmf,
2697 GDIPCONST WmfPlaceableFileHeader *placeable, MetafileHeader *header)
2699 GpStatus status;
2700 GpMetafile *metafile;
2702 TRACE("(%p,%p,%p)\n", hwmf, placeable, header);
2704 status = GdipCreateMetafileFromWmf(hwmf, FALSE, placeable, &metafile);
2705 if (status == Ok)
2707 status = GdipGetMetafileHeaderFromMetafile(metafile, header);
2708 GdipDisposeImage(&metafile->image);
2710 return status;
2713 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR *filename,
2714 MetafileHeader *header)
2716 GpStatus status;
2717 GpMetafile *metafile;
2719 TRACE("(%s,%p)\n", debugstr_w(filename), header);
2721 if (!filename || !header)
2722 return InvalidParameter;
2724 status = GdipCreateMetafileFromFile(filename, &metafile);
2725 if (status == Ok)
2727 status = GdipGetMetafileHeaderFromMetafile(metafile, header);
2728 GdipDisposeImage(&metafile->image);
2730 return status;
2733 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromStream(IStream *stream,
2734 MetafileHeader *header)
2736 GpStatus status;
2737 GpMetafile *metafile;
2739 TRACE("(%p,%p)\n", stream, header);
2741 if (!stream || !header)
2742 return InvalidParameter;
2744 status = GdipCreateMetafileFromStream(stream, &metafile);
2745 if (status == Ok)
2747 status = GdipGetMetafileHeaderFromMetafile(metafile, header);
2748 GdipDisposeImage(&metafile->image);
2750 return status;
2753 GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete,
2754 GpMetafile **metafile)
2756 GpStatus stat;
2757 MetafileHeader header;
2759 TRACE("(%p,%i,%p)\n", hemf, delete, metafile);
2761 if(!hemf || !metafile)
2762 return InvalidParameter;
2764 stat = GdipGetMetafileHeaderFromEmf(hemf, &header);
2765 if (stat != Ok)
2766 return stat;
2768 *metafile = heap_alloc_zero(sizeof(GpMetafile));
2769 if (!*metafile)
2770 return OutOfMemory;
2772 (*metafile)->image.type = ImageTypeMetafile;
2773 (*metafile)->image.format = ImageFormatEMF;
2774 (*metafile)->image.frame_count = 1;
2775 (*metafile)->image.xres = header.DpiX;
2776 (*metafile)->image.yres = header.DpiY;
2777 (*metafile)->bounds.X = (REAL)header.u.EmfHeader.rclFrame.left / 2540.0 * header.DpiX;
2778 (*metafile)->bounds.Y = (REAL)header.u.EmfHeader.rclFrame.top / 2540.0 * header.DpiY;
2779 (*metafile)->bounds.Width = (REAL)(header.u.EmfHeader.rclFrame.right - header.u.EmfHeader.rclFrame.left)
2780 / 2540.0 * header.DpiX;
2781 (*metafile)->bounds.Height = (REAL)(header.u.EmfHeader.rclFrame.bottom - header.u.EmfHeader.rclFrame.top)
2782 / 2540.0 * header.DpiY;
2783 (*metafile)->unit = UnitPixel;
2784 (*metafile)->metafile_type = header.Type;
2785 (*metafile)->hemf = hemf;
2786 (*metafile)->preserve_hemf = !delete;
2787 list_init(&(*metafile)->containers);
2789 TRACE("<-- %p\n", *metafile);
2791 return Ok;
2794 GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
2795 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
2797 UINT read;
2798 BYTE *copy;
2799 HENHMETAFILE hemf;
2800 GpStatus retval = Ok;
2802 TRACE("(%p, %d, %p, %p)\n", hwmf, delete, placeable, metafile);
2804 if(!hwmf || !metafile)
2805 return InvalidParameter;
2807 *metafile = NULL;
2808 read = GetMetaFileBitsEx(hwmf, 0, NULL);
2809 if(!read)
2810 return GenericError;
2811 copy = heap_alloc_zero(read);
2812 GetMetaFileBitsEx(hwmf, read, copy);
2814 hemf = SetWinMetaFileBits(read, copy, NULL, NULL);
2815 heap_free(copy);
2817 /* FIXME: We should store and use hwmf instead of converting to hemf */
2818 retval = GdipCreateMetafileFromEmf(hemf, TRUE, metafile);
2820 if (retval == Ok)
2822 if (placeable)
2824 (*metafile)->image.xres = (REAL)placeable->Inch;
2825 (*metafile)->image.yres = (REAL)placeable->Inch;
2826 (*metafile)->bounds.X = ((REAL)placeable->BoundingBox.Left) / ((REAL)placeable->Inch);
2827 (*metafile)->bounds.Y = ((REAL)placeable->BoundingBox.Top) / ((REAL)placeable->Inch);
2828 (*metafile)->bounds.Width = (REAL)(placeable->BoundingBox.Right -
2829 placeable->BoundingBox.Left);
2830 (*metafile)->bounds.Height = (REAL)(placeable->BoundingBox.Bottom -
2831 placeable->BoundingBox.Top);
2832 (*metafile)->metafile_type = MetafileTypeWmfPlaceable;
2834 else
2835 (*metafile)->metafile_type = MetafileTypeWmf;
2836 (*metafile)->image.format = ImageFormatWMF;
2838 if (delete) DeleteMetaFile(hwmf);
2840 else
2841 DeleteEnhMetaFile(hemf);
2842 return retval;
2845 GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file,
2846 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
2848 HMETAFILE hmf;
2849 HENHMETAFILE emf;
2851 TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile);
2853 hmf = GetMetaFileW(file);
2854 if(hmf)
2855 return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile);
2857 emf = GetEnhMetaFileW(file);
2858 if(emf)
2859 return GdipCreateMetafileFromEmf(emf, TRUE, metafile);
2861 return GenericError;
2864 GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file,
2865 GpMetafile **metafile)
2867 GpStatus status;
2868 IStream *stream;
2870 TRACE("(%p, %p)\n", file, metafile);
2872 if (!file || !metafile) return InvalidParameter;
2874 *metafile = NULL;
2876 status = GdipCreateStreamOnFile(file, GENERIC_READ, &stream);
2877 if (status == Ok)
2879 status = GdipCreateMetafileFromStream(stream, metafile);
2880 IStream_Release(stream);
2882 return status;
2885 GpStatus WINGDIPAPI GdipCreateMetafileFromStream(IStream *stream,
2886 GpMetafile **metafile)
2888 GpStatus stat;
2890 TRACE("%p %p\n", stream, metafile);
2892 stat = GdipLoadImageFromStream(stream, (GpImage **)metafile);
2893 if (stat != Ok) return stat;
2895 if ((*metafile)->image.type != ImageTypeMetafile)
2897 GdipDisposeImage(&(*metafile)->image);
2898 *metafile = NULL;
2899 return GenericError;
2902 return Ok;
2905 GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile *metafile,
2906 UINT limitDpi)
2908 TRACE("(%p,%u)\n", metafile, limitDpi);
2910 return Ok;
2913 GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
2914 GpMetafile* metafile, BOOL* succ, EmfType emfType,
2915 const WCHAR* description, GpMetafile** out_metafile)
2917 static int calls;
2919 TRACE("(%p,%p,%p,%u,%s,%p)\n", ref, metafile, succ, emfType,
2920 debugstr_w(description), out_metafile);
2922 if(!ref || !metafile || !out_metafile || emfType < EmfTypeEmfOnly || emfType > EmfTypeEmfPlusDual)
2923 return InvalidParameter;
2925 if(succ)
2926 *succ = FALSE;
2927 *out_metafile = NULL;
2929 if(!(calls++))
2930 FIXME("not implemented\n");
2932 return NotImplemented;
2935 GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE hemf, UINT cbData16,
2936 LPBYTE pData16, INT iMapMode, INT eFlags)
2938 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf, cbData16, pData16, iMapMode, eFlags);
2939 return NotImplemented;
2942 GpStatus WINGDIPAPI GdipRecordMetafileFileName(GDIPCONST WCHAR* fileName,
2943 HDC hdc, EmfType type, GDIPCONST GpRectF *pFrameRect,
2944 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc,
2945 GpMetafile **metafile)
2947 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
2948 frameUnit, debugstr_w(desc), metafile);
2950 return NotImplemented;
2953 GpStatus WINGDIPAPI GdipRecordMetafileFileNameI(GDIPCONST WCHAR* fileName, HDC hdc, EmfType type,
2954 GDIPCONST GpRect *pFrameRect, MetafileFrameUnit frameUnit,
2955 GDIPCONST WCHAR *desc, GpMetafile **metafile)
2957 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
2958 frameUnit, debugstr_w(desc), metafile);
2960 return NotImplemented;
2963 /*****************************************************************************
2964 * GdipConvertToEmfPlusToFile [GDIPLUS.@]
2967 GpStatus WINGDIPAPI GdipConvertToEmfPlusToFile(const GpGraphics* refGraphics,
2968 GpMetafile* metafile, BOOL* conversionSuccess,
2969 const WCHAR* filename, EmfType emfType,
2970 const WCHAR* description, GpMetafile** out_metafile)
2972 FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics, metafile, conversionSuccess, filename, emfType, description, out_metafile);
2973 return NotImplemented;
2976 static GpStatus METAFILE_CreateCompressedImageStream(GpImage *image, IStream **stream, DWORD *size)
2978 LARGE_INTEGER zero;
2979 STATSTG statstg;
2980 GpStatus stat;
2981 HRESULT hr;
2983 *size = 0;
2985 hr = CreateStreamOnHGlobal(NULL, TRUE, stream);
2986 if (FAILED(hr)) return hresult_to_status(hr);
2988 stat = encode_image_png(image, *stream, NULL);
2989 if (stat != Ok)
2991 IStream_Release(*stream);
2992 return stat;
2995 hr = IStream_Stat(*stream, &statstg, 1);
2996 if (FAILED(hr))
2998 IStream_Release(*stream);
2999 return hresult_to_status(hr);
3001 *size = statstg.cbSize.u.LowPart;
3003 zero.QuadPart = 0;
3004 hr = IStream_Seek(*stream, zero, STREAM_SEEK_SET, NULL);
3005 if (FAILED(hr))
3007 IStream_Release(*stream);
3008 return hresult_to_status(hr);
3011 return Ok;
3014 static GpStatus METAFILE_FillEmfPlusBitmap(EmfPlusBitmap *record, IStream *stream, DWORD size)
3016 HRESULT hr;
3018 record->Width = 0;
3019 record->Height = 0;
3020 record->Stride = 0;
3021 record->PixelFormat = 0;
3022 record->Type = BitmapDataTypeCompressed;
3024 hr = IStream_Read(stream, record->BitmapData, size, NULL);
3025 if (FAILED(hr)) return hresult_to_status(hr);
3026 return Ok;
3029 static GpStatus METAFILE_AddImageObject(GpMetafile *metafile, GpImage *image, DWORD *id)
3031 EmfPlusObject *object_record;
3032 GpStatus stat;
3033 DWORD size;
3035 *id = -1;
3037 if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
3038 return Ok;
3040 if (image->type == ImageTypeBitmap)
3042 IStream *stream;
3043 DWORD aligned_size;
3045 stat = METAFILE_CreateCompressedImageStream(image, &stream, &size);
3046 if (stat != Ok) return stat;
3047 aligned_size = (size + 3) & ~3;
3049 stat = METAFILE_AllocateRecord(metafile,
3050 FIELD_OFFSET(EmfPlusObject, ObjectData.image.ImageData.bitmap.BitmapData[aligned_size]),
3051 (void**)&object_record);
3052 if (stat != Ok)
3054 IStream_Release(stream);
3055 return stat;
3057 memset(object_record->ObjectData.image.ImageData.bitmap.BitmapData + size, 0, aligned_size - size);
3059 *id = METAFILE_AddObjectId(metafile);
3060 object_record->Header.Type = EmfPlusRecordTypeObject;
3061 object_record->Header.Flags = *id | ObjectTypeImage << 8;
3062 object_record->ObjectData.image.Version = VERSION_MAGIC2;
3063 object_record->ObjectData.image.Type = ImageDataTypeBitmap;
3065 stat = METAFILE_FillEmfPlusBitmap(&object_record->ObjectData.image.ImageData.bitmap, stream, size);
3066 IStream_Release(stream);
3067 if (stat != Ok) METAFILE_RemoveLastRecord(metafile, &object_record->Header);
3068 return stat;
3070 else if (image->type == ImageTypeMetafile)
3072 HENHMETAFILE hemf = ((GpMetafile*)image)->hemf;
3073 EmfPlusMetafile *metafile_record;
3075 if (!hemf) return InvalidParameter;
3077 size = GetEnhMetaFileBits(hemf, 0, NULL);
3078 if (!size) return GenericError;
3080 stat = METAFILE_AllocateRecord(metafile,
3081 FIELD_OFFSET(EmfPlusObject, ObjectData.image.ImageData.metafile.MetafileData[size]),
3082 (void**)&object_record);
3083 if (stat != Ok) return stat;
3085 *id = METAFILE_AddObjectId(metafile);
3086 object_record->Header.Type = EmfPlusRecordTypeObject;
3087 object_record->Header.Flags = *id | ObjectTypeImage << 8;
3088 object_record->ObjectData.image.Version = VERSION_MAGIC2;
3089 object_record->ObjectData.image.Type = ImageDataTypeMetafile;
3090 metafile_record = &object_record->ObjectData.image.ImageData.metafile;
3091 metafile_record->Type = ((GpMetafile*)image)->metafile_type;
3092 metafile_record->MetafileDataSize = size;
3093 if (GetEnhMetaFileBits(hemf, size, metafile_record->MetafileData) != size)
3095 METAFILE_RemoveLastRecord(metafile, &object_record->Header);
3096 return GenericError;
3098 return Ok;
3100 else
3102 FIXME("not supported image type (%d)\n", image->type);
3103 return NotImplemented;
3107 static GpStatus METAFILE_AddImageAttributesObject(GpMetafile *metafile, const GpImageAttributes *attrs, DWORD *id)
3109 EmfPlusObject *object_record;
3110 EmfPlusImageAttributes *attrs_record;
3111 GpStatus stat;
3113 *id = -1;
3115 if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
3116 return Ok;
3118 if (!attrs)
3119 return Ok;
3121 stat = METAFILE_AllocateRecord(metafile,
3122 FIELD_OFFSET(EmfPlusObject, ObjectData.image_attributes) + sizeof(EmfPlusImageAttributes),
3123 (void**)&object_record);
3124 if (stat != Ok) return stat;
3126 *id = METAFILE_AddObjectId(metafile);
3127 object_record->Header.Type = EmfPlusRecordTypeObject;
3128 object_record->Header.Flags = *id | (ObjectTypeImageAttributes << 8);
3129 attrs_record = &object_record->ObjectData.image_attributes;
3130 attrs_record->Version = VERSION_MAGIC2;
3131 attrs_record->Reserved1 = 0;
3132 attrs_record->WrapMode = attrs->wrap;
3133 attrs_record->ClampColor.Blue = attrs->outside_color & 0xff;
3134 attrs_record->ClampColor.Green = (attrs->outside_color >> 8) & 0xff;
3135 attrs_record->ClampColor.Red = (attrs->outside_color >> 16) & 0xff;
3136 attrs_record->ClampColor.Alpha = attrs->outside_color >> 24;
3137 attrs_record->ObjectClamp = attrs->clamp;
3138 attrs_record->Reserved2 = 0;
3139 return Ok;
3142 GpStatus METAFILE_DrawImagePointsRect(GpMetafile *metafile, GpImage *image,
3143 GDIPCONST GpPointF *points, INT count, REAL srcx, REAL srcy, REAL srcwidth,
3144 REAL srcheight, GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes,
3145 DrawImageAbort callback, VOID *callbackData)
3147 EmfPlusDrawImagePoints *draw_image_record;
3148 DWORD image_id, attributes_id;
3149 GpStatus stat;
3151 if (count != 3) return InvalidParameter;
3153 if (metafile->metafile_type == MetafileTypeEmf)
3155 FIXME("MetafileTypeEmf metafiles not supported\n");
3156 return NotImplemented;
3158 else
3159 FIXME("semi-stub\n");
3161 if (!imageAttributes)
3163 stat = METAFILE_AddImageObject(metafile, image, &image_id);
3165 else if (image->type == ImageTypeBitmap)
3167 INT width = ((GpBitmap*)image)->width;
3168 INT height = ((GpBitmap*)image)->height;
3169 GpGraphics *graphics;
3170 GpBitmap *bitmap;
3172 stat = GdipCreateBitmapFromScan0(width, height,
3173 0, PixelFormat32bppARGB, NULL, &bitmap);
3174 if (stat != Ok) return stat;
3176 stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics);
3177 if (stat != Ok)
3179 GdipDisposeImage((GpImage*)bitmap);
3180 return stat;
3183 stat = GdipDrawImageRectRectI(graphics, image, 0, 0, width, height,
3184 0, 0, width, height, UnitPixel, imageAttributes, NULL, NULL);
3185 GdipDeleteGraphics(graphics);
3186 if (stat != Ok)
3188 GdipDisposeImage((GpImage*)bitmap);
3189 return stat;
3192 stat = METAFILE_AddImageObject(metafile, (GpImage*)bitmap, &image_id);
3193 GdipDisposeImage((GpImage*)bitmap);
3195 else
3197 FIXME("imageAttributes not supported (image type %d)\n", image->type);
3198 return NotImplemented;
3200 if (stat != Ok) return stat;
3202 stat = METAFILE_AddImageAttributesObject(metafile, imageAttributes, &attributes_id);
3203 if (stat != Ok) return stat;
3205 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusDrawImagePoints), (void**)&draw_image_record);
3206 if (stat != Ok) return stat;
3207 draw_image_record->Header.Type = EmfPlusRecordTypeDrawImagePoints;
3208 draw_image_record->Header.Flags = image_id;
3209 draw_image_record->ImageAttributesID = attributes_id;
3210 draw_image_record->SrcUnit = UnitPixel;
3211 draw_image_record->SrcRect.X = units_to_pixels(srcx, srcUnit, metafile->image.xres);
3212 draw_image_record->SrcRect.Y = units_to_pixels(srcy, srcUnit, metafile->image.yres);
3213 draw_image_record->SrcRect.Width = units_to_pixels(srcwidth, srcUnit, metafile->image.xres);
3214 draw_image_record->SrcRect.Height = units_to_pixels(srcheight, srcUnit, metafile->image.yres);
3215 draw_image_record->count = 3;
3216 memcpy(draw_image_record->PointData.pointsF, points, 3 * sizeof(*points));
3217 METAFILE_WriteRecords(metafile);
3218 return Ok;
3221 GpStatus METAFILE_AddSimpleProperty(GpMetafile *metafile, SHORT prop, SHORT val)
3223 EmfPlusRecordHeader *record;
3224 GpStatus stat;
3226 if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
3227 return Ok;
3229 stat = METAFILE_AllocateRecord(metafile, sizeof(*record), (void**)&record);
3230 if (stat != Ok) return stat;
3232 record->Type = prop;
3233 record->Flags = val;
3235 METAFILE_WriteRecords(metafile);
3236 return Ok;
3239 static GpStatus METAFILE_AddPathObject(GpMetafile *metafile, GpPath *path, DWORD *id)
3241 EmfPlusObject *object_record;
3242 GpStatus stat;
3243 DWORD size;
3245 *id = -1;
3246 if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
3247 return Ok;
3249 size = write_path_data(path, NULL);
3250 stat = METAFILE_AllocateRecord(metafile,
3251 FIELD_OFFSET(EmfPlusObject, ObjectData.path) + size,
3252 (void**)&object_record);
3253 if (stat != Ok) return stat;
3255 *id = METAFILE_AddObjectId(metafile);
3256 object_record->Header.Type = EmfPlusRecordTypeObject;
3257 object_record->Header.Flags = *id | ObjectTypePath << 8;
3258 write_path_data(path, &object_record->ObjectData.path);
3259 return Ok;
3262 static GpStatus METAFILE_PrepareBrushData(GpBrush *brush, DWORD *size)
3264 if (brush->bt == BrushTypeSolidColor)
3266 *size = FIELD_OFFSET(EmfPlusBrush, BrushData.solid) + sizeof(EmfPlusSolidBrushData);
3267 return Ok;
3270 FIXME("unsupported brush type: %d\n", brush->bt);
3271 return NotImplemented;
3274 static void METAFILE_FillBrushData(GpBrush *brush, EmfPlusBrush *data)
3276 if (brush->bt == BrushTypeSolidColor)
3278 GpSolidFill *solid = (GpSolidFill*)brush;
3280 data->Version = VERSION_MAGIC2;
3281 data->Type = solid->brush.bt;
3282 data->BrushData.solid.SolidColor.Blue = solid->color & 0xff;
3283 data->BrushData.solid.SolidColor.Green = (solid->color >> 8) & 0xff;
3284 data->BrushData.solid.SolidColor.Red = (solid->color >> 16) & 0xff;
3285 data->BrushData.solid.SolidColor.Alpha = solid->color >> 24;
3289 static GpStatus METAFILE_AddPenObject(GpMetafile *metafile, GpPen *pen, DWORD *id)
3291 DWORD i, data_flags, pen_data_size, brush_size;
3292 EmfPlusObject *object_record;
3293 EmfPlusPenData *pen_data;
3294 GpStatus stat;
3295 BOOL result;
3297 *id = -1;
3298 if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
3299 return Ok;
3301 data_flags = 0;
3302 pen_data_size = FIELD_OFFSET(EmfPlusPenData, OptionalData);
3304 GdipIsMatrixIdentity(&pen->transform, &result);
3305 if (!result)
3307 data_flags |= PenDataTransform;
3308 pen_data_size += sizeof(EmfPlusTransformMatrix);
3310 if (pen->startcap != LineCapFlat)
3312 data_flags |= PenDataStartCap;
3313 pen_data_size += sizeof(DWORD);
3315 if (pen->endcap != LineCapFlat)
3317 data_flags |= PenDataEndCap;
3318 pen_data_size += sizeof(DWORD);
3320 if (pen->join != LineJoinMiter)
3322 data_flags |= PenDataJoin;
3323 pen_data_size += sizeof(DWORD);
3325 if (pen->miterlimit != 10.0)
3327 data_flags |= PenDataMiterLimit;
3328 pen_data_size += sizeof(REAL);
3330 if (pen->style != GP_DEFAULT_PENSTYLE)
3332 data_flags |= PenDataLineStyle;
3333 pen_data_size += sizeof(DWORD);
3335 if (pen->dashcap != DashCapFlat)
3337 data_flags |= PenDataDashedLineCap;
3338 pen_data_size += sizeof(DWORD);
3340 data_flags |= PenDataDashedLineOffset;
3341 pen_data_size += sizeof(REAL);
3342 if (pen->numdashes)
3344 data_flags |= PenDataDashedLine;
3345 pen_data_size += sizeof(DWORD) + pen->numdashes*sizeof(REAL);
3347 if (pen->align != PenAlignmentCenter)
3349 data_flags |= PenDataNonCenter;
3350 pen_data_size += sizeof(DWORD);
3352 /* TODO: Add support for PenDataCompoundLine */
3353 if (pen->customstart)
3355 FIXME("ignoring custom start cup\n");
3357 if (pen->customend)
3359 FIXME("ignoring custom end cup\n");
3362 stat = METAFILE_PrepareBrushData(pen->brush, &brush_size);
3363 if (stat != Ok) return stat;
3365 stat = METAFILE_AllocateRecord(metafile,
3366 FIELD_OFFSET(EmfPlusObject, ObjectData.pen.data) + pen_data_size + brush_size,
3367 (void**)&object_record);
3368 if (stat != Ok) return stat;
3370 *id = METAFILE_AddObjectId(metafile);
3371 object_record->Header.Type = EmfPlusRecordTypeObject;
3372 object_record->Header.Flags = *id | ObjectTypePen << 8;
3373 object_record->ObjectData.pen.Version = VERSION_MAGIC2;
3374 object_record->ObjectData.pen.Type = 0;
3376 pen_data = (EmfPlusPenData*)object_record->ObjectData.pen.data;
3377 pen_data->PenDataFlags = data_flags;
3378 pen_data->PenUnit = pen->unit;
3379 pen_data->PenWidth = pen->width;
3381 i = 0;
3382 if (data_flags & PenDataTransform)
3384 EmfPlusTransformMatrix *m = (EmfPlusTransformMatrix*)(pen_data->OptionalData + i);
3385 memcpy(m, &pen->transform, sizeof(*m));
3386 i += sizeof(EmfPlusTransformMatrix);
3388 if (data_flags & PenDataStartCap)
3390 *(DWORD*)(pen_data->OptionalData + i) = pen->startcap;
3391 i += sizeof(DWORD);
3393 if (data_flags & PenDataEndCap)
3395 *(DWORD*)(pen_data->OptionalData + i) = pen->endcap;
3396 i += sizeof(DWORD);
3398 if (data_flags & PenDataJoin)
3400 *(DWORD*)(pen_data->OptionalData + i) = pen->join;
3401 i += sizeof(DWORD);
3403 if (data_flags & PenDataMiterLimit)
3405 *(REAL*)(pen_data->OptionalData + i) = pen->miterlimit;
3406 i += sizeof(REAL);
3408 if (data_flags & PenDataLineStyle)
3410 switch (pen->style & PS_STYLE_MASK)
3412 case PS_SOLID: *(DWORD*)(pen_data->OptionalData + i) = LineStyleSolid; break;
3413 case PS_DASH: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDash; break;
3414 case PS_DOT: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDot; break;
3415 case PS_DASHDOT: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDashDot; break;
3416 case PS_DASHDOTDOT: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDashDotDot; break;
3417 default: *(DWORD*)(pen_data->OptionalData + i) = LineStyleCustom; break;
3419 i += sizeof(DWORD);
3421 if (data_flags & PenDataDashedLineCap)
3423 *(DWORD*)(pen_data->OptionalData + i) = pen->dashcap;
3424 i += sizeof(DWORD);
3426 if (data_flags & PenDataDashedLineOffset)
3428 *(REAL*)(pen_data->OptionalData + i) = pen->offset;
3429 i += sizeof(REAL);
3431 if (data_flags & PenDataDashedLine)
3433 int j;
3435 *(DWORD*)(pen_data->OptionalData + i) = pen->numdashes;
3436 i += sizeof(DWORD);
3438 for (j=0; j<pen->numdashes; j++)
3440 *(REAL*)(pen_data->OptionalData + i) = pen->dashes[j];
3441 i += sizeof(REAL);
3444 if (data_flags & PenDataNonCenter)
3446 *(REAL*)(pen_data->OptionalData + i) = pen->align;
3447 i += sizeof(DWORD);
3450 METAFILE_FillBrushData(pen->brush,
3451 (EmfPlusBrush*)(object_record->ObjectData.pen.data + pen_data_size));
3452 return Ok;
3455 GpStatus METAFILE_DrawPath(GpMetafile *metafile, GpPen *pen, GpPath *path)
3457 EmfPlusDrawPath *draw_path_record;
3458 DWORD path_id;
3459 DWORD pen_id;
3460 GpStatus stat;
3462 if (metafile->metafile_type == MetafileTypeEmf)
3464 FIXME("stub!\n");
3465 return NotImplemented;
3468 stat = METAFILE_AddPenObject(metafile, pen, &pen_id);
3469 if (stat != Ok) return stat;
3471 stat = METAFILE_AddPathObject(metafile, path, &path_id);
3472 if (stat != Ok) return stat;
3474 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusDrawPath), (void**)&draw_path_record);
3475 if (stat != Ok) return stat;
3476 draw_path_record->Header.Type = EmfPlusRecordTypeDrawPath;
3477 draw_path_record->Header.Flags = path_id;
3478 draw_path_record->PenId = pen_id;
3480 METAFILE_WriteRecords(metafile);
3481 return Ok;
3484 static GpStatus METAFILE_AddBrushObject(GpMetafile *metafile, GpBrush *brush, DWORD *id)
3486 EmfPlusObject *object_record;
3487 GpStatus stat;
3488 DWORD size;
3490 *id = -1;
3491 if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
3492 return Ok;
3494 stat = METAFILE_PrepareBrushData(brush, &size);
3495 if (stat != Ok) return stat;
3497 stat = METAFILE_AllocateRecord(metafile,
3498 FIELD_OFFSET(EmfPlusObject, ObjectData) + size, (void**)&object_record);
3499 if (stat != Ok) return stat;
3501 *id = METAFILE_AddObjectId(metafile);
3502 object_record->Header.Type = EmfPlusRecordTypeObject;
3503 object_record->Header.Flags = *id | ObjectTypeBrush << 8;
3504 METAFILE_FillBrushData(brush, &object_record->ObjectData.brush);
3505 return Ok;
3508 GpStatus METAFILE_FillPath(GpMetafile *metafile, GpBrush *brush, GpPath *path)
3510 EmfPlusFillPath *fill_path_record;
3511 DWORD brush_id = -1, path_id;
3512 BOOL inline_color;
3513 GpStatus stat;
3515 if (metafile->metafile_type == MetafileTypeEmf)
3517 FIXME("stub!\n");
3518 return NotImplemented;
3521 inline_color = brush->bt == BrushTypeSolidColor;
3522 if (!inline_color)
3524 stat = METAFILE_AddBrushObject(metafile, brush, &brush_id);
3525 if (stat != Ok) return stat;
3528 stat = METAFILE_AddPathObject(metafile, path, &path_id);
3529 if (stat != Ok) return stat;
3531 stat = METAFILE_AllocateRecord(metafile,
3532 sizeof(EmfPlusFillPath), (void**)&fill_path_record);
3533 if (stat != Ok) return stat;
3534 fill_path_record->Header.Type = EmfPlusRecordTypeFillPath;
3535 if (inline_color)
3537 fill_path_record->Header.Flags = 0x8000 | path_id;
3538 fill_path_record->data.Color.Blue = ((GpSolidFill*)brush)->color & 0xff;
3539 fill_path_record->data.Color.Green = (((GpSolidFill*)brush)->color >> 8) & 0xff;
3540 fill_path_record->data.Color.Red = (((GpSolidFill*)brush)->color >> 16) & 0xff;
3541 fill_path_record->data.Color.Alpha = ((GpSolidFill*)brush)->color >> 24;
3543 else
3545 fill_path_record->Header.Flags = path_id;
3546 fill_path_record->data.BrushId = brush_id;
3549 METAFILE_WriteRecords(metafile);
3550 return Ok;