ReactOS  0.4.14-dev-98-gb0d4763
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 
48 typedef ARGB EmfPlusARGB;
49 
50 typedef struct EmfPlusRecordHeader
51 {
57 
58 typedef struct EmfPlusHeader
59 {
66 
67 typedef struct EmfPlusClear
68 {
71 } EmfPlusClear;
72 
73 typedef struct EmfPlusFillRects
74 {
79 
80 typedef struct EmfPlusSetClipRect
81 {
85 
87 {
91 
92 typedef struct EmfPlusRect
93 {
98 } EmfPlusRect;
99 
101 {
105 
107 {
112 
114 {
118 
120 {
124 
126 {
131 
132 typedef struct EmfPlusBeginContainer
133 {
139 
141 {
145 
147 {
150 };
151 
152 typedef struct container
153 {
154  struct list entry;
162 } container;
163 
165 {
167  PenDataStartCap = 0x0002,
168  PenDataEndCap = 0x0004,
169  PenDataJoin = 0x0008,
179 };
180 
182 {
185 
187 {
194 };
195 
196 typedef struct EmfPlusDashedLineData
197 {
199  BYTE data[1];
201 
203 {
205  BYTE data[1];
207 
209 {
211  BYTE data[1];
213 
215 {
217  BYTE data[1];
219 
220 typedef struct EmfPlusPenData
221 {
227 
229 {
230  BrushDataPath = 1 << 0,
238 };
239 
240 typedef struct EmfPlusSolidBrushData
241 {
244 
245 typedef struct EmfPlusHatchBrushData
246 {
251 
253 {
258 
259 typedef struct EmfPlusRectF
260 {
261  float X;
262  float Y;
263  float Width;
264  float Height;
265 } EmfPlusRectF;
266 
268 {
278 
279 typedef struct EmfPlusBrush
280 {
283  union {
288  } BrushData;
289 } EmfPlusBrush;
290 
291 typedef struct EmfPlusPen
292 {
295  /* EmfPlusPenData */
296  /* EmfPlusBrush */
297  BYTE data[1];
298 } EmfPlusPen;
299 
300 typedef struct EmfPlusPath
301 {
305  /* PathPoints[] */
306  /* PathPointTypes[] */
307  /* AlignmentPadding */
308  BYTE data[1];
309 } EmfPlusPath;
310 
311 typedef struct EmfPlusRegionNodePath
312 {
316 
317 typedef struct EmfPlusRegion
318 {
322 } EmfPlusRegion;
323 
324 typedef struct EmfPlusPalette
325 {
330 
331 typedef enum
332 {
336 
337 typedef struct EmfPlusBitmap
338 {
345 } EmfPlusBitmap;
346 
347 typedef struct EmfPlusMetafile
348 {
353 
354 typedef enum ImageDataType
355 {
359 } ImageDataType;
360 
361 typedef struct EmfPlusImage
362 {
365  union
366  {
369  } ImageData;
370 } EmfPlusImage;
371 
373 {
381 
382 typedef struct EmfPlusObject
383 {
385  union
386  {
393  } ObjectData;
394 } EmfPlusObject;
395 
396 typedef struct EmfPlusPointR7
397 {
401 
402 typedef struct EmfPlusPoint
403 {
404  short X;
405  short Y;
406 } EmfPlusPoint;
407 
408 typedef struct EmfPlusPointF
409 {
410  float X;
411  float Y;
412 } EmfPlusPointF;
413 
414 typedef struct EmfPlusDrawImage
415 {
420  union
421  {
424  } RectData;
426 
428 {
434  union
435  {
439  } PointData;
441 
442 typedef struct EmfPlusDrawPath
443 {
447 
448 typedef struct EmfPlusDrawArc
449 {
451  float StartAngle;
452  float SweepAngle;
453  union
454  {
457  } RectData;
459 
460 typedef struct EmfPlusDrawEllipse
461 {
463  union
464  {
467  } RectData;
469 
470 typedef struct EmfPlusDrawPie
471 {
473  float StartAngle;
474  float SweepAngle;
475  union
476  {
479  } RectData;
481 
482 typedef struct EmfPlusDrawRects
483 {
486  union
487  {
490  } RectData;
492 
493 typedef struct EmfPlusFillPath
494 {
496  union
497  {
500  } data;
502 
504 {
507  float Tension;
509  union
510  {
514  } PointData;
516 
517 typedef struct EmfPlusFillEllipse
518 {
521  union
522  {
525  } RectData;
527 
528 typedef struct EmfPlusFillPie
529 {
532  float StartAngle;
533  float SweepAngle;
534  union
535  {
538  } RectData;
540 
541 typedef struct EmfPlusFont
542 {
544  float EmSize;
550 } EmfPlusFont;
551 
553 {
554  struct emfplus_object *object = &metafile->objtable[id];
555 
556  switch (object->type)
557  {
558  case ObjectTypeInvalid:
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 {
681  GpStatus stat;
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 {
716  GpStatus stat;
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;
742  GpStatus stat;
743 
744  TRACE("(%p %d %p %d %p %p)\n", hdc, type, frameRect, frameUnit, desc, metafile);
745 
747  return InvalidParameter;
748 
749  dpix = (REAL)GetDeviceCaps(hdc, HORZRES) / GetDeviceCaps(hdc, HORZSIZE) * 25.4;
750  dpiy = (REAL)GetDeviceCaps(hdc, VERTRES) / GetDeviceCaps(hdc, VERTSIZE) * 25.4;
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 {
866  GpStatus stat;
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 {
910  GpStatus stat;
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  {
932  GpStatus stat;
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  {
954  GpStatus stat;
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  {
987  case BrushTypeSolidColor:
988  *size = FIELD_OFFSET(EmfPlusBrush, BrushData) + sizeof(EmfPlusSolidBrushData);
989  break;
990  case BrushTypeHatchFill:
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  {
1008  case BrushTypeSolidColor:
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 
1063  if (brush->bt == BrushTypeSolidColor)
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 
1201  stat = METAFILE_AddRegionObject(metafile, region, &region_id);
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 
1222  sizeof(EmfPlusSetPageTransform),
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 
1245  sizeof(EmfPlusSetWorldTransform),
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 
1388  record->Header.Type = EmfPlusRecordTypeBeginContainer;
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 
1436  record->Header.Type = EmfPlusRecordTypeEndContainer;
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;
1526  UINT buffer_size;
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 
1552  new_hemf = SetEnhMetaFileBits(buffer_size, buffer);
1553 
1554  if (new_hemf)
1555  {
1556  DeleteEnhMetaFile(metafile->hemf);
1557  metafile->hemf = new_hemf;
1558  }
1559  else
1560  stat = OutOfMemory;
1561 
1562  heap_free(buffer);
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;
1582  UINT buffer_size;
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 
1598  heap_free(buffer);
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 
1726 static GpStatus metafile_deserialize_image(const BYTE *record_data, UINT data_size, GpImage **image)
1727 {
1728  EmfPlusImage *data = (EmfPlusImage *)record_data;
1729  GpStatus status;
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  {
1739  case ImageDataTypeBitmap:
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  {
1749  case BitmapDataTypePixel:
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  {
1795  IWICStream *stream;
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
1809  status = GenericError;
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 
1828 static GpStatus metafile_deserialize_path(const BYTE *record_data, UINT data_size, GpPath **path)
1829 {
1830  EmfPlusPath *data = (EmfPlusPath *)record_data;
1831  GpStatus status;
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  {
1871  GdipDeletePath(*path);
1872  return OutOfMemory;
1873  }
1874 
1875  if (data->PathPointFlags & 0x4000) /* C */
1876  {
1877  EmfPlusPoint *points = (EmfPlusPoint *)data->data;
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  {
1887  EmfPlusPointF *points = (EmfPlusPointF *)data->data;
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;
1900  GpStatus status;
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:
1910  case CombineModeIntersect:
1911  case CombineModeUnion:
1912  case CombineModeXor:
1913  case CombineModeExclude:
1914  case CombineModeComplement:
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);
1943  heap_free(right);
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  }
1980  case RegionDataEmptyRect:
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 
1992 static GpStatus metafile_deserialize_region(const BYTE *record_data, UINT data_size, GpRegion **region)
1993 {
1994  struct memory_buffer mbuf;
1995  GpStatus status;
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 
2023 static 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;
2029  GpStatus status;
2030  UINT offset;
2031 
2032  *brush = NULL;
2033 
2034  if (data_size < header_size)
2035  return InvalidParameter;
2036 
2037  switch (data->Type)
2038  {
2039  case BrushTypeSolidColor:
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;
2052  case BrushTypeTextureFill:
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))
2075  GdipSetTextureTransform((GpTexture *)*brush, (const GpMatrix *)transform);
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 
2195  if (pendata->PenDataFlags & PenDataDashedLineOffset)
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 
2249 static 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;
2254  GpStatus status;
2255 
2256  if (type > ObjectTypeMax || id >= EmfPlusObjectTableSize)
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 
2334  if (pendata->PenDataFlags & PenDataDashedLineOffset)
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");
2345  offset += FIELD_OFFSET(EmfPlusDashedLineData, data) + dashedline->DashedLineDataSize * sizeof(float);
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");
2358  offset += FIELD_OFFSET(EmfPlusCompoundLineData, data) + compoundline->CompoundLineDataSize * sizeof(float);
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:
2484  case EMR_SETVIEWPORTORGEX:
2485  case EMR_SETVIEWPORTEXTEX:
2487  case EMR_SCALEWINDOWEXTEX:
2489  FIXME("not implemented for record type %x\n", recordType);
2490  break;
2491  case EMR_SETWORLDTRANSFORM:
2492  {
2493  const XFORM* xform = (void*)data;
2494  real_metafile->gdiworldtransform = *xform;
2495  METAFILE_PlaybackUpdateGdiTransform(real_metafile);
2496  break;
2497  }
2498  case EMR_EXTSELECTCLIPRGN:
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 
2516  DeleteObject(hrgn);
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 
2534  heap_free(record);
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  {
2701  GpUnit unit = (GpUnit)flags;
2702 
2703  if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusSetPageTransform))
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 
2715  if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusSetWorldTransform))
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  {
2738  GpMatrix matrix;
2739 
2741  return InvalidParameter;
2742 
2743  memcpy(matrix.matrix, record->MatrixData, sizeof(matrix.matrix));
2744 
2745  GdipMultiplyMatrix(real_metafile->world_transform, &matrix, order);
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  }
2837  case EmfPlusRecordTypeSave:
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 
2853  if (recordType == EmfPlusRecordTypeBeginContainerNoParams)
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;
2866  if (recordType == EmfPlusRecordTypeBeginContainerNoParams)
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
2888  type = SAVE_GRAPHICS;
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;
3097  GpFillMode mode;
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);
3159  GdipFree(points);
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;
3218  dataSize -= FIELD_OFFSET(EmfPlusFillPie, RectData) - sizeof(EmfPlusRecordHeader);
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 
3385 static 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  {
3406  const EmfPlusRecordHeader *record = (const EmfPlusRecordHeader*)&comment->Data[offset];
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)
3497  stat = GdipCreatePath(FillModeAlternate, &dst_path);
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);
3616 }
3617 
3621 {
3622  GpPointF ptf;
3623 
3624  if (!graphics || !metafile || !dest) return InvalidParameter;
3625 
3626  ptf.X = dest->X;
3627  ptf.Y = dest->Y;
3628 
3629  return GdipEnumerateMetafileDestPoint(graphics, metafile, &ptf, callback, cb_data, attrs);
3630 }
3631 
3634 {
3635  GpStatus status;
3636 
3637  TRACE("(%p, %p)\n", metafile, header);
3638 
3639  if(!metafile || !header)
3640  return InvalidParameter;
3641 
3642  if (metafile->hemf)
3643  {
3645  if (status != Ok) return status;
3646  }
3647  else
3648  {
3649  memset(header, 0, sizeof(*header));
3650  header->Version = VERSION_MAGIC2;
3651  }
3652 
3653  header->Type = metafile->metafile_type;
3654  header->DpiX = metafile->image.xres;
3655  header->DpiY = metafile->image.yres;
3656  header->Width = gdip_round(metafile->bounds.Width);
3657  header->Height = gdip_round(metafile->bounds.Height);
3658 
3659  return Ok;
3660 }
3661 
3662 static int CALLBACK get_emfplus_header_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR,
3663  int nObj, LPARAM lpData)
3664 {
3665  EmfPlusHeader *dst_header = (EmfPlusHeader*)lpData;
3666 
3667  if (lpEMFR->iType == EMR_GDICOMMENT)
3668  {
3669  const EMRGDICOMMENT *comment = (const EMRGDICOMMENT*)lpEMFR;
3670 
3671  if (comment->cbData >= 4 && memcmp(comment->Data, "EMF+", 4) == 0)
3672  {
3673  const EmfPlusRecordHeader *header = (const EmfPlusRecordHeader*)&comment->Data[4];
3674 
3675  if (4 + sizeof(EmfPlusHeader) <= comment->cbData &&
3677  {
3678  memcpy(dst_header, header, sizeof(*dst_header));
3679  }
3680  }
3681  }
3682  else if (lpEMFR->iType == EMR_HEADER)
3683  return TRUE;
3684 
3685  return FALSE;
3686 }
3687 
3690 {
3691  ENHMETAHEADER3 emfheader;
3692  EmfPlusHeader emfplusheader;
3693  MetafileType metafile_type;
3694 
3695  TRACE("(%p,%p)\n", hemf, header);
3696 
3697  if(!hemf || !header)
3698  return InvalidParameter;
3699 
3700  if (GetEnhMetaFileHeader(hemf, sizeof(emfheader), (ENHMETAHEADER*)&emfheader) == 0)
3701  return GenericError;
3702 
3703  emfplusheader.Header.Type = 0;
3704 
3705  EnumEnhMetaFile(NULL, hemf, get_emfplus_header_proc, &emfplusheader, NULL);
3706 
3707  if (emfplusheader.Header.Type == EmfPlusRecordTypeHeader)
3708  {
3709  if ((emfplusheader.Header.Flags & 1) == 1)
3710  metafile_type = MetafileTypeEmfPlusDual;
3711  else
3712  metafile_type = MetafileTypeEmfPlusOnly;
3713  }
3714  else
3715  metafile_type = MetafileTypeEmf;
3716 
3717  header->Type = metafile_type;
3718  header->Size = emfheader.nBytes;
3719  header->DpiX = (REAL)emfheader.szlDevice.cx * 25.4 / emfheader.szlMillimeters.cx;
3720  header->DpiY = (REAL)emfheader.szlDevice.cy * 25.4 / emfheader.szlMillimeters.cy;
3721  header->X = gdip_round((REAL)emfheader.rclFrame.left / 2540.0 * header->DpiX);
3722  header->Y = gdip_round((REAL)emfheader.rclFrame.top / 2540.0 * header->DpiY);
3723  header->Width = gdip_round((REAL)(emfheader.rclFrame.right - emfheader.rclFrame.left) / 2540.0 * header->DpiX);
3724  header->Height = gdip_round((REAL)(emfheader.rclFrame.bottom - emfheader.rclFrame.top) / 2540.0 * header->DpiY);
3725  header->u.EmfHeader = emfheader;
3726 
3727  if (metafile_type == MetafileTypeEmfPlusDual || metafile_type == MetafileTypeEmfPlusOnly)
3728  {
3729  header->Version = emfplusheader.Version;
3730  header->EmfPlusFlags = emfplusheader.EmfPlusFlags;
3731  header->EmfPlusHeaderSize = emfplusheader.Header.Size;
3732  header->LogicalDpiX = emfplusheader.LogicalDpiX;
3733  header->LogicalDpiY = emfplusheader.LogicalDpiY;
3734  }
3735  else
3736  {
3737  header->Version = emfheader.nVersion;
3738  header->EmfPlusFlags = 0;
3739  header->EmfPlusHeaderSize = 0;
3740  header->LogicalDpiX = 0;
3741  header->LogicalDpiY = 0;
3742  }
3743 
3744  return Ok;
3745 }
3746 
3749 {
3750  GpStatus status;
3752 
3753  TRACE("(%p,%p,%p)\n", hwmf, placeable, header);
3754 
3755  status = GdipCreateMetafileFromWmf(hwmf, FALSE, placeable, &metafile);
3756  if (status == Ok)
3757  {
3759  GdipDisposeImage(&metafile->image);
3760  }
3761  return status;
3762 }
3763 
3766 {
3767  GpStatus status;
3769 
3770  TRACE("(%s,%p)\n", debugstr_w(filename), header);
3771 
3772  if (!filename || !header)
3773  return InvalidParameter;
3774 
3776  if (status == Ok)
3777  {
3779  GdipDisposeImage(&metafile->image);
3780  }
3781  return status;
3782 }
3783 
3786 {
3787  GpStatus status;
3789 
3790  TRACE("(%p,%p)\n", stream, header);
3791 
3792  if (!stream || !header)
3793  return InvalidParameter;
3794 
3796  if (status == Ok)
3797  {
3799  GdipDisposeImage(&metafile->image);
3800  }
3801  return status;
3802 }
3803 
3805  GpMetafile **metafile)
3806 {
3807  GpStatus stat;
3809 
3810  TRACE("(%p,%i,%p)\n", hemf, delete, metafile);
3811 
3812  if(!hemf || !metafile)
3813  return InvalidParameter;
3814 
3816  if (stat != Ok)
3817  return stat;
3818 
3819  *metafile = heap_alloc_zero(sizeof(GpMetafile));
3820  if (!*metafile)
3821  return OutOfMemory;
3822 
3823  (*metafile)->image.type = ImageTypeMetafile;
3824  (*metafile)->image.format = ImageFormatEMF;
3825  (*metafile)->image.frame_count = 1;
3826  (*metafile)->image.xres = header.DpiX;
3827  (*metafile)->image.yres = header.DpiY;
3828  (*metafile)->bounds.X = (REAL)header.u.EmfHeader.rclFrame.left / 2540.0 * header.DpiX;
3829  (*metafile)->bounds.Y = (REAL)header.u.EmfHeader.rclFrame.top / 2540.0 * header.DpiY;
3830  (*metafile)->bounds.Width = (REAL)(header.u.EmfHeader.rclFrame.right - header.u.EmfHeader.rclFrame.left)
3831  / 2540.0 * header.DpiX;
3832  (*metafile)->bounds.Height = (REAL)(header.u.EmfHeader.rclFrame.bottom - header.u.EmfHeader.rclFrame.top)
3833  / 2540.0 * header.DpiY;
3834  (*metafile)->unit = UnitPixel;
3835  (*metafile)->metafile_type = header.Type;
3836  (*metafile)->hemf = hemf;
3837  (*metafile)->preserve_hemf = !delete;
3838  list_init(&(*metafile)->containers);
3839 
3840  TRACE("<-- %p\n", *metafile);
3841 
3842  return Ok;
3843 }
3844 
3847 {
3848  UINT read;
3849  BYTE *copy;
3850  HENHMETAFILE hemf;
3851  GpStatus retval = Ok;
3852 
3853  TRACE("(%p, %d, %p, %p)\n", hwmf, delete, placeable, metafile);
3854 
3855  if(!hwmf || !metafile)
3856  return InvalidParameter;
3857 
3858  *metafile = NULL;
3859  read = GetMetaFileBitsEx(hwmf, 0, NULL);
3860  if(!read)
3861  return GenericError;
3862  copy = heap_alloc_zero(read);
3863  GetMetaFileBitsEx(hwmf, read, copy);
3864 
3865  hemf = SetWinMetaFileBits(read, copy, NULL, NULL);
3866  heap_free(copy);
3867 
3868  /* FIXME: We should store and use hwmf instead of converting to hemf */
3869  retval = GdipCreateMetafileFromEmf(hemf, TRUE, metafile);
3870 
3871  if (retval == Ok)
3872  {
3873  if (placeable)
3874  {
3875  (*metafile)->image.xres = (REAL)placeable->Inch;
3876  (*metafile)->image.yres = (REAL)placeable->Inch;
3877  (*metafile)->bounds.X = ((REAL)placeable->BoundingBox.Left) / ((REAL)placeable->Inch);
3878  (*metafile)->bounds.Y = ((REAL)placeable->BoundingBox.Top) / ((REAL)placeable->Inch);
3879  (*metafile)->bounds.Width = (REAL)(placeable->BoundingBox.Right -
3880  placeable->BoundingBox.Left);
3881  (*metafile)->bounds.Height = (REAL)(placeable->BoundingBox.Bottom -
3882  placeable->BoundingBox.Top);
3883  (*metafile)->metafile_type = MetafileTypeWmfPlaceable;
3884  }
3885  else
3886  (*metafile)->metafile_type = MetafileTypeWmf;
3887  (*metafile)->image.format = ImageFormatWMF;
3888 
3889  if (delete) DeleteMetaFile(hwmf);
3890  }
3891  else
3892  DeleteEnhMetaFile(hemf);
3893  return retval;
3894 }
3895 
3898 {
3899  HMETAFILE hmf;
3900  HENHMETAFILE emf;
3901 
3902  TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile);
3903 
3904  hmf =