ReactOS 0.4.15-dev-8127-g6338913
metafile.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2011 Vincent Povirk for CodeWeavers
3 *
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.
8 *
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.
13 *
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
17 */
18
19#include <stdarg.h>
20#include <math.h>
21#include <assert.h>
22
23#define NONAMELESSUNION
24
25#include "windef.h"
26#include "winbase.h"
27#include "wingdi.h"
28#include "wine/unicode.h"
29
30#define COBJMACROS
31#include "objbase.h"
32#include "ocidl.h"
33#include "olectl.h"
34#include "ole2.h"
35
36#include "winreg.h"
37#include "shlwapi.h"
38
39#include "gdiplus.h"
40#include "gdiplus_private.h"
41#include "wine/debug.h"
42#include "wine/list.h"
43
45
47
49
50typedef struct EmfPlusRecordHeader
51{
57
58typedef struct EmfPlusHeader
59{
66
67typedef struct EmfPlusClear
68{
72
73typedef struct EmfPlusFillRects
74{
79
80typedef struct EmfPlusSetClipRect
81{
85
87{
91
92typedef struct EmfPlusRect
93{
99
101{
105
107{
112
114{
118
120{
124
126{
131
133{
139
141{
145
147{
151
152typedef struct container
153{
154 struct list entry;
163
165{
169 PenDataJoin = 0x0008,
178 PenDataCustomEndCap = 0x1000
180
182{
185
187{
195
197{
201
203{
207
209{
213
215{
219
220typedef struct EmfPlusPenData
221{
227
229{
238};
239
241{
244
246{
251
253{
258
259typedef struct EmfPlusRectF
260{
261 float X;
262 float Y;
263 float Width;
264 float Height;
266
268{
278
279typedef struct EmfPlusBrush
280{
283 union {
290
291typedef struct EmfPlusPen
292{
295 /* EmfPlusPenData */
296 /* EmfPlusBrush */
299
300typedef struct EmfPlusPath
301{
305 /* PathPoints[] */
306 /* PathPointTypes[] */
307 /* AlignmentPadding */
310
312{
316
317typedef struct EmfPlusRegion
318{
323
324typedef struct EmfPlusPalette
325{
330
331typedef enum
332{
336
337typedef struct EmfPlusBitmap
338{
346
347typedef struct EmfPlusMetafile
348{
353
354typedef enum ImageDataType
355{
360
361typedef struct EmfPlusImage
362{
365 union
366 {
371
373{
381
382typedef struct EmfPlusObject
383{
385 union
386 {
395
396typedef struct EmfPlusPointR7
397{
401
402typedef struct EmfPlusPoint
403{
404 short X;
405 short Y;
407
408typedef struct EmfPlusPointF
409{
410 float X;
411 float Y;
413
414typedef struct EmfPlusDrawImage
415{
420 union
421 {
426
428{
434 union
435 {
441
442typedef struct EmfPlusDrawPath
443{
447
448typedef struct EmfPlusDrawArc
449{
453 union
454 {
459
460typedef struct EmfPlusDrawEllipse
461{
463 union
464 {
469
470typedef struct EmfPlusDrawPie
471{
475 union
476 {
481
482typedef struct EmfPlusDrawRects
483{
486 union
487 {
492
493typedef struct EmfPlusFillPath
494{
496 union
497 {
502
504{
507 float Tension;
509 union
510 {
516
517typedef struct EmfPlusFillEllipse
518{
521 union
522 {
527
528typedef struct EmfPlusFillPie
529{
534 union
535 {
540
541typedef struct EmfPlusFont
542{
544 float EmSize;
551
553{
554 struct emfplus_object *object = &metafile->objtable[id];
555
556 switch (object->type)
557 {
559 break;
560 case ObjectTypeBrush:
561 GdipDeleteBrush(object->u.brush);
562 break;
563 case ObjectTypePen:
564 GdipDeletePen(object->u.pen);
565 break;
566 case ObjectTypePath:
567 GdipDeletePath(object->u.path);
568 break;
569 case ObjectTypeRegion:
570 GdipDeleteRegion(object->u.region);
571 break;
572 case ObjectTypeImage:
573 GdipDisposeImage(object->u.image);
574 break;
575 case ObjectTypeFont:
576 GdipDeleteFont(object->u.font);
577 break;
579 GdipDisposeImageAttributes(object->u.image_attributes);
580 break;
581 default:
582 FIXME("not implemented for object type %u.\n", object->type);
583 return;
584 }
585
586 object->type = ObjectTypeInvalid;
587 object->u.object = NULL;
588}
589
591{
592 unsigned int i;
593
594 heap_free(metafile->comment_data);
596 if (!metafile->preserve_hemf)
598 if (metafile->record_graphics)
599 {
600 WARN("metafile closed while recording\n");
601 /* not sure what to do here; for now just prevent the graphics from functioning or using this object */
602 metafile->record_graphics->image = NULL;
603 metafile->record_graphics->busy = TRUE;
604 }
605
606 if (metafile->record_stream)
607 IStream_Release(metafile->record_stream);
608
609 for (i = 0; i < ARRAY_SIZE(metafile->objtable); i++)
611}
612
614{
615 return (metafile->next_object_id++) % EmfPlusObjectTableSize;
616}
617
619{
620 DWORD size_needed;
622
623 if (!metafile->comment_data_size)
624 {
625 DWORD data_size = max(256, size * 2 + 4);
626 metafile->comment_data = heap_alloc_zero(data_size);
627
628 if (!metafile->comment_data)
629 return OutOfMemory;
630
631 memcpy(metafile->comment_data, "EMF+", 4);
632
633 metafile->comment_data_size = data_size;
634 metafile->comment_data_length = 4;
635 }
636
637 size_needed = size + metafile->comment_data_length;
638
639 if (size_needed > metafile->comment_data_size)
640 {
641 DWORD data_size = size_needed * 2;
642 BYTE *new_data = heap_alloc_zero(data_size);
643
644 if (!new_data)
645 return OutOfMemory;
646
647 memcpy(new_data, metafile->comment_data, metafile->comment_data_length);
648
649 metafile->comment_data_size = data_size;
650 heap_free(metafile->comment_data);
651 metafile->comment_data = new_data;
652 }
653
654 *result = metafile->comment_data + metafile->comment_data_length;
655 metafile->comment_data_length += size;
656
658 record->Size = size;
659 record->DataSize = size - sizeof(EmfPlusRecordHeader);
660
661 return Ok;
662}
663
665{
666 assert(metafile->comment_data + metafile->comment_data_length == (BYTE*)record + record->Size);
667 metafile->comment_data_length -= record->Size;
668}
669
671{
672 if (metafile->comment_data_length > 4)
673 {
674 GdiComment(metafile->record_dc, metafile->comment_data_length, metafile->comment_data);
675 metafile->comment_data_length = 4;
676 }
677}
678
680{
682
683 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
684 {
686
688 if (stat != Ok)
689 return stat;
690
691 header->Header.Type = EmfPlusRecordTypeHeader;
692
693 if (metafile->metafile_type == MetafileTypeEmfPlusDual)
694 header->Header.Flags = 1;
695 else
696 header->Header.Flags = 0;
697
698 header->Version = VERSION_MAGIC2;
699
701 header->EmfPlusFlags = 1;
702 else
703 header->EmfPlusFlags = 0;
704
705 header->LogicalDpiX = GetDeviceCaps(hdc, LOGPIXELSX);
706 header->LogicalDpiY = GetDeviceCaps(hdc, LOGPIXELSY);
707
709 }
710
711 return Ok;
712}
713
715{
717
718 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
719 {
721
723 if (stat != Ok)
724 return stat;
725
727 record->Flags = 0;
728
730 }
731
732 return Ok;
733}
734
737{
738 HDC record_dc;
739 REAL dpix, dpiy;
740 REAL framerect_factor_x, framerect_factor_y;
741 RECT rc, *lprc;
743
744 TRACE("(%p %d %p %d %p %p)\n", hdc, type, frameRect, frameUnit, desc, metafile);
745
746 if (!hdc || type < EmfTypeEmfOnly || type > EmfTypeEmfPlusDual || !metafile)
747 return InvalidParameter;
748
751
752 if (frameRect)
753 {
754 switch (frameUnit)
755 {
757 framerect_factor_x = 2540.0 / dpix;
758 framerect_factor_y = 2540.0 / dpiy;
759 break;
761 framerect_factor_x = framerect_factor_y = 2540.0 / 72.0;
762 break;
764 framerect_factor_x = framerect_factor_y = 2540.0;
765 break;
767 framerect_factor_x = framerect_factor_y = 2540.0 / 300.0;
768 break;
770 framerect_factor_x = framerect_factor_y = 100.0;
771 break;
773 framerect_factor_x = framerect_factor_y = 1.0;
774 break;
775 default:
776 return InvalidParameter;
777 }
778
779 rc.left = framerect_factor_x * frameRect->X;
780 rc.top = framerect_factor_y * frameRect->Y;
781 rc.right = rc.left + framerect_factor_x * frameRect->Width;
782 rc.bottom = rc.top + framerect_factor_y * frameRect->Height;
783
784 lprc = &rc;
785 }
786 else
787 lprc = NULL;
788
789 record_dc = CreateEnhMetaFileW(hdc, NULL, lprc, desc);
790
791 if (!record_dc)
792 return GenericError;
793
794 *metafile = heap_alloc_zero(sizeof(GpMetafile));
795 if(!*metafile)
796 {
798 return OutOfMemory;
799 }
800
801 (*metafile)->image.type = ImageTypeMetafile;
802 (*metafile)->image.flags = ImageFlagsNone;
803 (*metafile)->image.palette = NULL;
804 (*metafile)->image.xres = dpix;
805 (*metafile)->image.yres = dpiy;
806 (*metafile)->bounds.X = (*metafile)->bounds.Y = 0.0;
807 (*metafile)->bounds.Width = (*metafile)->bounds.Height = 1.0;
808 (*metafile)->unit = UnitPixel;
809 (*metafile)->metafile_type = type;
810 (*metafile)->record_dc = record_dc;
811 (*metafile)->comment_data = NULL;
812 (*metafile)->comment_data_size = 0;
813 (*metafile)->comment_data_length = 0;
814 (*metafile)->hemf = NULL;
815 list_init(&(*metafile)->containers);
816
817 if (!frameRect)
818 {
819 (*metafile)->auto_frame = TRUE;
820 (*metafile)->auto_frame_min.X = 0;
821 (*metafile)->auto_frame_min.Y = 0;
822 (*metafile)->auto_frame_max.X = -1;
823 (*metafile)->auto_frame_max.Y = -1;
824 }
825
827
828 if (stat != Ok)
829 {
832 *metafile = NULL;
833 return OutOfMemory;
834 }
835
836 return stat;
837}
838
839/*****************************************************************************
840 * GdipRecordMetafileI [GDIPLUS.@]
841 */
844{
845 GpRectF frameRectF, *pFrameRectF;
846
847 TRACE("(%p %d %p %d %p %p)\n", hdc, type, frameRect, frameUnit, desc, metafile);
848
849 if (frameRect)
850 {
851 frameRectF.X = frameRect->X;
852 frameRectF.Y = frameRect->Y;
853 frameRectF.Width = frameRect->Width;
854 frameRectF.Height = frameRect->Height;
855 pFrameRectF = &frameRectF;
856 }
857 else
858 pFrameRectF = NULL;
859
860 return GdipRecordMetafile(hdc, type, pFrameRectF, frameUnit, desc, metafile);
861}
862
865{
867
868 TRACE("(%p %p %d %p %d %p %p)\n", stream, hdc, type, frameRect, frameUnit, desc, metafile);
869
870 if (!stream)
871 return InvalidParameter;
872
873 stat = GdipRecordMetafile(hdc, type, frameRect, frameUnit, desc, metafile);
874
875 if (stat == Ok)
876 {
877 (*metafile)->record_stream = stream;
878 IStream_AddRef(stream);
879 }
880
881 return stat;
882}
883
885 UINT num_points)
886{
887 int i;
888
889 if (!metafile->auto_frame || !num_points)
890 return;
891
892 if (metafile->auto_frame_max.X < metafile->auto_frame_min.X)
893 metafile->auto_frame_max = metafile->auto_frame_min = points[0];
894
895 for (i=0; i<num_points; i++)
896 {
897 if (points[i].X < metafile->auto_frame_min.X)
898 metafile->auto_frame_min.X = points[i].X;
899 if (points[i].X > metafile->auto_frame_max.X)
900 metafile->auto_frame_max.X = points[i].X;
901 if (points[i].Y < metafile->auto_frame_min.Y)
902 metafile->auto_frame_min.Y = points[i].Y;
903 if (points[i].Y > metafile->auto_frame_max.Y)
904 metafile->auto_frame_max.Y = points[i].Y;
905 }
906}
907
909{
911
912 if (!metafile->record_dc || metafile->record_graphics)
913 return InvalidParameter;
914
915 stat = graphics_from_image((GpImage*)metafile, &metafile->record_graphics);
916
917 if (stat == Ok)
918 {
919 *result = metafile->record_graphics;
920 metafile->record_graphics->xres = 96.0;
921 metafile->record_graphics->yres = 96.0;
922 }
923
924 return stat;
925}
926
928{
929 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
930 {
933
935 if (stat != Ok)
936 return stat;
937
939 record->Flags = 0;
940
942 }
943
944 *hdc = metafile->record_dc;
945
946 return Ok;
947}
948
950{
951 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
952 {
955
957 if (stat != Ok)
958 return stat;
959
960 record->Header.Type = EmfPlusRecordTypeClear;
961 record->Header.Flags = 0;
962 record->Color = color;
963
965 }
966
967 return Ok;
968}
969
971{
972 SHORT x, y, width, height;
973 x = rect->X;
974 y = rect->Y;
975 width = rect->Width;
976 height = rect->Height;
977 if (rect->X != (REAL)x || rect->Y != (REAL)y ||
978 rect->Width != (REAL)width || rect->Height != (REAL)height)
979 return FALSE;
980 return TRUE;
981}
982
984{
985 switch (brush->bt)
986 {
988 *size = FIELD_OFFSET(EmfPlusBrush, BrushData) + sizeof(EmfPlusSolidBrushData);
989 break;
991 *size = FIELD_OFFSET(EmfPlusBrush, BrushData) + sizeof(EmfPlusHatchBrushData);
992 break;
993 default:
994 FIXME("unsupported brush type: %d\n", brush->bt);
995 return NotImplemented;
996 }
997
998 return Ok;
999}
1000
1002{
1003 data->Version = VERSION_MAGIC2;
1004 data->Type = brush->bt;
1005
1006 switch (brush->bt)
1007 {
1009 {
1010 GpSolidFill *solid = (GpSolidFill *)brush;
1011 data->BrushData.solid.SolidColor = solid->color;
1012 break;
1013 }
1014 case BrushTypeHatchFill:
1015 {
1016 GpHatch *hatch = (GpHatch *)brush;
1017 data->BrushData.hatch.HatchStyle = hatch->hatchstyle;
1018 data->BrushData.hatch.ForeColor = hatch->forecol;
1019 data->BrushData.hatch.BackColor = hatch->backcol;
1020 break;
1021 }
1022 default:
1023 FIXME("unsupported brush type: %d\n", brush->bt);
1024 }
1025}
1026
1028{
1029 EmfPlusObject *object_record;
1030 GpStatus stat;
1031 DWORD size;
1032
1033 *id = -1;
1034 if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
1035 return Ok;
1036
1038 if (stat != Ok) return stat;
1039
1041 FIELD_OFFSET(EmfPlusObject, ObjectData) + size, (void**)&object_record);
1042 if (stat != Ok) return stat;
1043
1045 object_record->Header.Type = EmfPlusRecordTypeObject;
1046 object_record->Header.Flags = *id | ObjectTypeBrush << 8;
1047 METAFILE_FillBrushData(brush, &object_record->ObjectData.brush);
1048 return Ok;
1049}
1050
1052 GDIPCONST GpRectF* rects, INT count)
1053{
1054 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1055 {
1057 GpStatus stat;
1058 BOOL integer_rects = TRUE;
1059 int i;
1060 DWORD brushid;
1061 int flags = 0;
1062
1064 {
1065 flags |= 0x8000;
1066 brushid = ((GpSolidFill*)brush)->color;
1067 }
1068 else
1069 {
1071 if (stat != Ok)
1072 return stat;
1073 }
1074
1075 for (i=0; i<count; i++)
1076 {
1077 if (!is_integer_rect(&rects[i]))
1078 {
1079 integer_rects = FALSE;
1080 break;
1081 }
1082 }
1083
1084 if (integer_rects)
1085 flags |= 0x4000;
1086
1088 sizeof(EmfPlusFillRects) + count * (integer_rects ? sizeof(EmfPlusRect) : sizeof(GpRectF)),
1089 (void**)&record);
1090 if (stat != Ok)
1091 return stat;
1092
1093 record->Header.Type = EmfPlusRecordTypeFillRects;
1094 record->Header.Flags = flags;
1095 record->BrushID = brushid;
1096 record->Count = count;
1097
1098 if (integer_rects)
1099 {
1100 EmfPlusRect *record_rects = (EmfPlusRect*)(record+1);
1101 for (i=0; i<count; i++)
1102 {
1103 record_rects[i].X = (SHORT)rects[i].X;
1104 record_rects[i].Y = (SHORT)rects[i].Y;
1105 record_rects[i].Width = (SHORT)rects[i].Width;
1106 record_rects[i].Height = (SHORT)rects[i].Height;
1107 }
1108 }
1109 else
1110 memcpy(record+1, rects, sizeof(GpRectF) * count);
1111
1113 }
1114
1115 if (metafile->auto_frame)
1116 {
1117 GpPointF corners[4];
1118 int i;
1119
1120 for (i=0; i<count; i++)
1121 {
1122 corners[0].X = rects[i].X;
1123 corners[0].Y = rects[i].Y;
1124 corners[1].X = rects[i].X + rects[i].Width;
1125 corners[1].Y = rects[i].Y;
1126 corners[2].X = rects[i].X;
1127 corners[2].Y = rects[i].Y + rects[i].Height;
1128 corners[3].X = rects[i].X + rects[i].Width;
1129 corners[3].Y = rects[i].Y + rects[i].Height;
1130
1132 CoordinateSpaceWorld, corners, 4);
1133
1134 METAFILE_AdjustFrame(metafile, corners, 4);
1135 }
1136 }
1137
1138 return Ok;
1139}
1140
1142{
1143 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1144 {
1146 GpStatus stat;
1147
1149 sizeof(EmfPlusSetClipRect),
1150 (void**)&record);
1151 if (stat != Ok)
1152 return stat;
1153
1154 record->Header.Type = EmfPlusRecordTypeSetClipRect;
1155 record->Header.Flags = (mode & 0xf) << 8;
1156 record->ClipRect.X = x;
1157 record->ClipRect.Y = y;
1158 record->ClipRect.Width = width;
1159 record->ClipRect.Height = height;
1160
1162 }
1163
1164 return Ok;
1165}
1166
1168{
1169 EmfPlusObject *object_record;
1170 DWORD size;
1171 GpStatus stat;
1172
1173 *id = -1;
1174 if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual)
1175 return Ok;
1176
1179 FIELD_OFFSET(EmfPlusObject, ObjectData.region) + size, (void**)&object_record);
1180 if (stat != Ok) return stat;
1181
1183 object_record->Header.Type = EmfPlusRecordTypeObject;
1184 object_record->Header.Flags = *id | ObjectTypeRegion << 8;
1185 write_region_data(region, &object_record->ObjectData.region);
1186 return Ok;
1187}
1188
1190{
1192 DWORD region_id;
1193 GpStatus stat;
1194
1195 if (metafile->metafile_type == MetafileTypeEmf)
1196 {
1197 FIXME("stub!\n");
1198 return NotImplemented;
1199 }
1200
1202 if (stat != Ok) return stat;
1203
1204 stat = METAFILE_AllocateRecord(metafile, sizeof(*record), (void**)&record);
1205 if (stat != Ok) return stat;
1206
1208 record->Flags = region_id | mode << 8;
1209
1211 return Ok;
1212}
1213
1215{
1216 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1217 {
1219 GpStatus stat;
1220
1223 (void**)&record);
1224 if (stat != Ok)
1225 return stat;
1226
1228 record->Header.Flags = unit;
1229 record->PageScale = scale;
1230
1232 }
1233
1234 return Ok;
1235}
1236
1238{
1239 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1240 {
1242 GpStatus stat;
1243
1246 (void**)&record);
1247 if (stat != Ok)
1248 return stat;
1249
1251 record->Header.Flags = 0;
1252 memcpy(record->MatrixData, transform->matrix, sizeof(record->MatrixData));
1253
1255 }
1256
1257 return Ok;
1258}
1259
1261{
1262 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1263 {
1265 GpStatus stat;
1266
1269 (void**)&record);
1270 if (stat != Ok)
1271 return stat;
1272
1274 record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0);
1275 record->Sx = sx;
1276 record->Sy = sy;
1277
1279 }
1280
1281 return Ok;
1282}
1283
1285{
1286 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1287 {
1289 GpStatus stat;
1290
1293 (void**)&record);
1294 if (stat != Ok)
1295 return stat;
1296
1298 record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0);
1299 memcpy(record->MatrixData, matrix->matrix, sizeof(record->MatrixData));
1300
1302 }
1303
1304 return Ok;
1305}
1306
1308{
1309 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1310 {
1312 GpStatus stat;
1313
1316 (void**)&record);
1317 if (stat != Ok)
1318 return stat;
1319
1321 record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0);
1322 record->Angle = angle;
1323
1325 }
1326
1327 return Ok;
1328}
1329
1331{
1332 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1333 {
1335 GpStatus stat;
1336
1339 (void**)&record);
1340 if (stat != Ok)
1341 return stat;
1342
1344 record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0);
1345 record->dx = dx;
1346 record->dy = dy;
1347
1349 }
1350
1351 return Ok;
1352}
1353
1355{
1356 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1357 {
1359 GpStatus stat;
1360
1362 sizeof(EmfPlusRecordHeader),
1363 (void**)&record);
1364 if (stat != Ok)
1365 return stat;
1366
1368 record->Flags = 0;
1369
1371 }
1372
1373 return Ok;
1374}
1375
1377 GDIPCONST GpRectF *srcrect, GpUnit unit, DWORD StackIndex)
1378{
1379 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1380 {
1382 GpStatus stat;
1383
1384 stat = METAFILE_AllocateRecord(metafile, sizeof(*record), (void**)&record);
1385 if (stat != Ok)
1386 return stat;
1387
1389 record->Header.Flags = unit & 0xff;
1390 record->DestRect = *dstrect;
1391 record->SrcRect = *srcrect;
1392 record->StackIndex = StackIndex;
1393
1395 }
1396
1397 return Ok;
1398}
1399
1401{
1402 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1403 {
1405 GpStatus stat;
1406
1408 sizeof(EmfPlusContainerRecord),
1409 (void**)&record);
1410 if (stat != Ok)
1411 return stat;
1412
1414 record->Header.Flags = 0;
1415 record->StackIndex = StackIndex;
1416
1418 }
1419
1420 return Ok;
1421}
1422
1424{
1425 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1426 {
1428 GpStatus stat;
1429
1431 sizeof(EmfPlusContainerRecord),
1432 (void**)&record);
1433 if (stat != Ok)
1434 return stat;
1435
1437 record->Header.Flags = 0;
1438 record->StackIndex = StackIndex;
1439
1441 }
1442
1443 return Ok;
1444}
1445
1447{
1448 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1449 {
1451 GpStatus stat;
1452
1454 sizeof(EmfPlusContainerRecord),
1455 (void**)&record);
1456 if (stat != Ok)
1457 return stat;
1458
1459 record->Header.Type = EmfPlusRecordTypeSave;
1460 record->Header.Flags = 0;
1461 record->StackIndex = StackIndex;
1462
1464 }
1465
1466 return Ok;
1467}
1468
1470{
1471 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual)
1472 {
1474 GpStatus stat;
1475
1477 sizeof(EmfPlusContainerRecord),
1478 (void**)&record);
1479 if (stat != Ok)
1480 return stat;
1481
1482 record->Header.Type = EmfPlusRecordTypeRestore;
1483 record->Header.Flags = 0;
1484 record->StackIndex = StackIndex;
1485
1487 }
1488
1489 return Ok;
1490}
1491
1493{
1494 if (hdc != metafile->record_dc)
1495 return InvalidParameter;
1496
1497 return Ok;
1498}
1499
1501{
1502 GpStatus stat;
1503
1505 metafile->record_graphics = NULL;
1506
1507 metafile->hemf = CloseEnhMetaFile(metafile->record_dc);
1508 metafile->record_dc = NULL;
1509
1510 heap_free(metafile->comment_data);
1511 metafile->comment_data = NULL;
1512 metafile->comment_data_size = 0;
1513
1514 if (stat == Ok)
1515 {
1517
1519 if (stat == Ok && metafile->auto_frame &&
1520 metafile->auto_frame_max.X >= metafile->auto_frame_min.X)
1521 {
1522 RECTL bounds_rc, gdi_bounds_rc;
1523 REAL x_scale = 2540.0 / header.DpiX;
1524 REAL y_scale = 2540.0 / header.DpiY;
1525 BYTE* buffer;
1527
1528 bounds_rc.left = floorf(metafile->auto_frame_min.X * x_scale);
1529 bounds_rc.top = floorf(metafile->auto_frame_min.Y * y_scale);
1530 bounds_rc.right = ceilf(metafile->auto_frame_max.X * x_scale);
1531 bounds_rc.bottom = ceilf(metafile->auto_frame_max.Y * y_scale);
1532
1533 gdi_bounds_rc = header.u.EmfHeader.rclBounds;
1534 if (gdi_bounds_rc.right > gdi_bounds_rc.left && gdi_bounds_rc.bottom > gdi_bounds_rc.top)
1535 {
1536 bounds_rc.left = min(bounds_rc.left, gdi_bounds_rc.left);
1537 bounds_rc.top = min(bounds_rc.top, gdi_bounds_rc.top);
1538 bounds_rc.right = max(bounds_rc.right, gdi_bounds_rc.right);
1539 bounds_rc.bottom = max(bounds_rc.bottom, gdi_bounds_rc.bottom);
1540 }
1541
1544 if (buffer)
1545 {
1546 HENHMETAFILE new_hemf;
1547
1549
1550 ((ENHMETAHEADER*)buffer)->rclFrame = bounds_rc;
1551
1553
1554 if (new_hemf)
1555 {
1557 metafile->hemf = new_hemf;
1558 }
1559 else
1560 stat = OutOfMemory;
1561
1563 }
1564 else
1565 stat = OutOfMemory;
1566
1567 if (stat == Ok)
1569 }
1570 if (stat == Ok)
1571 {
1572 metafile->bounds.X = header.X;
1573 metafile->bounds.Y = header.Y;
1574 metafile->bounds.Width = header.Width;
1575 metafile->bounds.Height = header.Height;
1576 }
1577 }
1578
1579 if (stat == Ok && metafile->record_stream)
1580 {
1581 BYTE *buffer;
1583
1585
1587 if (buffer)
1588 {
1589 HRESULT hr;
1590
1592
1593 hr = IStream_Write(metafile->record_stream, buffer, buffer_size, NULL);
1594
1595 if (FAILED(hr))
1597
1599 }
1600 else
1601 stat = OutOfMemory;
1602 }
1603
1604 if (metafile->record_stream)
1605 {
1606 IStream_Release(metafile->record_stream);
1607 metafile->record_stream = NULL;
1608 }
1609
1610 return stat;
1611}
1612
1614{
1615 TRACE("(%p,%p)\n", metafile, hEmf);
1616
1617 if (!metafile || !hEmf || !metafile->hemf)
1618 return InvalidParameter;
1619
1620 *hEmf = metafile->hemf;
1621 metafile->hemf = NULL;
1622
1623 return Ok;
1624}
1625
1627{
1628 const GpRectF *rect;
1629 const GpPointF *pt;
1630
1631 /* This transforms metafile device space to output points. */
1632 rect = &metafile->src_rect;
1633 pt = metafile->playback_points;
1634 result->eM11 = (pt[1].X - pt[0].X) / rect->Width;
1635 result->eM21 = (pt[2].X - pt[0].X) / rect->Height;
1636 result->eDx = pt[0].X - result->eM11 * rect->X - result->eM21 * rect->Y;
1637 result->eM12 = (pt[1].Y - pt[0].Y) / rect->Width;
1638 result->eM22 = (pt[2].Y - pt[0].Y) / rect->Height;
1639 result->eDy = pt[0].Y - result->eM12 * rect->X - result->eM22 * rect->Y;
1640}
1641
1643{
1644 XFORM combined, final;
1645
1647
1648 CombineTransform(&combined, &metafile->gdiworldtransform, &final);
1649
1650 SetGraphicsMode(metafile->playback_dc, GM_ADVANCED);
1651 SetWorldTransform(metafile->playback_dc, &combined);
1652
1653 return Ok;
1654}
1655
1657{
1658 GpStatus stat = Ok;
1659
1660 stat = GdipGetDC(metafile->playback_graphics, &metafile->playback_dc);
1661
1662 if (stat == Ok)
1663 {
1664 static const XFORM identity = {1, 0, 0, 1, 0, 0};
1665
1666 metafile->gdiworldtransform = identity;
1668 }
1669
1670 return stat;
1671}
1672
1674{
1675 if (metafile->playback_dc)
1676 {
1677 GdipReleaseDC(metafile->playback_graphics, metafile->playback_dc);
1678 metafile->playback_dc = NULL;
1679 }
1680}
1681
1683{
1684 GpStatus stat;
1685 stat = GdipCombineRegionRegion(metafile->playback_graphics->clip, metafile->base_clip, CombineModeReplace);
1686 if (stat == Ok)
1687 stat = GdipCombineRegionRegion(metafile->playback_graphics->clip, metafile->clip, CombineModeIntersect);
1688 return stat;
1689}
1690
1692{
1693 GpMatrix *real_transform;
1694 GpStatus stat;
1695
1696 stat = GdipCreateMatrix3(&metafile->src_rect, metafile->playback_points, &real_transform);
1697
1698 if (stat == Ok)
1699 {
1700 REAL scale = units_to_pixels(1.0, metafile->page_unit, 96.0);
1701
1702 if (metafile->page_unit != UnitDisplay)
1703 scale *= metafile->page_scale;
1704
1705 stat = GdipScaleMatrix(real_transform, scale, scale, MatrixOrderPrepend);
1706
1707 if (stat == Ok)
1708 stat = GdipMultiplyMatrix(real_transform, metafile->world_transform, MatrixOrderPrepend);
1709
1710 if (stat == Ok)
1711 stat = GdipSetWorldTransform(metafile->playback_graphics, real_transform);
1712
1713 GdipDeleteMatrix(real_transform);
1714 }
1715
1716 return stat;
1717}
1718
1720{
1722 metafile->objtable[id].type = type;
1723 metafile->objtable[id].u.object = object;
1724}
1725
1726static GpStatus metafile_deserialize_image(const BYTE *record_data, UINT data_size, GpImage **image)
1727{
1728 EmfPlusImage *data = (EmfPlusImage *)record_data;
1730
1731 *image = NULL;
1732
1733 if (data_size < FIELD_OFFSET(EmfPlusImage, ImageData))
1734 return InvalidParameter;
1735 data_size -= FIELD_OFFSET(EmfPlusImage, ImageData);
1736
1737 switch (data->Type)
1738 {
1740 {
1741 EmfPlusBitmap *bitmapdata = &data->ImageData.bitmap;
1742
1743 if (data_size <= FIELD_OFFSET(EmfPlusBitmap, BitmapData))
1744 return InvalidParameter;
1745 data_size -= FIELD_OFFSET(EmfPlusBitmap, BitmapData);
1746
1747 switch (bitmapdata->Type)
1748 {
1750 {
1752 BYTE *scan0;
1753
1754 if (bitmapdata->PixelFormat & PixelFormatIndexed)
1755 {
1756 EmfPlusPalette *palette_obj = (EmfPlusPalette *)bitmapdata->BitmapData;
1757 UINT palette_size = FIELD_OFFSET(EmfPlusPalette, PaletteEntries);
1758
1759 if (data_size <= palette_size)
1760 return InvalidParameter;
1761 palette_size += palette_obj->PaletteCount * sizeof(EmfPlusARGB);
1762
1763 if (data_size < palette_size)
1764 return InvalidParameter;
1765 data_size -= palette_size;
1766
1767 palette = (ColorPalette *)bitmapdata->BitmapData;
1768 scan0 = (BYTE *)bitmapdata->BitmapData + palette_size;
1769 }
1770 else
1771 {
1772 palette = NULL;
1773 scan0 = bitmapdata->BitmapData;
1774 }
1775
1776 if (data_size < bitmapdata->Height * bitmapdata->Stride)
1777 return InvalidParameter;
1778
1779 status = GdipCreateBitmapFromScan0(bitmapdata->Width, bitmapdata->Height, bitmapdata->Stride,
1780 bitmapdata->PixelFormat, scan0, (GpBitmap **)image);
1781 if (status == Ok && palette)
1782 {
1784 if (status != Ok)
1785 {
1787 *image = NULL;
1788 }
1789 }
1790 break;
1791 }
1793 {
1796 HRESULT hr;
1797
1798 if (WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory) != S_OK)
1799 return GenericError;
1800
1801 hr = IWICImagingFactory_CreateStream(factory, &stream);
1802 IWICImagingFactory_Release(factory);
1803 if (hr != S_OK)
1804 return GenericError;
1805
1806 if (IWICStream_InitializeFromMemory(stream, bitmapdata->BitmapData, data_size) == S_OK)
1808 else
1810
1811 IWICStream_Release(stream);
1812 break;
1813 }
1814 default:
1815 WARN("Invalid bitmap type %d.\n", bitmapdata->Type);
1816 return InvalidParameter;
1817 }
1818 break;
1819 }
1820 default:
1821 FIXME("image type %d not supported.\n", data->Type);
1822 return NotImplemented;
1823 }
1824
1825 return status;
1826}
1827
1828static GpStatus metafile_deserialize_path(const BYTE *record_data, UINT data_size, GpPath **path)
1829{
1830 EmfPlusPath *data = (EmfPlusPath *)record_data;
1832 BYTE *types;
1833 UINT size;
1834 DWORD i;
1835
1836 *path = NULL;
1837
1838 if (data_size <= FIELD_OFFSET(EmfPlusPath, data))
1839 return InvalidParameter;
1840 data_size -= FIELD_OFFSET(EmfPlusPath, data);
1841
1842 if (data->PathPointFlags & 0x800) /* R */
1843 {
1844 FIXME("RLE encoded path data is not supported.\n");
1845 return NotImplemented;
1846 }
1847 else
1848 {
1849 if (data->PathPointFlags & 0x4000) /* C */
1850 size = sizeof(EmfPlusPoint);
1851 else
1852 size = sizeof(EmfPlusPointF);
1853 size += sizeof(BYTE); /* EmfPlusPathPointType */
1854 size *= data->PathPointCount;
1855 }
1856
1857 if (data_size < size)
1858 return InvalidParameter;
1859
1861 if (status != Ok)
1862 return status;
1863
1864 (*path)->pathdata.Count = data->PathPointCount;
1865 (*path)->pathdata.Points = GdipAlloc(data->PathPointCount * sizeof(*(*path)->pathdata.Points));
1866 (*path)->pathdata.Types = GdipAlloc(data->PathPointCount * sizeof(*(*path)->pathdata.Types));
1867 (*path)->datalen = (*path)->pathdata.Count;
1868
1869 if (!(*path)->pathdata.Points || !(*path)->pathdata.Types)
1870 {
1872 return OutOfMemory;
1873 }
1874
1875 if (data->PathPointFlags & 0x4000) /* C */
1876 {
1878 for (i = 0; i < data->PathPointCount; i++)
1879 {
1880 (*path)->pathdata.Points[i].X = points[i].X;
1881 (*path)->pathdata.Points[i].Y = points[i].Y;
1882 }
1883 types = (BYTE *)(points + i);
1884 }
1885 else
1886 {
1888 memcpy((*path)->pathdata.Points, points, sizeof(*points) * data->PathPointCount);
1889 types = (BYTE *)(points + data->PathPointCount);
1890 }
1891
1892 memcpy((*path)->pathdata.Types, types, sizeof(*types) * data->PathPointCount);
1893
1894 return Ok;
1895}
1896
1898{
1899 const DWORD *type;
1901
1902 type = buffer_read(mbuf, sizeof(*type));
1903 if (!type) return Ok;
1904
1905 node->type = *type;
1906
1907 switch (node->type)
1908 {
1909 case CombineModeReplace:
1911 case CombineModeUnion:
1912 case CombineModeXor:
1913 case CombineModeExclude:
1915 {
1917
1918 left = heap_alloc_zero(sizeof(*left));
1919 if (!left)
1920 return OutOfMemory;
1921
1922 right = heap_alloc_zero(sizeof(*right));
1923 if (!right)
1924 {
1925 heap_free(left);
1926 return OutOfMemory;
1927 }
1928
1930 if (status == Ok)
1931 {
1933 if (status == Ok)
1934 {
1935 node->elementdata.combine.left = left;
1936 node->elementdata.combine.right = right;
1937 region->num_children += 2;
1938 return Ok;
1939 }
1940 }
1941
1942 heap_free(left);
1944 return status;
1945 }
1946 case RegionDataRect:
1947 {
1948 const EmfPlusRectF *rect;
1949
1950 rect = buffer_read(mbuf, sizeof(*rect));
1951 if (!rect)
1952 return InvalidParameter;
1953
1954 memcpy(&node->elementdata.rect, rect, sizeof(*rect));
1955 *count += 1;
1956 return Ok;
1957 }
1958 case RegionDataPath:
1959 {
1960 const BYTE *path_data;
1961 const UINT *data_size;
1962 GpPath *path;
1963
1964 data_size = buffer_read(mbuf, FIELD_OFFSET(EmfPlusRegionNodePath, RegionNodePath));
1965 if (!data_size)
1966 return InvalidParameter;
1967
1968 path_data = buffer_read(mbuf, *data_size);
1969 if (!path_data)
1970 return InvalidParameter;
1971
1972 status = metafile_deserialize_path(path_data, *data_size, &path);
1973 if (status == Ok)
1974 {
1975 node->elementdata.path = path;
1976 *count += 1;
1977 }
1978 return Ok;
1979 }
1982 *count += 1;
1983 return Ok;
1984 default:
1985 FIXME("element type %#x is not supported\n", *type);
1986 break;
1987 }
1988
1989 return InvalidParameter;
1990}
1991
1992static GpStatus metafile_deserialize_region(const BYTE *record_data, UINT data_size, GpRegion **region)
1993{
1994 struct memory_buffer mbuf;
1996 UINT count;
1997
1998 *region = NULL;
1999
2000 init_memory_buffer(&mbuf, record_data, data_size);
2001
2002 if (!buffer_read(&mbuf, FIELD_OFFSET(EmfPlusRegion, RegionNode)))
2003 return InvalidParameter;
2004
2005 status = GdipCreateRegion(region);
2006 if (status != Ok)
2007 return status;
2008
2009 count = 0;
2010 status = metafile_read_region_node(&mbuf, *region, &(*region)->node, &count);
2011 if (status == Ok && !count)
2013
2014 if (status != Ok)
2015 {
2016 GdipDeleteRegion(*region);
2017 *region = NULL;
2018 }
2019
2020 return status;
2021}
2022
2023static GpStatus metafile_deserialize_brush(const BYTE *record_data, UINT data_size, GpBrush **brush)
2024{
2025 static const UINT header_size = FIELD_OFFSET(EmfPlusBrush, BrushData);
2026 EmfPlusBrush *data = (EmfPlusBrush *)record_data;
2028 DWORD brushflags;
2030 UINT offset;
2031
2032 *brush = NULL;
2033
2034 if (data_size < header_size)
2035 return InvalidParameter;
2036
2037 switch (data->Type)
2038 {
2040 if (data_size != header_size + sizeof(EmfPlusSolidBrushData))
2041 return InvalidParameter;
2042
2043 status = GdipCreateSolidFill(data->BrushData.solid.SolidColor, (GpSolidFill **)brush);
2044 break;
2045 case BrushTypeHatchFill:
2046 if (data_size != header_size + sizeof(EmfPlusHatchBrushData))
2047 return InvalidParameter;
2048
2049 status = GdipCreateHatchBrush(data->BrushData.hatch.HatchStyle, data->BrushData.hatch.ForeColor,
2050 data->BrushData.hatch.BackColor, (GpHatch **)brush);
2051 break;
2053 {
2054 GpImage *image;
2055
2056 offset = header_size + FIELD_OFFSET(EmfPlusTextureBrushData, OptionalData);
2057 if (data_size <= offset)
2058 return InvalidParameter;
2059
2060 brushflags = data->BrushData.texture.BrushDataFlags;
2061 if (brushflags & BrushDataTransform)
2062 {
2063 if (data_size <= offset + sizeof(EmfPlusTransformMatrix))
2064 return InvalidParameter;
2065 transform = (EmfPlusTransformMatrix *)(record_data + offset);
2066 offset += sizeof(EmfPlusTransformMatrix);
2067 }
2068
2069 status = metafile_deserialize_image(record_data + offset, data_size - offset, &image);
2070 if (status != Ok)
2071 return status;
2072
2073 status = GdipCreateTexture(image, data->BrushData.texture.WrapMode, (GpTexture **)brush);
2074 if (status == Ok && transform && !(brushflags & BrushDataDoNotTransform))
2076
2078 break;
2079 }
2081 {
2082 GpLineGradient *gradient = NULL;
2083 GpPointF startpoint, endpoint;
2084 UINT position_count = 0;
2085
2086 offset = header_size + FIELD_OFFSET(EmfPlusLinearGradientBrushData, OptionalData);
2087 if (data_size <= offset)
2088 return InvalidParameter;
2089
2090 brushflags = data->BrushData.lineargradient.BrushDataFlags;
2091 if ((brushflags & BrushDataPresetColors) && (brushflags & (BrushDataBlendFactorsH | BrushDataBlendFactorsV)))
2092 return InvalidParameter;
2093
2094 if (brushflags & BrushDataTransform)
2095 {
2096 if (data_size <= offset + sizeof(EmfPlusTransformMatrix))
2097 return InvalidParameter;
2098 transform = (EmfPlusTransformMatrix *)(record_data + offset);
2099 offset += sizeof(EmfPlusTransformMatrix);
2100 }
2101
2103 {
2104 if (data_size <= offset + sizeof(DWORD)) /* Number of factors/preset colors. */
2105 return InvalidParameter;
2106 position_count = *(DWORD *)(record_data + offset);
2107 offset += sizeof(DWORD);
2108 }
2109
2110 if (brushflags & BrushDataPresetColors)
2111 {
2112 if (data_size != offset + position_count * (sizeof(float) + sizeof(EmfPlusARGB)))
2113 return InvalidParameter;
2114 }
2115 else if (brushflags & BrushDataBlendFactorsH)
2116 {
2117 if (data_size != offset + position_count * 2 * sizeof(float))
2118 return InvalidParameter;
2119 }
2120
2121 startpoint.X = data->BrushData.lineargradient.RectF.X;
2122 startpoint.Y = data->BrushData.lineargradient.RectF.Y;
2123 endpoint.X = startpoint.X + data->BrushData.lineargradient.RectF.Width;
2124 endpoint.Y = startpoint.Y + data->BrushData.lineargradient.RectF.Height;
2125
2126 status = GdipCreateLineBrush(&startpoint, &endpoint, data->BrushData.lineargradient.StartColor,
2127 data->BrushData.lineargradient.EndColor, data->BrushData.lineargradient.WrapMode, &gradient);
2128 if (status == Ok)
2129 {
2130 if (transform)
2131 status = GdipSetLineTransform(gradient, (const GpMatrix *)transform);
2132
2133 if (status == Ok)
2134 {
2135 if (brushflags & BrushDataPresetColors)
2136 status = GdipSetLinePresetBlend(gradient, (ARGB *)(record_data + offset +
2137 position_count * sizeof(REAL)), (REAL *)(record_data + offset), position_count);
2138 else if (brushflags & BrushDataBlendFactorsH)
2139 status = GdipSetLineBlend(gradient, (REAL *)(record_data + offset + position_count * sizeof(REAL)),
2140 (REAL *)(record_data + offset), position_count);
2141
2142 if (brushflags & BrushDataIsGammaCorrected)
2143 FIXME("BrushDataIsGammaCorrected is not handled.\n");
2144 }
2145 }
2146
2147 if (status == Ok)
2148 *brush = (GpBrush *)gradient;
2149 else
2150 GdipDeleteBrush((GpBrush *)gradient);
2151
2152 break;
2153 }
2154 default:
2155 FIXME("brush type %u is not supported.\n", data->Type);
2156 return NotImplemented;
2157 }
2158
2159 return status;
2160}
2161
2163{
2164 EmfPlusPenData *pendata = (EmfPlusPenData *)data->data;
2166
2167 if (data_size <= offset)
2168 return InvalidParameter;
2169
2170 offset += FIELD_OFFSET(EmfPlusPenData, OptionalData);
2171 if (data_size <= offset)
2172 return InvalidParameter;
2173
2174 if (pendata->PenDataFlags & PenDataTransform)
2175 offset += sizeof(EmfPlusTransformMatrix);
2176
2177 if (pendata->PenDataFlags & PenDataStartCap)
2178 offset += sizeof(DWORD);
2179
2180 if (pendata->PenDataFlags & PenDataEndCap)
2181 offset += sizeof(DWORD);
2182
2183 if (pendata->PenDataFlags & PenDataJoin)
2184 offset += sizeof(DWORD);
2185
2186 if (pendata->PenDataFlags & PenDataMiterLimit)
2187 offset += sizeof(REAL);
2188
2189 if (pendata->PenDataFlags & PenDataLineStyle)
2190 offset += sizeof(DWORD);
2191
2192 if (pendata->PenDataFlags & PenDataDashedLineCap)
2193 offset += sizeof(DWORD);
2194
2196 offset += sizeof(REAL);
2197
2198 if (pendata->PenDataFlags & PenDataDashedLine)
2199 {
2201
2203 if (data_size <= offset)
2204 return InvalidParameter;
2205
2206 offset += dashedline->DashedLineDataSize * sizeof(float);
2207 }
2208
2209 if (pendata->PenDataFlags & PenDataNonCenter)
2210 offset += sizeof(DWORD);
2211
2212 if (pendata->PenDataFlags & PenDataCompoundLine)
2213 {
2215
2217 if (data_size <= offset)
2218 return InvalidParameter;
2219
2220 offset += compoundline->CompoundLineDataSize * sizeof(float);
2221 }
2222
2223 if (pendata->PenDataFlags & PenDataCustomStartCap)
2224 {
2226
2228 if (data_size <= offset)
2229 return InvalidParameter;
2230
2231 offset += startcap->CustomStartCapSize;
2232 }
2233
2234 if (pendata->PenDataFlags & PenDataCustomEndCap)
2235 {
2237
2239 if (data_size <= offset)
2240 return InvalidParameter;
2241
2242 offset += endcap->CustomEndCapSize;
2243 }
2244
2245 *ret = offset;
2246 return Ok;
2247}
2248
2249static GpStatus METAFILE_PlaybackObject(GpMetafile *metafile, UINT flags, UINT data_size, const BYTE *record_data)
2250{
2251 BYTE type = (flags >> 8) & 0xff;
2252 BYTE id = flags & 0xff;
2253 void *object = NULL;
2255
2257 return InvalidParameter;
2258
2259 switch (type)
2260 {
2261 case ObjectTypeBrush:
2262 status = metafile_deserialize_brush(record_data, data_size, (GpBrush **)&object);
2263 break;
2264 case ObjectTypePen:
2265 {
2266 EmfPlusPen *data = (EmfPlusPen *)record_data;
2267 EmfPlusPenData *pendata = (EmfPlusPenData *)data->data;
2268 GpBrush *brush;
2269 DWORD offset;
2270 GpPen *pen;
2271
2273 if (status != Ok)
2274 return status;
2275
2276 status = metafile_deserialize_brush(record_data + offset, data_size - offset, &brush);
2277 if (status != Ok)
2278 return status;
2279
2280 status = GdipCreatePen2(brush, pendata->PenWidth, pendata->PenUnit, &pen);
2281 GdipDeleteBrush(brush);
2282 if (status != Ok)
2283 return status;
2284
2285 offset = FIELD_OFFSET(EmfPlusPenData, OptionalData);
2286
2287 if (pendata->PenDataFlags & PenDataTransform)
2288 {
2289 FIXME("PenDataTransform is not supported.\n");
2290 offset += sizeof(EmfPlusTransformMatrix);
2291 }
2292
2293 if (pendata->PenDataFlags & PenDataStartCap)
2294 {
2295 if ((status = GdipSetPenStartCap(pen, *(DWORD *)((BYTE *)pendata + offset))) != Ok)
2296 goto penfailed;
2297 offset += sizeof(DWORD);
2298 }
2299
2300 if (pendata->PenDataFlags & PenDataEndCap)
2301 {
2302 if ((status = GdipSetPenEndCap(pen, *(DWORD *)((BYTE *)pendata + offset))) != Ok)
2303 goto penfailed;
2304 offset += sizeof(DWORD);
2305 }
2306
2307 if (pendata->PenDataFlags & PenDataJoin)
2308 {
2309 if ((status = GdipSetPenLineJoin(pen, *(DWORD *)((BYTE *)pendata + offset))) != Ok)
2310 goto penfailed;
2311 offset += sizeof(DWORD);
2312 }
2313
2314 if (pendata->PenDataFlags & PenDataMiterLimit)
2315 {
2316 if ((status = GdipSetPenMiterLimit(pen, *(REAL *)((BYTE *)pendata + offset))) != Ok)
2317 goto penfailed;
2318 offset += sizeof(REAL);
2319 }
2320
2321 if (pendata->PenDataFlags & PenDataLineStyle)
2322 {
2323 if ((status = GdipSetPenDashStyle(pen, *(DWORD *)((BYTE *)pendata + offset))) != Ok)
2324 goto penfailed;
2325 offset += sizeof(DWORD);
2326 }
2327
2328 if (pendata->PenDataFlags & PenDataDashedLineCap)
2329 {
2330 FIXME("PenDataDashedLineCap is not supported.\n");
2331 offset += sizeof(DWORD);
2332 }
2333
2335 {
2336 if ((status = GdipSetPenDashOffset(pen, *(REAL *)((BYTE *)pendata + offset))) != Ok)
2337 goto penfailed;
2338 offset += sizeof(REAL);
2339 }
2340
2341 if (pendata->PenDataFlags & PenDataDashedLine)
2342 {
2343 EmfPlusDashedLineData *dashedline = (EmfPlusDashedLineData *)((BYTE *)pendata + offset);
2344 FIXME("PenDataDashedLine is not supported.\n");
2346 }
2347
2348 if (pendata->PenDataFlags & PenDataNonCenter)
2349 {
2350 FIXME("PenDataNonCenter is not supported.\n");
2351 offset += sizeof(DWORD);
2352 }
2353
2354 if (pendata->PenDataFlags & PenDataCompoundLine)
2355 {
2356 EmfPlusCompoundLineData *compoundline = (EmfPlusCompoundLineData *)((BYTE *)pendata + offset);
2357 FIXME("PenDataCompundLine is not supported.\n");
2359 }
2360
2361 if (pendata->PenDataFlags & PenDataCustomStartCap)
2362 {
2363 EmfPlusCustomStartCapData *startcap = (EmfPlusCustomStartCapData *)((BYTE *)pendata + offset);
2364 FIXME("PenDataCustomStartCap is not supported.\n");
2366 }
2367
2368 if (pendata->PenDataFlags & PenDataCustomEndCap)
2369 {
2370 EmfPlusCustomEndCapData *endcap = (EmfPlusCustomEndCapData *)((BYTE *)pendata + offset);
2371 FIXME("PenDataCustomEndCap is not supported.\n");
2373 }
2374
2375 object = pen;
2376 break;
2377
2378 penfailed:
2379 GdipDeletePen(pen);
2380 return status;
2381 }
2382 case ObjectTypePath:
2383 status = metafile_deserialize_path(record_data, data_size, (GpPath **)&object);
2384 break;
2385 case ObjectTypeRegion:
2386 status = metafile_deserialize_region(record_data, data_size, (GpRegion **)&object);
2387 break;
2388 case ObjectTypeImage:
2389 status = metafile_deserialize_image(record_data, data_size, (GpImage **)&object);
2390 break;
2391 case ObjectTypeFont:
2392 {
2393 EmfPlusFont *data = (EmfPlusFont *)record_data;
2394 GpFontFamily *family;
2395 WCHAR *familyname;
2396
2397 if (data_size <= FIELD_OFFSET(EmfPlusFont, FamilyName))
2398 return InvalidParameter;
2399 data_size -= FIELD_OFFSET(EmfPlusFont, FamilyName);
2400
2401 if (data_size < data->Length * sizeof(WCHAR))
2402 return InvalidParameter;
2403
2404 if (!(familyname = GdipAlloc((data->Length + 1) * sizeof(*familyname))))
2405 return OutOfMemory;
2406
2407 memcpy(familyname, data->FamilyName, data->Length * sizeof(*familyname));
2408 familyname[data->Length] = 0;
2409
2410 status = GdipCreateFontFamilyFromName(familyname, NULL, &family);
2411 GdipFree(familyname);
2412 if (status != Ok)
2413 return InvalidParameter;
2414
2415 status = GdipCreateFont(family, data->EmSize, data->FontStyleFlags, data->SizeUnit, (GpFont **)&object);
2416 GdipDeleteFontFamily(family);
2417 break;
2418 }
2420 {
2422 GpImageAttributes *attributes = NULL;
2423
2424 if (data_size != sizeof(*data))
2425 return InvalidParameter;
2426
2427 if ((status = GdipCreateImageAttributes(&attributes)) != Ok)
2428 return status;
2429
2430 status = GdipSetImageAttributesWrapMode(attributes, data->WrapMode, *(DWORD *)&data->ClampColor,
2431 !!data->ObjectClamp);
2432 if (status == Ok)
2433 object = attributes;
2434 else
2435 GdipDisposeImageAttributes(attributes);
2436 break;
2437 }
2438 default:
2439 FIXME("not implemented for object type %d.\n", type);
2440 return NotImplemented;
2441 }
2442
2443 if (status == Ok)
2445
2446 return status;
2447}
2448
2450{
2451 GpMatrix world_to_device;
2452
2453 get_graphics_transform(metafile->playback_graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, &world_to_device);
2454
2455 GdipTransformRegion(region, &world_to_device);
2456 GdipCombineRegionRegion(metafile->clip, region, mode);
2457
2459}
2460
2463{
2464 GpStatus stat;
2465 GpMetafile *real_metafile = (GpMetafile*)metafile;
2466
2467 TRACE("(%p,%x,%x,%d,%p)\n", metafile, recordType, flags, dataSize, data);
2468
2469 if (!metafile || (dataSize && !data) || !metafile->playback_graphics)
2470 return InvalidParameter;
2471
2472 if (recordType >= 1 && recordType <= 0x7a)
2473 {
2474 /* regular EMF record */
2475 if (metafile->playback_dc)
2476 {
2477 switch (recordType)
2478 {
2479 case EMR_SETMAPMODE:
2480 case EMR_SAVEDC:
2481 case EMR_RESTOREDC:
2482 case EMR_SETWINDOWORGEX:
2483 case EMR_SETWINDOWEXTEX:
2489 FIXME("not implemented for record type %x\n", recordType);
2490 break;
2492 {
2493 const XFORM* xform = (void*)data;
2494 real_metafile->gdiworldtransform = *xform;
2496 break;
2497 }
2499 {
2500 DWORD rgndatasize = *(DWORD*)data;
2501 DWORD mode = *(DWORD*)(data + 4);
2502 const RGNDATA *rgndata = (const RGNDATA*)(data + 8);
2503 HRGN hrgn = NULL;
2504
2505 if (dataSize > 8)
2506 {
2507 XFORM final;
2508
2510
2511 hrgn = ExtCreateRegion(&final, rgndatasize, rgndata);
2512 }
2513
2514 ExtSelectClipRgn(metafile->playback_dc, hrgn, mode);
2515
2517
2518 return Ok;
2519 }
2520 default:
2521 {
2522 ENHMETARECORD *record = heap_alloc_zero(dataSize + 8);
2523
2524 if (record)
2525 {
2526 record->iType = recordType;
2527 record->nSize = dataSize + 8;
2528 memcpy(record->dParm, data, dataSize);
2529
2530 if(PlayEnhMetaFileRecord(metafile->playback_dc, metafile->handle_table,
2531 record, metafile->handle_count) == 0)
2532 ERR("PlayEnhMetaFileRecord failed\n");
2533
2535 }
2536 else
2537 return OutOfMemory;
2538
2539 break;
2540 }
2541 }
2542 }
2543 }
2544 else
2545 {
2547
2549
2550 switch(recordType)
2551 {
2554 break;
2557 break;
2559 {
2561
2562 if (dataSize != sizeof(record->Color))
2563 return InvalidParameter;
2564
2565 return GdipGraphicsClear(metafile->playback_graphics, record->Color);
2566 }
2568 {
2570 GpBrush *brush, *temp_brush=NULL;
2571 GpRectF *rects, *temp_rects=NULL;
2572
2573 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects))
2574 return InvalidParameter;
2575
2576 if (flags & 0x4000)
2577 {
2578 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(EmfPlusRect) * record->Count)
2579 return InvalidParameter;
2580 }
2581 else
2582 {
2583 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusFillRects) + sizeof(GpRectF) * record->Count)
2584 return InvalidParameter;
2585 }
2586
2587 if (flags & 0x8000)
2588 {
2589 stat = GdipCreateSolidFill(record->BrushID, (GpSolidFill **)&temp_brush);
2590 brush = temp_brush;
2591 }
2592 else
2593 {
2594 if (record->BrushID >= EmfPlusObjectTableSize ||
2595 real_metafile->objtable[record->BrushID].type != ObjectTypeBrush)
2596 return InvalidParameter;
2597
2598 brush = real_metafile->objtable[record->BrushID].u.brush;
2599 stat = Ok;
2600 }
2601
2602 if (stat == Ok)
2603 {
2604 if (flags & 0x4000)
2605 {
2606 EmfPlusRect *int_rects = (EmfPlusRect*)(record+1);
2607 int i;
2608
2609 rects = temp_rects = heap_alloc_zero(sizeof(GpRectF) * record->Count);
2610 if (rects)
2611 {
2612 for (i=0; i<record->Count; i++)
2613 {
2614 rects[i].X = int_rects[i].X;
2615 rects[i].Y = int_rects[i].Y;
2616 rects[i].Width = int_rects[i].Width;
2617 rects[i].Height = int_rects[i].Height;
2618 }
2619 }
2620 else
2621 stat = OutOfMemory;
2622 }
2623 else
2624 rects = (GpRectF*)(record+1);
2625 }
2626
2627 if (stat == Ok)
2628 {
2629 stat = GdipFillRectangles(metafile->playback_graphics, brush, rects, record->Count);
2630 }
2631
2632 GdipDeleteBrush(temp_brush);
2633 heap_free(temp_rects);
2634
2635 return stat;
2636 }
2638 {
2640 CombineMode mode = (CombineMode)((flags >> 8) & 0xf);
2641 GpRegion *region;
2642
2643 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(*record))
2644 return InvalidParameter;
2645
2646 stat = GdipCreateRegionRect(&record->ClipRect, &region);
2647
2648 if (stat == Ok)
2649 {
2650 stat = metafile_set_clip_region(real_metafile, region, mode);
2651 GdipDeleteRegion(region);
2652 }
2653
2654 return stat;
2655 }
2657 {
2658 CombineMode mode = (flags >> 8) & 0xf;
2659 BYTE regionid = flags & 0xff;
2660 GpRegion *region;
2661
2662 if (dataSize != 0)
2663 return InvalidParameter;
2664
2665 if (regionid >= EmfPlusObjectTableSize || real_metafile->objtable[regionid].type != ObjectTypeRegion)
2666 return InvalidParameter;
2667
2668 stat = GdipCloneRegion(real_metafile->objtable[regionid].u.region, &region);
2669 if (stat == Ok)
2670 {
2671 stat = metafile_set_clip_region(real_metafile, region, mode);
2672 GdipDeleteRegion(region);
2673 }
2674
2675 return stat;
2676 }
2678 {
2679 CombineMode mode = (flags >> 8) & 0xf;
2680 BYTE pathid = flags & 0xff;
2681 GpRegion *region;
2682
2683 if (dataSize != 0)
2684 return InvalidParameter;
2685
2686 if (pathid >= EmfPlusObjectTableSize || real_metafile->objtable[pathid].type != ObjectTypePath)
2687 return InvalidParameter;
2688
2689 stat = GdipCreateRegionPath(real_metafile->objtable[pathid].u.path, &region);
2690 if (stat == Ok)
2691 {
2692 stat = metafile_set_clip_region(real_metafile, region, mode);
2693 GdipDeleteRegion(region);
2694 }
2695
2696 return stat;
2697 }
2699 {
2702
2704 return InvalidParameter;
2705
2706 real_metafile->page_unit = unit;
2707 real_metafile->page_scale = record->PageScale;
2708
2709 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
2710 }
2712 {
2714
2716 return InvalidParameter;
2717
2718 memcpy(real_metafile->world_transform->matrix, record->MatrixData, sizeof(record->MatrixData));
2719
2720 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
2721 }
2723 {
2726
2728 return InvalidParameter;
2729
2730 GdipScaleMatrix(real_metafile->world_transform, record->Sx, record->Sy, order);
2731
2732 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
2733 }
2735 {
2739
2741 return InvalidParameter;
2742
2743 memcpy(matrix.matrix, record->MatrixData, sizeof(matrix.matrix));
2744
2746
2747 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
2748 }
2750 {
2753
2755 return InvalidParameter;
2756
2757 GdipRotateMatrix(real_metafile->world_transform, record->Angle, order);
2758
2759 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
2760 }
2762 {
2765
2767 return InvalidParameter;
2768
2769 GdipTranslateMatrix(real_metafile->world_transform, record->dx, record->dy, order);
2770
2771 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
2772 }
2774 {
2775 GdipSetMatrixElements(real_metafile->world_transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
2776
2777 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
2778 }
2780 {
2782 container* cont;
2783 GpUnit unit;
2784 REAL scale_x, scale_y;
2785 GpRectF scaled_srcrect;
2787
2788 cont = heap_alloc_zero(sizeof(*cont));
2789 if (!cont)
2790 return OutOfMemory;
2791
2792 stat = GdipCloneRegion(metafile->clip, &cont->clip);
2793 if (stat != Ok)
2794 {
2795 heap_free(cont);
2796 return stat;
2797 }
2798
2799 stat = GdipBeginContainer2(metafile->playback_graphics, &cont->state);
2800
2801 if (stat != Ok)
2802 {
2803 GdipDeleteRegion(cont->clip);
2804 heap_free(cont);
2805 return stat;
2806 }
2807
2808 cont->id = record->StackIndex;
2809 cont->type = BEGIN_CONTAINER;
2810 cont->world_transform = *metafile->world_transform;
2811 cont->page_unit = metafile->page_unit;
2812 cont->page_scale = metafile->page_scale;
2813 list_add_head(&real_metafile->containers, &cont->entry);
2814
2815 unit = record->Header.Flags & 0xff;
2816
2817 scale_x = units_to_pixels(1.0, unit, metafile->image.xres);
2818 scale_y = units_to_pixels(1.0, unit, metafile->image.yres);
2819
2820 scaled_srcrect.X = scale_x * record->SrcRect.X;
2821 scaled_srcrect.Y = scale_y * record->SrcRect.Y;
2822 scaled_srcrect.Width = scale_x * record->SrcRect.Width;
2823 scaled_srcrect.Height = scale_y * record->SrcRect.Height;
2824
2825 transform.matrix[0] = record->DestRect.Width / scaled_srcrect.Width;
2826 transform.matrix[1] = 0.0;
2827 transform.matrix[2] = 0.0;
2828 transform.matrix[3] = record->DestRect.Height / scaled_srcrect.Height;
2829 transform.matrix[4] = record->DestRect.X - scaled_srcrect.X;
2830 transform.matrix[5] = record->DestRect.Y - scaled_srcrect.Y;
2831
2833
2834 return METAFILE_PlaybackUpdateWorldTransform(real_metafile);
2835 }
2838 {
2840 container* cont;
2841
2842 cont = heap_alloc_zero(sizeof(*cont));
2843 if (!cont)
2844 return OutOfMemory;
2845
2846 stat = GdipCloneRegion(metafile->clip, &cont->clip);
2847 if (stat != Ok)
2848 {
2849 heap_free(cont);
2850 return stat;
2851 }
2852
2854 stat = GdipBeginContainer2(metafile->playback_graphics, &cont->state);
2855 else
2856 stat = GdipSaveGraphics(metafile->playback_graphics, &cont->state);
2857
2858 if (stat != Ok)
2859 {
2860 GdipDeleteRegion(cont->clip);
2861 heap_free(cont);
2862 return stat;
2863 }
2864
2865 cont->id = record->StackIndex;
2867 cont->type = BEGIN_CONTAINER;
2868 else
2869 cont->type = SAVE_GRAPHICS;
2870 cont->world_transform = *metafile->world_transform;
2871 cont->page_unit = metafile->page_unit;
2872 cont->page_scale = metafile->page_scale;
2873 list_add_head(&real_metafile->containers, &cont->entry);
2874
2875 break;
2876 }
2879 {
2881 container* cont;
2882 enum container_type type;
2883 BOOL found=FALSE;
2884
2885 if (recordType == EmfPlusRecordTypeEndContainer)
2887 else
2889
2890 LIST_FOR_EACH_ENTRY(cont, &real_metafile->containers, container, entry)
2891 {
2892 if (cont->id == record->StackIndex && cont->type == type)
2893 {
2894 found = TRUE;
2895 break;
2896 }
2897 }
2898
2899 if (found)
2900 {
2901 container* cont2;
2902
2903 /* pop any newer items on the stack */
2904 while ((cont2 = LIST_ENTRY(list_head(&real_metafile->containers), container, entry)) != cont)
2905 {
2906 list_remove(&cont2->entry);
2907 GdipDeleteRegion(cont2->clip);
2908 heap_free(cont2);
2909 }
2910
2911 if (type == BEGIN_CONTAINER)
2912 GdipEndContainer(real_metafile->playback_graphics, cont->state);
2913 else
2914 GdipRestoreGraphics(real_metafile->playback_graphics, cont->state);
2915
2916 *real_metafile->world_transform = cont->world_transform;
2917 real_metafile->page_unit = cont->page_unit;
2918 real_metafile->page_scale = cont->page_scale;
2919 GdipCombineRegionRegion(real_metafile->clip, cont->clip, CombineModeReplace);
2920
2921 list_remove(&cont->entry);
2922 GdipDeleteRegion(cont->clip);
2923 heap_free(cont);
2924 }
2925
2926 break;
2927 }
2929 {
2930 return GdipSetPixelOffsetMode(real_metafile->playback_graphics, flags & 0xff);
2931 }
2933 {
2934 return GdipSetCompositingQuality(real_metafile->playback_graphics, flags & 0xff);
2935 }
2937 {
2938 return GdipSetInterpolationMode(real_metafile->playback_graphics, flags & 0xff);
2939 }
2941 {
2942 return GdipSetTextRenderingHint(real_metafile->playback_graphics, flags & 0xff);
2943 }
2945 {
2946 return GdipSetSmoothingMode(real_metafile->playback_graphics, (flags >> 1) & 0xff);
2947 }
2949 {
2950 return GdipSetCompositingMode(real_metafile->playback_graphics, flags & 0xff);
2951 }
2953 {
2954 return METAFILE_PlaybackObject(real_metafile, flags, dataSize, data);
2955 }
2957 {
2959 BYTE image = flags & 0xff;
2960 GpPointF points[3];
2961
2962 if (image >= EmfPlusObjectTableSize || real_metafile->objtable[image].type != ObjectTypeImage)
2963 return InvalidParameter;
2964
2965 if (dataSize != FIELD_OFFSET(EmfPlusDrawImage, RectData) - sizeof(EmfPlusRecordHeader) +
2966 (flags & 0x4000 ? sizeof(EmfPlusRect) : sizeof(EmfPlusRectF)))
2967 return InvalidParameter;
2968
2970 real_metafile->objtable[draw->ImageAttributesID].type != ObjectTypeImageAttributes)
2971 return InvalidParameter;
2972
2973 if (flags & 0x4000) /* C */
2974 {
2975 points[0].X = draw->RectData.rect.X;
2976 points[0].Y = draw->RectData.rect.Y;
2977 points[1].X = points[0].X + draw->RectData.rect.Width;
2978 points[1].Y = points[0].Y;
2979 points[2].X = points[1].X;
2980 points[2].Y = points[1].Y + draw->RectData.rect.Height;
2981 }
2982 else
2983 {
2984 points[0].X = draw->RectData.rectF.X;
2985 points[0].Y = draw->RectData.rectF.Y;
2986 points[1].X = points[0].X + draw->RectData.rectF.Width;
2987 points[1].Y = points[0].Y;
2988 points[2].X = points[1].X;
2989 points[2].Y = points[1].Y + draw->RectData.rectF.Height;
2990 }
2991
2992 return GdipDrawImagePointsRect(real_metafile->playback_graphics, real_metafile->objtable[image].u.image,
2993 points, 3, draw->SrcRect.X, draw->SrcRect.Y, draw->SrcRect.Width, draw->SrcRect.Height, draw->SrcUnit,
2994 real_metafile->objtable[draw->ImageAttributesID].u.image_attributes, NULL, NULL);
2995 }
2997 {
2999 static const UINT fixed_part_size = FIELD_OFFSET(EmfPlusDrawImagePoints, PointData) -
3000 FIELD_OFFSET(EmfPlusDrawImagePoints, ImageAttributesID);
3001 BYTE image = flags & 0xff;
3002 GpPointF points[3];
3003 unsigned int i;
3004 UINT size;
3005
3006 if (image >= EmfPlusObjectTableSize || real_metafile->objtable[image].type != ObjectTypeImage)
3007 return InvalidParameter;
3008
3009 if (dataSize <= fixed_part_size)
3010 return InvalidParameter;
3011 dataSize -= fixed_part_size;
3012
3014 real_metafile->objtable[draw->ImageAttributesID].type != ObjectTypeImageAttributes)
3015 return InvalidParameter;
3016
3017 if (draw->count != 3)
3018 return InvalidParameter;
3019
3020 if ((flags >> 13) & 1) /* E */
3021 FIXME("image effects are not supported.\n");
3022
3023 if ((flags >> 11) & 1) /* P */
3024 size = sizeof(EmfPlusPointR7) * draw->count;
3025 else if ((flags >> 14) & 1) /* C */
3026 size = sizeof(EmfPlusPoint) * draw->count;
3027 else
3028 size = sizeof(EmfPlusPointF) * draw->count;
3029
3030 if (dataSize != size)
3031 return InvalidParameter;
3032
3033 if ((flags >> 11) & 1) /* P */
3034 {
3035 points[0].X = draw->PointData.pointsR[0].X;
3036 points[0].Y = draw->PointData.pointsR[0].Y;
3037 for (i = 1; i < 3; i++)
3038 {
3039 points[i].X = points[i-1].X + draw->PointData.pointsR[i].X;
3040 points[i].Y = points[i-1].Y + draw->PointData.pointsR[i].Y;
3041 }
3042 }
3043 else if ((flags >> 14) & 1) /* C */
3044 {
3045 for (i = 0; i < 3; i++)
3046 {
3047 points[i].X = draw->PointData.points[i].X;
3048 points[i].Y = draw->PointData.points[i].Y;
3049 }
3050 }
3051 else
3052 memcpy(points, draw->PointData.pointsF, sizeof(points));
3053
3054 return GdipDrawImagePointsRect(real_metafile->playback_graphics, real_metafile->objtable[image].u.image,
3055 points, 3, draw->SrcRect.X, draw->SrcRect.Y, draw->SrcRect.Width, draw->SrcRect.Height, draw->SrcUnit,
3056 real_metafile->objtable[draw->ImageAttributesID].u.image_attributes, NULL, NULL);
3057 }
3059 {
3061 GpSolidFill *solidfill = NULL;
3062 BYTE path = flags & 0xff;
3063 GpBrush *brush;
3064
3065 if (path >= EmfPlusObjectTableSize || real_metafile->objtable[path].type != ObjectTypePath)
3066 return InvalidParameter;
3067
3068 if (dataSize != sizeof(fill->data.BrushId))
3069 return InvalidParameter;
3070
3071 if (flags & 0x8000)
3072 {
3073 stat = GdipCreateSolidFill(fill->data.Color, (GpSolidFill **)&solidfill);
3074 if (stat != Ok)
3075 return stat;
3076 brush = (GpBrush *)solidfill;
3077 }
3078 else
3079 {
3080 if (fill->data.BrushId >= EmfPlusObjectTableSize ||
3081 real_metafile->objtable[fill->data.BrushId].type != ObjectTypeBrush)
3082 return InvalidParameter;
3083
3084 brush = real_metafile->objtable[fill->data.BrushId].u.brush;
3085 }
3086
3087 stat = GdipFillPath(real_metafile->playback_graphics, brush, real_metafile->objtable[path].u.path);
3088 GdipDeleteBrush((GpBrush *)solidfill);
3089 return stat;
3090 }
3092 {
3093 static const UINT fixed_part_size = FIELD_OFFSET(EmfPlusFillClosedCurve, PointData) -
3094 sizeof(EmfPlusRecordHeader);
3096 GpSolidFill *solidfill = NULL;
3098 GpBrush *brush;
3099 UINT size, i;
3100
3101 if (dataSize <= fixed_part_size)
3102 return InvalidParameter;
3103
3104 if (fill->Count == 0)
3105 return InvalidParameter;
3106
3107 if (flags & 0x800) /* P */
3108 size = (fixed_part_size + sizeof(EmfPlusPointR7) * fill->Count + 3) & ~3;
3109 else if (flags & 0x4000) /* C */
3110 size = fixed_part_size + sizeof(EmfPlusPoint) * fill->Count;
3111 else
3112 size = fixed_part_size + sizeof(EmfPlusPointF) * fill->Count;
3113
3114 if (dataSize != size)
3115 return InvalidParameter;
3116
3117 mode = flags & 0x200 ? FillModeWinding : FillModeAlternate; /* W */
3118
3119 if (flags & 0x8000) /* S */
3120 {
3121 stat = GdipCreateSolidFill(fill->BrushId, (GpSolidFill **)&solidfill);
3122 if (stat != Ok)
3123 return stat;
3124 brush = (GpBrush *)solidfill;
3125 }
3126 else
3127 {
3128 if (fill->BrushId >= EmfPlusObjectTableSize ||
3129 real_metafile->objtable[fill->BrushId].type != ObjectTypeBrush)
3130 return InvalidParameter;
3131
3132 brush = real_metafile->objtable[fill->BrushId].u.brush;
3133 }
3134
3135 if (flags & (0x800 | 0x4000))
3136 {
3137 GpPointF *points = GdipAlloc(fill->Count * sizeof(*points));
3138 if (points)
3139 {
3140 if (flags & 0x800) /* P */
3141 {
3142 for (i = 1; i < fill->Count; i++)
3143 {
3144 points[i].X = points[i - 1].X + fill->PointData.pointsR[i].X;
3145 points[i].Y = points[i - 1].Y + fill->PointData.pointsR[i].Y;
3146 }
3147 }
3148 else
3149 {
3150 for (i = 0; i < fill->Count; i++)
3151 {
3152 points[i].X = fill->PointData.points[i].X;
3153 points[i].Y = fill->PointData.points[i].Y;
3154 }
3155 }
3156
3157 stat = GdipFillClosedCurve2(real_metafile->playback_graphics, brush,
3158 points, fill->Count, fill->Tension, mode);
3160 }
3161 else
3162 stat = OutOfMemory;
3163 }
3164 else
3165 stat = GdipFillClosedCurve2(real_metafile->playback_graphics, brush,
3166 (const GpPointF *)fill->PointData.pointsF, fill->Count, fill->Tension, mode);
3167
3168 GdipDeleteBrush((GpBrush *)solidfill);
3169 return stat;
3170 }
3172 {
3174 GpSolidFill *solidfill = NULL;
3175 GpBrush *brush;
3176
3177 if (dataSize <= FIELD_OFFSET(EmfPlusFillEllipse, RectData) - sizeof(EmfPlusRecordHeader))
3178 return InvalidParameter;
3180
3181 if (dataSize != (flags & 0x4000 ? sizeof(EmfPlusRect) : sizeof(EmfPlusRectF)))
3182 return InvalidParameter;
3183
3184 if (flags & 0x8000)
3185 {
3186 stat = GdipCreateSolidFill(fill->BrushId, (GpSolidFill **)&solidfill);
3187 if (stat != Ok)
3188 return stat;
3189 brush = (GpBrush *)solidfill;
3190 }
3191 else
3192 {
3193 if (fill->BrushId >= EmfPlusObjectTableSize ||
3194 real_metafile->objtable[fill->BrushId].type != ObjectTypeBrush)
3195 return InvalidParameter;
3196
3197 brush = real_metafile->objtable[fill->BrushId].u.brush;
3198 }
3199
3200 if (flags & 0x4000)
3201 stat = GdipFillEllipseI(real_metafile->playback_graphics, brush, fill->RectData.rect.X,
3202 fill->RectData.rect.Y, fill->RectData.rect.Width, fill->RectData.rect.Height);
3203 else
3204 stat = GdipFillEllipse(real_metafile->playback_graphics, brush, fill->RectData.rectF.X,
3205 fill->RectData.rectF.Y, fill->RectData.rectF.Width, fill->RectData.rectF.Height);
3206
3207 GdipDeleteBrush((GpBrush *)solidfill);
3208 return stat;
3209 }
3211 {
3213 GpSolidFill *solidfill = NULL;
3214 GpBrush *brush;
3215
3216 if (dataSize <= FIELD_OFFSET(EmfPlusFillPie, RectData) - sizeof(EmfPlusRecordHeader))
3217 return InvalidParameter;
3219
3220 if (dataSize != (flags & 0x4000 ? sizeof(EmfPlusRect) : sizeof(EmfPlusRectF)))
3221 return InvalidParameter;
3222
3223 if (flags & 0x8000) /* S */
3224 {
3225 stat = GdipCreateSolidFill(fill->BrushId, (GpSolidFill **)&solidfill);
3226 if (stat != Ok)
3227 return stat;
3228 brush = (GpBrush *)solidfill;
3229 }
3230 else
3231 {
3232 if (fill->BrushId >= EmfPlusObjectTableSize ||
3233 real_metafile->objtable[fill->BrushId].type != ObjectTypeBrush)
3234 return InvalidParameter;
3235
3236 brush = real_metafile->objtable[fill->BrushId].u.brush;
3237 }
3238
3239 if (flags & 0x4000) /* C */
3240 stat = GdipFillPieI(real_metafile->playback_graphics, brush, fill->RectData.rect.X,
3241 fill->RectData.rect.Y, fill->RectData.rect.Width, fill->RectData.rect.Height,
3242 fill->StartAngle, fill->SweepAngle);
3243 else
3244 stat = GdipFillPie(real_metafile->playback_graphics, brush, fill->RectData.rectF.X,
3245 fill->RectData.rectF.Y, fill->RectData.rectF.Width, fill->RectData.rectF.Height,
3246 fill->StartAngle, fill->SweepAngle);
3247
3248 GdipDeleteBrush((GpBrush *)solidfill);
3249 return stat;
3250 }
3252 {
3254 BYTE path = flags & 0xff;
3255
3256 if (dataSize != sizeof(draw->PenId))
3257 return InvalidParameter;
3258
3260 return InvalidParameter;
3261
3262 if (real_metafile->objtable[path].type != ObjectTypePath ||
3263 real_metafile->objtable[draw->PenId].type != ObjectTypePen)
3264 return InvalidParameter;
3265
3266 return GdipDrawPath(real_metafile->playback_graphics, real_metafile->objtable[draw->PenId].u.pen,
3267 real_metafile->objtable[path].u.path);
3268 }
3270 {
3272 BYTE pen = flags & 0xff;
3273
3274 if (pen >= EmfPlusObjectTableSize || real_metafile->objtable[pen].type != ObjectTypePen)
3275 return InvalidParameter;
3276
3277 if (dataSize != FIELD_OFFSET(EmfPlusDrawArc, RectData) - sizeof(EmfPlusRecordHeader) +
3278 (flags & 0x4000 ? sizeof(EmfPlusRect) : sizeof(EmfPlusRectF)))
3279 return InvalidParameter;
3280
3281 if (flags & 0x4000) /* C */
3282 return GdipDrawArcI(real_metafile->playback_graphics, real_metafile->objtable[pen].u.pen,
3283 draw->RectData.rect.X, draw->RectData.rect.Y, draw->RectData.rect.Width,
3284 draw->RectData.rect.Height, draw->StartAngle, draw->SweepAngle);
3285 else
3286 return GdipDrawArc(real_metafile->playback_graphics, real_metafile->objtable[pen].u.pen,
3287 draw->RectData.rectF.X, draw->RectData.rectF.Y, draw->RectData.rectF.Width,
3288 draw->RectData.rectF.Height, draw->StartAngle, draw->SweepAngle);
3289 }
3291 {
3293 BYTE pen = flags & 0xff;
3294
3295 if (pen >= EmfPlusObjectTableSize || real_metafile->objtable[pen].type != ObjectTypePen)
3296 return InvalidParameter;
3297
3298 if (dataSize != (flags & 0x4000 ? sizeof(EmfPlusRect) : sizeof(EmfPlusRectF)))
3299 return InvalidParameter;
3300
3301 if (flags & 0x4000) /* C */
3302 return GdipDrawEllipseI(real_metafile->playback_graphics, real_metafile->objtable[pen].u.pen,
3303 draw->RectData.rect.X, draw->RectData.rect.Y, draw->RectData.rect.Width,
3304 draw->RectData.rect.Height);
3305 else
3306 return GdipDrawEllipse(real_metafile->playback_graphics, real_metafile->objtable[pen].u.pen,
3307 draw->RectData.rectF.X, draw->RectData.rectF.Y, draw->RectData.rectF.Width,
3308 draw->RectData.rectF.Height);
3309 }
3311 {
3313 BYTE pen = flags & 0xff;
3314
3315 if (pen >= EmfPlusObjectTableSize || real_metafile->objtable[pen].type != ObjectTypePen)
3316 return InvalidParameter;
3317
3318 if (dataSize != FIELD_OFFSET(EmfPlusDrawPie, RectData) - sizeof(EmfPlusRecordHeader) +
3319 (flags & 0x4000 ? sizeof(EmfPlusRect) : sizeof(EmfPlusRectF)))
3320 return InvalidParameter;
3321
3322 if (flags & 0x4000) /* C */
3323 return GdipDrawPieI(real_metafile->playback_graphics, real_metafile->objtable[pen].u.pen,
3324 draw->RectData.rect.X, draw->RectData.rect.Y, draw->RectData.rect.Width,
3325 draw->RectData.rect.Height, draw->StartAngle, draw->SweepAngle);
3326 else
3327 return GdipDrawPie(real_metafile->playback_graphics, real_metafile->objtable[pen].u.pen,
3328 draw->RectData.rectF.X, draw->RectData.rectF.Y, draw->RectData.rectF.Width,
3329 draw->RectData.rectF.Height, draw->StartAngle, draw->SweepAngle);
3330 }
3332 {
3334 BYTE pen = flags & 0xff;
3335 GpRectF *rects = NULL;
3336
3337 if (pen >= EmfPlusObjectTableSize || real_metafile->objtable[pen].type != ObjectTypePen)
3338 return InvalidParameter;
3339
3340 if (dataSize <= FIELD_OFFSET(EmfPlusDrawRects, RectData) - sizeof(EmfPlusRecordHeader))
3341 return InvalidParameter;
3343
3344 if (dataSize != draw->Count * (flags & 0x4000 ? sizeof(EmfPlusRect) : sizeof(EmfPlusRectF)))
3345 return InvalidParameter;
3346
3347 if (flags & 0x4000)
3348 {
3349 DWORD i;
3350
3351 rects = GdipAlloc(draw->Count * sizeof(*rects));
3352 if (!rects)
3353 return OutOfMemory;
3354
3355 for (i = 0; i < draw->Count; i++)
3356 {
3357 rects[i].X = draw->RectData.rect[i].X;
3358 rects[i].Y = draw->RectData.rect[i].Y;
3359 rects[i].Width = draw->RectData.rect[i].Width;
3360 rects[i].Height = draw->RectData.rect[i].Height;
3361 }
3362 }
3363
3364 stat = GdipDrawRectangles(real_metafile->playback_graphics, real_metafile->objtable[pen].u.pen,
3365 rects ? rects : (GpRectF *)draw->RectData.rectF, draw->Count);
3366 GdipFree(rects);
3367 return stat;
3368 }
3369 default:
3370 FIXME("Not implemented for record type %x\n", recordType);
3371 return NotImplemented;
3372 }
3373 }
3374
3375 return Ok;
3376}
3377
3379{
3383};
3384
3385static int CALLBACK enum_metafile_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR,
3386 int nObj, LPARAM lpData)
3387{
3388 BOOL ret;
3389 struct enum_metafile_data *data = (struct enum_metafile_data*)lpData;
3390 const BYTE* pStr;
3391
3392 data->metafile->handle_table = lpHTable;
3393 data->metafile->handle_count = nObj;
3394
3395 /* First check for an EMF+ record. */
3396 if (lpEMFR->iType == EMR_GDICOMMENT)
3397 {
3398 const EMRGDICOMMENT *comment = (const EMRGDICOMMENT*)lpEMFR;
3399
3400 if (comment->cbData >= 4 && memcmp(comment->Data, "EMF+", 4) == 0)
3401 {
3402 int offset = 4;
3403
3404 while (offset + sizeof(EmfPlusRecordHeader) <= comment->cbData)
3405 {
3407
3408 if (record->DataSize)
3409 pStr = (const BYTE*)(record+1);
3410 else
3411 pStr = NULL;
3412
3413 ret = data->callback(record->Type, record->Flags, record->DataSize,
3414 pStr, data->callback_data);
3415
3416 if (!ret)
3417 return 0;
3418
3419 offset += record->Size;
3420 }
3421
3422 return 1;
3423 }
3424 }
3425
3426 if (lpEMFR->nSize != 8)
3427 pStr = (const BYTE*)lpEMFR->dParm;
3428 else
3429 pStr = NULL;
3430
3431 return data->callback(lpEMFR->iType, 0, lpEMFR->nSize-8,
3432 pStr, data->callback_data);
3433}
3434
3438 VOID *callbackData, GDIPCONST GpImageAttributes *imageAttributes)
3439{
3440 struct enum_metafile_data data;
3441 GpStatus stat;
3442 GpMetafile *real_metafile = (GpMetafile*)metafile; /* whoever made this const was joking */
3444 GpPath *dst_path;
3445
3446 TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics, metafile,
3447 destPoints, count, srcRect, srcUnit, callback, callbackData,
3448 imageAttributes);
3449
3450 if (!graphics || !metafile || !destPoints || count != 3 || !srcRect)
3451 return InvalidParameter;
3452
3453 if (!metafile->hemf)
3454 return InvalidParameter;
3455
3456 if (metafile->playback_graphics)
3457 return ObjectBusy;
3458
3459 TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect), srcUnit,
3460 debugstr_pointf(&destPoints[0]), debugstr_pointf(&destPoints[1]),
3461 debugstr_pointf(&destPoints[2]));
3462
3463 data.callback = callback;
3464 data.callback_data = callbackData;
3465 data.metafile = real_metafile;
3466
3467 real_metafile->playback_graphics = graphics;
3468 real_metafile->playback_dc = NULL;
3469 real_metafile->src_rect = *srcRect;
3470
3471 memcpy(real_metafile->playback_points, destPoints, sizeof(PointF) * 3);
3473
3474 if (stat == Ok)
3475 stat = GdipBeginContainer2(graphics, &state);
3476
3477 if (stat == Ok)
3478 {
3479 stat = GdipSetPageScale(graphics, 1.0);
3480
3481 if (stat == Ok)
3482 stat = GdipSetPageUnit(graphics, UnitPixel);
3483
3484 if (stat == Ok)
3485 stat = GdipResetWorldTransform(graphics);
3486
3487 if (stat == Ok)
3488 stat = GdipCreateRegion(&real_metafile->base_clip);
3489
3490 if (stat == Ok)
3491 stat = GdipGetClip(graphics, real_metafile->base_clip);
3492
3493 if (stat == Ok)
3494 stat = GdipCreateRegion(&real_metafile->clip);
3495
3496 if (stat == Ok)
3498
3499 if (stat == Ok)
3500 {
3501 GpPointF clip_points[4];
3502
3503 clip_points[0] = real_metafile->playback_points[0];
3504 clip_points[1] = real_metafile->playback_points[1];
3505 clip_points[2].X = real_metafile->playback_points[1].X + real_metafile->playback_points[2].X
3506 - real_metafile->playback_points[0].X;
3507 clip_points[2].Y = real_metafile->playback_points[1].Y + real_metafile->playback_points[2].Y
3508 - real_metafile->playback_points[0].Y;
3509 clip_points[3] = real_metafile->playback_points[2];
3510
3511 stat = GdipAddPathPolygon(dst_path, clip_points, 4);
3512
3513 if (stat == Ok)
3514 stat = GdipCombineRegionPath(real_metafile->base_clip, dst_path, CombineModeIntersect);
3515
3516 GdipDeletePath(dst_path);
3517 }
3518
3519 if (stat == Ok)
3520 stat = GdipCreateMatrix(&real_metafile->world_transform);
3521
3522 if (stat == Ok)
3523 {
3524 real_metafile->page_unit = UnitDisplay;
3525 real_metafile->page_scale = 1.0;
3527 }
3528
3529 if (stat == Ok)
3530 {
3531 stat = METAFILE_PlaybackUpdateClip(real_metafile);
3532 }
3533
3534 if (stat == Ok && (metafile->metafile_type == MetafileTypeEmf ||
3535 metafile->metafile_type == MetafileTypeWmfPlaceable ||
3536 metafile->metafile_type == MetafileTypeWmf))
3537 stat = METAFILE_PlaybackGetDC(real_metafile);
3538
3539 if (stat == Ok)
3541
3542 METAFILE_PlaybackReleaseDC(real_metafile);
3543
3544 GdipDeleteMatrix(real_metafile->world_transform);
3545 real_metafile->world_transform = NULL;
3546
3547 GdipDeleteRegion(real_metafile->base_clip);
3548 real_metafile->base_clip = NULL;
3549
3550 GdipDeleteRegion(real_metafile->clip);
3551 real_metafile->clip = NULL;
3552
3553 while (list_head(&real_metafile->containers))
3554 {
3555 container* cont = LIST_ENTRY(list_head(&real_metafile->containers), container, entry);
3556 list_remove(&cont->entry);
3557 GdipDeleteRegion(cont->clip);
3558 heap_free(cont);
3559 }
3560
3561 GdipEndContainer(graphics, state);
3562 }
3563
3564 real_metafile->playback_graphics = NULL;
3565
3566 return stat;
3567}
3568
3572{
3573 GpPointF points[3];
3574
3575 if (!graphics || !metafile || !dest) return InvalidParameter;
3576
3577 points[0].X = points[2].X = dest->X;
3578 points[0].Y = points[1].Y = dest->Y;
3579 points[1].X = dest->X + dest->Width;
3580 points[2].Y = dest->Y + dest->Height;
3581
3583 &metafile->bounds, metafile->unit, callback, cb_data, attrs);
3584}
3585
3589{
3590 GpRectF destf;
3591
3592 if (!graphics || !metafile || !dest) return InvalidParameter;
3593
3594 destf.X = dest->X;
3595 destf.Y = dest->Y;
3596 destf.Width = dest->Width;
3597 destf.Height = dest->Height;
3598
3599 return GdipEnumerateMetafileDestRect(graphics, metafile, &destf, callback, cb_data, attrs);
3600}
3601
3605{
3606 GpRectF destf;
3607
3608 if (!graphics || !metafile || !dest) return InvalidParameter;
3609
3610 destf.X = dest->X;
3611 destf.Y = dest->Y;
3612 destf.Width = units_to_pixels(metafile->bounds.Width, metafile->unit, metafile->image.xres);
3613 destf.Height = units_to_pixels(metafile->bounds.Height, metafile->unit, metafile->image.yres);
3614
3615 return GdipEnumerateMetafileDestRect(graphics, metafile, &destf, callback, cb_data, attrs);