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 44 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus); 45 46 HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**); 47 48 typedef ARGB EmfPlusARGB; 49 50 typedef struct EmfPlusRecordHeader 51 { 52 WORD Type; 53 WORD Flags; 54 DWORD Size; 55 DWORD DataSize; 56 } EmfPlusRecordHeader; 57 58 typedef struct EmfPlusHeader 59 { 60 EmfPlusRecordHeader Header; 61 DWORD Version; 62 DWORD EmfPlusFlags; 63 DWORD LogicalDpiX; 64 DWORD LogicalDpiY; 65 } EmfPlusHeader; 66 67 typedef struct EmfPlusClear 68 { 69 EmfPlusRecordHeader Header; 70 DWORD Color; 71 } EmfPlusClear; 72 73 typedef struct EmfPlusFillRects 74 { 75 EmfPlusRecordHeader Header; 76 DWORD BrushID; 77 DWORD Count; 78 } EmfPlusFillRects; 79 80 typedef struct EmfPlusSetClipRect 81 { 82 EmfPlusRecordHeader Header; 83 GpRectF ClipRect; 84 } EmfPlusSetClipRect; 85 86 typedef struct EmfPlusSetPageTransform 87 { 88 EmfPlusRecordHeader Header; 89 REAL PageScale; 90 } EmfPlusSetPageTransform; 91 92 typedef struct EmfPlusRect 93 { 94 SHORT X; 95 SHORT Y; 96 SHORT Width; 97 SHORT Height; 98 } EmfPlusRect; 99 100 typedef struct EmfPlusSetWorldTransform 101 { 102 EmfPlusRecordHeader Header; 103 REAL MatrixData[6]; 104 } EmfPlusSetWorldTransform; 105 106 typedef struct EmfPlusScaleWorldTransform 107 { 108 EmfPlusRecordHeader Header; 109 REAL Sx; 110 REAL Sy; 111 } EmfPlusScaleWorldTransform; 112 113 typedef struct EmfPlusMultiplyWorldTransform 114 { 115 EmfPlusRecordHeader Header; 116 REAL MatrixData[6]; 117 } EmfPlusMultiplyWorldTransform; 118 119 typedef struct EmfPlusRotateWorldTransform 120 { 121 EmfPlusRecordHeader Header; 122 REAL Angle; 123 } EmfPlusRotateWorldTransform; 124 125 typedef struct EmfPlusTranslateWorldTransform 126 { 127 EmfPlusRecordHeader Header; 128 REAL dx; 129 REAL dy; 130 } EmfPlusTranslateWorldTransform; 131 132 typedef struct EmfPlusBeginContainer 133 { 134 EmfPlusRecordHeader Header; 135 GpRectF DestRect; 136 GpRectF SrcRect; 137 DWORD StackIndex; 138 } EmfPlusBeginContainer; 139 140 typedef struct EmfPlusContainerRecord 141 { 142 EmfPlusRecordHeader Header; 143 DWORD StackIndex; 144 } EmfPlusContainerRecord; 145 146 enum container_type 147 { 148 BEGIN_CONTAINER, 149 SAVE_GRAPHICS 150 }; 151 152 typedef struct container 153 { 154 struct list entry; 155 DWORD id; 156 enum container_type type; 157 GraphicsContainer state; 158 GpMatrix world_transform; 159 GpUnit page_unit; 160 REAL page_scale; 161 GpRegion *clip; 162 } container; 163 164 enum PenDataFlags 165 { 166 PenDataTransform = 0x0001, 167 PenDataStartCap = 0x0002, 168 PenDataEndCap = 0x0004, 169 PenDataJoin = 0x0008, 170 PenDataMiterLimit = 0x0010, 171 PenDataLineStyle = 0x0020, 172 PenDataDashedLineCap = 0x0040, 173 PenDataDashedLineOffset = 0x0080, 174 PenDataDashedLine = 0x0100, 175 PenDataNonCenter = 0x0200, 176 PenDataCompoundLine = 0x0400, 177 PenDataCustomStartCap = 0x0800, 178 PenDataCustomEndCap = 0x1000 179 }; 180 181 typedef struct EmfPlusTransformMatrix 182 { 183 REAL TransformMatrix[6]; 184 } EmfPlusTransformMatrix; 185 186 enum LineStyle 187 { 188 LineStyleSolid, 189 LineStyleDash, 190 LineStyleDot, 191 LineStyleDashDot, 192 LineStyleDashDotDot, 193 LineStyleCustom 194 }; 195 196 typedef struct EmfPlusDashedLineData 197 { 198 DWORD DashedLineDataSize; 199 BYTE data[1]; 200 } EmfPlusDashedLineData; 201 202 typedef struct EmfPlusCompoundLineData 203 { 204 DWORD CompoundLineDataSize; 205 BYTE data[1]; 206 } EmfPlusCompoundLineData; 207 208 typedef struct EmfPlusCustomStartCapData 209 { 210 DWORD CustomStartCapSize; 211 BYTE data[1]; 212 } EmfPlusCustomStartCapData; 213 214 typedef struct EmfPlusCustomEndCapData 215 { 216 DWORD CustomEndCapSize; 217 BYTE data[1]; 218 } EmfPlusCustomEndCapData; 219 220 typedef struct EmfPlusPenData 221 { 222 DWORD PenDataFlags; 223 DWORD PenUnit; 224 REAL PenWidth; 225 BYTE OptionalData[1]; 226 } EmfPlusPenData; 227 228 enum BrushDataFlags 229 { 230 BrushDataPath = 1 << 0, 231 BrushDataTransform = 1 << 1, 232 BrushDataPresetColors = 1 << 2, 233 BrushDataBlendFactorsH = 1 << 3, 234 BrushDataBlendFactorsV = 1 << 4, 235 BrushDataFocusScales = 1 << 6, 236 BrushDataIsGammaCorrected = 1 << 7, 237 BrushDataDoNotTransform = 1 << 8, 238 }; 239 240 typedef struct EmfPlusSolidBrushData 241 { 242 EmfPlusARGB SolidColor; 243 } EmfPlusSolidBrushData; 244 245 typedef struct EmfPlusHatchBrushData 246 { 247 DWORD HatchStyle; 248 EmfPlusARGB ForeColor; 249 EmfPlusARGB BackColor; 250 } EmfPlusHatchBrushData; 251 252 typedef struct EmfPlusTextureBrushData 253 { 254 DWORD BrushDataFlags; 255 INT WrapMode; 256 BYTE OptionalData[1]; 257 } EmfPlusTextureBrushData; 258 259 typedef struct EmfPlusRectF 260 { 261 float X; 262 float Y; 263 float Width; 264 float Height; 265 } EmfPlusRectF; 266 267 typedef struct EmfPlusLinearGradientBrushData 268 { 269 DWORD BrushDataFlags; 270 INT WrapMode; 271 EmfPlusRectF RectF; 272 EmfPlusARGB StartColor; 273 EmfPlusARGB EndColor; 274 DWORD Reserved1; 275 DWORD Reserved2; 276 BYTE OptionalData[1]; 277 } EmfPlusLinearGradientBrushData; 278 279 typedef struct EmfPlusBrush 280 { 281 DWORD Version; 282 DWORD Type; 283 union { 284 EmfPlusSolidBrushData solid; 285 EmfPlusHatchBrushData hatch; 286 EmfPlusTextureBrushData texture; 287 EmfPlusLinearGradientBrushData lineargradient; 288 } BrushData; 289 } EmfPlusBrush; 290 291 typedef struct EmfPlusPen 292 { 293 DWORD Version; 294 DWORD Type; 295 /* EmfPlusPenData */ 296 /* EmfPlusBrush */ 297 BYTE data[1]; 298 } EmfPlusPen; 299 300 typedef struct EmfPlusPath 301 { 302 DWORD Version; 303 DWORD PathPointCount; 304 DWORD PathPointFlags; 305 /* PathPoints[] */ 306 /* PathPointTypes[] */ 307 /* AlignmentPadding */ 308 BYTE data[1]; 309 } EmfPlusPath; 310 311 typedef struct EmfPlusRegionNodePath 312 { 313 DWORD RegionNodePathLength; 314 EmfPlusPath RegionNodePath; 315 } EmfPlusRegionNodePath; 316 317 typedef struct EmfPlusRegion 318 { 319 DWORD Version; 320 DWORD RegionNodeCount; 321 BYTE RegionNode[1]; 322 } EmfPlusRegion; 323 324 typedef struct EmfPlusPalette 325 { 326 DWORD PaletteStyleFlags; 327 DWORD PaletteCount; 328 BYTE PaletteEntries[1]; 329 } EmfPlusPalette; 330 331 typedef enum 332 { 333 BitmapDataTypePixel, 334 BitmapDataTypeCompressed, 335 } BitmapDataType; 336 337 typedef struct EmfPlusBitmap 338 { 339 DWORD Width; 340 DWORD Height; 341 DWORD Stride; 342 DWORD PixelFormat; 343 DWORD Type; 344 BYTE BitmapData[1]; 345 } EmfPlusBitmap; 346 347 typedef struct EmfPlusMetafile 348 { 349 DWORD Type; 350 DWORD MetafileDataSize; 351 BYTE MetafileData[1]; 352 } EmfPlusMetafile; 353 354 typedef enum ImageDataType 355 { 356 ImageDataTypeUnknown, 357 ImageDataTypeBitmap, 358 ImageDataTypeMetafile, 359 } ImageDataType; 360 361 typedef struct EmfPlusImage 362 { 363 DWORD Version; 364 ImageDataType Type; 365 union 366 { 367 EmfPlusBitmap bitmap; 368 EmfPlusMetafile metafile; 369 } ImageData; 370 } EmfPlusImage; 371 372 typedef struct EmfPlusImageAttributes 373 { 374 DWORD Version; 375 DWORD Reserved1; 376 DWORD WrapMode; 377 EmfPlusARGB ClampColor; 378 DWORD ObjectClamp; 379 DWORD Reserved2; 380 } EmfPlusImageAttributes; 381 382 typedef struct EmfPlusObject 383 { 384 EmfPlusRecordHeader Header; 385 union 386 { 387 EmfPlusBrush brush; 388 EmfPlusPen pen; 389 EmfPlusPath path; 390 EmfPlusRegion region; 391 EmfPlusImage image; 392 EmfPlusImageAttributes image_attributes; 393 } ObjectData; 394 } EmfPlusObject; 395 396 typedef struct EmfPlusPointR7 397 { 398 BYTE X; 399 BYTE Y; 400 } EmfPlusPointR7; 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 { 416 EmfPlusRecordHeader Header; 417 DWORD ImageAttributesID; 418 DWORD SrcUnit; 419 EmfPlusRectF SrcRect; 420 union 421 { 422 EmfPlusRect rect; 423 EmfPlusRectF rectF; 424 } RectData; 425 } EmfPlusDrawImage; 426 427 typedef struct EmfPlusDrawImagePoints 428 { 429 EmfPlusRecordHeader Header; 430 DWORD ImageAttributesID; 431 DWORD SrcUnit; 432 EmfPlusRectF SrcRect; 433 DWORD count; 434 union 435 { 436 EmfPlusPointR7 pointsR[3]; 437 EmfPlusPoint points[3]; 438 EmfPlusPointF pointsF[3]; 439 } PointData; 440 } EmfPlusDrawImagePoints; 441 442 typedef struct EmfPlusDrawPath 443 { 444 EmfPlusRecordHeader Header; 445 DWORD PenId; 446 } EmfPlusDrawPath; 447 448 typedef struct EmfPlusDrawArc 449 { 450 EmfPlusRecordHeader Header; 451 float StartAngle; 452 float SweepAngle; 453 union 454 { 455 EmfPlusRect rect; 456 EmfPlusRectF rectF; 457 } RectData; 458 } EmfPlusDrawArc; 459 460 typedef struct EmfPlusDrawEllipse 461 { 462 EmfPlusRecordHeader Header; 463 union 464 { 465 EmfPlusRect rect; 466 EmfPlusRectF rectF; 467 } RectData; 468 } EmfPlusDrawEllipse; 469 470 typedef struct EmfPlusDrawPie 471 { 472 EmfPlusRecordHeader Header; 473 float StartAngle; 474 float SweepAngle; 475 union 476 { 477 EmfPlusRect rect; 478 EmfPlusRectF rectF; 479 } RectData; 480 } EmfPlusDrawPie; 481 482 typedef struct EmfPlusDrawRects 483 { 484 EmfPlusRecordHeader Header; 485 DWORD Count; 486 union 487 { 488 EmfPlusRect rect[1]; 489 EmfPlusRectF rectF[1]; 490 } RectData; 491 } EmfPlusDrawRects; 492 493 typedef struct EmfPlusFillPath 494 { 495 EmfPlusRecordHeader Header; 496 union 497 { 498 DWORD BrushId; 499 EmfPlusARGB Color; 500 } data; 501 } EmfPlusFillPath; 502 503 typedef struct EmfPlusFillClosedCurve 504 { 505 EmfPlusRecordHeader Header; 506 DWORD BrushId; 507 float Tension; 508 DWORD Count; 509 union 510 { 511 EmfPlusPointR7 pointsR[1]; 512 EmfPlusPoint points[1]; 513 EmfPlusPointF pointsF[1]; 514 } PointData; 515 } EmfPlusFillClosedCurve; 516 517 typedef struct EmfPlusFillEllipse 518 { 519 EmfPlusRecordHeader Header; 520 DWORD BrushId; 521 union 522 { 523 EmfPlusRect rect; 524 EmfPlusRectF rectF; 525 } RectData; 526 } EmfPlusFillEllipse; 527 528 typedef struct EmfPlusFillPie 529 { 530 EmfPlusRecordHeader Header; 531 DWORD BrushId; 532 float StartAngle; 533 float SweepAngle; 534 union 535 { 536 EmfPlusRect rect; 537 EmfPlusRectF rectF; 538 } RectData; 539 } EmfPlusFillPie; 540 541 typedef struct EmfPlusFont 542 { 543 DWORD Version; 544 float EmSize; 545 DWORD SizeUnit; 546 DWORD FontStyleFlags; 547 DWORD Reserved; 548 DWORD Length; 549 WCHAR FamilyName[1]; 550 } EmfPlusFont; 551 552 static void metafile_free_object_table_entry(GpMetafile *metafile, BYTE id) 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; 578 case ObjectTypeImageAttributes: 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 590 void METAFILE_Free(GpMetafile *metafile) 591 { 592 unsigned int i; 593 594 heap_free(metafile->comment_data); 595 DeleteEnhMetaFile(CloseEnhMetaFile(metafile->record_dc)); 596 if (!metafile->preserve_hemf) 597 DeleteEnhMetaFile(metafile->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++) 610 metafile_free_object_table_entry(metafile, i); 611 } 612 613 static DWORD METAFILE_AddObjectId(GpMetafile *metafile) 614 { 615 return (metafile->next_object_id++) % EmfPlusObjectTableSize; 616 } 617 618 static GpStatus METAFILE_AllocateRecord(GpMetafile *metafile, DWORD size, void **result) 619 { 620 DWORD size_needed; 621 EmfPlusRecordHeader *record; 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 657 record = (EmfPlusRecordHeader*)*result; 658 record->Size = size; 659 record->DataSize = size - sizeof(EmfPlusRecordHeader); 660 661 return Ok; 662 } 663 664 static void METAFILE_RemoveLastRecord(GpMetafile *metafile, EmfPlusRecordHeader *record) 665 { 666 assert(metafile->comment_data + metafile->comment_data_length == (BYTE*)record + record->Size); 667 metafile->comment_data_length -= record->Size; 668 } 669 670 static void METAFILE_WriteRecords(GpMetafile *metafile) 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 679 static GpStatus METAFILE_WriteHeader(GpMetafile *metafile, HDC hdc) 680 { 681 GpStatus stat; 682 683 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) 684 { 685 EmfPlusHeader *header; 686 687 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusHeader), (void**)&header); 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 700 if (GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY) 701 header->EmfPlusFlags = 1; 702 else 703 header->EmfPlusFlags = 0; 704 705 header->LogicalDpiX = GetDeviceCaps(hdc, LOGPIXELSX); 706 header->LogicalDpiY = GetDeviceCaps(hdc, LOGPIXELSY); 707 708 METAFILE_WriteRecords(metafile); 709 } 710 711 return Ok; 712 } 713 714 static GpStatus METAFILE_WriteEndOfFile(GpMetafile *metafile) 715 { 716 GpStatus stat; 717 718 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) 719 { 720 EmfPlusRecordHeader *record; 721 722 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusRecordHeader), (void**)&record); 723 if (stat != Ok) 724 return stat; 725 726 record->Type = EmfPlusRecordTypeEndOfFile; 727 record->Flags = 0; 728 729 METAFILE_WriteRecords(metafile); 730 } 731 732 return Ok; 733 } 734 735 GpStatus WINGDIPAPI GdipRecordMetafile(HDC hdc, EmfType type, GDIPCONST GpRectF *frameRect, 736 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile) 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 746 if (!hdc || type < EmfTypeEmfOnly || type > EmfTypeEmfPlusDual || !metafile) 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 { 756 case MetafileFrameUnitPixel: 757 framerect_factor_x = 2540.0 / dpix; 758 framerect_factor_y = 2540.0 / dpiy; 759 break; 760 case MetafileFrameUnitPoint: 761 framerect_factor_x = framerect_factor_y = 2540.0 / 72.0; 762 break; 763 case MetafileFrameUnitInch: 764 framerect_factor_x = framerect_factor_y = 2540.0; 765 break; 766 case MetafileFrameUnitDocument: 767 framerect_factor_x = framerect_factor_y = 2540.0 / 300.0; 768 break; 769 case MetafileFrameUnitMillimeter: 770 framerect_factor_x = framerect_factor_y = 100.0; 771 break; 772 case MetafileFrameUnitGdi: 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 { 797 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc)); 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 826 stat = METAFILE_WriteHeader(*metafile, hdc); 827 828 if (stat != Ok) 829 { 830 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc)); 831 heap_free(*metafile); 832 *metafile = NULL; 833 return OutOfMemory; 834 } 835 836 return stat; 837 } 838 839 /***************************************************************************** 840 * GdipRecordMetafileI [GDIPLUS.@] 841 */ 842 GpStatus WINGDIPAPI GdipRecordMetafileI(HDC hdc, EmfType type, GDIPCONST GpRect *frameRect, 843 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile) 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 863 GpStatus WINGDIPAPI GdipRecordMetafileStream(IStream *stream, HDC hdc, EmfType type, GDIPCONST GpRectF *frameRect, 864 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, GpMetafile **metafile) 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 884 static void METAFILE_AdjustFrame(GpMetafile* metafile, const GpPointF *points, 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 908 GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result) 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 927 GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc) 928 { 929 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) 930 { 931 EmfPlusRecordHeader *record; 932 GpStatus stat; 933 934 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusRecordHeader), (void**)&record); 935 if (stat != Ok) 936 return stat; 937 938 record->Type = EmfPlusRecordTypeGetDC; 939 record->Flags = 0; 940 941 METAFILE_WriteRecords(metafile); 942 } 943 944 *hdc = metafile->record_dc; 945 946 return Ok; 947 } 948 949 GpStatus METAFILE_GraphicsClear(GpMetafile* metafile, ARGB color) 950 { 951 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) 952 { 953 EmfPlusClear *record; 954 GpStatus stat; 955 956 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusClear), (void**)&record); 957 if (stat != Ok) 958 return stat; 959 960 record->Header.Type = EmfPlusRecordTypeClear; 961 record->Header.Flags = 0; 962 record->Color = color; 963 964 METAFILE_WriteRecords(metafile); 965 } 966 967 return Ok; 968 } 969 970 static BOOL is_integer_rect(const GpRectF *rect) 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 983 static GpStatus METAFILE_PrepareBrushData(GpBrush *brush, DWORD *size) 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 1001 static void METAFILE_FillBrushData(GpBrush *brush, EmfPlusBrush *data) 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 1027 static GpStatus METAFILE_AddBrushObject(GpMetafile *metafile, GpBrush *brush, DWORD *id) 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 1037 stat = METAFILE_PrepareBrushData(brush, &size); 1038 if (stat != Ok) return stat; 1039 1040 stat = METAFILE_AllocateRecord(metafile, 1041 FIELD_OFFSET(EmfPlusObject, ObjectData) + size, (void**)&object_record); 1042 if (stat != Ok) return stat; 1043 1044 *id = METAFILE_AddObjectId(metafile); 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 1051 GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush, 1052 GDIPCONST GpRectF* rects, INT count) 1053 { 1054 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) 1055 { 1056 EmfPlusFillRects *record; 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 { 1070 stat = METAFILE_AddBrushObject(metafile, brush, &brushid); 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 1087 stat = METAFILE_AllocateRecord(metafile, 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 1112 METAFILE_WriteRecords(metafile); 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 1131 GdipTransformPoints(metafile->record_graphics, CoordinateSpaceDevice, 1132 CoordinateSpaceWorld, corners, 4); 1133 1134 METAFILE_AdjustFrame(metafile, corners, 4); 1135 } 1136 } 1137 1138 return Ok; 1139 } 1140 1141 GpStatus METAFILE_SetClipRect(GpMetafile* metafile, REAL x, REAL y, REAL width, REAL height, CombineMode mode) 1142 { 1143 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) 1144 { 1145 EmfPlusSetClipRect *record; 1146 GpStatus stat; 1147 1148 stat = METAFILE_AllocateRecord(metafile, 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 1161 METAFILE_WriteRecords(metafile); 1162 } 1163 1164 return Ok; 1165 } 1166 1167 static GpStatus METAFILE_AddRegionObject(GpMetafile *metafile, GpRegion *region, DWORD *id) 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 1177 size = write_region_data(region, NULL); 1178 stat = METAFILE_AllocateRecord(metafile, 1179 FIELD_OFFSET(EmfPlusObject, ObjectData.region) + size, (void**)&object_record); 1180 if (stat != Ok) return stat; 1181 1182 *id = METAFILE_AddObjectId(metafile); 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 1189 GpStatus METAFILE_SetClipRegion(GpMetafile* metafile, GpRegion* region, CombineMode mode) 1190 { 1191 EmfPlusRecordHeader *record; 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, ®ion_id); 1202 if (stat != Ok) return stat; 1203 1204 stat = METAFILE_AllocateRecord(metafile, sizeof(*record), (void**)&record); 1205 if (stat != Ok) return stat; 1206 1207 record->Type = EmfPlusRecordTypeSetClipRegion; 1208 record->Flags = region_id | mode << 8; 1209 1210 METAFILE_WriteRecords(metafile); 1211 return Ok; 1212 } 1213 1214 GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale) 1215 { 1216 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) 1217 { 1218 EmfPlusSetPageTransform *record; 1219 GpStatus stat; 1220 1221 stat = METAFILE_AllocateRecord(metafile, 1222 sizeof(EmfPlusSetPageTransform), 1223 (void**)&record); 1224 if (stat != Ok) 1225 return stat; 1226 1227 record->Header.Type = EmfPlusRecordTypeSetPageTransform; 1228 record->Header.Flags = unit; 1229 record->PageScale = scale; 1230 1231 METAFILE_WriteRecords(metafile); 1232 } 1233 1234 return Ok; 1235 } 1236 1237 GpStatus METAFILE_SetWorldTransform(GpMetafile* metafile, GDIPCONST GpMatrix* transform) 1238 { 1239 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) 1240 { 1241 EmfPlusSetWorldTransform *record; 1242 GpStatus stat; 1243 1244 stat = METAFILE_AllocateRecord(metafile, 1245 sizeof(EmfPlusSetWorldTransform), 1246 (void**)&record); 1247 if (stat != Ok) 1248 return stat; 1249 1250 record->Header.Type = EmfPlusRecordTypeSetWorldTransform; 1251 record->Header.Flags = 0; 1252 memcpy(record->MatrixData, transform->matrix, sizeof(record->MatrixData)); 1253 1254 METAFILE_WriteRecords(metafile); 1255 } 1256 1257 return Ok; 1258 } 1259 1260 GpStatus METAFILE_ScaleWorldTransform(GpMetafile* metafile, REAL sx, REAL sy, MatrixOrder order) 1261 { 1262 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) 1263 { 1264 EmfPlusScaleWorldTransform *record; 1265 GpStatus stat; 1266 1267 stat = METAFILE_AllocateRecord(metafile, 1268 sizeof(EmfPlusScaleWorldTransform), 1269 (void**)&record); 1270 if (stat != Ok) 1271 return stat; 1272 1273 record->Header.Type = EmfPlusRecordTypeScaleWorldTransform; 1274 record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0); 1275 record->Sx = sx; 1276 record->Sy = sy; 1277 1278 METAFILE_WriteRecords(metafile); 1279 } 1280 1281 return Ok; 1282 } 1283 1284 GpStatus METAFILE_MultiplyWorldTransform(GpMetafile* metafile, GDIPCONST GpMatrix* matrix, MatrixOrder order) 1285 { 1286 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) 1287 { 1288 EmfPlusMultiplyWorldTransform *record; 1289 GpStatus stat; 1290 1291 stat = METAFILE_AllocateRecord(metafile, 1292 sizeof(EmfPlusMultiplyWorldTransform), 1293 (void**)&record); 1294 if (stat != Ok) 1295 return stat; 1296 1297 record->Header.Type = EmfPlusRecordTypeMultiplyWorldTransform; 1298 record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0); 1299 memcpy(record->MatrixData, matrix->matrix, sizeof(record->MatrixData)); 1300 1301 METAFILE_WriteRecords(metafile); 1302 } 1303 1304 return Ok; 1305 } 1306 1307 GpStatus METAFILE_RotateWorldTransform(GpMetafile* metafile, REAL angle, MatrixOrder order) 1308 { 1309 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) 1310 { 1311 EmfPlusRotateWorldTransform *record; 1312 GpStatus stat; 1313 1314 stat = METAFILE_AllocateRecord(metafile, 1315 sizeof(EmfPlusRotateWorldTransform), 1316 (void**)&record); 1317 if (stat != Ok) 1318 return stat; 1319 1320 record->Header.Type = EmfPlusRecordTypeRotateWorldTransform; 1321 record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0); 1322 record->Angle = angle; 1323 1324 METAFILE_WriteRecords(metafile); 1325 } 1326 1327 return Ok; 1328 } 1329 1330 GpStatus METAFILE_TranslateWorldTransform(GpMetafile* metafile, REAL dx, REAL dy, MatrixOrder order) 1331 { 1332 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) 1333 { 1334 EmfPlusTranslateWorldTransform *record; 1335 GpStatus stat; 1336 1337 stat = METAFILE_AllocateRecord(metafile, 1338 sizeof(EmfPlusTranslateWorldTransform), 1339 (void**)&record); 1340 if (stat != Ok) 1341 return stat; 1342 1343 record->Header.Type = EmfPlusRecordTypeTranslateWorldTransform; 1344 record->Header.Flags = (order == MatrixOrderAppend ? 0x2000 : 0); 1345 record->dx = dx; 1346 record->dy = dy; 1347 1348 METAFILE_WriteRecords(metafile); 1349 } 1350 1351 return Ok; 1352 } 1353 1354 GpStatus METAFILE_ResetWorldTransform(GpMetafile* metafile) 1355 { 1356 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) 1357 { 1358 EmfPlusRecordHeader *record; 1359 GpStatus stat; 1360 1361 stat = METAFILE_AllocateRecord(metafile, 1362 sizeof(EmfPlusRecordHeader), 1363 (void**)&record); 1364 if (stat != Ok) 1365 return stat; 1366 1367 record->Type = EmfPlusRecordTypeResetWorldTransform; 1368 record->Flags = 0; 1369 1370 METAFILE_WriteRecords(metafile); 1371 } 1372 1373 return Ok; 1374 } 1375 1376 GpStatus METAFILE_BeginContainer(GpMetafile* metafile, GDIPCONST GpRectF *dstrect, 1377 GDIPCONST GpRectF *srcrect, GpUnit unit, DWORD StackIndex) 1378 { 1379 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) 1380 { 1381 EmfPlusBeginContainer *record; 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 1394 METAFILE_WriteRecords(metafile); 1395 } 1396 1397 return Ok; 1398 } 1399 1400 GpStatus METAFILE_BeginContainerNoParams(GpMetafile* metafile, DWORD StackIndex) 1401 { 1402 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) 1403 { 1404 EmfPlusContainerRecord *record; 1405 GpStatus stat; 1406 1407 stat = METAFILE_AllocateRecord(metafile, 1408 sizeof(EmfPlusContainerRecord), 1409 (void**)&record); 1410 if (stat != Ok) 1411 return stat; 1412 1413 record->Header.Type = EmfPlusRecordTypeBeginContainerNoParams; 1414 record->Header.Flags = 0; 1415 record->StackIndex = StackIndex; 1416 1417 METAFILE_WriteRecords(metafile); 1418 } 1419 1420 return Ok; 1421 } 1422 1423 GpStatus METAFILE_EndContainer(GpMetafile* metafile, DWORD StackIndex) 1424 { 1425 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) 1426 { 1427 EmfPlusContainerRecord *record; 1428 GpStatus stat; 1429 1430 stat = METAFILE_AllocateRecord(metafile, 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 1440 METAFILE_WriteRecords(metafile); 1441 } 1442 1443 return Ok; 1444 } 1445 1446 GpStatus METAFILE_SaveGraphics(GpMetafile* metafile, DWORD StackIndex) 1447 { 1448 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) 1449 { 1450 EmfPlusContainerRecord *record; 1451 GpStatus stat; 1452 1453 stat = METAFILE_AllocateRecord(metafile, 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 1463 METAFILE_WriteRecords(metafile); 1464 } 1465 1466 return Ok; 1467 } 1468 1469 GpStatus METAFILE_RestoreGraphics(GpMetafile* metafile, DWORD StackIndex) 1470 { 1471 if (metafile->metafile_type == MetafileTypeEmfPlusOnly || metafile->metafile_type == MetafileTypeEmfPlusDual) 1472 { 1473 EmfPlusContainerRecord *record; 1474 GpStatus stat; 1475 1476 stat = METAFILE_AllocateRecord(metafile, 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 1486 METAFILE_WriteRecords(metafile); 1487 } 1488 1489 return Ok; 1490 } 1491 1492 GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc) 1493 { 1494 if (hdc != metafile->record_dc) 1495 return InvalidParameter; 1496 1497 return Ok; 1498 } 1499 1500 GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile) 1501 { 1502 GpStatus stat; 1503 1504 stat = METAFILE_WriteEndOfFile(metafile); 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 { 1516 MetafileHeader header; 1517 1518 stat = GdipGetMetafileHeaderFromEmf(metafile->hemf, &header); 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 1542 buffer_size = GetEnhMetaFileBits(metafile->hemf, 0, NULL); 1543 buffer = heap_alloc(buffer_size); 1544 if (buffer) 1545 { 1546 HENHMETAFILE new_hemf; 1547 1548 GetEnhMetaFileBits(metafile->hemf, buffer_size, buffer); 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) 1568 stat = GdipGetMetafileHeaderFromEmf(metafile->hemf, &header); 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 1584 buffer_size = GetEnhMetaFileBits(metafile->hemf, 0, NULL); 1585 1586 buffer = heap_alloc(buffer_size); 1587 if (buffer) 1588 { 1589 HRESULT hr; 1590 1591 GetEnhMetaFileBits(metafile->hemf, buffer_size, buffer); 1592 1593 hr = IStream_Write(metafile->record_stream, buffer, buffer_size, NULL); 1594 1595 if (FAILED(hr)) 1596 stat = hresult_to_status(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 1613 GpStatus WINGDIPAPI GdipGetHemfFromMetafile(GpMetafile *metafile, HENHMETAFILE *hEmf) 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 1626 static void METAFILE_GetFinalGdiTransform(const GpMetafile *metafile, XFORM *result) 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 1642 static GpStatus METAFILE_PlaybackUpdateGdiTransform(GpMetafile *metafile) 1643 { 1644 XFORM combined, final; 1645 1646 METAFILE_GetFinalGdiTransform(metafile, &final); 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 1656 static GpStatus METAFILE_PlaybackGetDC(GpMetafile *metafile) 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; 1667 METAFILE_PlaybackUpdateGdiTransform(metafile); 1668 } 1669 1670 return stat; 1671 } 1672 1673 static void METAFILE_PlaybackReleaseDC(GpMetafile *metafile) 1674 { 1675 if (metafile->playback_dc) 1676 { 1677 GdipReleaseDC(metafile->playback_graphics, metafile->playback_dc); 1678 metafile->playback_dc = NULL; 1679 } 1680 } 1681 1682 static GpStatus METAFILE_PlaybackUpdateClip(GpMetafile *metafile) 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 1691 static GpStatus METAFILE_PlaybackUpdateWorldTransform(GpMetafile *metafile) 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 1719 static void metafile_set_object_table_entry(GpMetafile *metafile, BYTE id, BYTE type, void *object) 1720 { 1721 metafile_free_object_table_entry(metafile, id); 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 { 1751 ColorPalette *palette; 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 { 1783 status = GdipSetImagePalette(*image, palette); 1784 if (status != Ok) 1785 { 1786 GdipDisposeImage(*image); 1787 *image = NULL; 1788 } 1789 } 1790 break; 1791 } 1792 case BitmapDataTypeCompressed: 1793 { 1794 IWICImagingFactory *factory; 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) 1807 status = GdipCreateBitmapFromStream((IStream *)stream, (GpBitmap **)image); 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 1860 status = GdipCreatePath(FillModeAlternate, path); 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 1897 static GpStatus metafile_read_region_node(struct memory_buffer *mbuf, GpRegion *region, region_element *node, UINT *count) 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 { 1916 region_element *left, *right; 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 1929 status = metafile_read_region_node(mbuf, region, left, count); 1930 if (status == Ok) 1931 { 1932 status = metafile_read_region_node(mbuf, region, right, count); 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: 1981 case RegionDataInfiniteRect: 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) 2012 status = InvalidParameter; 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; 2027 EmfPlusTransformMatrix *transform = NULL; 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 2077 GdipDisposeImage(image); 2078 break; 2079 } 2080 case BrushTypeLinearGradient: 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 2102 if (brushflags & (BrushDataPresetColors | BrushDataBlendFactorsH | BrushDataBlendFactorsV)) 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 2162 static GpStatus metafile_get_pen_brush_data_offset(EmfPlusPen *data, UINT data_size, DWORD *ret) 2163 { 2164 EmfPlusPenData *pendata = (EmfPlusPenData *)data->data; 2165 DWORD offset = FIELD_OFFSET(EmfPlusPen, 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 { 2200 EmfPlusDashedLineData *dashedline = (EmfPlusDashedLineData *)((BYTE *)data + offset); 2201 2202 offset += FIELD_OFFSET(EmfPlusDashedLineData, data); 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 { 2214 EmfPlusCompoundLineData *compoundline = (EmfPlusCompoundLineData *)((BYTE *)data + offset); 2215 2216 offset += FIELD_OFFSET(EmfPlusCompoundLineData, data); 2217 if (data_size <= offset) 2218 return InvalidParameter; 2219 2220 offset += compoundline->CompoundLineDataSize * sizeof(float); 2221 } 2222 2223 if (pendata->PenDataFlags & PenDataCustomStartCap) 2224 { 2225 EmfPlusCustomStartCapData *startcap = (EmfPlusCustomStartCapData *)((BYTE *)data + offset); 2226 2227 offset += FIELD_OFFSET(EmfPlusCustomStartCapData, data); 2228 if (data_size <= offset) 2229 return InvalidParameter; 2230 2231 offset += startcap->CustomStartCapSize; 2232 } 2233 2234 if (pendata->PenDataFlags & PenDataCustomEndCap) 2235 { 2236 EmfPlusCustomEndCapData *endcap = (EmfPlusCustomEndCapData *)((BYTE *)data + offset); 2237 2238 offset += FIELD_OFFSET(EmfPlusCustomEndCapData, data); 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 2272 status = metafile_get_pen_brush_data_offset(data, data_size, &offset); 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"); 2365 offset += FIELD_OFFSET(EmfPlusCustomStartCapData, data) + startcap->CustomStartCapSize; 2366 } 2367 2368 if (pendata->PenDataFlags & PenDataCustomEndCap) 2369 { 2370 EmfPlusCustomEndCapData *endcap = (EmfPlusCustomEndCapData *)((BYTE *)pendata + offset); 2371 FIXME("PenDataCustomEndCap is not supported.\n"); 2372 offset += FIELD_OFFSET(EmfPlusCustomEndCapData, data) + endcap->CustomEndCapSize; 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 } 2419 case ObjectTypeImageAttributes: 2420 { 2421 EmfPlusImageAttributes *data = (EmfPlusImageAttributes *)record_data; 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) 2444 metafile_set_object_table_entry(metafile, id, type, object); 2445 2446 return status; 2447 } 2448 2449 static GpStatus metafile_set_clip_region(GpMetafile *metafile, GpRegion *region, CombineMode mode) 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 2458 return METAFILE_PlaybackUpdateClip(metafile); 2459 } 2460 2461 GpStatus WINGDIPAPI GdipPlayMetafileRecord(GDIPCONST GpMetafile *metafile, 2462 EmfPlusRecordType recordType, UINT flags, UINT dataSize, GDIPCONST BYTE *data) 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: 2486 case EMR_SCALEVIEWPORTEXTEX: 2487 case EMR_SCALEWINDOWEXTEX: 2488 case EMR_MODIFYWORLDTRANSFORM: 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 2509 METAFILE_GetFinalGdiTransform(metafile, &final); 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 { 2546 EmfPlusRecordHeader *header = (EmfPlusRecordHeader*)(data)-1; 2547 2548 METAFILE_PlaybackReleaseDC((GpMetafile*)metafile); 2549 2550 switch(recordType) 2551 { 2552 case EmfPlusRecordTypeHeader: 2553 case EmfPlusRecordTypeEndOfFile: 2554 break; 2555 case EmfPlusRecordTypeGetDC: 2556 METAFILE_PlaybackGetDC((GpMetafile*)metafile); 2557 break; 2558 case EmfPlusRecordTypeClear: 2559 { 2560 EmfPlusClear *record = (EmfPlusClear*)header; 2561 2562 if (dataSize != sizeof(record->Color)) 2563 return InvalidParameter; 2564 2565 return GdipGraphicsClear(metafile->playback_graphics, record->Color); 2566 } 2567 case EmfPlusRecordTypeFillRects: 2568 { 2569 EmfPlusFillRects *record = (EmfPlusFillRects*)header; 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 } 2637 case EmfPlusRecordTypeSetClipRect: 2638 { 2639 EmfPlusSetClipRect *record = (EmfPlusSetClipRect*)header; 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, ®ion); 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 } 2656 case EmfPlusRecordTypeSetClipRegion: 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, ®ion); 2669 if (stat == Ok) 2670 { 2671 stat = metafile_set_clip_region(real_metafile, region, mode); 2672 GdipDeleteRegion(region); 2673 } 2674 2675 return stat; 2676 } 2677 case EmfPlusRecordTypeSetClipPath: 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, ®ion); 2690 if (stat == Ok) 2691 { 2692 stat = metafile_set_clip_region(real_metafile, region, mode); 2693 GdipDeleteRegion(region); 2694 } 2695 2696 return stat; 2697 } 2698 case EmfPlusRecordTypeSetPageTransform: 2699 { 2700 EmfPlusSetPageTransform *record = (EmfPlusSetPageTransform*)header; 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 } 2711 case EmfPlusRecordTypeSetWorldTransform: 2712 { 2713 EmfPlusSetWorldTransform *record = (EmfPlusSetWorldTransform*)header; 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 } 2722 case EmfPlusRecordTypeScaleWorldTransform: 2723 { 2724 EmfPlusScaleWorldTransform *record = (EmfPlusScaleWorldTransform*)header; 2725 MatrixOrder order = (flags & 0x2000) ? MatrixOrderAppend : MatrixOrderPrepend; 2726 2727 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusScaleWorldTransform)) 2728 return InvalidParameter; 2729 2730 GdipScaleMatrix(real_metafile->world_transform, record->Sx, record->Sy, order); 2731 2732 return METAFILE_PlaybackUpdateWorldTransform(real_metafile); 2733 } 2734 case EmfPlusRecordTypeMultiplyWorldTransform: 2735 { 2736 EmfPlusMultiplyWorldTransform *record = (EmfPlusMultiplyWorldTransform*)header; 2737 MatrixOrder order = (flags & 0x2000) ? MatrixOrderAppend : MatrixOrderPrepend; 2738 GpMatrix matrix; 2739 2740 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusMultiplyWorldTransform)) 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 } 2749 case EmfPlusRecordTypeRotateWorldTransform: 2750 { 2751 EmfPlusRotateWorldTransform *record = (EmfPlusRotateWorldTransform*)header; 2752 MatrixOrder order = (flags & 0x2000) ? MatrixOrderAppend : MatrixOrderPrepend; 2753 2754 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusRotateWorldTransform)) 2755 return InvalidParameter; 2756 2757 GdipRotateMatrix(real_metafile->world_transform, record->Angle, order); 2758 2759 return METAFILE_PlaybackUpdateWorldTransform(real_metafile); 2760 } 2761 case EmfPlusRecordTypeTranslateWorldTransform: 2762 { 2763 EmfPlusTranslateWorldTransform *record = (EmfPlusTranslateWorldTransform*)header; 2764 MatrixOrder order = (flags & 0x2000) ? MatrixOrderAppend : MatrixOrderPrepend; 2765 2766 if (dataSize + sizeof(EmfPlusRecordHeader) < sizeof(EmfPlusTranslateWorldTransform)) 2767 return InvalidParameter; 2768 2769 GdipTranslateMatrix(real_metafile->world_transform, record->dx, record->dy, order); 2770 2771 return METAFILE_PlaybackUpdateWorldTransform(real_metafile); 2772 } 2773 case EmfPlusRecordTypeResetWorldTransform: 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 } 2779 case EmfPlusRecordTypeBeginContainer: 2780 { 2781 EmfPlusBeginContainer *record = (EmfPlusBeginContainer*)header; 2782 container* cont; 2783 GpUnit unit; 2784 REAL scale_x, scale_y; 2785 GpRectF scaled_srcrect; 2786 GpMatrix transform; 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 2832 GdipMultiplyMatrix(real_metafile->world_transform, &transform, MatrixOrderPrepend); 2833 2834 return METAFILE_PlaybackUpdateWorldTransform(real_metafile); 2835 } 2836 case EmfPlusRecordTypeBeginContainerNoParams: 2837 case EmfPlusRecordTypeSave: 2838 { 2839 EmfPlusContainerRecord *record = (EmfPlusContainerRecord*)header; 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 } 2877 case EmfPlusRecordTypeEndContainer: 2878 case EmfPlusRecordTypeRestore: 2879 { 2880 EmfPlusContainerRecord *record = (EmfPlusContainerRecord*)header; 2881 container* cont; 2882 enum container_type type; 2883 BOOL found=FALSE; 2884 2885 if (recordType == EmfPlusRecordTypeEndContainer) 2886 type = BEGIN_CONTAINER; 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 } 2928 case EmfPlusRecordTypeSetPixelOffsetMode: 2929 { 2930 return GdipSetPixelOffsetMode(real_metafile->playback_graphics, flags & 0xff); 2931 } 2932 case EmfPlusRecordTypeSetCompositingQuality: 2933 { 2934 return GdipSetCompositingQuality(real_metafile->playback_graphics, flags & 0xff); 2935 } 2936 case EmfPlusRecordTypeSetInterpolationMode: 2937 { 2938 return GdipSetInterpolationMode(real_metafile->playback_graphics, flags & 0xff); 2939 } 2940 case EmfPlusRecordTypeSetTextRenderingHint: 2941 { 2942 return GdipSetTextRenderingHint(real_metafile->playback_graphics, flags & 0xff); 2943 } 2944 case EmfPlusRecordTypeSetAntiAliasMode: 2945 { 2946 return GdipSetSmoothingMode(real_metafile->playback_graphics, (flags >> 1) & 0xff); 2947 } 2948 case EmfPlusRecordTypeSetCompositingMode: 2949 { 2950 return GdipSetCompositingMode(real_metafile->playback_graphics, flags & 0xff); 2951 } 2952 case EmfPlusRecordTypeObject: 2953 { 2954 return METAFILE_PlaybackObject(real_metafile, flags, dataSize, data); 2955 } 2956 case EmfPlusRecordTypeDrawImage: 2957 { 2958 EmfPlusDrawImage *draw = (EmfPlusDrawImage *)header; 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 2969 if (draw->ImageAttributesID >= EmfPlusObjectTableSize || 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 } 2996 case EmfPlusRecordTypeDrawImagePoints: 2997 { 2998 EmfPlusDrawImagePoints *draw = (EmfPlusDrawImagePoints *)header; 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 3013 if (draw->ImageAttributesID >= EmfPlusObjectTableSize || 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 } 3058 case EmfPlusRecordTypeFillPath: 3059 { 3060 EmfPlusFillPath *fill = (EmfPlusFillPath *)header; 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 } 3091 case EmfPlusRecordTypeFillClosedCurve: 3092 { 3093 static const UINT fixed_part_size = FIELD_OFFSET(EmfPlusFillClosedCurve, PointData) - 3094 sizeof(EmfPlusRecordHeader); 3095 EmfPlusFillClosedCurve *fill = (EmfPlusFillClosedCurve *)header; 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 } 3171 case EmfPlusRecordTypeFillEllipse: 3172 { 3173 EmfPlusFillEllipse *fill = (EmfPlusFillEllipse *)header; 3174 GpSolidFill *solidfill = NULL; 3175 GpBrush *brush; 3176 3177 if (dataSize <= FIELD_OFFSET(EmfPlusFillEllipse, RectData) - sizeof(EmfPlusRecordHeader)) 3178 return InvalidParameter; 3179 dataSize -= FIELD_OFFSET(EmfPlusFillEllipse, RectData) - sizeof(EmfPlusRecordHeader); 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 } 3210 case EmfPlusRecordTypeFillPie: 3211 { 3212 EmfPlusFillPie *fill = (EmfPlusFillPie *)header; 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 } 3251 case EmfPlusRecordTypeDrawPath: 3252 { 3253 EmfPlusDrawPath *draw = (EmfPlusDrawPath *)header; 3254 BYTE path = flags & 0xff; 3255 3256 if (dataSize != sizeof(draw->PenId)) 3257 return InvalidParameter; 3258 3259 if (path >= EmfPlusObjectTableSize || draw->PenId >= EmfPlusObjectTableSize) 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 } 3269 case EmfPlusRecordTypeDrawArc: 3270 { 3271 EmfPlusDrawArc *draw = (EmfPlusDrawArc *)header; 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 } 3290 case EmfPlusRecordTypeDrawEllipse: 3291 { 3292 EmfPlusDrawEllipse *draw = (EmfPlusDrawEllipse *)header; 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 } 3310 case EmfPlusRecordTypeDrawPie: 3311 { 3312 EmfPlusDrawPie *draw = (EmfPlusDrawPie *)header; 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 } 3331 case EmfPlusRecordTypeDrawRects: 3332 { 3333 EmfPlusDrawRects *draw = (EmfPlusDrawRects *)header; 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; 3342 dataSize -= FIELD_OFFSET(EmfPlusDrawRects, RectData) - sizeof(EmfPlusRecordHeader); 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 3378 struct enum_metafile_data 3379 { 3380 EnumerateMetafileProc callback; 3381 void *callback_data; 3382 GpMetafile *metafile; 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 3435 GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics, 3436 GDIPCONST GpMetafile *metafile, GDIPCONST GpPointF *destPoints, INT count, 3437 GDIPCONST GpRectF *srcRect, Unit srcUnit, EnumerateMetafileProc callback, 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 */ 3443 GraphicsContainer state; 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); 3472 stat = GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, real_metafile->playback_points, 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; 3526 stat = METAFILE_PlaybackUpdateWorldTransform(real_metafile); 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) 3540 EnumEnhMetaFile(0, metafile->hemf, enum_metafile_proc, &data, NULL); 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 3569 GpStatus WINGDIPAPI GdipEnumerateMetafileDestRect(GpGraphics *graphics, 3570 GDIPCONST GpMetafile *metafile, GDIPCONST GpRectF *dest, 3571 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs) 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 3582 return GdipEnumerateMetafileSrcRectDestPoints(graphics, metafile, points, 3, 3583 &metafile->bounds, metafile->unit, callback, cb_data, attrs); 3584 } 3585 3586 GpStatus WINGDIPAPI GdipEnumerateMetafileDestRectI(GpGraphics *graphics, 3587 GDIPCONST GpMetafile *metafile, GDIPCONST GpRect *dest, 3588 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs) 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 3602 GpStatus WINGDIPAPI GdipEnumerateMetafileDestPoint(GpGraphics *graphics, 3603 GDIPCONST GpMetafile *metafile, GDIPCONST GpPointF *dest, 3604 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs) 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 3618 GpStatus WINGDIPAPI GdipEnumerateMetafileDestPointI(GpGraphics *graphics, 3619 GDIPCONST GpMetafile *metafile, GDIPCONST GpPoint *dest, 3620 EnumerateMetafileProc callback, VOID *cb_data, GDIPCONST GpImageAttributes *attrs) 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 3632 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile, 3633 MetafileHeader * header) 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 { 3644 status = GdipGetMetafileHeaderFromEmf(metafile->hemf, header); 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 && 3676 header->Type == EmfPlusRecordTypeHeader) 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 3688 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromEmf(HENHMETAFILE hemf, 3689 MetafileHeader *header) 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 3747 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromWmf(HMETAFILE hwmf, 3748 GDIPCONST WmfPlaceableFileHeader *placeable, MetafileHeader *header) 3749 { 3750 GpStatus status; 3751 GpMetafile *metafile; 3752 3753 TRACE("(%p,%p,%p)\n", hwmf, placeable, header); 3754 3755 status = GdipCreateMetafileFromWmf(hwmf, FALSE, placeable, &metafile); 3756 if (status == Ok) 3757 { 3758 status = GdipGetMetafileHeaderFromMetafile(metafile, header); 3759 GdipDisposeImage(&metafile->image); 3760 } 3761 return status; 3762 } 3763 3764 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR *filename, 3765 MetafileHeader *header) 3766 { 3767 GpStatus status; 3768 GpMetafile *metafile; 3769 3770 TRACE("(%s,%p)\n", debugstr_w(filename), header); 3771 3772 if (!filename || !header) 3773 return InvalidParameter; 3774 3775 status = GdipCreateMetafileFromFile(filename, &metafile); 3776 if (status == Ok) 3777 { 3778 status = GdipGetMetafileHeaderFromMetafile(metafile, header); 3779 GdipDisposeImage(&metafile->image); 3780 } 3781 return status; 3782 } 3783 3784 GpStatus WINGDIPAPI GdipGetMetafileHeaderFromStream(IStream *stream, 3785 MetafileHeader *header) 3786 { 3787 GpStatus status; 3788 GpMetafile *metafile; 3789 3790 TRACE("(%p,%p)\n", stream, header); 3791 3792 if (!stream || !header) 3793 return InvalidParameter; 3794 3795 status = GdipCreateMetafileFromStream(stream, &metafile); 3796 if (status == Ok) 3797 { 3798 status = GdipGetMetafileHeaderFromMetafile(metafile, header); 3799 GdipDisposeImage(&metafile->image); 3800 } 3801 return status; 3802 } 3803 3804 GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete, 3805 GpMetafile **metafile) 3806 { 3807 GpStatus stat; 3808 MetafileHeader header; 3809 3810 TRACE("(%p,%i,%p)\n", hemf, delete, metafile); 3811 3812 if(!hemf || !metafile) 3813 return InvalidParameter; 3814 3815 stat = GdipGetMetafileHeaderFromEmf(hemf, &header); 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 3845 GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete, 3846 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile) 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 3896 GpStatus WINGDIPAPI GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR *file, 3897 GDIPCONST WmfPlaceableFileHeader * placeable, GpMetafile **metafile) 3898 { 3899 HMETAFILE hmf; 3900 HENHMETAFILE emf; 3901 3902 TRACE("(%s, %p, %p)\n", debugstr_w(file), placeable, metafile); 3903 3904 hmf = GetMetaFileW(file); 3905 if(hmf) 3906 return GdipCreateMetafileFromWmf(hmf, TRUE, placeable, metafile); 3907 3908 emf = GetEnhMetaFileW(file); 3909 if(emf) 3910 return GdipCreateMetafileFromEmf(emf, TRUE, metafile); 3911 3912 return GenericError; 3913 } 3914 3915 GpStatus WINGDIPAPI GdipCreateMetafileFromFile(GDIPCONST WCHAR *file, 3916 GpMetafile **metafile) 3917 { 3918 GpStatus status; 3919 IStream *stream; 3920 3921 TRACE("(%p, %p)\n", file, metafile); 3922 3923 if (!file || !metafile) return InvalidParameter; 3924 3925 *metafile = NULL; 3926 3927 status = GdipCreateStreamOnFile(file, GENERIC_READ, &stream); 3928 if (status == Ok) 3929 { 3930 status = GdipCreateMetafileFromStream(stream, metafile); 3931 IStream_Release(stream); 3932 } 3933 return status; 3934 } 3935 3936 GpStatus WINGDIPAPI GdipCreateMetafileFromStream(IStream *stream, 3937 GpMetafile **metafile) 3938 { 3939 GpStatus stat; 3940 3941 TRACE("%p %p\n", stream, metafile); 3942 3943 stat = GdipLoadImageFromStream(stream, (GpImage **)metafile); 3944 if (stat != Ok) return stat; 3945 3946 if ((*metafile)->image.type != ImageTypeMetafile) 3947 { 3948 GdipDisposeImage(&(*metafile)->image); 3949 *metafile = NULL; 3950 return GenericError; 3951 } 3952 3953 return Ok; 3954 } 3955 3956 GpStatus WINGDIPAPI GdipSetMetafileDownLevelRasterizationLimit(GpMetafile *metafile, 3957 UINT limitDpi) 3958 { 3959 TRACE("(%p,%u)\n", metafile, limitDpi); 3960 3961 return Ok; 3962 } 3963 3964 GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref, 3965 GpMetafile* metafile, BOOL* succ, EmfType emfType, 3966 const WCHAR* description, GpMetafile** out_metafile) 3967 { 3968 static int calls; 3969 3970 TRACE("(%p,%p,%p,%u,%s,%p)\n", ref, metafile, succ, emfType, 3971 debugstr_w(description), out_metafile); 3972 3973 if(!ref || !metafile || !out_metafile || emfType < EmfTypeEmfOnly || emfType > EmfTypeEmfPlusDual) 3974 return InvalidParameter; 3975 3976 if(succ) 3977 *succ = FALSE; 3978 *out_metafile = NULL; 3979 3980 if(!(calls++)) 3981 FIXME("not implemented\n"); 3982 3983 return NotImplemented; 3984 } 3985 3986 GpStatus WINGDIPAPI GdipEmfToWmfBits(HENHMETAFILE hemf, UINT cbData16, 3987 LPBYTE pData16, INT iMapMode, INT eFlags) 3988 { 3989 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf, cbData16, pData16, iMapMode, eFlags); 3990 return NotImplemented; 3991 } 3992 3993 GpStatus WINGDIPAPI GdipRecordMetafileFileName(GDIPCONST WCHAR* fileName, 3994 HDC hdc, EmfType type, GDIPCONST GpRectF *pFrameRect, 3995 MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc, 3996 GpMetafile **metafile) 3997 { 3998 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect, 3999 frameUnit, debugstr_w(desc), metafile); 4000 4001 return NotImplemented; 4002 } 4003 4004 GpStatus WINGDIPAPI GdipRecordMetafileFileNameI(GDIPCONST WCHAR* fileName, HDC hdc, EmfType type, 4005 GDIPCONST GpRect *pFrameRect, MetafileFrameUnit frameUnit, 4006 GDIPCONST WCHAR *desc, GpMetafile **metafile) 4007 { 4008 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect, 4009 frameUnit, debugstr_w(desc), metafile); 4010 4011 return NotImplemented; 4012 } 4013 4014 /***************************************************************************** 4015 * GdipConvertToEmfPlusToFile [GDIPLUS.@] 4016 */ 4017 4018 GpStatus WINGDIPAPI GdipConvertToEmfPlusToFile(const GpGraphics* refGraphics, 4019 GpMetafile* metafile, BOOL* conversionSuccess, 4020 const WCHAR* filename, EmfType emfType, 4021 const WCHAR* description, GpMetafile** out_metafile) 4022 { 4023 FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics, metafile, conversionSuccess, filename, emfType, description, out_metafile); 4024 return NotImplemented; 4025 } 4026 4027 static GpStatus METAFILE_CreateCompressedImageStream(GpImage *image, IStream **stream, DWORD *size) 4028 { 4029 LARGE_INTEGER zero; 4030 STATSTG statstg; 4031 GpStatus stat; 4032 HRESULT hr; 4033 4034 *size = 0; 4035 4036 hr = CreateStreamOnHGlobal(NULL, TRUE, stream); 4037 if (FAILED(hr)) return hresult_to_status(hr); 4038 4039 stat = encode_image_png(image, *stream, NULL); 4040 if (stat != Ok) 4041 { 4042 IStream_Release(*stream); 4043 return stat; 4044 } 4045 4046 hr = IStream_Stat(*stream, &statstg, 1); 4047 if (FAILED(hr)) 4048 { 4049 IStream_Release(*stream); 4050 return hresult_to_status(hr); 4051 } 4052 *size = statstg.cbSize.u.LowPart; 4053 4054 zero.QuadPart = 0; 4055 hr = IStream_Seek(*stream, zero, STREAM_SEEK_SET, NULL); 4056 if (FAILED(hr)) 4057 { 4058 IStream_Release(*stream); 4059 return hresult_to_status(hr); 4060 } 4061 4062 return Ok; 4063 } 4064 4065 static GpStatus METAFILE_FillEmfPlusBitmap(EmfPlusBitmap *record, IStream *stream, DWORD size) 4066 { 4067 HRESULT hr; 4068 4069 record->Width = 0; 4070 record->Height = 0; 4071 record->Stride = 0; 4072 record->PixelFormat = 0; 4073 record->Type = BitmapDataTypeCompressed; 4074 4075 hr = IStream_Read(stream, record->BitmapData, size, NULL); 4076 if (FAILED(hr)) return hresult_to_status(hr); 4077 return Ok; 4078 } 4079 4080 static GpStatus METAFILE_AddImageObject(GpMetafile *metafile, GpImage *image, DWORD *id) 4081 { 4082 EmfPlusObject *object_record; 4083 GpStatus stat; 4084 DWORD size; 4085 4086 *id = -1; 4087 4088 if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual) 4089 return Ok; 4090 4091 if (image->type == ImageTypeBitmap) 4092 { 4093 IStream *stream; 4094 DWORD aligned_size; 4095 4096 stat = METAFILE_CreateCompressedImageStream(image, &stream, &size); 4097 if (stat != Ok) return stat; 4098 aligned_size = (size + 3) & ~3; 4099 4100 stat = METAFILE_AllocateRecord(metafile, 4101 FIELD_OFFSET(EmfPlusObject, ObjectData.image.ImageData.bitmap.BitmapData[aligned_size]), 4102 (void**)&object_record); 4103 if (stat != Ok) 4104 { 4105 IStream_Release(stream); 4106 return stat; 4107 } 4108 memset(object_record->ObjectData.image.ImageData.bitmap.BitmapData + size, 0, aligned_size - size); 4109 4110 *id = METAFILE_AddObjectId(metafile); 4111 object_record->Header.Type = EmfPlusRecordTypeObject; 4112 object_record->Header.Flags = *id | ObjectTypeImage << 8; 4113 object_record->ObjectData.image.Version = VERSION_MAGIC2; 4114 object_record->ObjectData.image.Type = ImageDataTypeBitmap; 4115 4116 stat = METAFILE_FillEmfPlusBitmap(&object_record->ObjectData.image.ImageData.bitmap, stream, size); 4117 IStream_Release(stream); 4118 if (stat != Ok) METAFILE_RemoveLastRecord(metafile, &object_record->Header); 4119 return stat; 4120 } 4121 else if (image->type == ImageTypeMetafile) 4122 { 4123 HENHMETAFILE hemf = ((GpMetafile*)image)->hemf; 4124 EmfPlusMetafile *metafile_record; 4125 4126 if (!hemf) return InvalidParameter; 4127 4128 size = GetEnhMetaFileBits(hemf, 0, NULL); 4129 if (!size) return GenericError; 4130 4131 stat = METAFILE_AllocateRecord(metafile, 4132 FIELD_OFFSET(EmfPlusObject, ObjectData.image.ImageData.metafile.MetafileData[size]), 4133 (void**)&object_record); 4134 if (stat != Ok) return stat; 4135 4136 *id = METAFILE_AddObjectId(metafile); 4137 object_record->Header.Type = EmfPlusRecordTypeObject; 4138 object_record->Header.Flags = *id | ObjectTypeImage << 8; 4139 object_record->ObjectData.image.Version = VERSION_MAGIC2; 4140 object_record->ObjectData.image.Type = ImageDataTypeMetafile; 4141 metafile_record = &object_record->ObjectData.image.ImageData.metafile; 4142 metafile_record->Type = ((GpMetafile*)image)->metafile_type; 4143 metafile_record->MetafileDataSize = size; 4144 if (GetEnhMetaFileBits(hemf, size, metafile_record->MetafileData) != size) 4145 { 4146 METAFILE_RemoveLastRecord(metafile, &object_record->Header); 4147 return GenericError; 4148 } 4149 return Ok; 4150 } 4151 else 4152 { 4153 FIXME("not supported image type (%d)\n", image->type); 4154 return NotImplemented; 4155 } 4156 } 4157 4158 static GpStatus METAFILE_AddImageAttributesObject(GpMetafile *metafile, const GpImageAttributes *attrs, DWORD *id) 4159 { 4160 EmfPlusObject *object_record; 4161 EmfPlusImageAttributes *attrs_record; 4162 GpStatus stat; 4163 4164 *id = -1; 4165 4166 if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual) 4167 return Ok; 4168 4169 if (!attrs) 4170 return Ok; 4171 4172 stat = METAFILE_AllocateRecord(metafile, 4173 FIELD_OFFSET(EmfPlusObject, ObjectData.image_attributes) + sizeof(EmfPlusImageAttributes), 4174 (void**)&object_record); 4175 if (stat != Ok) return stat; 4176 4177 *id = METAFILE_AddObjectId(metafile); 4178 object_record->Header.Type = EmfPlusRecordTypeObject; 4179 object_record->Header.Flags = *id | (ObjectTypeImageAttributes << 8); 4180 attrs_record = &object_record->ObjectData.image_attributes; 4181 attrs_record->Version = VERSION_MAGIC2; 4182 attrs_record->Reserved1 = 0; 4183 attrs_record->WrapMode = attrs->wrap; 4184 attrs_record->ClampColor = attrs->outside_color; 4185 attrs_record->ObjectClamp = attrs->clamp; 4186 attrs_record->Reserved2 = 0; 4187 return Ok; 4188 } 4189 4190 GpStatus METAFILE_DrawImagePointsRect(GpMetafile *metafile, GpImage *image, 4191 GDIPCONST GpPointF *points, INT count, REAL srcx, REAL srcy, REAL srcwidth, 4192 REAL srcheight, GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes, 4193 DrawImageAbort callback, VOID *callbackData) 4194 { 4195 EmfPlusDrawImagePoints *draw_image_record; 4196 DWORD image_id, attributes_id; 4197 GpStatus stat; 4198 4199 if (count != 3) return InvalidParameter; 4200 4201 if (metafile->metafile_type == MetafileTypeEmf) 4202 { 4203 FIXME("MetafileTypeEmf metafiles not supported\n"); 4204 return NotImplemented; 4205 } 4206 else 4207 FIXME("semi-stub\n"); 4208 4209 if (!imageAttributes) 4210 { 4211 stat = METAFILE_AddImageObject(metafile, image, &image_id); 4212 } 4213 else if (image->type == ImageTypeBitmap) 4214 { 4215 INT width = ((GpBitmap*)image)->width; 4216 INT height = ((GpBitmap*)image)->height; 4217 GpGraphics *graphics; 4218 GpBitmap *bitmap; 4219 4220 stat = GdipCreateBitmapFromScan0(width, height, 4221 0, PixelFormat32bppARGB, NULL, &bitmap); 4222 if (stat != Ok) return stat; 4223 4224 stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics); 4225 if (stat != Ok) 4226 { 4227 GdipDisposeImage((GpImage*)bitmap); 4228 return stat; 4229 } 4230 4231 stat = GdipDrawImageRectRectI(graphics, image, 0, 0, width, height, 4232 0, 0, width, height, UnitPixel, imageAttributes, NULL, NULL); 4233 GdipDeleteGraphics(graphics); 4234 if (stat != Ok) 4235 { 4236 GdipDisposeImage((GpImage*)bitmap); 4237 return stat; 4238 } 4239 4240 stat = METAFILE_AddImageObject(metafile, (GpImage*)bitmap, &image_id); 4241 GdipDisposeImage((GpImage*)bitmap); 4242 } 4243 else 4244 { 4245 FIXME("imageAttributes not supported (image type %d)\n", image->type); 4246 return NotImplemented; 4247 } 4248 if (stat != Ok) return stat; 4249 4250 stat = METAFILE_AddImageAttributesObject(metafile, imageAttributes, &attributes_id); 4251 if (stat != Ok) return stat; 4252 4253 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusDrawImagePoints), (void**)&draw_image_record); 4254 if (stat != Ok) return stat; 4255 draw_image_record->Header.Type = EmfPlusRecordTypeDrawImagePoints; 4256 draw_image_record->Header.Flags = image_id; 4257 draw_image_record->ImageAttributesID = attributes_id; 4258 draw_image_record->SrcUnit = UnitPixel; 4259 draw_image_record->SrcRect.X = units_to_pixels(srcx, srcUnit, metafile->image.xres); 4260 draw_image_record->SrcRect.Y = units_to_pixels(srcy, srcUnit, metafile->image.yres); 4261 draw_image_record->SrcRect.Width = units_to_pixels(srcwidth, srcUnit, metafile->image.xres); 4262 draw_image_record->SrcRect.Height = units_to_pixels(srcheight, srcUnit, metafile->image.yres); 4263 draw_image_record->count = 3; 4264 memcpy(draw_image_record->PointData.pointsF, points, 3 * sizeof(*points)); 4265 METAFILE_WriteRecords(metafile); 4266 return Ok; 4267 } 4268 4269 GpStatus METAFILE_AddSimpleProperty(GpMetafile *metafile, SHORT prop, SHORT val) 4270 { 4271 EmfPlusRecordHeader *record; 4272 GpStatus stat; 4273 4274 if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual) 4275 return Ok; 4276 4277 stat = METAFILE_AllocateRecord(metafile, sizeof(*record), (void**)&record); 4278 if (stat != Ok) return stat; 4279 4280 record->Type = prop; 4281 record->Flags = val; 4282 4283 METAFILE_WriteRecords(metafile); 4284 return Ok; 4285 } 4286 4287 static GpStatus METAFILE_AddPathObject(GpMetafile *metafile, GpPath *path, DWORD *id) 4288 { 4289 EmfPlusObject *object_record; 4290 GpStatus stat; 4291 DWORD size; 4292 4293 *id = -1; 4294 if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual) 4295 return Ok; 4296 4297 size = write_path_data(path, NULL); 4298 stat = METAFILE_AllocateRecord(metafile, 4299 FIELD_OFFSET(EmfPlusObject, ObjectData.path) + size, 4300 (void**)&object_record); 4301 if (stat != Ok) return stat; 4302 4303 *id = METAFILE_AddObjectId(metafile); 4304 object_record->Header.Type = EmfPlusRecordTypeObject; 4305 object_record->Header.Flags = *id | ObjectTypePath << 8; 4306 write_path_data(path, &object_record->ObjectData.path); 4307 return Ok; 4308 } 4309 4310 static GpStatus METAFILE_AddPenObject(GpMetafile *metafile, GpPen *pen, DWORD *id) 4311 { 4312 DWORD i, data_flags, pen_data_size, brush_size; 4313 EmfPlusObject *object_record; 4314 EmfPlusPenData *pen_data; 4315 GpStatus stat; 4316 BOOL result; 4317 4318 *id = -1; 4319 if (metafile->metafile_type != MetafileTypeEmfPlusOnly && metafile->metafile_type != MetafileTypeEmfPlusDual) 4320 return Ok; 4321 4322 data_flags = 0; 4323 pen_data_size = FIELD_OFFSET(EmfPlusPenData, OptionalData); 4324 4325 GdipIsMatrixIdentity(&pen->transform, &result); 4326 if (!result) 4327 { 4328 data_flags |= PenDataTransform; 4329 pen_data_size += sizeof(EmfPlusTransformMatrix); 4330 } 4331 if (pen->startcap != LineCapFlat) 4332 { 4333 data_flags |= PenDataStartCap; 4334 pen_data_size += sizeof(DWORD); 4335 } 4336 if (pen->endcap != LineCapFlat) 4337 { 4338 data_flags |= PenDataEndCap; 4339 pen_data_size += sizeof(DWORD); 4340 } 4341 if (pen->join != LineJoinMiter) 4342 { 4343 data_flags |= PenDataJoin; 4344 pen_data_size += sizeof(DWORD); 4345 } 4346 if (pen->miterlimit != 10.0) 4347 { 4348 data_flags |= PenDataMiterLimit; 4349 pen_data_size += sizeof(REAL); 4350 } 4351 if (pen->style != GP_DEFAULT_PENSTYLE) 4352 { 4353 data_flags |= PenDataLineStyle; 4354 pen_data_size += sizeof(DWORD); 4355 } 4356 if (pen->dashcap != DashCapFlat) 4357 { 4358 data_flags |= PenDataDashedLineCap; 4359 pen_data_size += sizeof(DWORD); 4360 } 4361 data_flags |= PenDataDashedLineOffset; 4362 pen_data_size += sizeof(REAL); 4363 if (pen->numdashes) 4364 { 4365 data_flags |= PenDataDashedLine; 4366 pen_data_size += sizeof(DWORD) + pen->numdashes*sizeof(REAL); 4367 } 4368 if (pen->align != PenAlignmentCenter) 4369 { 4370 data_flags |= PenDataNonCenter; 4371 pen_data_size += sizeof(DWORD); 4372 } 4373 /* TODO: Add support for PenDataCompoundLine */ 4374 if (pen->customstart) 4375 { 4376 FIXME("ignoring custom start cup\n"); 4377 } 4378 if (pen->customend) 4379 { 4380 FIXME("ignoring custom end cup\n"); 4381 } 4382 4383 stat = METAFILE_PrepareBrushData(pen->brush, &brush_size); 4384 if (stat != Ok) return stat; 4385 4386 stat = METAFILE_AllocateRecord(metafile, 4387 FIELD_OFFSET(EmfPlusObject, ObjectData.pen.data) + pen_data_size + brush_size, 4388 (void**)&object_record); 4389 if (stat != Ok) return stat; 4390 4391 *id = METAFILE_AddObjectId(metafile); 4392 object_record->Header.Type = EmfPlusRecordTypeObject; 4393 object_record->Header.Flags = *id | ObjectTypePen << 8; 4394 object_record->ObjectData.pen.Version = VERSION_MAGIC2; 4395 object_record->ObjectData.pen.Type = 0; 4396 4397 pen_data = (EmfPlusPenData*)object_record->ObjectData.pen.data; 4398 pen_data->PenDataFlags = data_flags; 4399 pen_data->PenUnit = pen->unit; 4400 pen_data->PenWidth = pen->width; 4401 4402 i = 0; 4403 if (data_flags & PenDataTransform) 4404 { 4405 EmfPlusTransformMatrix *m = (EmfPlusTransformMatrix*)(pen_data->OptionalData + i); 4406 memcpy(m, &pen->transform, sizeof(*m)); 4407 i += sizeof(EmfPlusTransformMatrix); 4408 } 4409 if (data_flags & PenDataStartCap) 4410 { 4411 *(DWORD*)(pen_data->OptionalData + i) = pen->startcap; 4412 i += sizeof(DWORD); 4413 } 4414 if (data_flags & PenDataEndCap) 4415 { 4416 *(DWORD*)(pen_data->OptionalData + i) = pen->endcap; 4417 i += sizeof(DWORD); 4418 } 4419 if (data_flags & PenDataJoin) 4420 { 4421 *(DWORD*)(pen_data->OptionalData + i) = pen->join; 4422 i += sizeof(DWORD); 4423 } 4424 if (data_flags & PenDataMiterLimit) 4425 { 4426 *(REAL*)(pen_data->OptionalData + i) = pen->miterlimit; 4427 i += sizeof(REAL); 4428 } 4429 if (data_flags & PenDataLineStyle) 4430 { 4431 switch (pen->style & PS_STYLE_MASK) 4432 { 4433 case PS_SOLID: *(DWORD*)(pen_data->OptionalData + i) = LineStyleSolid; break; 4434 case PS_DASH: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDash; break; 4435 case PS_DOT: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDot; break; 4436 case PS_DASHDOT: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDashDot; break; 4437 case PS_DASHDOTDOT: *(DWORD*)(pen_data->OptionalData + i) = LineStyleDashDotDot; break; 4438 default: *(DWORD*)(pen_data->OptionalData + i) = LineStyleCustom; break; 4439 } 4440 i += sizeof(DWORD); 4441 } 4442 if (data_flags & PenDataDashedLineCap) 4443 { 4444 *(DWORD*)(pen_data->OptionalData + i) = pen->dashcap; 4445 i += sizeof(DWORD); 4446 } 4447 if (data_flags & PenDataDashedLineOffset) 4448 { 4449 *(REAL*)(pen_data->OptionalData + i) = pen->offset; 4450 i += sizeof(REAL); 4451 } 4452 if (data_flags & PenDataDashedLine) 4453 { 4454 int j; 4455 4456 *(DWORD*)(pen_data->OptionalData + i) = pen->numdashes; 4457 i += sizeof(DWORD); 4458 4459 for (j=0; j<pen->numdashes; j++) 4460 { 4461 *(REAL*)(pen_data->OptionalData + i) = pen->dashes[j]; 4462 i += sizeof(REAL); 4463 } 4464 } 4465 if (data_flags & PenDataNonCenter) 4466 { 4467 *(REAL*)(pen_data->OptionalData + i) = pen->align; 4468 i += sizeof(DWORD); 4469 } 4470 4471 METAFILE_FillBrushData(pen->brush, 4472 (EmfPlusBrush*)(object_record->ObjectData.pen.data + pen_data_size)); 4473 return Ok; 4474 } 4475 4476 GpStatus METAFILE_DrawPath(GpMetafile *metafile, GpPen *pen, GpPath *path) 4477 { 4478 EmfPlusDrawPath *draw_path_record; 4479 DWORD path_id; 4480 DWORD pen_id; 4481 GpStatus stat; 4482 4483 if (metafile->metafile_type == MetafileTypeEmf) 4484 { 4485 FIXME("stub!\n"); 4486 return NotImplemented; 4487 } 4488 4489 stat = METAFILE_AddPenObject(metafile, pen, &pen_id); 4490 if (stat != Ok) return stat; 4491 4492 stat = METAFILE_AddPathObject(metafile, path, &path_id); 4493 if (stat != Ok) return stat; 4494 4495 stat = METAFILE_AllocateRecord(metafile, sizeof(EmfPlusDrawPath), (void**)&draw_path_record); 4496 if (stat != Ok) return stat; 4497 draw_path_record->Header.Type = EmfPlusRecordTypeDrawPath; 4498 draw_path_record->Header.Flags = path_id; 4499 draw_path_record->PenId = pen_id; 4500 4501 METAFILE_WriteRecords(metafile); 4502 return Ok; 4503 } 4504 4505 GpStatus METAFILE_FillPath(GpMetafile *metafile, GpBrush *brush, GpPath *path) 4506 { 4507 EmfPlusFillPath *fill_path_record; 4508 DWORD brush_id = -1, path_id; 4509 BOOL inline_color; 4510 GpStatus stat; 4511 4512 if (metafile->metafile_type == MetafileTypeEmf) 4513 { 4514 FIXME("stub!\n"); 4515 return NotImplemented; 4516 } 4517 4518 inline_color = brush->bt == BrushTypeSolidColor; 4519 if (!inline_color) 4520 { 4521 stat = METAFILE_AddBrushObject(metafile, brush, &brush_id); 4522 if (stat != Ok) return stat; 4523 } 4524 4525 stat = METAFILE_AddPathObject(metafile, path, &path_id); 4526 if (stat != Ok) return stat; 4527 4528 stat = METAFILE_AllocateRecord(metafile, 4529 sizeof(EmfPlusFillPath), (void**)&fill_path_record); 4530 if (stat != Ok) return stat; 4531 fill_path_record->Header.Type = EmfPlusRecordTypeFillPath; 4532 if (inline_color) 4533 { 4534 fill_path_record->Header.Flags = 0x8000 | path_id; 4535 fill_path_record->data.Color = ((GpSolidFill *)brush)->color; 4536 } 4537 else 4538 { 4539 fill_path_record->Header.Flags = path_id; 4540 fill_path_record->data.BrushId = brush_id; 4541 } 4542 4543 METAFILE_WriteRecords(metafile); 4544 return Ok; 4545 } 4546