wined3d: Replace wined3d_surface_update_desc() with wined3d_texture_update_desc().
[wine.git] / dlls / gdiplus / metafile.c
blob24ab6be4bdbc663f562d288dfc8ebbd242ce2d08
1 /*
2 * Copyright (C) 2011 Vincent Povirk for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <stdarg.h>
20 #include <math.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wingdi.h"
25 #include "wine/unicode.h"
27 #define COBJMACROS
28 #include "objbase.h"
29 #include "ocidl.h"
30 #include "olectl.h"
31 #include "ole2.h"
33 #include "winreg.h"
34 #include "shlwapi.h"
36 #include "gdiplus.h"
37 #include "gdiplus_private.h"
38 #include "wine/debug.h"
39 #include "wine/list.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
43 typedef struct EmfPlusRecordHeader
45 WORD Type;
46 WORD Flags;
47 DWORD Size;
48 DWORD DataSize;
49 } EmfPlusRecordHeader;
51 typedef struct EmfPlusHeader
53 EmfPlusRecordHeader Header;
54 DWORD Version;
55 DWORD EmfPlusFlags;
56 DWORD LogicalDpiX;
57 DWORD LogicalDpiY;
58 } EmfPlusHeader;
60 typedef struct EmfPlusFillRects
62 EmfPlusRecordHeader Header;
63 DWORD BrushID;
64 DWORD Count;
65 } EmfPlusFillRects;
67 typedef struct EmfPlusSetPageTransform
69 EmfPlusRecordHeader Header;
70 REAL PageScale;
71 } EmfPlusSetPageTransform;
73 typedef struct EmfPlusRect
75 SHORT X;
76 SHORT Y;
77 SHORT Width;
78 SHORT Height;
79 } EmfPlusRect;
81 static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result)
83 DWORD size_needed;
84 EmfPlusRecordHeader *record;
86 if (!metafile->comment_data_size)
88 DWORD data_size = max(256, size * 2 + 4);
89 metafile->comment_data = GdipAlloc(data_size);
91 if (!metafile->comment_data)
92 return OutOfMemory;
94 memcpy(metafile->comment_data, "EMF+", 4);
96 metafile->comment_data_size = data_size;
97 metafile->comment_data_length = 4;
100 size_needed = size + metafile->comment_data_length;
102 if (size_needed > metafile->comment_data_size)
104 DWORD data_size = size_needed * 2;
105 BYTE *new_data = GdipAlloc(data_size);
107 if (!new_data)
108 return OutOfMemory;
110 memcpy(new_data, metafile->comment_data, metafile->comment_data_length);
112 metafile->comment_data_size = data_size;
113 GdipFree(metafile->comment_data);
114 metafile->comment_data = new_data;
117 *result = metafile->comment_data + metafile->comment_data_length;
118 metafile->comment_data_length += size;
120 record = (EmfPlusRecordHeader*)*result;
121 record->Size = size;
122 record->DataSize = size - sizeof(EmfPlusRecordHeader);
124 return Ok;
127 static void METAFILE_WriteRecords(GpMetafile *metafile)
129 if (metafile->comment_data_length > 4)
131 GdiComment(metafile->record_dc, metafile->comment_data_length, metafile->comment_data);
132 metafile->comment_data_length = 4;
136 static GpStatus METAFILE_WriteHeader(GpMetafile *metafile, HDC hdc)
138 GpStatus stat;
140 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
142 EmfPlusHeader *header;
144 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusHeader), (void**)&header);
145 if (stat != Ok)
146 return stat;
148 header->Header.Type = EmfPlusRecordTypeHeader;
150 if (metafile->metafile_type == MetafileTypeEmfPlusDual)
151 header->Header.Flags = 1;
152 else
153 header->Header.Flags = 0;
155 header->Version = 0xDBC01002;
157 if (GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY)
158 header->EmfPlusFlags = 1;
159 else
160 header->EmfPlusFlags = 0;
162 header->LogicalDpiX = GetDeviceCaps(hdc, LOGPIXELSX);
163 header->LogicalDpiY = GetDeviceCaps(hdc, LOGPIXELSY);
165 METAFILE_WriteRecords(metafile);
168 return Ok;
171 static GpStatus METAFILE_WriteEndOfFile(GpMetafile *metafile)
173 GpStatus stat;
175 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
177 EmfPlusRecordHeader *record;
179 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusRecordHeader), (void**)&record);
180 if (stat != Ok)
181 return stat;
183 record->Type = EmfPlusRecordTypeEndOfFile;
184 record->Flags = 0;
186 METAFILE_WriteRecords(metafile);
189 return Ok;
192 GpStatus WINGDIPAPI GdipRecordMetafile(HDC hdc, EmfType type, GDIPCONST GpRectF *frameRect,
193 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
195 HDC record_dc;
196 REAL framerect_factor_x, framerect_factor_y;
197 RECT rc;
198 GpStatus stat;
200 TRACE("(%p %d %p %d %p %p)\n", hdc, type, frameRect, frameUnit, desc, metafile);
202 if (!hdc || type < EmfTypeEmfOnly || type > EmfTypeEmfPlusDual || !metafile)
203 return InvalidParameter;
205 if (!frameRect)
207 FIXME("not implemented for NULL rect\n");
208 return NotImplemented;
211 switch (frameUnit)
213 case MetafileFrameUnitPixel:
214 framerect_factor_x = 2540.0 / GetDeviceCaps(hdc, LOGPIXELSX);
215 framerect_factor_y = 2540.0 / GetDeviceCaps(hdc, LOGPIXELSY);
216 break;
217 case MetafileFrameUnitPoint:
218 framerect_factor_x = framerect_factor_y = 2540.0 / 72.0;
219 break;
220 case MetafileFrameUnitInch:
221 framerect_factor_x = framerect_factor_y = 2540.0;
222 break;
223 case MetafileFrameUnitDocument:
224 framerect_factor_x = framerect_factor_y = 2540.0 / 300.0;
225 break;
226 case MetafileFrameUnitMillimeter:
227 framerect_factor_x = framerect_factor_y = 100.0;
228 break;
229 case MetafileFrameUnitGdi:
230 framerect_factor_x = framerect_factor_y = 1.0;
231 break;
232 default:
233 return InvalidParameter;
236 rc.left = framerect_factor_x * frameRect->X;
237 rc.top = framerect_factor_y * frameRect->Y;
238 rc.right = rc.left + framerect_factor_x * frameRect->Width;
239 rc.bottom = rc.top + framerect_factor_y * frameRect->Height;
241 record_dc = CreateEnhMetaFileW(hdc, NULL, &rc, desc);
243 if (!record_dc)
244 return GenericError;
246 *metafile = GdipAlloc(sizeof(GpMetafile));
247 if(!*metafile)
249 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc));
250 return OutOfMemory;
253 (*metafile)->image.type = ImageTypeMetafile;
254 (*metafile)->image.picture = NULL;
255 (*metafile)->image.flags = ImageFlagsNone;
256 (*metafile)->image.palette = NULL;
257 (*metafile)->image.xres = 72.0;
258 (*metafile)->image.yres = 72.0;
259 (*metafile)->bounds = *frameRect;
260 (*metafile)->unit = frameUnit;
261 (*metafile)->metafile_type = type;
262 (*metafile)->record_dc = record_dc;
263 (*metafile)->comment_data = NULL;
264 (*metafile)->comment_data_size = 0;
265 (*metafile)->comment_data_length = 0;
266 (*metafile)->hemf = NULL;
268 stat = METAFILE_WriteHeader(*metafile, hdc);
270 if (stat != Ok)
272 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc));
273 GdipFree(*metafile);
274 *metafile = NULL;
275 return OutOfMemory;
278 return stat;
281 /*****************************************************************************
282 * GdipRecordMetafileI [GDIPLUS.@]
284 GpStatus WINGDIPAPI GdipRecordMetafileI(HDC hdc, EmfType type, GDIPCONST GpRect *frameRect,
285 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile)
287 GpRectF frameRectF, *pFrameRectF;
289 TRACE("(%p %d %p %d %p %p)\n", hdc, type, frameRect, frameUnit, desc, metafile);
291 if (frameRect)
293 frameRectF.X = frameRect->X;
294 frameRectF.Y = frameRect->Y;
295 frameRectF.Width = frameRect->Width;
296 frameRectF.Height = frameRect->Height;
297 pFrameRectF = &frameRectF;
299 else
300 pFrameRectF = NULL;
302 return GdipRecordMetafile(hdc, type, pFrameRectF, frameUnit, desc, metafile);
305 GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result)
307 GpStatus stat;
309 if (!metafile->record_dc || metafile->record_graphics)
310 return InvalidParameter;
312 stat = graphics_from_image((GpImage*)metafile, &metafile->record_graphics);
314 if (stat == Ok)
316 *result = metafile->record_graphics;
317 metafile->record_graphics->xres = 96.0;
318 metafile->record_graphics->yres = 96.0;
321 return stat;
324 GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc)
326 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
328 EmfPlusRecordHeader *record;
329 GpStatus stat;
331 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusRecordHeader), (void**)&record);
332 if (stat != Ok)
333 return stat;
335 record->Type = EmfPlusRecordTypeGetDC;
336 record->Flags = 0;
338 METAFILE_WriteRecords(metafile);
341 *hdc = metafile->record_dc;
343 return Ok;
346 static BOOL is_integer_rect(const GpRectF *rect)
348 SHORT x, y, width, height;
349 x = rect->X;
350 y = rect->Y;
351 width = rect->Width;
352 height = rect->Height;
353 if (rect->X != (REAL)x || rect->Y != (REAL)y ||
354 rect->Width != (REAL)width || rect->Height != (REAL)height)
355 return FALSE;
356 return TRUE;
359 GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush,
360 GDIPCONST GpRectF* rects, INT count)
362 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
364 EmfPlusFillRects *record;
365 GpStatus stat;
366 BOOL integer_rects = TRUE;
367 int i;
368 DWORD brushid;
369 int flags = 0;
371 if (brush->bt == BrushTypeSolidColor)
373 flags |= 0x8000;
374 brushid = ((GpSolidFill*)brush)->color;
376 else
378 FIXME("brush serialization not implemented\n");
379 return NotImplemented;
382 for (i=0; i<count; i++)
384 if (!is_integer_rect(&rects[i]))
386 integer_rects = FALSE;
387 break;
391 if (integer_rects)
392 flags |= 0x4000;
394 stat = METAFILE_AllocateRecord(metafile,
395 sizeof(EmfPlusFillRects) + count * (integer_rects ? sizeof(EmfPlusRect) : sizeof(GpRectF)),
396 (void**)&record);
397 if (stat != Ok)
398 return stat;
400 record->Header.Type = EmfPlusRecordTypeFillRects;
401 record->Header.Flags = flags;
402 record->BrushID = brushid;
403 record->Count = count;
405 if (integer_rects)
407 EmfPlusRect *record_rects = (EmfPlusRect*)(record+1);
408 for (i=0; i<count; i++)
410 record_rects[i].X = (SHORT)rects[i].X;
411 record_rects[i].Y = (SHORT)rects[i].Y;
412 record_rects[i].Width = (SHORT)rects[i].Width;
413 record_rects[i].Height = (SHORT)rects[i].Height;
416 else
417 memcpy(record+1, rects, sizeof(GpRectF) * count);
419 METAFILE_WriteRecords(metafile);
422 return Ok;
425 GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale)
427 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
429 EmfPlusSetPageTransform *record;
430 GpStatus stat;
432 stat = METAFILE_AllocateRecord(metafile,
433 sizeof(EmfPlusSetPageTransform),
434 (void**)&record);
435 if (stat != Ok)
436 return stat;
438 record->Header.Type = EmfPlusRecordTypeSetPageTransform;
439 record->Header.Flags = unit;
440 record->PageScale = scale;
442 METAFILE_WriteRecords(metafile);
445 return Ok;
448 GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc)
450 if (hdc != metafile->record_dc)
451 return InvalidParameter;
453 return Ok;
456 GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile)
458 GpStatus stat;
460 stat = METAFILE_WriteEndOfFile(metafile);
461 metafile->record_graphics = NULL;
463 metafile->hemf = CloseEnhMetaFile(metafile->record_dc);
464 metafile->record_dc = NULL;
466 GdipFree(metafile->comment_data);
467 metafile->comment_data = NULL;
468 metafile->comment_data_size = 0;
470 return stat;
473 GpStatus WINGDIPAPI GdipGetHemfFromMetafile(GpMetafile *metafile, HENHMETAFILE *hEmf)
475 TRACE("(%p,%p)\n", metafile, hEmf);
477 if (!metafile || !hEmf || !metafile->hemf)
478 return InvalidParameter;
480 *hEmf = metafile->hemf;
481 metafile->hemf = NULL;
483 return Ok;
486 static GpStatus METAFILE_PlaybackGetDC(GpMetafile *metafile)
488 GpStatus stat = Ok;
490 stat = GdipGetDC(metafile->playback_graphics, &metafile->playback_dc);
492 if (stat == Ok)
494 /* The result of GdipGetDC always expects device co-ordinates, but the
495 * device co-ordinates of the source metafile do not correspond to
496 * device co-ordinates of the destination. Therefore, we set up the DC
497 * so that the metafile's bounds map to the destination points where we
498 * are drawing this metafile. */
499 SetMapMode(metafile->playback_dc, MM_ANISOTROPIC);
501 SetWindowOrgEx(metafile->playback_dc, metafile->bounds.X, metafile->bounds.Y, NULL);
502 SetWindowExtEx(metafile->playback_dc, metafile->bounds.Width, metafile->bounds.Height, NULL);
504 SetViewportOrgEx(metafile->playback_dc, metafile->playback_points[0].X, metafile->playback_points[0].Y, NULL);
505 SetViewportExtEx(metafile->playback_dc,
506 metafile->playback_points[1].X - metafile->playback_points[0].X,
507 metafile->playback_points[2].Y - metafile->playback_points[0].Y, NULL);
510 return stat;
513 static void METAFILE_PlaybackReleaseDC(GpMetafile *metafile)
515 if (metafile->playback_dc)
517 GdipReleaseDC(metafile->playback_graphics, metafile->playback_dc);
518 metafile->playback_dc = NULL;
522 static GpStatus METAFILE_PlaybackUpdateWorldTransform(GpMetafile *metafile)
524 GpMatrix *real_transform;
525 GpStatus stat;
527 stat = GdipCreateMatrix3(&metafile->src_rect, metafile->playback_points, &real_transform);
529 if (stat == Ok)
531 REAL scale = units_to_pixels(1.0, metafile->page_unit, 96.0);
533 if (metafile->page_unit != UnitDisplay)
534 scale *= metafile->page_scale;
536 stat = GdipScaleMatrix(real_transform, scale, scale, MatrixOrderPrepend);
538 if (stat == Ok)
539 stat = GdipMultiplyMatrix(real_transform, metafile->world_transform, MatrixOrderPrepend);
541 if (stat == Ok)
542 stat = GdipSetWorldTransform(metafile->playback_graphics, real_transform);
544 GdipDeleteMatrix(real_transform);
547 return stat;
550 GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile,
551 EmfPlusRecordType recordType, UINT flags, UINT dataSize, GDIPCONST BYTE *data)
553 GpStatus stat;
554 GpMetafile *real_metafile = (GpMetafile*)metafile;
556 TRACE("(%p,%x,%x,%d,%p)\n", metafile, recordType, flags, dataSize, data);
558 if (!metafile || (dataSize && !data) || !metafile->playback_graphics)
559 return InvalidParameter;
561 if (recordType >= 1 && recordType <= 0x7a)
563 /* regular EMF record */
564 if (metafile->playback_dc)
566 ENHMETARECORD *record;
568 record = GdipAlloc(dataSize + 8);
570 if (record)
572 record->iType = recordType;
573 record->nSize = dataSize + 8;
574 memcpy(record->dParm, data, dataSize);
576 PlayEnhMetaFileRecord(metafile->playback_dc, metafile->handle_table,
577 record, metafile->handle_count);
579 GdipFree(record);
581 else
582 return OutOfMemory;
585 else
587 EmfPlusRecordHeader *header = (EmfPlusRecordHeader*)(data)-1;
589 METAFILE_PlaybackReleaseDC((GpMetafile*)metafile);
591 switch(recordType)
593 case EmfPlusRecordTypeHeader:
594 case EmfPlusRecordTypeEndOfFile:
595 break;
596 case EmfPlusRecordTypeGetDC:
597 METAFILE_PlaybackGetDC((GpMetafile*)metafile);
598 break;
599 case EmfPlusRecordTypeFillRects:
601 EmfPlusFillRects *record = (EmfPlusFillRects*)header;
602 GpBrush *brush, *temp_brush=NULL;
603 GpRectF *rects, *temp_rects=NULL;
605 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects))
606 return InvalidParameter;
608 if (flags & 0x4000)
610 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(EmfPlusRect) * record->Count)
611 return InvalidParameter;
613 else
615 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(GpRectF) * record->Count)
616 return InvalidParameter;
619 if (flags & 0x8000)
621 stat = GdipCreateSolidFill((ARGB)record->BrushID, (GpSolidFill**)&temp_brush);
622 brush = temp_brush;
624 else
626 FIXME("brush deserialization not implemented\n");
627 return NotImplemented;
630 if (stat == Ok)
632 if (flags & 0x4000)
634 EmfPlusRect *int_rects = (EmfPlusRect*)(record+1);
635 int i;
637 rects = temp_rects = GdipAlloc(sizeof(GpRectF) * record->Count);
638 if (rects)
640 for (i=0; i<record->Count; i++)
642 rects[i].X = int_rects[i].X;
643 rects[i].Y = int_rects[i].Y;
644 rects[i].Width = int_rects[i].Width;
645 rects[i].Height = int_rects[i].Height;
648 else
649 stat = OutOfMemory;
651 else
652 rects = (GpRectF*)(record+1);
655 if (stat == Ok)
657 stat = GdipFillRectangles(metafile->playback_graphics, brush, rects, record->Count);
660 GdipDeleteBrush(temp_brush);
661 GdipFree(temp_rects);
663 return stat;
665 case EmfPlusRecordTypeSetPageTransform:
667 EmfPlusSetPageTransform *record = (EmfPlusSetPageTransform*)header;
668 GpUnit unit = (GpUnit)flags;
670 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusSetPageTransform))
671 return InvalidParameter;
673 real_metafile->page_unit = unit;
674 real_metafile->page_scale = record->PageScale;
676 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
678 default:
679 FIXME("Not implemented for record type %x\n", recordType);
680 return NotImplemented;
684 return Ok;
687 struct enum_metafile_data
689 EnumerateMetafileProc callback;
690 void *callback_data;
691 GpMetafile *metafile;
694 static int CALLBACK enum_metafile_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR,
695 int nObj, LPARAM lpData)
697 BOOL ret;
698 struct enum_metafile_data *data = (struct enum_metafile_data*)lpData;
699 const BYTE* pStr;
701 data->metafile->handle_table = lpHTable;
702 data->metafile->handle_count = nObj;
704 /* First check for an EMF+ record. */
705 if (lpEMFR->iType == EMR_GDICOMMENT)
707 const EMRGDICOMMENT *comment = (const EMRGDICOMMENT*)lpEMFR;
709 if (comment->cbData >= 4 && memcmp(comment->Data, "EMF+", 4) == 0)
711 int offset = 4;
713 while (offset + sizeof(EmfPlusRecordHeader) <= comment->cbData)
715 const EmfPlusRecordHeader *record = (const EmfPlusRecordHeader*)&comment->Data[offset];
717 if (record->DataSize)
718 pStr = (const BYTE*)(record+1);
719 else
720 pStr = NULL;
722 ret = data->callback(record->Type, record->Flags, record->DataSize,
723 pStr, data->callback_data);
725 if (!ret)
726 return 0;
728 offset += record->Size;
731 return 1;
735 if (lpEMFR->nSize != 8)
736 pStr = (const BYTE*)lpEMFR->dParm;
737 else
738 pStr = NULL;
740 return data->callback(lpEMFR->iType, 0, lpEMFR->nSize-8,
741 pStr, data->callback_data);
744 GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics,
745 GDIPCONST GpMetafile *metafile, GDIPCONST GpPointF *destPoints, INT count,
746 GDIPCONST GpRectF *srcRect, Unit srcUnit, EnumerateMetafileProc callback,
747 VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes)
749 struct enum_metafile_data data;
750 GpStatus stat;
751 GpMetafile *real_metafile = (GpMetafile*)metafile; /* whoever made this const was joking */
752 GraphicsContainer state;
754 TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics, metafile,
755 destPoints, count, srcRect, srcUnit, callback, callbackData,
756 imageAttributes);
758 if (!graphics || !metafile || !destPoints || count != 3 || !srcRect)
759 return InvalidParameter;
761 if (!metafile->hemf)
762 return InvalidParameter;
764 if (metafile->playback_graphics)
765 return ObjectBusy;
767 TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect), srcUnit,
768 debugstr_pointf(&destPoints[0]), debugstr_pointf(&destPoints[1]),
769 debugstr_pointf(&destPoints[2]));
771 data.callback = callback;
772 data.callback_data = callbackData;
773 data.metafile = real_metafile;
775 real_metafile->playback_graphics = graphics;
776 real_metafile->playback_dc = NULL;
777 real_metafile->src_rect = *srcRect;
779 memcpy(real_metafile->playback_points, destPoints, sizeof(PointF) * 3);
780 stat = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, real_metafile->playback_points, 3);
782 if (stat == Ok)
783 stat = GdipBeginContainer2(graphics, &state);
785 if (stat == Ok)
787 stat = GdipSetPageScale(graphics, 1.0);
789 if (stat == Ok)
790 stat = GdipSetPageUnit(graphics, UnitPixel);
792 if (stat == Ok)
793 stat = GdipCreateMatrix(&real_metafile->world_transform);
795 if (stat == Ok)
797 real_metafile->page_unit = UnitDisplay;
798 real_metafile->page_scale = 1.0;
799 stat = METAFILE_PlaybackUpdateWorldTransform(real_metafile);
802 if (stat == Ok && (metafile->metafile_type == MetafileTypeEmf ||
803 metafile->metafile_type == MetafileTypeWmfPlaceable ||
804 metafile->metafile_type == MetafileTypeWmf))
805 stat = METAFILE_PlaybackGetDC(real_metafile);
807 if (stat == Ok)
808 EnumEnhMetaFile(0, metafile->hemf, enum_metafile_proc, &data, NULL);
810 METAFILE_PlaybackReleaseDC(real_metafile);
812 GdipDeleteMatrix(real_metafile->world_transform);
813 real_metafile->world_transform = NULL;
815 GdipEndContainer(graphics, state);
818 real_metafile->playback_graphics = NULL;
820 return stat;
823 GpStatus WINGDIPAPI GdipEnumerateMetafileDestRect(GpGraphics *graphics,
824 GDIPCONST GpMetafile *metafile, GDIPCONST GpRectF *dest,
825 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
827 GpPointF points[3];
829 if (!graphics || !metafile || !dest) return InvalidParameter;
831 points[0].X = points[2].X = dest->X;
832 points[0].Y = points[1].Y = dest->Y;
833 points[1].X = dest->X + dest->Width;
834 points[2].Y = dest->Y + dest->Height;
836 return GdipEnumerateMetafileSrcRectDestPoints(graphics, metafile, points, 3,
837 &metafile->bounds, metafile->unit, callback, cb_data, attrs);
840 GpStatus WINGDIPAPI GdipEnumerateMetafileDestRectI(GpGraphics *graphics,
841 GDIPCONST GpMetafile *metafile, GDIPCONST GpRect *dest,
842 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
844 GpRectF destf;
846 if (!graphics || !metafile || !dest) return InvalidParameter;
848 destf.X = dest->X;
849 destf.Y = dest->Y;
850 destf.Width = dest->Width;
851 destf.Height = dest->Height;
853 return GdipEnumerateMetafileDestRect(graphics, metafile, &destf, callback, cb_data, attrs);
856 GpStatus WINGDIPAPI GdipEnumerateMetafileDestPoint(GpGraphics *graphics,
857 GDIPCONST GpMetafile *metafile, GDIPCONST GpPointF *dest,
858 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
860 GpRectF destf;
862 if (!graphics || !metafile || !dest) return InvalidParameter;
864 destf.X = dest->X;
865 destf.Y = dest->Y;
866 destf.Width = units_to_pixels(metafile->bounds.Width, metafile->unit, metafile->image.xres);
867 destf.Height = units_to_pixels(metafile->bounds.Height, metafile->unit, metafile->image.yres);
869 return GdipEnumerateMetafileDestRect(graphics, metafile, &destf, callback, cb_data, attrs);
872 GpStatus WINGDIPAPI GdipEnumerateMetafileDestPointI(GpGraphics *graphics,
873 GDIPCONST GpMetafile *metafile, GDIPCONST GpPoint *dest,
874 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs)
876 GpPointF ptf;
878 if (!graphics || !metafile || !dest) return InvalidParameter;
880 ptf.X = dest->X;
881 ptf.Y = dest->Y;
883 return GdipEnumerateMetafileDestPoint(graphics, metafile, &ptf, callback, cb_data, attrs);
886 static int CALLBACK get_metafile_type_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR,
887 int nObj, LPARAM lpData)
889 MetafileType *result = (MetafileType*)lpData;
891 if (lpEMFR->iType == EMR_GDICOMMENT)
893 const EMRGDICOMMENT *comment = (const EMRGDICOMMENT*)lpEMFR;
895 if (comment->cbData >= 4 && memcmp(comment->Data, "EMF+", 4) == 0)
897 const EmfPlusRecordHeader *header = (const EmfPlusRecordHeader*)&comment->Data[4];
899 if (4 + sizeof(EmfPlusRecordHeader) <= comment->cbData &&
900 header->Type == EmfPlusRecordTypeHeader)
902 if ((header->Flags & 1) == 1)
903 *result = MetafileTypeEmfPlusDual;
904 else
905 *result = MetafileTypeEmfPlusOnly;
908 else
909 *result = MetafileTypeEmf;
911 else
912 *result = MetafileTypeEmf;
914 return FALSE;
917 static MetafileType METAFILE_GetEmfType(HENHMETAFILE hemf)
919 MetafileType result = MetafileTypeInvalid;
920 EnumEnhMetaFile(NULL, hemf, get_metafile_type_proc, &result, NULL);
921 return result;
924 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
925 MetafileHeader * header)
927 static int calls;
929 TRACE("(%p, %p)\n", metafile, header);
931 if(!metafile || !header)
932 return InvalidParameter;
934 if(!(calls++))
935 FIXME("not implemented\n");
937 memset(header, 0, sizeof(MetafileHeader));
939 return Ok;
942 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromEmf(HENHMETAFILE hEmf,
943 MetafileHeader *header)
945 static int calls;
947 if(!hEmf || !header)
948 return InvalidParameter;
950 if(!(calls++))
951 FIXME("not implemented\n");
953 memset(header, 0, sizeof(MetafileHeader));
955 return Ok;
958 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR *filename,
959 MetafileHeader *header)
961 static int calls;
963 TRACE("(%s,%p)\n", debugstr_w(filename), header);
965 if(!filename || !header)
966 return InvalidParameter;
968 if(!(calls++))
969 FIXME("not implemented\n");
971 memset(header, 0, sizeof(MetafileHeader));
973 return Ok;
976 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromStream(IStream *stream,
977 MetafileHeader *header)
979 static int calls;
981 TRACE("(%p,%p)\n", stream, header);
983 if(!stream || !header)
984 return InvalidParameter;
986 if(!(calls++))
987 FIXME("not implemented\n");
989 memset(header, 0, sizeof(MetafileHeader));
991 return Ok;
994 GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete,
995 GpMetafile **metafile)
997 ENHMETAHEADER header;
998 MetafileType metafile_type;
1000 TRACE("(%p,%i,%p)\n", hemf, delete, metafile);
1002 if(!hemf || !metafile)
1003 return InvalidParameter;
1005 if (GetEnhMetaFileHeader(hemf, sizeof(header), &header) == 0)
1006 return GenericError;
1008 metafile_type = METAFILE_GetEmfType(hemf);
1010 if (metafile_type == MetafileTypeInvalid)
1011 return GenericError;
1013 *metafile = GdipAlloc(sizeof(GpMetafile));
1014 if (!*metafile)
1015 return OutOfMemory;
1017 (*metafile)->image.type = ImageTypeMetafile;
1018 (*metafile)->image.format = ImageFormatEMF;
1019 (*metafile)->image.frame_count = 1;
1020 (*metafile)->image.xres = (REAL)header.szlDevice.cx;
1021 (*metafile)->image.yres = (REAL)header.szlDevice.cy;
1022 (*metafile)->bounds.X = (REAL)header.rclBounds.left;
1023 (*metafile)->bounds.Y = (REAL)header.rclBounds.top;
1024 (*metafile)->bounds.Width = (REAL)(header.rclBounds.right - header.rclBounds.left);
1025 (*metafile)->bounds.Height = (REAL)(header.rclBounds.bottom - header.rclBounds.top);
1026 (*metafile)->unit = UnitPixel;
1027 (*metafile)->metafile_type = metafile_type;
1028 (*metafile)->hemf = hemf;
1029 (*metafile)->preserve_hemf = !delete;
1031 TRACE("<-- %p\n", *metafile);
1033 return Ok;
1036 GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
1037 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
1039 UINT read;
1040 BYTE *copy;
1041 HENHMETAFILE hemf;
1042 GpStatus retval = Ok;
1044 TRACE("(%p, %d, %p, %p)\n", hwmf, delete, placeable, metafile);
1046 if(!hwmf || !metafile || !placeable)
1047 return InvalidParameter;
1049 *metafile = NULL;
1050 read = GetMetaFileBitsEx(hwmf, 0, NULL);
1051 if(!read)
1052 return GenericError;
1053 copy = GdipAlloc(read);
1054 GetMetaFileBitsEx(hwmf, read, copy);
1056 hemf = SetWinMetaFileBits(read, copy, NULL, NULL);
1057 GdipFree(copy);
1059 /* FIXME: We should store and use hwmf instead of converting to hemf */
1060 retval = GdipCreateMetafileFromEmf(hemf, TRUE, metafile);
1062 if (retval == Ok)
1064 (*metafile)->image.xres = (REAL)placeable->Inch;
1065 (*metafile)->image.yres = (REAL)placeable->Inch;
1066 (*metafile)->bounds.X = ((REAL)placeable->BoundingBox.Left) / ((REAL)placeable->Inch);
1067 (*metafile)->bounds.Y = ((REAL)placeable->BoundingBox.Top) / ((REAL)placeable->Inch);
1068 (*metafile)->bounds.Width = (REAL)(placeable->BoundingBox.Right -
1069 placeable->BoundingBox.Left);
1070 (*metafile)->bounds.Height = (REAL)(placeable->BoundingBox.Bottom -
1071 placeable->BoundingBox.Top);
1072 (*metafile)->metafile_type = MetafileTypeWmfPlaceable;
1073 (*metafile)->image.format = ImageFormatWMF;
1075 if (delete) DeleteMetaFile(hwmf);
1077 else
1078 DeleteEnhMetaFile(hemf);
1079 return retval;
1082 GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file,
1083 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile)
1085 HMETAFILE hmf = GetMetaFileW(file);
1087 TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile);
1089 if(!hmf) return InvalidParameter;
1091 return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile);
1094 GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file,
1095 GpMetafile **metafile)
1097 FIXME("(%p, %p): stub\n", file, metafile);
1098 return NotImplemented;
1101 GpStatus WINGDIPAPI GdipCreateMetafileFromStream(IStream *stream,
1102 GpMetafile **metafile)
1104 FIXME("(%p, %p): stub\n", stream, metafile);
1105 return NotImplemented;
1108 GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile *metafile,
1109 UINT limitDpi)
1111 static int calls;
1113 TRACE("(%p,%u)\n", metafile, limitDpi);
1115 if(!(calls++))
1116 FIXME("not implemented\n");
1118 return NotImplemented;
1121 GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
1122 GpMetafile* metafile, BOOL* succ, EmfType emfType,
1123 const WCHAR* description, GpMetafile** out_metafile)
1125 static int calls;
1127 TRACE("(%p,%p,%p,%u,%s,%p)\n", ref, metafile, succ, emfType,
1128 debugstr_w(description), out_metafile);
1130 if(!ref || !metafile || !out_metafile)
1131 return InvalidParameter;
1133 *succ = FALSE;
1134 *out_metafile = NULL;
1136 if(!(calls++))
1137 FIXME("not implemented\n");
1139 return NotImplemented;
1142 GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE hemf, UINT cbData16,
1143 LPBYTE pData16, INT iMapMode, INT eFlags)
1145 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf, cbData16, pData16, iMapMode, eFlags);
1146 return NotImplemented;
1149 GpStatus WINGDIPAPI GdipRecordMetafileFileName(GDIPCONST WCHAR* fileName,
1150 HDC hdc, EmfType type, GDIPCONST GpRectF *pFrameRect,
1151 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc,
1152 GpMetafile **metafile)
1154 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
1155 frameUnit, debugstr_w(desc), metafile);
1157 return NotImplemented;
1160 GpStatus WINGDIPAPI GdipRecordMetafileFileNameI(GDIPCONST WCHAR* fileName, HDC hdc, EmfType type,
1161 GDIPCONST GpRect *pFrameRect, MetafileFrameUnit frameUnit,
1162 GDIPCONST WCHAR *desc, GpMetafile **metafile)
1164 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
1165 frameUnit, debugstr_w(desc), metafile);
1167 return NotImplemented;
1170 /*****************************************************************************
1171 * GdipConvertToEmfPlusToFile [GDIPLUS.@]
1174 GpStatus WINGDIPAPI GdipConvertToEmfPlusToFile(const GpGraphics* refGraphics,
1175 GpMetafile* metafile, BOOL* conversionSuccess,
1176 const WCHAR* filename, EmfType emfType,
1177 const WCHAR* description, GpMetafile** out_metafile)
1179 FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics, metafile, conversionSuccess, filename, emfType, description, out_metafile);
1180 return NotImplemented;