Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6762 lines
210 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1999 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * MetaFile.cpp
  8. *
  9. * Abstract:
  10. *
  11. * Metafile object handling
  12. *
  13. * Created:
  14. *
  15. * 4/14/1999 DCurtis
  16. *
  17. \**************************************************************************/
  18. #include "precomp.hpp"
  19. #include "MetaWmf.hpp"
  20. #define GDIP_TRANSPARENT_COLOR_KEY 0xAA0D0B0C
  21. #define GDIP_WMF_PLACEABLEKEY 0x9AC6CDD7 // for Placeable WMFs
  22. #define GDIP_DO_CALLBACK_MASK 0x00000003 // when to do callback
  23. // Metafile constants not in Windows.h
  24. #define METAVERSION300 0x0300
  25. #define METAVERSION100 0x0100
  26. #define MEMORYMETAFILE 1
  27. #define DISKMETAFILE 2
  28. typedef VOID (EmfPlusRecordPlay::*PLAYRECORDFUNC)(MetafilePlayer * player, EmfPlusRecordType recordType, UINT flags, UINT dataSize) const;
  29. PLAYRECORDFUNC RecordPlayFuncs[];
  30. /**************************************************************************\
  31. *
  32. * Function Description:
  33. *
  34. * If the points were stored as 16-bit points, then convert them back to
  35. * REAL points. Otherwise, just return convert the point data pointer
  36. * to a REAL point pointer and return.
  37. *
  38. * Arguments:
  39. *
  40. * [IN] pointData - the point data that was recorded
  41. * [IN] count - the number of points
  42. * [IN] flags - says if the point data is 16-bit points or not
  43. * [IN] bufferSize - the size of the buffer
  44. * [IN/OUT] buffer - for converting back to REAL points
  45. * [IN/OUT] allocedBuffer - if buffer not big enough, alloc new one here
  46. *
  47. * Return Value:
  48. *
  49. * GpPointF * - the REAL points to play back
  50. *
  51. * Created:
  52. *
  53. * 6/15/1999 DCurtis
  54. *
  55. \**************************************************************************/
  56. GpPointF *
  57. GetPointsForPlayback(
  58. const BYTE * pointData,
  59. UINT pointDataSize,
  60. INT count,
  61. INT flags,
  62. UINT bufferSize,
  63. BYTE * buffer,
  64. BYTE * & allocedBuffer
  65. )
  66. {
  67. GpPointF * points = NULL;
  68. if (count > 0)
  69. {
  70. if ((flags & GDIP_EPRFLAGS_COMPRESSED) != 0)
  71. {
  72. if (pointDataSize >= (sizeof(GpPoint16) * count))
  73. {
  74. UINT sizePoints = count * sizeof(GpPointF);
  75. if (sizePoints <= bufferSize)
  76. {
  77. points = reinterpret_cast<GpPointF *>(buffer);
  78. }
  79. else
  80. {
  81. if ((allocedBuffer = new BYTE[sizePoints]) == NULL)
  82. {
  83. return NULL;
  84. }
  85. points = reinterpret_cast<GpPointF *>(allocedBuffer);
  86. }
  87. const GpPoint16 * points16 =
  88. reinterpret_cast<const GpPoint16 *>(pointData);
  89. do
  90. {
  91. count--;
  92. points[count].X = points16[count].X;
  93. points[count].Y = points16[count].Y;
  94. } while (count > 0);
  95. }
  96. else
  97. {
  98. WARNING(("pointDataSize is too small"));
  99. }
  100. }
  101. else if (pointDataSize >= (sizeof(GpPointF) * count))
  102. {
  103. points = (GpPointF *)(pointData);
  104. }
  105. else
  106. {
  107. WARNING(("pointDataSize is too small"));
  108. }
  109. }
  110. return points;
  111. }
  112. /**************************************************************************\
  113. *
  114. * Function Description:
  115. *
  116. * If the rects were stored as 16-bit rects, then convert them back to
  117. * REAL rects. Otherwise, just return convert the rect data pointer
  118. * to a REAL rect pointer and return.
  119. *
  120. * Arguments:
  121. *
  122. * [IN] rectData - the rect data that was recorded
  123. * [IN] count - the number of rects
  124. * [IN] flags - says if the point data is 16-bit rects or not
  125. * [IN] bufferSize - the size of the buffer
  126. * [IN/OUT] buffer - for converting back to REAL rects
  127. * [IN/OUT] allocedBuffer - if buffer not big enough, alloc new one here
  128. *
  129. * Return Value:
  130. *
  131. * GpPointF * - the REAL points to play back
  132. *
  133. * Created:
  134. *
  135. * 6/15/1999 DCurtis
  136. *
  137. \**************************************************************************/
  138. GpRectF *
  139. GetRectsForPlayback(
  140. const BYTE * rectData,
  141. UINT rectDataSize,
  142. INT count,
  143. INT flags,
  144. UINT bufferSize,
  145. BYTE * buffer,
  146. BYTE * & allocedBuffer
  147. )
  148. {
  149. GpRectF * rects = NULL;
  150. if (count > 0)
  151. {
  152. if ((flags & GDIP_EPRFLAGS_COMPRESSED) != 0)
  153. {
  154. if (rectDataSize >= (sizeof(GpRect16) * count))
  155. {
  156. UINT sizeRects = count * sizeof(GpRectF);
  157. if (sizeRects <= bufferSize)
  158. {
  159. rects = reinterpret_cast<GpRectF *>(buffer);
  160. }
  161. else
  162. {
  163. if ((allocedBuffer = new BYTE[sizeRects]) == NULL)
  164. {
  165. return NULL;
  166. }
  167. rects = reinterpret_cast<GpRectF *>(allocedBuffer);
  168. }
  169. const GpRect16 * rects16 =
  170. reinterpret_cast<const GpRect16 *>(rectData);
  171. do
  172. {
  173. count--;
  174. rects[count].X = rects16[count].X;
  175. rects[count].Y = rects16[count].Y;
  176. rects[count].Width = rects16[count].Width;
  177. rects[count].Height = rects16[count].Height;
  178. } while (count > 0);
  179. }
  180. else
  181. {
  182. WARNING(("rectDataSize is too small"));
  183. }
  184. }
  185. else if (rectDataSize >= (sizeof(GpRectF) * count))
  186. {
  187. rects = (GpRectF *)(rectData);
  188. }
  189. else
  190. {
  191. WARNING(("rectDataSize is too small"));
  192. }
  193. }
  194. return rects;
  195. }
  196. inline INT16
  197. GetWmfPlaceableCheckSum(
  198. const WmfPlaceableFileHeader * wmfPlaceableFileHeader
  199. )
  200. {
  201. const INT16 * headerWords = (const INT16 *)wmfPlaceableFileHeader;
  202. INT16 checkSum = *headerWords++;
  203. for (INT i = 9; i > 0; i--)
  204. {
  205. checkSum ^= *headerWords++;
  206. }
  207. return checkSum;
  208. }
  209. inline BOOL
  210. WmfPlaceableHeaderIsValid(
  211. const WmfPlaceableFileHeader * wmfPlaceableFileHeader
  212. )
  213. {
  214. ASSERT(wmfPlaceableFileHeader != NULL);
  215. return ((wmfPlaceableFileHeader->Key == GDIP_WMF_PLACEABLEKEY) &&
  216. (wmfPlaceableFileHeader->Checksum == GetWmfPlaceableCheckSum(wmfPlaceableFileHeader)) &&
  217. (wmfPlaceableFileHeader->BoundingBox.Left !=
  218. wmfPlaceableFileHeader->BoundingBox.Right) &&
  219. (wmfPlaceableFileHeader->BoundingBox.Top !=
  220. wmfPlaceableFileHeader->BoundingBox.Bottom));
  221. }
  222. inline BOOL
  223. WmfHeaderIsValid(
  224. const METAHEADER * wmfHeader
  225. )
  226. {
  227. return (((wmfHeader->mtType == MEMORYMETAFILE) ||
  228. (wmfHeader->mtType == DISKMETAFILE)) &&
  229. (wmfHeader->mtHeaderSize == (sizeof(METAHEADER)/sizeof(WORD))) &&
  230. ((wmfHeader->mtVersion == METAVERSION300) ||
  231. (wmfHeader->mtVersion ==METAVERSION100)));
  232. }
  233. VOID
  234. Init32BppDibToTransparent(
  235. UINT32 * bits,
  236. UINT numPixels
  237. );
  238. GpStatus
  239. Draw32BppDib(
  240. GpGraphics * g,
  241. UINT32 * bits,
  242. INT width,
  243. INT height,
  244. const GpRectF & destRect,
  245. REAL dpi,
  246. BOOL compareAlpha
  247. );
  248. extern "C"
  249. BOOL CALLBACK
  250. GdipPlayMetafileRecordCallback(
  251. EmfPlusRecordType recordType,
  252. UINT recordFlags,
  253. UINT recordDataSize,
  254. const BYTE * recordData,
  255. VOID * callbackData // player
  256. );
  257. // This method (defined below) enumerates/plays EMF+ comment records and also
  258. // plays down-level GDI records, when appropriate.
  259. extern "C"
  260. int CALLBACK
  261. EnumEmfWithDownLevel(
  262. HDC hdc,
  263. HANDLETABLE FAR * gdiHandleTable,
  264. CONST ENHMETARECORD * emfRecord,
  265. int numHandles,
  266. LPARAM play
  267. );
  268. extern "C"
  269. int CALLBACK
  270. EnumEmfDownLevel(
  271. HDC hdc,
  272. HANDLETABLE FAR * gdiHandleTable,
  273. CONST ENHMETARECORD * emfRecord,
  274. int numHandles,
  275. LPARAM play
  276. );
  277. extern "C"
  278. int CALLBACK
  279. EnumEmfToStream(
  280. HDC hdc,
  281. HANDLETABLE FAR * gdiHandleTable,
  282. CONST ENHMETARECORD * emfRecord,
  283. int numHandles,
  284. LPARAM stream
  285. );
  286. // Separate this out so we can initialize it to 0 all at once
  287. class MetafilePlayerBuffers
  288. {
  289. protected:
  290. BYTE RecordBuffer [GDIP_METAFILE_BUFFERSIZE];
  291. BYTE PointsBuffer [GDIP_METAFILE_BUFFERSIZE];
  292. GpObject * ObjectList [GDIP_MAX_OBJECTS];
  293. INT MemberStack [GDIP_SAVE_STACK_SIZE];
  294. GpObject * BackupObject [ObjectTypeMax - ObjectTypeMin + 1];
  295. };
  296. class MetafilePlayer : public MetafilePlayerBuffers
  297. {
  298. protected:
  299. BOOL Valid;
  300. UINT32 MaxStackSize;
  301. INT * Stack;
  302. IStream * Stream;
  303. BYTE * RecordAllocedBuffer;
  304. BYTE * PointsAllocedBuffer;
  305. GpSolidFill SolidBrush;
  306. BYTE * ConcatRecordBuffer;
  307. INT ConcatRecordBufferSize;
  308. BYTE * ConcatRecord;
  309. INT ConcatRecordTotalSize;
  310. INT ConcatRecordSize;
  311. UINT ConcatRecordFlags;
  312. InterpolationMode Interpolation;
  313. public:
  314. GpGraphics * Graphics; // The graphics we're playing to
  315. BOOL PlayEMFRecords; // TRUE when we see GetDC record
  316. HDC Hdc; // For playing downlevel records
  317. GpMatrix PreContainerMatrix; // Xform to use for down-level
  318. UINT32 * BitmapBits;
  319. INT BitmapWidth;
  320. INT BitmapHeight;
  321. GpRectF BitmapDestRect;
  322. REAL BitmapDpi;
  323. GpRecolor * Recolor;
  324. MfEnumState * MfState;
  325. ColorAdjustType AdjustType;
  326. UINT MultiFormatSection;
  327. UINT CurFormatSection;
  328. BOOL PlayMultiFormatSection;
  329. EnumerateMetafileProc EnumerateCallback; // for metafile enumeration
  330. VOID * CallbackData; // for metafile enumeration
  331. BOOL EnumerateAborted;
  332. DrawImageAbort DrawImageCallback;
  333. VOID* DrawImageCallbackData;
  334. INT DrawImageCallbackCount;
  335. BOOL RopUsed;
  336. public:
  337. // stream is NULL if using GDI to enumerate the hEmf.
  338. MetafilePlayer(
  339. GpGraphics * g,
  340. UINT maxStackSize,
  341. GpRecolor * recolor,
  342. ColorAdjustType adjustType,
  343. EnumerateMetafileProc enumerateCallback,
  344. VOID * callbackData,
  345. DrawImageAbort drawImageCallback,
  346. VOID* drawImageCallbackData
  347. );
  348. ~MetafilePlayer();
  349. BOOL IsValid() const { return Valid; }
  350. VOID
  351. PrepareToPlay(
  352. GpGraphics * g,
  353. GpRecolor * recolor,
  354. ColorAdjustType adjustType,
  355. EnumerateMetafileProc enumerateCallback,
  356. VOID * callbackData,
  357. DrawImageAbort drawImageCallback,
  358. VOID* drawImageCallbackData
  359. );
  360. VOID DonePlaying();
  361. VOID InitForDownLevel()
  362. {
  363. if (Hdc == NULL)
  364. {
  365. Hdc = Graphics->GetHdc();
  366. ASSERT(Hdc != NULL);
  367. if (BitmapBits != NULL)
  368. {
  369. Init32BppDibToTransparent(BitmapBits, BitmapWidth*BitmapHeight);
  370. MfState->ResetRopUsed();
  371. }
  372. }
  373. }
  374. VOID DoneWithDownLevel()
  375. {
  376. PlayEMFRecords = FALSE;
  377. if (Hdc != NULL)
  378. {
  379. Graphics->ReleaseHdc(Hdc);
  380. Hdc = NULL;
  381. if (BitmapBits != NULL)
  382. {
  383. // This is a hack to get around the problem that we are
  384. // inside a container, but we don't want to be in the
  385. // container for drawing the down-level records. We also
  386. // don't want any transforms inside the EMF+ to affect the
  387. // down-level records.
  388. // We should probably do something about the clipping too,
  389. // but for now, we won't worry about it.
  390. GpMatrix saveWorldToDevice = Graphics->Context->WorldToDevice;
  391. Graphics->Context->WorldToDevice = PreContainerMatrix;
  392. // Don't use NearestNeighbor to draw the rotated metafile --
  393. // it looks bad, and doesn't really save any time.
  394. InterpolationMode saveInterpolationMode = Graphics->Context->FilterType;
  395. if (saveInterpolationMode == InterpolationModeNearestNeighbor)
  396. {
  397. Graphics->Context->FilterType = InterpolationModeBilinear;
  398. }
  399. Graphics->Context->InverseOk = FALSE;
  400. Draw32BppDib(Graphics, BitmapBits, BitmapWidth, BitmapHeight,
  401. BitmapDestRect, BitmapDpi, !RopUsed);
  402. // restore the interpolation mode (in case we changed it).
  403. Graphics->Context->FilterType = saveInterpolationMode;
  404. Graphics->Context->WorldToDevice = saveWorldToDevice;
  405. Graphics->Context->InverseOk = FALSE;
  406. }
  407. }
  408. }
  409. // returns 0 to abort playback, 1 to continue
  410. INT
  411. ProcessDrawImageCallback(
  412. BOOL forceCallback
  413. )
  414. {
  415. if (DrawImageCallback)
  416. {
  417. // A DrawImage record could have already been aborted, so
  418. // we should immediately return.
  419. if (EnumerateAborted)
  420. {
  421. return 0; // abort
  422. }
  423. if (forceCallback)
  424. {
  425. DrawImageCallbackCount = 0;
  426. }
  427. if ((DrawImageCallbackCount++ & GDIP_DO_CALLBACK_MASK) == 0)
  428. {
  429. // The callback returns TRUE to abort, FALSE to continue.
  430. return ((*DrawImageCallback)(DrawImageCallbackData)) ? 0 : 1;
  431. }
  432. }
  433. return 1;
  434. }
  435. GpPointF *
  436. GetPoints(
  437. const BYTE * pointData,
  438. UINT pointDataSize,
  439. INT count,
  440. INT flags
  441. )
  442. {
  443. return GetPointsForPlayback(pointData, pointDataSize, count, flags,
  444. GDIP_METAFILE_BUFFERSIZE,
  445. PointsBuffer, PointsAllocedBuffer);
  446. }
  447. GpRectF *
  448. GetRects(
  449. const BYTE * rectData,
  450. UINT rectDataSize,
  451. INT count,
  452. INT flags
  453. )
  454. {
  455. return GetRectsForPlayback(rectData, rectDataSize, count, flags,
  456. GDIP_METAFILE_BUFFERSIZE,
  457. PointsBuffer, PointsAllocedBuffer);
  458. }
  459. GpObject *
  460. GetObject(
  461. UINT metaObjectId,
  462. ObjectType objectType
  463. );
  464. GpBrush *
  465. GetBrush(
  466. UINT brushValue,
  467. INT flags
  468. );
  469. GpString *
  470. GetString(
  471. const BYTE * stringData,
  472. INT len,
  473. INT flags
  474. )
  475. {
  476. // !!! convert back from 8-bit to 16-bit chars if necessary
  477. return new GpString((const WCHAR *)stringData, len);
  478. }
  479. VOID
  480. AddObject(
  481. INT flags,
  482. const BYTE * data,
  483. UINT dataSize
  484. );
  485. VOID
  486. NewSave(
  487. UINT stackIndex,
  488. INT saveID
  489. );
  490. INT
  491. GetSaveID(
  492. UINT stackIndex
  493. );
  494. VOID FreePointsBuffer()
  495. {
  496. if (PointsAllocedBuffer != NULL)
  497. {
  498. delete [] PointsAllocedBuffer;
  499. PointsAllocedBuffer = NULL;
  500. }
  501. }
  502. GpStatus
  503. ConcatenateRecords(
  504. UINT recordFlags,
  505. INT recordDataSize,
  506. const BYTE * recordData
  507. );
  508. GpStatus
  509. EnumerateEmfPlusRecords(
  510. UINT dataSize, // size of EMF+ record data
  511. const BYTE * data // pointer to the EMF+ record data
  512. );
  513. GpStatus
  514. EnumerateEmfRecords(
  515. HDC hdc,
  516. HENHMETAFILE hEmf,
  517. const RECT * dest,
  518. const RECT * deviceRect,
  519. ENHMFENUMPROC enumProc
  520. );
  521. GpStatus
  522. EnumerateWmfRecords(
  523. HDC hdc,
  524. HMETAFILE hWmf,
  525. const RECT * dstRect,
  526. const RECT * deviceRect
  527. );
  528. };
  529. VOID
  530. MetafilePlayer::PrepareToPlay(
  531. GpGraphics * g,
  532. GpRecolor * recolor,
  533. ColorAdjustType adjustType,
  534. EnumerateMetafileProc enumerateCallback,
  535. VOID * callbackData,
  536. DrawImageAbort drawImageCallback,
  537. VOID* drawImageCallbackData
  538. )
  539. {
  540. ASSERT(g != NULL);
  541. GpMemset(Stack, 0, MaxStackSize * sizeof (INT));
  542. // Initialize all the buffers to 0
  543. MetafilePlayerBuffers * buffers = this;
  544. GpMemset(buffers, 0, sizeof(MetafilePlayerBuffers));
  545. PlayEMFRecords = FALSE;
  546. Hdc = NULL;
  547. Graphics = g;
  548. BitmapBits = NULL;
  549. BitmapWidth = 0;
  550. BitmapHeight = 0;
  551. Interpolation = g->GetInterpolationMode();
  552. Recolor = recolor;
  553. AdjustType = adjustType;
  554. MultiFormatSection = 0;
  555. CurFormatSection = 0;
  556. PlayMultiFormatSection = TRUE;
  557. EnumerateAborted = FALSE;
  558. RopUsed = FALSE;
  559. if (enumerateCallback == NULL)
  560. {
  561. EnumerateCallback = GdipPlayMetafileRecordCallback;
  562. CallbackData = this;
  563. }
  564. else
  565. {
  566. EnumerateCallback = enumerateCallback;
  567. CallbackData = callbackData;
  568. }
  569. DrawImageCallback = drawImageCallback;
  570. DrawImageCallbackData = drawImageCallbackData;
  571. DrawImageCallbackCount = 0;
  572. ConcatRecord = NULL;
  573. ConcatRecordTotalSize = 0;
  574. ConcatRecordSize = 0;
  575. ConcatRecordFlags = 0;
  576. // We need this for rendering GDI records within a GDI+ file.
  577. // We have to do it before starting the container.
  578. g->GetWorldToDeviceTransform(&(this->PreContainerMatrix));
  579. }
  580. MetafilePlayer::MetafilePlayer(
  581. GpGraphics * g,
  582. UINT maxStackSize,
  583. GpRecolor * recolor,
  584. ColorAdjustType adjustType,
  585. EnumerateMetafileProc enumerateCallback,
  586. VOID * callbackData,
  587. DrawImageAbort drawImageCallback,
  588. VOID* drawImageCallbackData
  589. )
  590. {
  591. Valid = FALSE;
  592. MaxStackSize = GDIP_SAVE_STACK_SIZE;
  593. Stack = MemberStack;
  594. if (maxStackSize > GDIP_SAVE_STACK_SIZE)
  595. {
  596. Stack = new INT[maxStackSize];
  597. if (Stack == NULL)
  598. {
  599. return; // Valid is FALSE
  600. }
  601. MaxStackSize = maxStackSize;
  602. }
  603. RecordAllocedBuffer = NULL;
  604. PointsAllocedBuffer = NULL;
  605. Recolor = NULL;
  606. MfState = NULL;
  607. ConcatRecordBuffer = NULL;
  608. ConcatRecordBufferSize = 0;
  609. PrepareToPlay(g, recolor, adjustType, enumerateCallback, callbackData,
  610. drawImageCallback, drawImageCallbackData
  611. );
  612. Valid = TRUE;
  613. }
  614. MetafilePlayer::~MetafilePlayer()
  615. {
  616. if (Stack != MemberStack)
  617. {
  618. delete [] Stack;
  619. }
  620. if (ConcatRecordBuffer)
  621. {
  622. GpFree(ConcatRecordBuffer);
  623. }
  624. }
  625. inline bool
  626. ObjectTypeIsText(ObjectType type)
  627. {
  628. return type == ObjectTypeFont
  629. || type == ObjectTypeStringFormat;
  630. }
  631. VOID
  632. MetafilePlayer::DonePlaying()
  633. {
  634. INT i;
  635. i = 0;
  636. do
  637. {
  638. GpObject* pObject = ObjectList[i];
  639. if (pObject)
  640. {
  641. GlobalTextLockConditional(ObjectTypeIsText(pObject->GetObjectType()));
  642. delete pObject;
  643. }
  644. } while ((++i) < GDIP_MAX_OBJECTS);
  645. }
  646. GpObject *
  647. MetafilePlayer::GetObject(
  648. UINT metaObjectId,
  649. ObjectType objectType
  650. )
  651. {
  652. GpObject * object = NULL;
  653. // If the object was an unused optional parameter of some kind
  654. // it knows how to handle a NULL object, so we return that.
  655. if(metaObjectId == GDIP_OBJECTID_NONE)
  656. {
  657. return NULL;
  658. }
  659. ASSERT(metaObjectId < GDIP_MAX_OBJECTS);
  660. if (metaObjectId < GDIP_MAX_OBJECTS)
  661. {
  662. object = ObjectList[metaObjectId];
  663. ASSERT (object != NULL);
  664. if (object != NULL)
  665. {
  666. ASSERT(object->GetObjectType() == objectType);
  667. if (object->GetObjectType() == objectType)
  668. {
  669. return object;
  670. }
  671. }
  672. }
  673. if (ObjectTypeIsValid(objectType))
  674. {
  675. return BackupObject[objectType - ObjectTypeMin];
  676. }
  677. return NULL;
  678. }
  679. GpBrush *
  680. MetafilePlayer::GetBrush(
  681. UINT brushValue,
  682. INT flags
  683. )
  684. {
  685. GpBrush * brush;
  686. if ((flags & GDIP_EPRFLAGS_SOLIDCOLOR) != 0)
  687. {
  688. brush = &SolidBrush;
  689. (reinterpret_cast<GpSolidFill *>(brush))->SetColor(GpColor(brushValue));
  690. if (Recolor != NULL)
  691. {
  692. brush->ColorAdjust(Recolor, AdjustType);
  693. }
  694. }
  695. else
  696. {
  697. brush = (GpBrush *)this->GetObject(brushValue, ObjectTypeBrush);
  698. }
  699. return brush;
  700. }
  701. VOID
  702. MetafilePlayer::AddObject(
  703. INT flags,
  704. const BYTE * data,
  705. UINT dataSize
  706. )
  707. {
  708. ObjectType objectType = GetObjectType(flags);
  709. UINT objectId = GetMetaObjectId(flags);
  710. GpObject ** objectList = ObjectList;
  711. ASSERT((objectId < GDIP_MAX_OBJECTS) || (objectId == GDIP_BACKUP_OBJECTID));
  712. GlobalTextLockConditional(ObjectTypeIsText(objectType));
  713. // First see if this is a backup object
  714. if ((objectId == GDIP_BACKUP_OBJECTID) &&
  715. ObjectTypeIsValid(objectType))
  716. {
  717. objectList = BackupObject;
  718. objectId = objectType - ObjectTypeMin;
  719. }
  720. if (objectId < GDIP_MAX_OBJECTS)
  721. {
  722. GpObject * object = objectList[objectId];
  723. if (object != NULL)
  724. {
  725. object->Dispose();
  726. }
  727. object = GpObject::Factory(objectType, (const ObjectData *)data, dataSize);
  728. if (object)
  729. {
  730. if (object->SetData(data, dataSize) == Ok)
  731. {
  732. if (Recolor != NULL)
  733. {
  734. object->ColorAdjust(Recolor, AdjustType);
  735. }
  736. if (!object->IsValid())
  737. {
  738. WARNING(("Object is not valid"));
  739. object->Dispose();
  740. object = NULL;
  741. }
  742. }
  743. else
  744. {
  745. WARNING(("Object Set Data failed"));
  746. object->Dispose();
  747. object = NULL;
  748. }
  749. }
  750. else
  751. {
  752. WARNING(("Object Factory failed to create object"));
  753. }
  754. objectList[objectId] = object;
  755. }
  756. }
  757. VOID
  758. MetafilePlayer::NewSave(
  759. UINT stackIndex,
  760. INT saveID
  761. )
  762. {
  763. if (stackIndex >= MaxStackSize)
  764. {
  765. UINT maxStackSize = MaxStackSize + GDIP_SAVE_STACK_SIZE;
  766. if (stackIndex >= maxStackSize)
  767. {
  768. ASSERT (0);
  769. return;
  770. }
  771. INT * newStack = new INT[maxStackSize];
  772. if (newStack == NULL)
  773. {
  774. return;
  775. }
  776. GpMemcpy(newStack, Stack, MaxStackSize * sizeof(INT));
  777. GpMemset(newStack + MaxStackSize, 0,
  778. GDIP_SAVE_STACK_SIZE * sizeof (INT));
  779. MaxStackSize = maxStackSize;
  780. if (Stack != MemberStack)
  781. {
  782. delete [] Stack;
  783. }
  784. Stack = newStack;
  785. }
  786. Stack[stackIndex] = saveID;
  787. }
  788. INT
  789. MetafilePlayer::GetSaveID(
  790. UINT stackIndex
  791. )
  792. {
  793. ASSERT(stackIndex < MaxStackSize);
  794. INT saveID = 0;
  795. if (stackIndex < MaxStackSize)
  796. {
  797. saveID = Stack[stackIndex];
  798. Stack[stackIndex] = 0;
  799. }
  800. return saveID;
  801. }
  802. GpStatus
  803. MetafilePlayer::ConcatenateRecords(
  804. UINT recordFlags,
  805. INT recordDataSize,
  806. const BYTE * recordData
  807. )
  808. {
  809. ASSERT((recordData != NULL) && (recordDataSize > sizeof(INT32)));
  810. GpStatus status = Ok;
  811. if ((recordFlags & GDIP_EPRFLAGS_CONTINUEOBJECT) != 0)
  812. {
  813. INT dataSizeLeft = ((const INT32 *)recordData)[0];
  814. recordData += sizeof(INT32);
  815. recordDataSize -= sizeof(INT32);
  816. if (dataSizeLeft <= recordDataSize)
  817. {
  818. WARNING(("Total Data Size incorrect"));
  819. status = InvalidParameter;
  820. goto DoneWithRecord;
  821. }
  822. recordFlags &= ~GDIP_EPRFLAGS_CONTINUEOBJECT;
  823. if (ConcatRecord == NULL)
  824. {
  825. if ((ConcatRecordBuffer == NULL) ||
  826. (ConcatRecordBufferSize < dataSizeLeft))
  827. {
  828. GpFree(ConcatRecordBuffer);
  829. ConcatRecordBuffer = (BYTE *)GpMalloc(dataSizeLeft);
  830. if (ConcatRecordBuffer == NULL)
  831. {
  832. ConcatRecordBufferSize = 0;
  833. return OutOfMemory;
  834. }
  835. ConcatRecordBufferSize = dataSizeLeft;
  836. }
  837. ConcatRecord = ConcatRecordBuffer;
  838. ConcatRecordTotalSize = dataSizeLeft;
  839. ConcatRecordSize = 0;
  840. ConcatRecordFlags = recordFlags;
  841. goto SkipContinueChecks;
  842. }
  843. }
  844. if (recordFlags != ConcatRecordFlags)
  845. {
  846. WARNING(("Record headers do not match"));
  847. status = InvalidParameter;
  848. goto DoneWithRecord;
  849. }
  850. SkipContinueChecks:
  851. if (recordDataSize + ConcatRecordSize > ConcatRecordTotalSize)
  852. {
  853. WARNING(("sizes do not match"));
  854. recordDataSize = ConcatRecordTotalSize - ConcatRecordSize;
  855. }
  856. GpMemcpy(ConcatRecord + ConcatRecordSize, recordData, recordDataSize);
  857. ConcatRecordSize += recordDataSize;
  858. // see if we're done concatenating this record
  859. if (ConcatRecordSize >= ConcatRecordTotalSize)
  860. {
  861. if (EnumerateCallback(EmfPlusRecordTypeObject, recordFlags,
  862. ConcatRecordTotalSize, ConcatRecord,
  863. CallbackData) == 0)
  864. {
  865. status = Aborted;
  866. }
  867. DoneWithRecord:
  868. ConcatRecord = NULL;
  869. ConcatRecordTotalSize = 0;
  870. ConcatRecordSize = 0;
  871. ConcatRecordFlags = 0;
  872. }
  873. return status;
  874. }
  875. // Enumerate a set of EMF+ record contained inside an EMF comment record
  876. // which has been enumerated from an EMF file.
  877. //
  878. // NOTE that we can't change the metafile data. If we need to change it,
  879. // we must change a copy of it.
  880. GpStatus
  881. MetafilePlayer::EnumerateEmfPlusRecords(
  882. UINT dataSize, // size of EMF+ record data
  883. const BYTE * data // pointer to the EMF+ record data
  884. )
  885. {
  886. ASSERT((dataSize > 0) && (data != NULL));
  887. UINT curSize = 0;
  888. UINT recordSize;
  889. EmfPlusRecordType recordType;
  890. UINT recordFlags;
  891. UINT recordDataSize;
  892. const BYTE * recordData;
  893. // while there is at least one record header size left
  894. while (curSize <= (dataSize - sizeof(EmfPlusRecord)))
  895. {
  896. recordSize = ((const EmfPlusRecord *)data)->Size;
  897. recordDataSize = recordSize - sizeof(EmfPlusRecord);
  898. // Make sure we don't read past the end of the buffer
  899. // and make sure the size field is valid.
  900. if ((recordSize >= sizeof(EmfPlusRecord)) &&
  901. ((curSize + recordSize) <= dataSize) &&
  902. (recordDataSize == ((const EmfPlusRecord *)data)->DataSize))
  903. {
  904. recordType = (EmfPlusRecordType)(((const EmfPlusRecord *)data)->Type);
  905. // make sure the recordType is in some reasonable range
  906. // before we enumerate this record
  907. if ((recordType >= EmfPlusRecordTypeMin) &&
  908. (recordType < (EmfPlusRecordTypeMax + 1000)))
  909. {
  910. recordFlags = ((const EmfPlusRecord *)data)->Flags;
  911. if (recordDataSize == 0)
  912. {
  913. recordData = NULL;
  914. }
  915. else
  916. {
  917. recordData = data + sizeof(EmfPlusRecord);
  918. // if this object record is spread over several GDI comment
  919. // records, then we need to concatenate them together before
  920. // giving it to the callback
  921. // The GDIP_EPRFLAGS_CONTINUEOBJECT flag is only valid
  922. // with object records (since that bit is reused for other
  923. // flags with other record types).
  924. if ((recordType == EmfPlusRecordTypeObject) &&
  925. (((recordFlags & GDIP_EPRFLAGS_CONTINUEOBJECT) != 0) ||
  926. (ConcatRecord != NULL)))
  927. {
  928. if (this->ConcatenateRecords(recordFlags,
  929. recordDataSize,
  930. recordData) == Aborted)
  931. {
  932. return Aborted;
  933. }
  934. goto Increment;
  935. }
  936. }
  937. if (EnumerateCallback(recordType, recordFlags, recordDataSize,
  938. recordData, CallbackData) == 0)
  939. {
  940. return Aborted;
  941. }
  942. }
  943. else
  944. {
  945. WARNING1("Bad EMF+ record type");
  946. }
  947. Increment:
  948. data += recordSize;
  949. curSize += recordSize;
  950. // We have to set this here, because if we are just enumerating
  951. // for an application (not playing), then the GetDCEPR::Play
  952. // method will never be hit, so it will never get set!
  953. if (recordType == EmfPlusRecordTypeGetDC)
  954. {
  955. // Flag that the next down-level records should be played.
  956. PlayEMFRecords = TRUE;
  957. }
  958. }
  959. else
  960. {
  961. WARNING1("Bad EMF+ record size");
  962. return InvalidParameter;
  963. }
  964. }
  965. return Ok;
  966. }
  967. // Callback for EnumerateMetafile methods. The parameters are:
  968. // recordType (if >= EmfPlusRecordTypeMin, it's an EMF+ record)
  969. // flags (always 0 for EMF records)
  970. // dataSize size of the data, or 0 if no data
  971. // data pointer to the data, or NULL if no data (UINT32 aligned)
  972. // callbackData pointer to callbackData, if any
  973. // This method can then call Metafile::PlayRecord to play the
  974. // record that was just enumerated. If this method returns
  975. // FALSE, the enumeration process is aborted. Otherwise, it continues.
  976. extern "C"
  977. BOOL CALLBACK
  978. GdipPlayMetafileRecordCallback(
  979. EmfPlusRecordType recordType,
  980. UINT recordFlags,
  981. UINT recordDataSize,
  982. const BYTE * recordData,
  983. VOID * callbackData // player
  984. )
  985. {
  986. MetafilePlayer * player = (MetafilePlayer *)callbackData;
  987. // See if it is an EMF+ record
  988. if ((recordType >= EmfPlusRecordTypeMin) && (recordType <= EmfPlusRecordTypeMax))
  989. {
  990. if (player->PlayMultiFormatSection)
  991. {
  992. (((const EmfPlusRecordPlay *)recordData)->*RecordPlayFuncs[recordType-EmfPlusRecordTypeMin])(player, recordType, recordFlags, recordDataSize);
  993. return player->ProcessDrawImageCallback(FALSE);
  994. }
  995. return 1;
  996. }
  997. // See if we should play the WMF or EMF record
  998. // Always play the header and EOF EMF records
  999. if (player->PlayEMFRecords ||
  1000. (recordType == EmfRecordTypeHeader) ||
  1001. (recordType == EmfRecordTypeEOF))
  1002. {
  1003. ASSERT(player->MfState != NULL);
  1004. BOOL forceCallback = player->MfState->ProcessRecord(
  1005. recordType,
  1006. recordDataSize,
  1007. recordData);
  1008. return player->ProcessDrawImageCallback(forceCallback);
  1009. }
  1010. ASSERT (0); // shouldn't get here unless caller is doing something strange
  1011. return 1; // Keep playing
  1012. }
  1013. GpStatus
  1014. GpMetafile::PlayRecord(
  1015. EmfPlusRecordType recordType,
  1016. UINT recordFlags,
  1017. UINT recordDataSize, // must be multiple of 4 for EMF
  1018. const BYTE * recordData
  1019. ) const
  1020. {
  1021. if ((State != PlayingMetafileState) ||
  1022. (((recordDataSize & 0x03) != 0) &&
  1023. (!GDIP_IS_WMF_RECORDTYPE(recordType))))
  1024. {
  1025. return InvalidParameter;
  1026. }
  1027. ASSERT(Player != NULL);
  1028. GdipPlayMetafileRecordCallback(
  1029. recordType,
  1030. recordFlags,
  1031. recordDataSize,
  1032. recordData,
  1033. Player
  1034. );
  1035. return Ok;
  1036. }
  1037. inline BOOL
  1038. IsEmfPlusRecord(
  1039. CONST ENHMETARECORD * emfRecord
  1040. )
  1041. {
  1042. // dParm[0] is the comment data size
  1043. return ((emfRecord->iType == EMR_GDICOMMENT) &&
  1044. (emfRecord->nSize >= (sizeof(EMR) + (2 * sizeof(DWORD)))) &&
  1045. (emfRecord->dParm[1] == EMFPLUS_SIGNATURE));
  1046. }
  1047. // This method enumerates/plays EMF+ comment records and also
  1048. // plays down-level GDI records, when appropriate.
  1049. extern "C"
  1050. int CALLBACK
  1051. EnumEmfWithDownLevel(
  1052. HDC hdc, // should be non-NULL
  1053. HANDLETABLE FAR * gdiHandleTable,
  1054. CONST ENHMETARECORD * emfRecord,
  1055. int numHandles,
  1056. LPARAM play
  1057. )
  1058. {
  1059. if ((emfRecord != NULL) && (emfRecord->nSize >= sizeof(EMR)) &&
  1060. (play != NULL))
  1061. {
  1062. MetafilePlayer * player = (MetafilePlayer *)play;
  1063. if (IsEmfPlusRecord(emfRecord))
  1064. {
  1065. // We're done displaying GDI down-level records
  1066. player->DoneWithDownLevel();
  1067. // NOTE: cbData is the size of the comment data, not including
  1068. // the record header and not including itself.
  1069. //
  1070. // Must subtract out the Signature
  1071. INT dataSize = ((CONST EMRGDICOMMENT *)emfRecord)->cbData;
  1072. // subtract out signature
  1073. dataSize -= sizeof(INT32);
  1074. if (dataSize > 0)
  1075. {
  1076. if (player->EnumerateEmfPlusRecords(
  1077. dataSize,
  1078. ((CONST EMRGDICOMMENT *)emfRecord)->Data + sizeof(INT32))
  1079. == Aborted)
  1080. {
  1081. player->EnumerateAborted = TRUE;
  1082. return 0;
  1083. }
  1084. }
  1085. }
  1086. else
  1087. {
  1088. EmfPlusRecordType recordType = (EmfPlusRecordType)(emfRecord->iType);
  1089. if (player->PlayEMFRecords ||
  1090. (recordType == EmfRecordTypeHeader) ||
  1091. (recordType == EmfRecordTypeEOF))
  1092. {
  1093. if ((recordType != EmfRecordTypeHeader) &&
  1094. (recordType != EmfRecordTypeEOF))
  1095. {
  1096. player->InitForDownLevel();
  1097. }
  1098. INT recordDataSize = emfRecord->nSize - sizeof(EMR);
  1099. const BYTE * recordData = (const BYTE *)emfRecord->dParm;
  1100. if (recordDataSize <= 0)
  1101. {
  1102. recordDataSize = 0;
  1103. recordData = NULL;
  1104. }
  1105. player->MfState->StartRecord(hdc, gdiHandleTable, numHandles, emfRecord,
  1106. recordType, recordDataSize, recordData);
  1107. if (player->EnumerateCallback(recordType, 0, recordDataSize,
  1108. recordData,
  1109. player->CallbackData) == 0)
  1110. {
  1111. player->EnumerateAborted = TRUE;
  1112. return 0;
  1113. }
  1114. }
  1115. }
  1116. }
  1117. else
  1118. {
  1119. WARNING(("Bad Enumeration Parameter"));
  1120. }
  1121. return 1;
  1122. }
  1123. #define GDIP_MAX_DIBSECTION_SIZE 1024
  1124. #define GDIP_MINSCALED_DIBSECTION_SIZE (GDIP_MAX_DIBSECTION_SIZE / 2)
  1125. inline VOID
  1126. AdjustForMaximumSize(
  1127. LONG & bigSide,
  1128. LONG & smallSide
  1129. )
  1130. {
  1131. // Try to keep the aspect ratio the same,
  1132. // but don't let the smaller side get too small.
  1133. REAL scaleFactor = GDIP_MAX_DIBSECTION_SIZE / (REAL)bigSide;
  1134. bigSide = GDIP_MAX_DIBSECTION_SIZE;
  1135. if (smallSide > GDIP_MINSCALED_DIBSECTION_SIZE)
  1136. {
  1137. smallSide = GpRound(scaleFactor * smallSide);
  1138. if (smallSide < GDIP_MINSCALED_DIBSECTION_SIZE)
  1139. {
  1140. smallSide = GDIP_MINSCALED_DIBSECTION_SIZE;
  1141. }
  1142. }
  1143. }
  1144. // !!! If the hdc is a EMF, we really should take the rasterization limit
  1145. // into account when deciding the size of the dest bitmap.
  1146. static HBITMAP
  1147. CreateDibSection32Bpp(
  1148. HDC hdc,
  1149. const GpRectF & destRect,
  1150. RECT & dest, // actual dest
  1151. UINT32 ** bits,
  1152. REAL * dpi, // must init dpi before calling this method
  1153. GpMatrix * matrix
  1154. )
  1155. {
  1156. GpPointF destPoints[3];
  1157. REAL width;
  1158. REAL height;
  1159. // When we rasterize a WMF or EMF into a Dib Section, we limit the size
  1160. // so that we don't use huge amounts of memory when printing or when
  1161. // drawing the rotated metafile into another metafile.
  1162. *bits = NULL;
  1163. // the capped dpi keeps the image from getting too large
  1164. destPoints[0].X = destRect.X;
  1165. destPoints[0].Y = destRect.Y;
  1166. destPoints[1].X = destRect.GetRight();
  1167. destPoints[1].Y = destRect.Y;
  1168. destPoints[2].X = destRect.X;
  1169. destPoints[2].Y = destRect.GetBottom();
  1170. matrix->Transform(destPoints, 3);
  1171. // determine the size of the image by getting the distance
  1172. // between the transformed device points
  1173. width = ::GetDistance(destPoints[0], destPoints[1]);
  1174. height = ::GetDistance(destPoints[0], destPoints[2]);
  1175. dest.left = 0;
  1176. dest.top = 0;
  1177. dest.right = GpRound(width);
  1178. dest.bottom = GpRound(height);
  1179. // make sure we don't transform down to 0 size
  1180. if ((dest.right == 0) || (dest.bottom == 0))
  1181. {
  1182. return NULL;
  1183. }
  1184. if ((dest.right > GDIP_MAX_DIBSECTION_SIZE) ||
  1185. (dest.bottom > GDIP_MAX_DIBSECTION_SIZE))
  1186. {
  1187. REAL area = (REAL) dest.right * dest.bottom;
  1188. if (dest.right >= dest.bottom)
  1189. {
  1190. AdjustForMaximumSize(dest.right, dest.bottom);
  1191. }
  1192. else
  1193. {
  1194. AdjustForMaximumSize(dest.bottom, dest.right);
  1195. }
  1196. REAL newArea = (REAL) dest.right * dest.bottom;
  1197. ASSERT(newArea > 0.0f && newArea <= area);
  1198. // Adjust the effective DPI of the bitmap based on how much smaller it is.
  1199. *dpi = (*dpi)*newArea/area;
  1200. }
  1201. BITMAPINFO bmi;
  1202. // Create a 32-bpp dib section so we can add alpha to it
  1203. GpMemset(&bmi, 0, sizeof(bmi));
  1204. bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
  1205. bmi.bmiHeader.biWidth = dest.right;
  1206. bmi.bmiHeader.biHeight = dest.bottom;
  1207. bmi.bmiHeader.biPlanes = 1;
  1208. bmi.bmiHeader.biBitCount = 32;
  1209. bmi.bmiHeader.biCompression = BI_RGB;
  1210. bmi.bmiHeader.biSizeImage = dest.right * dest.bottom * 4;
  1211. return CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (VOID**)(bits), NULL, 0);
  1212. }
  1213. VOID
  1214. Init32BppDibToTransparent(
  1215. UINT32 * bits,
  1216. UINT numPixels
  1217. )
  1218. {
  1219. ASSERT((bits != NULL) && (numPixels > 0));
  1220. // initialize the image to a "transparent" color
  1221. while (numPixels--)
  1222. {
  1223. *bits++ = GDIP_TRANSPARENT_COLOR_KEY;
  1224. }
  1225. }
  1226. GpStatus
  1227. Draw32BppDib(
  1228. GpGraphics * g,
  1229. UINT32 * bits,
  1230. INT width,
  1231. INT height,
  1232. const GpRectF & destRect,
  1233. REAL dpi,
  1234. BOOL compareAlpha
  1235. )
  1236. {
  1237. // Make sure Gdi is done drawing to the dib section
  1238. ::GdiFlush();
  1239. // Set the alpha value to 0 whereever the transparent
  1240. // color is still in the image and to FF everywhere else
  1241. UINT32 * bitmapBits = bits;
  1242. UINT numPixels = width * height;
  1243. if (compareAlpha)
  1244. {
  1245. while (numPixels--)
  1246. {
  1247. if (*bitmapBits != GDIP_TRANSPARENT_COLOR_KEY)
  1248. {
  1249. *bitmapBits |= 0xFF000000;
  1250. }
  1251. else
  1252. {
  1253. *bitmapBits = 0;
  1254. }
  1255. bitmapBits++;
  1256. }
  1257. }
  1258. else
  1259. {
  1260. while (numPixels--)
  1261. {
  1262. if ((*bitmapBits & 0x00FFFFFF) != (GDIP_TRANSPARENT_COLOR_KEY & 0x00FFFFFF))
  1263. {
  1264. *bitmapBits |= 0xFF000000;
  1265. }
  1266. else
  1267. {
  1268. *bitmapBits = 0;
  1269. }
  1270. bitmapBits++;
  1271. }
  1272. }
  1273. // Create a bitamp from the dib section memory (which
  1274. // we've added alpha to). This constructor uses the
  1275. // memory we give it without doing a copy.
  1276. GpStatus status = GenericError;
  1277. GpBitmap * bitmap = new GpBitmap(width, height, -(width * 4),
  1278. PIXFMT_32BPP_PARGB,
  1279. (BYTE *)(bits + (width * (height - 1))));
  1280. if (bitmap != NULL)
  1281. {
  1282. if (bitmap->IsValid())
  1283. {
  1284. bitmap->SetResolution(dpi, dpi);
  1285. // If we want the outside edges to look smooth, then we have
  1286. // to outcrop both the src and dest rects (by at least a pixel).
  1287. GpRectF srcRect(-1.0f, -1.0f, width + 2.0f, height + 2.0f);
  1288. GpRectF outCroppedDestRect;
  1289. REAL xSize;
  1290. REAL ySize;
  1291. g->GetWorldPixelSize(xSize, ySize);
  1292. if (destRect.Width < 0.0f)
  1293. {
  1294. xSize = -xSize;
  1295. }
  1296. if (destRect.Height < 0.0f)
  1297. {
  1298. ySize = -ySize;
  1299. }
  1300. outCroppedDestRect.X = destRect.X - xSize;
  1301. outCroppedDestRect.Width = destRect.Width + (xSize * 2.0f);
  1302. outCroppedDestRect.Y = destRect.Y - ySize;
  1303. outCroppedDestRect.Height = destRect.Height + (ySize * 2.0f);
  1304. if (g->IsPrinter())
  1305. {
  1306. // If the resulting transform (and source rect/dest rect) is
  1307. // a rotation by 90, 180, or 270 degrees. Then flip the bitmap
  1308. // appropriately. Fix up source rect, dest rect, and world to
  1309. // device appropriately. Restore W2D afterwards.
  1310. GpMatrix worldToDevice;
  1311. g->GetWorldToDeviceTransform(&worldToDevice);
  1312. // Create the entire image source to device mapping to determine
  1313. // the entire rotation.
  1314. GpMatrix transform;
  1315. transform.InferAffineMatrix(destRect, srcRect);
  1316. GpMatrix::MultiplyMatrix(transform, transform, worldToDevice);
  1317. MatrixRotate rotation = transform.GetRotation();
  1318. if (rotation == MatrixRotateBy90 ||
  1319. rotation == MatrixRotateBy180 ||
  1320. rotation == MatrixRotateBy270)
  1321. {
  1322. // Normalize the destination rectangle
  1323. TransformBounds(NULL,
  1324. outCroppedDestRect.GetLeft(),
  1325. outCroppedDestRect.GetTop(),
  1326. outCroppedDestRect.GetRight(),
  1327. outCroppedDestRect.GetBottom(),
  1328. &outCroppedDestRect);
  1329. // Compute the destination rectangle in device space. Transform
  1330. // to device space and normalize.
  1331. // We know the world transform can have a 90 degree rotation
  1332. // so we need to do a point transform. We can do a 2 point
  1333. // transform and get the min and the max to make the bounding
  1334. // box
  1335. GpRectF deviceDestRect;
  1336. TransformBounds(&worldToDevice,
  1337. outCroppedDestRect.GetLeft(),
  1338. outCroppedDestRect.GetTop(),
  1339. outCroppedDestRect.GetRight(),
  1340. outCroppedDestRect.GetBottom(),
  1341. &deviceDestRect);
  1342. // Construct new world to page transform. Infers from the
  1343. // normalized outCroppedDestRect to normalized deviceDestRect.
  1344. //
  1345. // The World To Device is ordinarily computed as:
  1346. //
  1347. // World-To-Page * Scale(PageMultipliers) *
  1348. // Translate-By-Pixel-Offset * ContainerTransform
  1349. //
  1350. // The SetWorldTransform API only sets the World-To-Page.
  1351. //
  1352. // So we set the new World Transform as:
  1353. //
  1354. // World-To-Page * Inverse(World-To-Device)*
  1355. // Transform-CroppedDestRect-To-DeviceDestRect
  1356. //
  1357. // The result, as you can see from substitution is just
  1358. // Transform-CroppedDestRect-To-DeviceDestRect
  1359. GpMatrix newTransform;
  1360. newTransform.InferAffineMatrix(deviceDestRect, outCroppedDestRect);
  1361. g->GetDeviceToWorldTransform(&transform);
  1362. GpMatrix::MultiplyMatrix(newTransform, newTransform, transform);
  1363. g->GetWorldTransform(transform); // really World To Page XForm
  1364. GpMatrix::MultiplyMatrix(newTransform, newTransform, transform);
  1365. ASSERT(newTransform.IsTranslateScale());
  1366. // We are free to rotate in place because we know this is a
  1367. // throw away bitmap.
  1368. switch (rotation)
  1369. {
  1370. case MatrixRotateBy90:
  1371. status = bitmap->RotateFlip(Rotate90FlipNone);
  1372. break;
  1373. case MatrixRotateBy180:
  1374. status = bitmap->RotateFlip(Rotate180FlipNone);
  1375. break;
  1376. case MatrixRotateBy270:
  1377. status = bitmap->RotateFlip(Rotate270FlipNone);
  1378. break;
  1379. default:
  1380. status = GenericError;
  1381. ASSERT(FALSE);
  1382. break;
  1383. }
  1384. if (status == Ok)
  1385. {
  1386. g->SetWorldTransform(newTransform);
  1387. // Get new size (in case Height & Width were flipped.
  1388. Size bitmapSize;
  1389. bitmap->GetSize(&bitmapSize);
  1390. srcRect.Width = bitmapSize.Width + 2.0f;
  1391. srcRect.Height = bitmapSize.Height + 2.0f;
  1392. // Because the bitmap is already at device resolution
  1393. // (in most cases), nearest neighbor best preserves
  1394. // the image when printing.
  1395. InterpolationMode interpolationMode= g->GetInterpolationMode();
  1396. if (interpolationMode != InterpolationModeNearestNeighbor)
  1397. {
  1398. g->SetInterpolationMode(InterpolationModeNearestNeighbor);
  1399. }
  1400. // Draw the new image with the rotation/shear
  1401. status = g->DrawImage(bitmap, outCroppedDestRect, srcRect, UnitPixel);
  1402. if (interpolationMode != InterpolationModeNearestNeighbor)
  1403. {
  1404. g->SetInterpolationMode(interpolationMode);
  1405. }
  1406. g->SetWorldTransform(worldToDevice);
  1407. }
  1408. goto cleanupBitmap;
  1409. }
  1410. }
  1411. // Draw the new image with the rotation/shear
  1412. status = g->DrawImage(bitmap, outCroppedDestRect, srcRect, UnitPixel);
  1413. }
  1414. cleanupBitmap:
  1415. // Now clean up everything
  1416. bitmap->Dispose();
  1417. }
  1418. return status;
  1419. }
  1420. // Get multipliers to convert to pixel units
  1421. VOID
  1422. GetPixelMultipliers(
  1423. GpPageUnit srcUnit,
  1424. REAL srcDpiX,
  1425. REAL srcDpiY,
  1426. REAL * pixelMultiplierX,
  1427. REAL * pixelMultiplierY
  1428. )
  1429. {
  1430. REAL multiplierX;
  1431. REAL multiplierY;
  1432. // UnitDisplay is device-dependent and cannot be used for a source unit
  1433. ASSERT(srcUnit != UnitDisplay);
  1434. switch (srcUnit)
  1435. {
  1436. default:
  1437. ASSERT(0);
  1438. // FALLTHRU
  1439. case UnitPixel: // Each unit represents one device pixel.
  1440. multiplierX = 1.0f;
  1441. multiplierY = 1.0f;
  1442. break;
  1443. case UnitPoint: // Each unit represents a 1/72 inch.
  1444. multiplierX = srcDpiX / 72.0f;
  1445. multiplierY = srcDpiY / 72.0f;
  1446. break;
  1447. case UnitInch: // Each unit represents 1 inch.
  1448. multiplierX = srcDpiX;
  1449. multiplierY = srcDpiY;
  1450. break;
  1451. case UnitDocument: // Each unit represents 1/300 inch.
  1452. multiplierX = srcDpiX / 300.0f;
  1453. multiplierY = srcDpiY / 300.0f;
  1454. break;
  1455. case UnitMillimeter: // Each unit represents 1 millimeter.
  1456. // One Millimeter is 0.03937 inches
  1457. // One Inch is 25.4 millimeters
  1458. multiplierX = srcDpiX / 25.4f;
  1459. multiplierY = srcDpiY / 25.4f;
  1460. break;
  1461. }
  1462. *pixelMultiplierX = multiplierX;
  1463. *pixelMultiplierY = multiplierY;
  1464. }
  1465. extern "C"
  1466. int CALLBACK
  1467. EnumEmfDownLevel(
  1468. HDC hdc, // handle to device context
  1469. HANDLETABLE FAR * gdiHandleTable, // pointer to metafile handle table
  1470. CONST ENHMETARECORD * emfRecord, // pointer to metafile record
  1471. int numHandles, // count of objects
  1472. LPARAM play // pointer to optional data
  1473. )
  1474. {
  1475. if ((emfRecord != NULL) && (emfRecord->nSize >= sizeof(EMR)) &&
  1476. (play != NULL))
  1477. {
  1478. // If we're in this method, we don't want to play any EMF+ records,
  1479. // so skip them, so we don't record them into another metafile.
  1480. if (!IsEmfPlusRecord(emfRecord))
  1481. {
  1482. EmfPlusRecordType recordType = (EmfPlusRecordType)(emfRecord->iType);
  1483. const BYTE * recordData = (const BYTE *)emfRecord->dParm;
  1484. INT recordDataSize = emfRecord->nSize - sizeof(EMR);
  1485. if (recordDataSize <= 0)
  1486. {
  1487. recordDataSize = 0;
  1488. recordData = NULL;
  1489. }
  1490. MetafilePlayer * player = (MetafilePlayer *)play;
  1491. player->MfState->StartRecord(hdc, gdiHandleTable, numHandles, emfRecord,
  1492. recordType, recordDataSize, recordData);
  1493. if (player->EnumerateCallback(recordType, 0, recordDataSize,
  1494. recordData,
  1495. player->CallbackData) == 0)
  1496. {
  1497. player->EnumerateAborted = TRUE;
  1498. return 0;
  1499. }
  1500. }
  1501. }
  1502. else
  1503. {
  1504. WARNING(("Bad Enumeration Parameter"));
  1505. }
  1506. return 1;
  1507. }
  1508. // Assumes the hdc has already been set up with the correct transform and
  1509. // clipping for displaying the metafile.
  1510. GpStatus
  1511. MetafilePlayer::EnumerateEmfRecords(
  1512. HDC hdc,
  1513. HENHMETAFILE hEmf,
  1514. const RECT * dest,
  1515. const RECT * deviceRect,
  1516. ENHMFENUMPROC enumProc
  1517. )
  1518. {
  1519. ASSERT(hdc != NULL);
  1520. ASSERT(hEmf != NULL);
  1521. ASSERT(dest->bottom > dest->top && dest->right > dest->left);
  1522. // GDI uses an Inclusive-Inclusive bound for Metafile Playback
  1523. RECT destRect = *dest;
  1524. destRect.bottom--;
  1525. destRect.right--;
  1526. GpStatus status = GenericError;
  1527. BOOL externalEnumeration =
  1528. (EnumerateCallback != GdipPlayMetafileRecordCallback);
  1529. EmfEnumState emfState(hdc, hEmf, &destRect, deviceRect, externalEnumeration,
  1530. Interpolation, Graphics->Context, Recolor, AdjustType);
  1531. if (emfState.IsValid())
  1532. {
  1533. MfState = &emfState;
  1534. // If the metafile is empty the following fails.
  1535. status = ::EnumEnhMetaFile(hdc, hEmf, enumProc, this, &destRect) ?
  1536. Ok : GenericError;
  1537. RopUsed = MfState->GetRopUsed();
  1538. MfState = NULL;
  1539. if (EnumerateAborted)
  1540. {
  1541. status = Aborted;
  1542. }
  1543. }
  1544. return status;
  1545. }
  1546. extern "C"
  1547. int CALLBACK
  1548. EnumWmfDownLevel(
  1549. HDC hdc,
  1550. HANDLETABLE FAR * gdiHandleTable,
  1551. METARECORD FAR * wmfRecord,
  1552. int numHandles,
  1553. LPARAM play
  1554. )
  1555. {
  1556. if ((wmfRecord != NULL) &&
  1557. (((UNALIGNED METARECORD *)wmfRecord)->rdSize >= 3) &&
  1558. (play != NULL))
  1559. {
  1560. EmfPlusRecordType recordType = (EmfPlusRecordType)(GDIP_WMF_RECORD_TO_EMFPLUS(wmfRecord->rdFunction));
  1561. const BYTE * recordData = (const BYTE *)((UNALIGNED METARECORD *)wmfRecord)->rdParm;
  1562. INT recordDataSize = (((UNALIGNED METARECORD *)wmfRecord)->rdSize * 2) - SIZEOF_METARECORDHEADER;
  1563. if (recordDataSize <= 0)
  1564. {
  1565. recordDataSize = 0;
  1566. recordData = NULL;
  1567. }
  1568. MetafilePlayer * player = (MetafilePlayer *)play;
  1569. player->MfState->StartRecord(hdc, gdiHandleTable, numHandles, wmfRecord,
  1570. recordType, recordDataSize, recordData);
  1571. if (player->EnumerateCallback(recordType, 0, recordDataSize,
  1572. recordData,
  1573. player->CallbackData) == 0)
  1574. {
  1575. player->EnumerateAborted = TRUE;
  1576. return 0;
  1577. }
  1578. }
  1579. else
  1580. {
  1581. WARNING(("Bad Enumeration Parameter"));
  1582. }
  1583. return 1;
  1584. }
  1585. // Assumes the hdc has already been set up with the correct transform and
  1586. // clipping for displaying the metafile.
  1587. GpStatus
  1588. MetafilePlayer::EnumerateWmfRecords(
  1589. HDC hdc,
  1590. HMETAFILE hWmf,
  1591. const RECT * dstRect,
  1592. const RECT * deviceRect
  1593. )
  1594. {
  1595. ASSERT(hdc != NULL);
  1596. ASSERT(hWmf != NULL);
  1597. GpStatus status = GenericError;
  1598. BOOL externalEnumeration =
  1599. (EnumerateCallback != GdipPlayMetafileRecordCallback);
  1600. WmfEnumState wmfState(hdc, hWmf, externalEnumeration, Interpolation,
  1601. dstRect, deviceRect, Graphics->Context, Recolor, AdjustType);
  1602. if (wmfState.IsValid())
  1603. {
  1604. MfState = &wmfState;
  1605. // If the metafile is empty the following fails.
  1606. status = ::EnumMetaFile(hdc, hWmf, EnumWmfDownLevel, (LPARAM)this) ?
  1607. Ok : GenericError;
  1608. RopUsed = MfState->GetRopUsed();
  1609. MfState = NULL;
  1610. if (EnumerateAborted)
  1611. {
  1612. status = Aborted;
  1613. }
  1614. }
  1615. return status;
  1616. }
  1617. inline BOOL
  1618. IsMetafileHdc(
  1619. HDC hdc
  1620. )
  1621. {
  1622. DWORD hdcType = GetDCType(hdc);
  1623. return ((hdcType == OBJ_ENHMETADC) || (hdcType == OBJ_METADC));
  1624. }
  1625. class SetupClippingForMetafilePlayback
  1626. {
  1627. public:
  1628. SetupClippingForMetafilePlayback(
  1629. HDC hdc,
  1630. DpDriver * driver,
  1631. DpContext * context,
  1632. BOOL forEMFPlus = FALSE
  1633. )
  1634. {
  1635. Hdc = hdc;
  1636. Driver = driver;
  1637. IsClip = FALSE;
  1638. ClippedOut = FALSE;
  1639. ReenableClipEscapes = FALSE;
  1640. if (!context->VisibleClip.IsInfinite())
  1641. {
  1642. // Use GDI path clipping for playback to metafile only
  1643. UsePathClipping = IsMetafileHdc(hdc) && !context->IsPrinter;
  1644. // NT4 has a postscript driver bug where embedded EPS corrupt the
  1645. // current postscript clipping stack. To get around this, we resort to
  1646. // using GDI to clip for us.
  1647. // The problem is not limited to NT4 drivers alooe. There seems to
  1648. // be a family of injected EPS which doesn't interop with embedded
  1649. // postscript clipping escapes. The reason may have to do with the
  1650. // fact that many implementations don't reset the current path after
  1651. // sending the escape. See Office bugs 284388, 316074
  1652. if (context->IsPrinter)
  1653. {
  1654. if ((!forEMFPlus && !Globals::IsNt) ||
  1655. (Globals::IsNt &&
  1656. Globals::VersionInfoInitialized &&
  1657. ((Globals::OsVer.dwMajorVersion <= 4) ||
  1658. ((Globals::OsVer.dwMajorVersion >= 5) &&
  1659. (context->VisibleClip.IsSimple())) )))
  1660. {
  1661. DriverPrint *pdriver = (DriverPrint*) Driver;
  1662. pdriver->DisableClipEscapes();
  1663. ReenableClipEscapes = TRUE;
  1664. }
  1665. }
  1666. // The trick here is we want to force the driver to clip, even if
  1667. // totally visible because cropping requires this. We pass in the flag
  1668. // to force clipping
  1669. GpRect drawBounds;
  1670. context->VisibleClip.GetBounds(&drawBounds);
  1671. if (drawBounds.IsEmpty())
  1672. {
  1673. ClippedOut = TRUE;
  1674. return;
  1675. }
  1676. // Use appropriate driver clipping on playback
  1677. Driver->SetupClipping(Hdc,
  1678. context,
  1679. &drawBounds,
  1680. IsClip,
  1681. UsePathClipping,
  1682. TRUE);
  1683. // Prevent metafile from drawing outside of the DestRect
  1684. // Can only do it for NT because Win9x doesn't restore the
  1685. // MetaRgn properly
  1686. // We handle this in the Metafile Player for Win9x
  1687. if (Globals::IsNt)
  1688. {
  1689. ::SetMetaRgn(hdc);
  1690. }
  1691. }
  1692. }
  1693. ~SetupClippingForMetafilePlayback()
  1694. {
  1695. if (IsClip)
  1696. {
  1697. Driver->RestoreClipping(Hdc,
  1698. IsClip,
  1699. UsePathClipping);
  1700. if (ReenableClipEscapes)
  1701. {
  1702. DriverPrint *pdriver = (DriverPrint*) Driver;
  1703. pdriver->EnableClipEscapes();
  1704. }
  1705. }
  1706. }
  1707. BOOL IsClippedOut()
  1708. {
  1709. return ClippedOut;
  1710. }
  1711. private:
  1712. DpDriver * Driver;
  1713. HDC Hdc;
  1714. BOOL IsClip;
  1715. BOOL UsePathClipping;
  1716. BOOL ClippedOut;
  1717. BOOL ReenableClipEscapes;
  1718. };
  1719. // We already set up the transform to handle the srcRect and also to
  1720. // handle any flipping in the srcRect and destRect, so the 2 rects
  1721. // should have positive widths and heights at this point.
  1722. GpStatus
  1723. GpGraphics::EnumEmf(
  1724. MetafilePlayer * player,
  1725. HENHMETAFILE hEmf,
  1726. const GpRectF & destRect,
  1727. const GpRectF & srcRect, // in pixel units
  1728. const GpRectF & deviceDestRect, // The destRect in Device Units
  1729. MetafileType type,
  1730. BOOL isTranslateScale,
  1731. BOOL renderToBitmap,
  1732. const GpMatrix & flipAndCropTransform
  1733. )
  1734. {
  1735. ASSERT(hEmf != NULL);
  1736. HDC hdc = Context->GetHdc(Surface);
  1737. if (hdc == NULL)
  1738. {
  1739. return GenericError;
  1740. }
  1741. INT saveDC;
  1742. if ((saveDC = ::SaveDC(hdc)) == 0)
  1743. {
  1744. Context->ReleaseHdc(hdc, Surface);
  1745. return GenericError;
  1746. }
  1747. // Since we might have an HDC from a GpBitmap that's not clean, clean the
  1748. // HDC for now....
  1749. Context->CleanTheHdc(hdc);
  1750. player->PlayEMFRecords = TRUE; // play all EMF records
  1751. GpStatus status = Ok;
  1752. // the srcRect is already in pixel units
  1753. GpRect deviceSrcRect;
  1754. deviceSrcRect.X = GpRound(srcRect.X);
  1755. deviceSrcRect.Y = GpRound(srcRect.Y);
  1756. deviceSrcRect.Width = GpRound(srcRect.Width);
  1757. deviceSrcRect.Height = GpRound(srcRect.Height);
  1758. RECT deviceClipRect;
  1759. deviceClipRect.left = RasterizerCeiling(deviceDestRect.X);
  1760. deviceClipRect.top = RasterizerCeiling(deviceDestRect.Y);
  1761. deviceClipRect.right = RasterizerCeiling(deviceDestRect.GetRight());
  1762. deviceClipRect.bottom = RasterizerCeiling(deviceDestRect.GetBottom());
  1763. // If it's a translate/scale matrix, do the transform ourselves,
  1764. // even on NT, so that we can control how the rounding is done
  1765. // to avoid cases where we round the metafile dest differently
  1766. // than the clipping rect, resulting in clipped out edges.
  1767. if (isTranslateScale)
  1768. {
  1769. SetupClippingForMetafilePlayback clipPlayback(hdc, Driver, Context);
  1770. if (!clipPlayback.IsClippedOut())
  1771. {
  1772. RECT deviceRect;
  1773. GpPointF points[2];
  1774. points[0] = GpPointF(destRect.X, destRect.Y);
  1775. points[1] = GpPointF(destRect.GetRight(), destRect.GetBottom());
  1776. player->PreContainerMatrix.Transform(points, 2);
  1777. // We have to use the same method to convert REAL -> INT
  1778. // that we do when we set up the clipping. Otherwise, some
  1779. // of the points get rounded differently, causing a
  1780. // portion of the metafile to get clipped out.
  1781. deviceRect.left = RasterizerCeiling(points[0].X);
  1782. deviceRect.top = RasterizerCeiling(points[0].Y);
  1783. deviceRect.right = RasterizerCeiling(points[1].X);
  1784. deviceRect.bottom = RasterizerCeiling(points[1].Y);
  1785. if (deviceRect.left < deviceRect.right &&
  1786. deviceRect.top < deviceRect.bottom)
  1787. {
  1788. if ((type == MetafileTypeWmf) || (type == MetafileTypeWmfPlaceable))
  1789. {
  1790. // map the source rect to the dest rect to play the metafile
  1791. ::SetMapMode(hdc, MM_ANISOTROPIC);
  1792. ::SetWindowOrgEx(hdc, deviceSrcRect.X, deviceSrcRect.Y, NULL);
  1793. ::SetWindowExtEx(hdc, deviceSrcRect.Width, deviceSrcRect.Height,
  1794. NULL);
  1795. ::SetViewportOrgEx(hdc, deviceRect.left, deviceRect.top, NULL);
  1796. ::SetViewportExtEx(hdc, deviceRect.right - deviceRect.left,
  1797. deviceRect.bottom - deviceRect.top, NULL);
  1798. status = player->EnumerateWmfRecords(hdc, (HMETAFILE)hEmf,
  1799. &deviceRect, &deviceClipRect);
  1800. }
  1801. else // play as down-level EMF
  1802. {
  1803. ASSERT((type == MetafileTypeEmf) || (type == MetafileTypeEmfPlusDual));
  1804. status = player->EnumerateEmfRecords(hdc, hEmf, &deviceRect,
  1805. &deviceClipRect, EnumEmfDownLevel);
  1806. }
  1807. }
  1808. // else empty rect, nothing to draw
  1809. }
  1810. // else it's all clipped out
  1811. }
  1812. else // flip and/or rotate and/or shear
  1813. {
  1814. RECT dest;
  1815. // Can't play a WMF with any rotate or skew transformation.
  1816. // If we're on NT but we're drawing to a metafile hdc, then we
  1817. // can't rely on the transforms working for that case.
  1818. if (!renderToBitmap)
  1819. {
  1820. dest.left = GpRound(destRect.X);
  1821. dest.top = GpRound(destRect.Y);
  1822. dest.right = GpRound(destRect.GetRight());
  1823. dest.bottom = GpRound(destRect.GetBottom());
  1824. if ((dest.bottom > dest.top) && (dest.right > dest.left))
  1825. {
  1826. // If NT, then set the transform in GDI, and play the metafile
  1827. SetupClippingForMetafilePlayback clipPlayback(hdc, Driver, Context);
  1828. if (!clipPlayback.IsClippedOut())
  1829. {
  1830. ASSERT(Globals::IsNt);
  1831. SetGraphicsMode(hdc, GM_ADVANCED);
  1832. ASSERT(sizeof(XFORM) == sizeof(REAL)*6);
  1833. XFORM xform;
  1834. player->PreContainerMatrix.GetMatrix((REAL*) &xform);
  1835. ::SetWorldTransform(hdc, &xform);
  1836. RECT dummyRect = {0,0,0,0};
  1837. status = player->EnumerateEmfRecords(hdc, hEmf, &dest,
  1838. &dummyRect, EnumEmfDownLevel);
  1839. }
  1840. }
  1841. }
  1842. else // Win9x with rotation or shear
  1843. // WinNT WMF with Rotate or shear
  1844. {
  1845. // 1 - Draw into a 32-bit DIB Section
  1846. // 2 - Create an image from the DIB Section
  1847. // 3 - Call g->DrawImage
  1848. status = GenericError;
  1849. UINT32 * bits;
  1850. HBITMAP hBitmap;
  1851. player->BitmapDpi = Context->ContainerDpiX;
  1852. hBitmap = CreateDibSection32Bpp(hdc, destRect, dest, &bits, &player->BitmapDpi, &player->PreContainerMatrix);
  1853. if (hBitmap != NULL)
  1854. {
  1855. Init32BppDibToTransparent(bits, dest.right * dest.bottom);
  1856. HDC hdcDib = CreateCompatibleDC(NULL);
  1857. if (hdcDib != NULL)
  1858. {
  1859. ::SelectObject(hdcDib, hBitmap);
  1860. if ((type == MetafileTypeWmf) || (type == MetafileTypeWmfPlaceable))
  1861. {
  1862. // map the source rect to the dest rect to play the metafile
  1863. ::SetMapMode(hdcDib, MM_ANISOTROPIC);
  1864. ::SetWindowOrgEx(hdcDib, deviceSrcRect.X, deviceSrcRect.Y, NULL);
  1865. ::SetWindowExtEx(hdcDib, deviceSrcRect.Width, deviceSrcRect.Height,
  1866. NULL);
  1867. ::SetViewportOrgEx(hdcDib, 0, 0, NULL);
  1868. ::SetViewportExtEx(hdcDib, dest.right, dest.bottom, NULL);
  1869. status = player->EnumerateWmfRecords(hdcDib, (HMETAFILE)hEmf,
  1870. &dest, &dest);
  1871. }
  1872. else // play as down-level EMF
  1873. {
  1874. ASSERT((type == MetafileTypeEmf) || (type == MetafileTypeEmfPlusDual));
  1875. status = player->EnumerateEmfRecords(hdcDib, hEmf, &dest,
  1876. &dest, EnumEmfDownLevel);
  1877. }
  1878. ::DeleteDC(hdcDib);
  1879. if (status != Aborted)
  1880. {
  1881. // Don't use NearestNeighbor to draw the rotated metafile --
  1882. // it looks bad, and doesn't really save any time.
  1883. InterpolationMode saveInterpolationMode = Context->FilterType;
  1884. if (saveInterpolationMode == InterpolationModeNearestNeighbor)
  1885. {
  1886. Context->FilterType = InterpolationModeBilinear;
  1887. }
  1888. // Apply the flip/crop transform. Now the worldToDevice transform
  1889. // should be equivalent to the PreContainerMatrix.
  1890. this->SetWorldTransform(flipAndCropTransform);
  1891. status = Draw32BppDib(this, bits, dest.right,
  1892. dest.bottom, destRect,
  1893. player->BitmapDpi, !player->RopUsed);
  1894. // restore the interpolation mode (in case we changed it).
  1895. Context->FilterType = saveInterpolationMode;
  1896. }
  1897. }
  1898. DeleteObject(hBitmap);
  1899. }
  1900. else if ((dest.right == 0) || (dest.bottom == 0))
  1901. {
  1902. status = Ok;
  1903. }
  1904. }
  1905. }
  1906. ::RestoreDC(hdc, saveDC);
  1907. Context->ReleaseHdc(hdc, Surface);
  1908. return status;
  1909. }
  1910. // We already set up the transform to handle the srcRect and also to
  1911. // handle any flipping in the srcRect and destRect, so the 2 rects
  1912. // should have positive widths and heights at this point.
  1913. GpStatus
  1914. GpGraphics::EnumEmfPlusDual(
  1915. MetafilePlayer * player,
  1916. HENHMETAFILE hEmf,
  1917. const GpRectF& destRect, // inclusive, exclusive
  1918. const GpRectF& deviceDestRect, // inclusive, exclusive
  1919. BOOL isTranslateScale,
  1920. BOOL renderToBitmap
  1921. )
  1922. {
  1923. GpStatus status = Ok;
  1924. HDC hdc;
  1925. HWND hwnd = Context->Hwnd;
  1926. INT saveDC = -1;
  1927. BOOL needToReleaseHdc = FALSE;
  1928. // We are going to take the role of the application and set up the HDC
  1929. // like we want it and then let GDI+ change it from there. This is so
  1930. // that when we play back the GDI records, the HDC will already be set
  1931. // up correctly so those records get played back in the right place.
  1932. // In other words, I'm doing my own version of Context->GetHdc().
  1933. Surface->Flush(FlushIntentionFlush);
  1934. if (hwnd != NULL)
  1935. {
  1936. // We have to guarantee that we use the same HDC throughout the
  1937. // enumeration/playing of the metafile -- so change how the HDC is
  1938. // set up in the graphics context (if we need to).
  1939. ASSERT(Context->Hdc == NULL);
  1940. ASSERT(Context->SaveDc == 0);
  1941. hdc = ::GetCleanHdc(hwnd);
  1942. if (hdc == NULL)
  1943. {
  1944. WARNING(("GetCleanHdc failed"));
  1945. return Win32Error;
  1946. }
  1947. Context->Hwnd = NULL;
  1948. Context->Hdc = hdc;
  1949. }
  1950. else
  1951. {
  1952. if ((hdc = Context->Hdc) != NULL)
  1953. {
  1954. // Restore the HDC back to the state the application had it in.
  1955. Context->ResetHdc();
  1956. }
  1957. else // might be a bitmap surface
  1958. {
  1959. hdc = Context->GetHdc(Surface);
  1960. // Still have to call CleanTheHdc to fix bug #121666.
  1961. // It seems like the hdc should have come back clean
  1962. // from the context.
  1963. if (hdc == NULL)
  1964. {
  1965. WARNING(("Could not get an hdc"));
  1966. return InvalidParameter;
  1967. }
  1968. needToReleaseHdc = TRUE;
  1969. }
  1970. // Now save the state of the HDC so we can get back to it later.
  1971. saveDC = SaveDC(hdc);
  1972. // Get the hdc into a clean state before we start.
  1973. Context->CleanTheHdc(hdc);
  1974. }
  1975. // This block needs to be within braces so that SetupClippingForMetafile
  1976. // will have it's destructor called before the cleanup code.
  1977. {
  1978. // set the clipping for the down-level records
  1979. SetupClippingForMetafilePlayback clipPlayback(hdc, Driver, Context, TRUE);
  1980. if (!clipPlayback.IsClippedOut())
  1981. {
  1982. RECT deviceClipRect;
  1983. deviceClipRect.left = RasterizerCeiling(deviceDestRect.X);
  1984. deviceClipRect.top = RasterizerCeiling(deviceDestRect.Y);
  1985. deviceClipRect.right = RasterizerCeiling(deviceDestRect.GetRight());
  1986. deviceClipRect.bottom = RasterizerCeiling(deviceDestRect.GetBottom());
  1987. // If it's a translate/scale matrix, do the transform ourselves,
  1988. // even on NT, so that we can control how the rounding is done
  1989. // to avoid cases where we round the metafile dest differently
  1990. // than the clipping rect, resulting in clipped out edges.
  1991. if (isTranslateScale)
  1992. {
  1993. RECT deviceRect;
  1994. GpPointF points[2];
  1995. points[0] = GpPointF(destRect.X, destRect.Y);
  1996. points[1] = GpPointF(destRect.GetRight(), destRect.GetBottom());
  1997. player->PreContainerMatrix.Transform(points, 2);
  1998. // We have to use the same method to convert REAL -> INT
  1999. // that we do when we set up the clipping. Otherwise, some
  2000. // of the points get rounded differently, causing a
  2001. // portion of the metafile to get clipped out.
  2002. deviceRect.left = RasterizerCeiling(points[0].X);
  2003. deviceRect.top = RasterizerCeiling(points[0].Y);
  2004. deviceRect.right = RasterizerCeiling(points[1].X);
  2005. deviceRect.bottom = RasterizerCeiling(points[1].Y);
  2006. // If we don't have a destrect then we are done
  2007. if (deviceRect.left < deviceRect.right &&
  2008. deviceRect.top < deviceRect.bottom)
  2009. {
  2010. status = player->EnumerateEmfRecords(hdc, hEmf, &deviceRect,
  2011. &deviceClipRect, EnumEmfWithDownLevel);
  2012. }
  2013. }
  2014. else // flip and/or rotate and/or shear
  2015. {
  2016. RECT dest;
  2017. dest.left = GpRound(destRect.X);
  2018. dest.top = GpRound(destRect.Y);
  2019. dest.right = GpRound(destRect.GetRight());
  2020. dest.bottom = GpRound(destRect.GetBottom());
  2021. if ((dest.bottom > dest.top) && (dest.right > dest.left))
  2022. {
  2023. // If we're on NT but we're drawing to a metafile hdc, then we
  2024. // can't rely on the transforms working for that case.
  2025. if (!renderToBitmap)
  2026. {
  2027. ASSERT(Globals::IsNt);
  2028. // set the transform for the down-level records
  2029. SetGraphicsMode(hdc, GM_ADVANCED);
  2030. ASSERT(sizeof(XFORM) == sizeof(REAL)*6);
  2031. // We want to set the transform in the HDC to the Pre-container matrix,
  2032. // so that it will be used to render the down-level records.
  2033. XFORM xform;
  2034. player->PreContainerMatrix.GetMatrix((REAL*)(&xform));
  2035. ::SetWorldTransform(hdc, &xform);
  2036. RECT dummyRect = {0,0,0,0};
  2037. status = player->EnumerateEmfRecords(hdc, hEmf, &dest,
  2038. &dummyRect, EnumEmfWithDownLevel);
  2039. }
  2040. else
  2041. {
  2042. UINT32 * bits;
  2043. HBITMAP hBitmap;
  2044. // The down-level records will get drawn into a dib section HDC
  2045. // which will then be drawn to the real hdc by g->DrawImage.
  2046. // !!! I should probably save the visible clip region at this
  2047. // point so that clipping in the EMF+ doesn't affect the down-level
  2048. // records.
  2049. // Set the World Tranform to be the PreContainer Transform
  2050. // And restore it after we're transformed the dest
  2051. player->BitmapDpi = Context->ContainerDpiX;
  2052. hBitmap = CreateDibSection32Bpp(hdc, destRect, dest, &bits, &player->BitmapDpi, &player->PreContainerMatrix);
  2053. status = GenericError;
  2054. if (hBitmap != NULL)
  2055. {
  2056. HDC hdcDib = CreateCompatibleDC(NULL);
  2057. if (hdcDib != NULL)
  2058. {
  2059. // set up the player data
  2060. player->BitmapBits = bits;
  2061. player->BitmapWidth = dest.right;
  2062. player->BitmapHeight = dest.bottom;
  2063. player->BitmapDestRect = destRect;
  2064. ::SelectObject(hdcDib, hBitmap);
  2065. status = player->EnumerateEmfRecords(hdcDib, hEmf, &dest,
  2066. &dest, EnumEmfWithDownLevel);
  2067. ::DeleteDC(hdcDib);
  2068. // so DoneWithDownLevel call below works right
  2069. player->BitmapBits = NULL;
  2070. }
  2071. DeleteObject(hBitmap);
  2072. }
  2073. else if ((dest.right == 0) || (dest.bottom == 0))
  2074. {
  2075. status = Ok;
  2076. }
  2077. }
  2078. }
  2079. }
  2080. }
  2081. // else Nothing to play Everything is clipped out
  2082. }
  2083. // The Hdc should get set back to null when we reach the EMF+ EOF record
  2084. // But clean up anyway, just in case something went wrong.
  2085. player->DoneWithDownLevel();
  2086. // Restore the HDC back to the state we initially set up.
  2087. Context->ResetHdc();
  2088. if (hwnd != NULL)
  2089. {
  2090. ReleaseDC(hwnd, hdc);
  2091. // Now, restore the hwnd in the graphics context.
  2092. Context->Hwnd = hwnd;
  2093. Context->Hdc = NULL;
  2094. }
  2095. else
  2096. {
  2097. // Now restore the HDC back to the real application state.
  2098. RestoreDC(hdc, saveDC);
  2099. if (needToReleaseHdc)
  2100. {
  2101. Context->ReleaseHdc(hdc);
  2102. }
  2103. }
  2104. return status;
  2105. }
  2106. /**************************************************************************\
  2107. *
  2108. * Function Description:
  2109. *
  2110. * GpMetafile destructor
  2111. *
  2112. * Arguments:
  2113. *
  2114. * NONE
  2115. *
  2116. * Return Value:
  2117. *
  2118. * NONE
  2119. *
  2120. * Created:
  2121. *
  2122. * 6/15/1999 DCurtis
  2123. *
  2124. \**************************************************************************/
  2125. GpMetafile::~GpMetafile()
  2126. {
  2127. CleanUp();
  2128. }
  2129. VOID
  2130. GpMetafile::CleanUp()
  2131. {
  2132. if ((MetaGraphics != NULL) && (!RequestedMetaGraphics))
  2133. {
  2134. // If for some reason the app never requsted the MetaGraphics,
  2135. // then we'd better delete it.
  2136. delete MetaGraphics;
  2137. }
  2138. if (State == RecordingMetafileState)
  2139. {
  2140. // EndRecording was never called, which means that the MetaGraphics
  2141. // was never deleted. So clean things up and invalidate the
  2142. // MetaGraphics.
  2143. ASSERT(MetaGraphics->Metafile != NULL);
  2144. MetaGraphics->Metafile->EndRecording(); // deletes the recorder
  2145. // Endrecording sets the MetaGraphics to NULL so don't touch it anymore
  2146. WARNING(("Deleted Metafile before deleting MetaGraphics"));
  2147. }
  2148. if ((Hemf != NULL) && DeleteHemf)
  2149. {
  2150. if (Header.IsEmfOrEmfPlus())
  2151. {
  2152. DeleteEnhMetaFile(Hemf);
  2153. }
  2154. else
  2155. {
  2156. DeleteMetaFile((HMETAFILE)Hemf);
  2157. }
  2158. }
  2159. if (Filename != NULL)
  2160. {
  2161. GpFree(Filename);
  2162. }
  2163. else if (Stream != NULL) // only for recording
  2164. {
  2165. // the stream position should already be at the end
  2166. // of the metafile.
  2167. Stream->Release();
  2168. }
  2169. delete Player;
  2170. }
  2171. extern "C"
  2172. int CALLBACK
  2173. EnumGetEmfPlusHeader(
  2174. HDC hdc, // should be NULL
  2175. HANDLETABLE FAR * gdiHandleTable,
  2176. CONST ENHMETARECORD * emfRecord,
  2177. int numHandles,
  2178. LPARAM emfPlusHeader
  2179. )
  2180. {
  2181. if ((emfRecord != NULL) && (emfRecord->nSize >= sizeof(EMR)) &&
  2182. (emfPlusHeader != NULL))
  2183. {
  2184. if (emfRecord->iType == EMR_HEADER)
  2185. {
  2186. return 1; // skip the header and keep enumerating
  2187. }
  2188. if (IsEmfPlusRecord(emfRecord) &&
  2189. (emfRecord->nSize >= (sizeof(EMR) + sizeof(DWORD) + // comment data size
  2190. sizeof(INT32) + // signature
  2191. sizeof(EmfPlusRecord) +
  2192. sizeof(EmfPlusHeaderRecord))))
  2193. {
  2194. GpMemcpy((VOID*)emfPlusHeader,
  2195. ((CONST EMRGDICOMMENT *)emfRecord)->Data + sizeof(INT32),
  2196. sizeof(EmfPlusRecord) + sizeof(EmfPlusHeaderRecord));
  2197. }
  2198. }
  2199. else
  2200. {
  2201. WARNING(("Bad Enumeration Parameter"));
  2202. }
  2203. return 0; // don't enumerate any more records
  2204. }
  2205. HENHMETAFILE
  2206. GetEmfFromWmfData(
  2207. HMETAFILE hWmf,
  2208. BYTE * wmfData,
  2209. UINT size
  2210. )
  2211. {
  2212. if (wmfData == NULL ||
  2213. hWmf == NULL ||
  2214. size < (sizeof(METAHEADER)+sizeof(META_ESCAPE_ENHANCED_METAFILE)))
  2215. {
  2216. ASSERTMSG(FALSE, ("GetEmfFromWmfData: Someone passed an invalid argument"));
  2217. return NULL;
  2218. }
  2219. HENHMETAFILE hemf32 = NULL;
  2220. HDC hMFDC = NULL;
  2221. PMETA_ESCAPE_ENHANCED_METAFILE pmfeEnhMF;
  2222. PBYTE pMetaData32 = (PBYTE) NULL;
  2223. pmfeEnhMF = (PMETA_ESCAPE_ENHANCED_METAFILE) &wmfData[sizeof(METAHEADER)];
  2224. if (IsMetaEscapeEnhancedMetafile(pmfeEnhMF))
  2225. {
  2226. UINT i;
  2227. UINT cbMetaData32;
  2228. if (pmfeEnhMF->fFlags != 0)
  2229. {
  2230. ASSERTMSG(FALSE, ("GetEmfFromWmfData: Unrecognized Windows metafile\n"));
  2231. goto SWMFB_UseConverter;
  2232. }
  2233. // Validate checksum
  2234. if (GetWordCheckSum(size, (PWORD) wmfData))
  2235. {
  2236. ASSERTMSG(FALSE, ("GetEmfFromWmfData: Metafile has been modified\n"));
  2237. goto SWMFB_UseConverter;
  2238. }
  2239. // Unpack the data from the small chunks of metafile comment records
  2240. // Windows 3.0 chokes on Comment Record > 8K?
  2241. // We probably could probably just error out if out of memory but
  2242. // lets try to convert just because the embedded comment might be bad.
  2243. TERSE(("GetEmfFromWmfData: Using embedded enhanced metafile\n"));
  2244. cbMetaData32 = (UINT) pmfeEnhMF->cbEnhMetaFile;
  2245. if (!(pMetaData32 = (PBYTE) GpMalloc(cbMetaData32)))
  2246. {
  2247. ASSERTMSG(FALSE, ("GetEmfFromWmfData: LocalAlloc Failed"));
  2248. goto SWMFB_UseConverter;
  2249. }
  2250. i = 0;
  2251. do
  2252. {
  2253. if (i + pmfeEnhMF->cbCurrent > cbMetaData32)
  2254. {
  2255. ASSERTMSG(FALSE, ("GetEmfFromWmfData: Bad metafile comment"));
  2256. goto SWMFB_UseConverter;
  2257. }
  2258. GpMemcpy(&pMetaData32[i], (PBYTE) &pmfeEnhMF[1], pmfeEnhMF->cbCurrent);
  2259. i += (UINT) pmfeEnhMF->cbCurrent;
  2260. pmfeEnhMF = (PMETA_ESCAPE_ENHANCED_METAFILE)
  2261. ((PWORD) pmfeEnhMF + pmfeEnhMF->rdSize);
  2262. } while (IsMetaEscapeEnhancedMetafile(pmfeEnhMF));
  2263. if (i != cbMetaData32)
  2264. {
  2265. ASSERTMSG(FALSE, ("GetEmfFromWmfData: Insufficient metafile data"));
  2266. goto SWMFB_UseConverter;
  2267. }
  2268. // Set the memory directly into the enhanced metafile and return the
  2269. // metafile.
  2270. hemf32 = SetEnhMetaFileBits(cbMetaData32, pMetaData32);
  2271. }
  2272. SWMFB_UseConverter:
  2273. if( hemf32 == NULL)
  2274. {
  2275. hMFDC = CreateEnhMetaFileA(NULL, NULL, NULL, NULL);
  2276. if (hMFDC != NULL)
  2277. {
  2278. // Set the MapMode and Extent to
  2279. INT iMapMode = MM_ANISOTROPIC;
  2280. HDC hdcRef = ::GetDC(NULL);
  2281. INT xExtPels = ::GetDeviceCaps(hdcRef, HORZRES);
  2282. INT yExtPels = ::GetDeviceCaps(hdcRef, VERTRES);
  2283. ::ReleaseDC(NULL, hdcRef);
  2284. BOOL success = (::SetMapMode(hMFDC, iMapMode) &&
  2285. ::SetViewportExtEx(hMFDC, xExtPels, yExtPels, NULL) &&
  2286. ::SetWindowExtEx(hMFDC, xExtPels, yExtPels, NULL) &&
  2287. ::PlayMetaFile(hMFDC, hWmf));
  2288. hemf32 = CloseEnhMetaFile(hMFDC);
  2289. if ((!success) && (hemf32 != NULL))
  2290. {
  2291. DeleteEnhMetaFile(hemf32);
  2292. hemf32 = NULL;
  2293. }
  2294. }
  2295. }
  2296. if (pMetaData32 != NULL)
  2297. {
  2298. GpFree(pMetaData32);
  2299. }
  2300. return hemf32 ;
  2301. }
  2302. GpStatus
  2303. GetEmfHeader(
  2304. MetafileHeader & header,
  2305. ENHMETAHEADER3 & emfHeader,
  2306. EmfPlusRecord * record,
  2307. INT signature
  2308. )
  2309. {
  2310. GpStatus status = Ok;
  2311. // !!! how to handle versioning for shipping?
  2312. // !!! allow different minor versions, but not major versions?
  2313. EmfPlusHeaderRecord * emfPlusHeader = (EmfPlusHeaderRecord *)(record + 1);
  2314. // See if this is an EMF+ file
  2315. if ((signature == EMFPLUS_SIGNATURE) &&
  2316. (record->Size >= (sizeof(EmfPlusRecord) + sizeof(EmfPlusHeaderRecord))) &&
  2317. (record->Type == EmfPlusRecordTypeHeader) &&
  2318. (record->DataSize == (record->Size - sizeof(EmfPlusRecord))) &&
  2319. (ObjectData::MajorVersionMatches(emfPlusHeader->Version)) &&
  2320. (emfPlusHeader->LogicalDpiX > 0) &&
  2321. (emfPlusHeader->LogicalDpiY > 0))
  2322. {
  2323. if (GetIsEmfPlusDual(record->Flags))
  2324. {
  2325. header.Type = MetafileTypeEmfPlusDual;
  2326. }
  2327. else
  2328. {
  2329. header.Type = MetafileTypeEmfPlusOnly;
  2330. }
  2331. header.EmfPlusHeaderSize = record->Size;
  2332. header.Version = emfPlusHeader->Version;
  2333. header.EmfPlusFlags = emfPlusHeader->EmfPlusFlags;
  2334. header.LogicalDpiX = emfPlusHeader->LogicalDpiX;
  2335. header.LogicalDpiY = emfPlusHeader->LogicalDpiY;
  2336. }
  2337. else
  2338. {
  2339. header.Type = MetafileTypeEmf;
  2340. header.Version = emfHeader.nVersion;
  2341. }
  2342. header.Size = emfHeader.nBytes;
  2343. // EmfHeaderIsValid() verifies that these are all > 0
  2344. REAL dpmmX = ((REAL)(emfHeader.szlDevice.cx) /
  2345. (REAL)(emfHeader.szlMillimeters.cx));
  2346. REAL dpmmY = ((REAL)(emfHeader.szlDevice.cy) /
  2347. (REAL)(emfHeader.szlMillimeters.cy));
  2348. header.DpiX = dpmmX * 25.4f;
  2349. header.DpiY = dpmmY * 25.4f;
  2350. INT top;
  2351. INT left;
  2352. INT right;
  2353. INT bottom;
  2354. // Make sure we have a normalized frameRect
  2355. if (emfHeader.rclFrame.left <= emfHeader.rclFrame.right)
  2356. {
  2357. left = emfHeader.rclFrame.left;
  2358. right = emfHeader.rclFrame.right;
  2359. }
  2360. else
  2361. {
  2362. left = emfHeader.rclFrame.right;
  2363. right = emfHeader.rclFrame.left;
  2364. }
  2365. if (emfHeader.rclFrame.top <= emfHeader.rclFrame.bottom)
  2366. {
  2367. top = emfHeader.rclFrame.top;
  2368. bottom = emfHeader.rclFrame.bottom;
  2369. }
  2370. else
  2371. {
  2372. top = emfHeader.rclFrame.bottom;
  2373. bottom = emfHeader.rclFrame.top;
  2374. }
  2375. // Make the device bounds reflect the frameRect,
  2376. // not the actual size of the drawing.
  2377. dpmmX *= 0.01f;
  2378. dpmmY *= 0.01f;
  2379. // The frameRect is inclusive-inclusive, but the bounds in
  2380. // the header is inclusive-exclusive.
  2381. REAL x = (REAL)(left) * dpmmX;
  2382. REAL y = (REAL)(top) * dpmmY;
  2383. REAL w = ((REAL)(right - left) * dpmmX) + 1.0f;
  2384. REAL h = ((REAL)(bottom - top) * dpmmY) + 1.0f;
  2385. header.X = GpRound(x);
  2386. header.Y = GpRound(y);
  2387. header.Width = GpRound(w);
  2388. header.Height = GpRound(h);
  2389. header.EmfHeader = emfHeader;
  2390. if ((header.Width == 0) || (header.Height == 0))
  2391. {
  2392. status = InvalidParameter;
  2393. }
  2394. return status;
  2395. }
  2396. HENHMETAFILE
  2397. GetEmf(
  2398. IStream * stream,
  2399. BOOL isWmf,
  2400. UINT size
  2401. )
  2402. {
  2403. HENHMETAFILE hEmf = NULL;
  2404. #if PROFILE_MEMORY_USAGE
  2405. MC_LogAllocation(size);
  2406. #endif
  2407. HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, size);
  2408. if (hGlobal != NULL)
  2409. {
  2410. HRESULT hResult;
  2411. IStream * memoryStream = NULL;
  2412. hResult = CreateStreamOnHGlobal(hGlobal, TRUE, &memoryStream);
  2413. if (HResultSuccess(hResult) && (memoryStream != NULL))
  2414. {
  2415. if (CopyStream(stream, memoryStream, size))
  2416. {
  2417. BYTE * metaData = (BYTE *)GlobalLock(hGlobal);
  2418. if (metaData != NULL)
  2419. {
  2420. if (isWmf)
  2421. {
  2422. hEmf = (HENHMETAFILE)SetMetaFileBitsEx(size, metaData);
  2423. }
  2424. else
  2425. {
  2426. hEmf = SetEnhMetaFileBits(size, metaData);
  2427. }
  2428. }
  2429. GlobalUnlock(hGlobal);
  2430. }
  2431. memoryStream->Release(); // frees the memory
  2432. }
  2433. else
  2434. {
  2435. GlobalFree(hGlobal);
  2436. }
  2437. }
  2438. return hEmf;
  2439. }
  2440. static VOID
  2441. GetWmfHeader(
  2442. MetafileHeader & header,
  2443. METAHEADER & wmfHeader,
  2444. const WmfPlaceableFileHeader * wmfPlaceableFileHeader
  2445. )
  2446. {
  2447. ASSERT(WmfPlaceableHeaderIsValid(wmfPlaceableFileHeader));
  2448. ASSERT(WmfHeaderIsValid(&wmfHeader));
  2449. header.Type = MetafileTypeWmfPlaceable;
  2450. header.Size = wmfHeader.mtSize * 2L;
  2451. header.Version = wmfHeader.mtVersion;
  2452. header.WmfHeader = wmfHeader;
  2453. if (wmfPlaceableFileHeader->Inch > 0)
  2454. {
  2455. header.DpiX = wmfPlaceableFileHeader->Inch;
  2456. header.DpiY = wmfPlaceableFileHeader->Inch;
  2457. }
  2458. else // guess at the Dpi
  2459. {
  2460. header.DpiX = 1440.0f;
  2461. header.DpiY = 1440.0f;
  2462. // Something wrong but continue
  2463. }
  2464. // already verified the checksum
  2465. // Unlike the EMF header the Placeable header is Inclusive-Exclusive
  2466. // So don't add 1 device unit
  2467. if (wmfPlaceableFileHeader->BoundingBox.Left <
  2468. wmfPlaceableFileHeader->BoundingBox.Right)
  2469. {
  2470. header.X = wmfPlaceableFileHeader->BoundingBox.Left;
  2471. header.Width = wmfPlaceableFileHeader->BoundingBox.Right -
  2472. wmfPlaceableFileHeader->BoundingBox.Left;
  2473. }
  2474. else
  2475. {
  2476. header.X = wmfPlaceableFileHeader->BoundingBox.Right;
  2477. header.Width = wmfPlaceableFileHeader->BoundingBox.Left -
  2478. wmfPlaceableFileHeader->BoundingBox.Right;
  2479. }
  2480. if (wmfPlaceableFileHeader->BoundingBox.Top <
  2481. wmfPlaceableFileHeader->BoundingBox.Bottom)
  2482. {
  2483. header.Y = wmfPlaceableFileHeader->BoundingBox.Top;
  2484. header.Height = wmfPlaceableFileHeader->BoundingBox.Bottom -
  2485. wmfPlaceableFileHeader->BoundingBox.Top;
  2486. }
  2487. else
  2488. {
  2489. header.Y = wmfPlaceableFileHeader->BoundingBox.Bottom;
  2490. header.Height = wmfPlaceableFileHeader->BoundingBox.Top -
  2491. wmfPlaceableFileHeader->BoundingBox.Bottom;
  2492. }
  2493. }
  2494. extern "C"
  2495. int CALLBACK
  2496. EnumWmfToGetHeader(
  2497. HDC hdc, // should be NULL
  2498. HANDLETABLE FAR * gdiHandleTable,
  2499. METARECORD FAR * wmfRecord,
  2500. int numHandles,
  2501. LPARAM wmfHeader
  2502. )
  2503. {
  2504. ASSERT(wmfHeader != NULL);
  2505. if ((wmfRecord != NULL) &&
  2506. (((UNALIGNED METARECORD *)wmfRecord)->rdSize >= 3))
  2507. {
  2508. // The first record that it gives us is the first one past the header,
  2509. // not the header itself, so we have to back up on the pointer.
  2510. GpMemcpy((VOID *)wmfHeader, ((BYTE *)wmfRecord) - sizeof(METAHEADER),
  2511. sizeof(METAHEADER));
  2512. }
  2513. else
  2514. {
  2515. WARNING(("Bad Enumeration Parameter"));
  2516. }
  2517. return 0; // Don't enumerate any more records
  2518. }
  2519. GpStatus
  2520. GetMetafileHeader(
  2521. HMETAFILE hWmf,
  2522. const WmfPlaceableFileHeader * wmfPlaceableFileHeader,
  2523. MetafileHeader & header
  2524. )
  2525. {
  2526. ASSERT((hWmf != NULL) && (wmfPlaceableFileHeader != NULL));
  2527. GpMemset(&header, 0, sizeof(header));
  2528. if (WmfPlaceableHeaderIsValid(wmfPlaceableFileHeader))
  2529. {
  2530. METAHEADER wmfHeader;
  2531. GpMemset(&wmfHeader, 0, sizeof(wmfHeader));
  2532. ::EnumMetaFile(NULL, hWmf, EnumWmfToGetHeader, (LPARAM)&wmfHeader);
  2533. if (!WmfHeaderIsValid(&wmfHeader))
  2534. {
  2535. //ASSERT(WmfHeaderIsValid(&wmfHeader));
  2536. WARNING(("GetMetafileHeader: WmfHeaderIsValid FAILED!"));
  2537. wmfHeader.mtType = MEMORYMETAFILE;
  2538. wmfHeader.mtHeaderSize = sizeof(METAHEADER) / sizeof(WORD);
  2539. wmfHeader.mtVersion = METAVERSION300;
  2540. wmfHeader.mtSize = GetMetaFileBitsEx(hWmf, 0, NULL) / 2;
  2541. wmfHeader.mtNoObjects = 0;
  2542. wmfHeader.mtMaxRecord = 0;
  2543. wmfHeader.mtNoParameters = 0;
  2544. }
  2545. GetWmfHeader(header, wmfHeader, wmfPlaceableFileHeader);
  2546. return Ok;
  2547. }
  2548. return InvalidParameter;
  2549. }
  2550. GpStatus
  2551. GetMetafileHeader(
  2552. HENHMETAFILE hEmf,
  2553. MetafileHeader & header,
  2554. BOOL * isCorrupted
  2555. )
  2556. {
  2557. ASSERT(hEmf != NULL);
  2558. GpMemset(&header, 0, sizeof(header));
  2559. ENHMETAHEADER3 emfHeader;
  2560. if ((GetEnhMetaFileHeader(hEmf, sizeof(emfHeader),
  2561. (ENHMETAHEADER*)(&emfHeader)) <= 0) ||
  2562. !EmfHeaderIsValid(emfHeader))
  2563. {
  2564. if (isCorrupted != NULL)
  2565. {
  2566. *isCorrupted = FALSE;
  2567. }
  2568. return InvalidParameter;
  2569. }
  2570. // Now we know it is an EMF
  2571. BYTE buffer[sizeof(EmfPlusRecord) + sizeof(EmfPlusHeaderRecord)];
  2572. GpMemset(buffer, 0, sizeof(EmfPlusRecord) + sizeof(EmfPlusHeaderRecord));
  2573. // No reason to enumerate the metafile if there are only
  2574. // header and EOF records.
  2575. if (emfHeader.nRecords > 2)
  2576. {
  2577. ::EnumEnhMetaFile(NULL, hEmf, EnumGetEmfPlusHeader, buffer, NULL);
  2578. }
  2579. GpStatus status;
  2580. status = GetEmfHeader(header, emfHeader, (EmfPlusRecord *)buffer,
  2581. (((EmfPlusRecord *)buffer)->Size != 0) ? EMFPLUS_SIGNATURE : 0);
  2582. if (isCorrupted != NULL)
  2583. {
  2584. *isCorrupted = (status != Ok);
  2585. }
  2586. return status;
  2587. }
  2588. GpStatus
  2589. GetEmfFromWmf(
  2590. IStream * stream,
  2591. UINT streamSize,
  2592. MetafileHeader & header,
  2593. HENHMETAFILE * hEMF
  2594. )
  2595. {
  2596. if (stream == NULL || hEMF == NULL)
  2597. {
  2598. ASSERT(FALSE);
  2599. return InvalidParameter;
  2600. }
  2601. GpStatus status = Win32Error;
  2602. IStream * memStream;
  2603. ASSERT(hEMF != NULL);
  2604. *hEMF = NULL ;
  2605. HMETAFILE hWMF = (HMETAFILE) GetEmf(stream, TRUE, streamSize);
  2606. if (hWMF != NULL)
  2607. {
  2608. BYTE * wmfData = (BYTE*)GpMalloc(streamSize);
  2609. if (wmfData != NULL)
  2610. {
  2611. GetMetaFileBitsEx(hWMF, streamSize, wmfData);
  2612. *hEMF = GetEmfFromWmfData(hWMF, wmfData, streamSize);
  2613. if (*hEMF != NULL)
  2614. {
  2615. status = GetMetafileHeader(*hEMF, header);
  2616. }
  2617. GpFree(wmfData);
  2618. }
  2619. }
  2620. if (hWMF != NULL)
  2621. {
  2622. DeleteMetaFile(hWMF);
  2623. }
  2624. return status;
  2625. }
  2626. // If we fail, the stream position will be right where it started.
  2627. // If we succeed, the stream position will be at the end of the WMF/EMF
  2628. static GpStatus
  2629. GetHeaderAndMetafile(
  2630. IStream * stream,
  2631. MetafileHeader & header,
  2632. HENHMETAFILE * hEMF, // We can have a NULL hEMF, then we just want the header.
  2633. BOOL * isCorrupted,
  2634. BOOL tryWmfOnly = FALSE
  2635. )
  2636. {
  2637. GpMemset(&header, 0, sizeof(header));
  2638. if (stream == NULL || isCorrupted == NULL)
  2639. {
  2640. WARNING(("IN Parameter Stream or Corruption flag is NULL"));
  2641. return InvalidParameter;
  2642. }
  2643. GpStatus status = InvalidParameter;
  2644. LONGLONG startPosition;
  2645. LONGLONG streamSize;
  2646. STATSTG statstg;
  2647. BOOL corrupted = FALSE;
  2648. // Save the start position of the metafile in case we have to try
  2649. // more than once.
  2650. if (!GetStreamPosition(stream, startPosition))
  2651. {
  2652. return Win32Error;
  2653. }
  2654. // We don't want to read past the end of the steam so make sure
  2655. // that we don't exceed it. If we succeed the set the streamSize
  2656. if(SUCCEEDED(stream->Stat(&statstg, STATFLAG_NONAME)))
  2657. {
  2658. streamSize = statstg.cbSize.QuadPart;
  2659. }
  2660. else
  2661. {
  2662. WARNING1("Couldn't get size of Stream");
  2663. streamSize = INT_MAX;
  2664. }
  2665. if (!tryWmfOnly)
  2666. {
  2667. ENHMETAHEADER3 emfHeader;
  2668. BOOL isEmf;
  2669. // Read the EMF header and make sure it's valid
  2670. isEmf = (ReadBytes(stream, &emfHeader, sizeof(emfHeader)) &&
  2671. EmfHeaderIsValid(emfHeader));
  2672. if (isEmf)
  2673. {
  2674. struct EmfPlusSecondMetafileRecord {
  2675. EMR emr;
  2676. DWORD commentDataSize;
  2677. INT32 signature;
  2678. EmfPlusRecord record;
  2679. EmfPlusHeaderRecord emfPlusHeader;
  2680. } secondRecord;
  2681. GpMemset(&secondRecord, 0, sizeof(secondRecord));
  2682. // No reason to read the metafile if there are only
  2683. // header and EOF records.
  2684. if ((emfHeader.nRecords > 2) &&
  2685. (emfHeader.nBytes >= (emfHeader.nSize + sizeof(secondRecord))))
  2686. {
  2687. if (SeekFromStart(stream, startPosition + emfHeader.nSize))
  2688. {
  2689. ReadBytes(stream, &secondRecord, sizeof(secondRecord));
  2690. if (!IsEmfPlusRecord((ENHMETARECORD *)&secondRecord))
  2691. {
  2692. // make sure that whatever data was there isn't
  2693. // interpreted as a EMF+ header
  2694. secondRecord.signature = 0;
  2695. }
  2696. }
  2697. }
  2698. status = GetEmfHeader(header, emfHeader, &secondRecord.record, secondRecord.signature);
  2699. // Seek back to the start of the metafile.
  2700. if ((hEMF != NULL) && (status == Ok))
  2701. {
  2702. if (!SeekFromStart(stream, startPosition))
  2703. {
  2704. *isCorrupted = TRUE;
  2705. return Win32Error;
  2706. }
  2707. *hEMF = GetEmf(stream, FALSE /*isWMF*/,
  2708. (UINT)min(header.GetMetafileSize(), streamSize - startPosition));
  2709. if (*hEMF == NULL)
  2710. {
  2711. status = GenericError;
  2712. }
  2713. }
  2714. corrupted = (status != Ok);
  2715. goto Exit;
  2716. }
  2717. // Seek back to the start of the metafile so we can try WMF
  2718. if (!SeekFromStart(stream, startPosition))
  2719. {
  2720. *isCorrupted = FALSE;
  2721. return Win32Error;
  2722. }
  2723. }
  2724. // It's not an EMF, try a WMF
  2725. {
  2726. WmfPlaceableFileHeader wmfPlaceableFileHeader;
  2727. METAHEADER wmfHeader;
  2728. BOOL isPlaceable;
  2729. BOOL isWMF;
  2730. isPlaceable = (ReadBytes(stream, &wmfPlaceableFileHeader, sizeof(wmfPlaceableFileHeader)) &&
  2731. WmfPlaceableHeaderIsValid(&wmfPlaceableFileHeader) &&
  2732. ReadBytes(stream, &wmfHeader, sizeof(wmfHeader)) &&
  2733. WmfHeaderIsValid(&wmfHeader));
  2734. if (isPlaceable)
  2735. {
  2736. GetWmfHeader(header, wmfHeader, &wmfPlaceableFileHeader);
  2737. status = Ok;
  2738. corrupted = FALSE;
  2739. if (hEMF != NULL)
  2740. {
  2741. if (!SeekFromStart(stream, startPosition + sizeof(wmfPlaceableFileHeader)))
  2742. {
  2743. *isCorrupted = TRUE;
  2744. return Win32Error;
  2745. }
  2746. *hEMF = GetEmf(stream, TRUE /* isWMF */,
  2747. (UINT)min(header.GetMetafileSize(), streamSize - (startPosition + sizeof(wmfPlaceableFileHeader))));
  2748. if (*hEMF == NULL)
  2749. {
  2750. status = GenericError;
  2751. corrupted = TRUE;
  2752. }
  2753. }
  2754. goto Exit;
  2755. }
  2756. // We could have an placeableWmf header with bad data in it, so skip
  2757. // the placeable header for subsequent access to the WMF.
  2758. INT wmfOffset = (wmfPlaceableFileHeader.Key == GDIP_WMF_PLACEABLEKEY) ?
  2759. sizeof(WmfPlaceableFileHeader) : 0;
  2760. if (!SeekFromStart(stream, startPosition + wmfOffset))
  2761. {
  2762. *isCorrupted = FALSE;
  2763. return Win32Error;
  2764. }
  2765. isWMF = (ReadBytes(stream, &wmfHeader, sizeof(wmfHeader)) &&
  2766. WmfHeaderIsValid(&wmfHeader));
  2767. if (isWMF)
  2768. {
  2769. // Seek to the start of the WMF metafile.
  2770. if (!SeekFromStart(stream, startPosition + wmfOffset))
  2771. {
  2772. *isCorrupted = TRUE;
  2773. return Win32Error;
  2774. }
  2775. UINT wmfSize = min((wmfHeader.mtSize * 2L),
  2776. (UINT)(streamSize - (startPosition + wmfOffset)));
  2777. if (hEMF != NULL)
  2778. {
  2779. status = GetEmfFromWmf(stream, wmfSize, header, hEMF);
  2780. }
  2781. else
  2782. {
  2783. HENHMETAFILE tmpEMF = NULL;
  2784. status = GetEmfFromWmf(stream, wmfSize, header, &tmpEMF);
  2785. if (tmpEMF != NULL)
  2786. {
  2787. DeleteEnhMetaFile(tmpEMF);
  2788. }
  2789. }
  2790. corrupted = (status != Ok);
  2791. }
  2792. }
  2793. Exit:
  2794. *isCorrupted = corrupted;
  2795. if (status == Ok)
  2796. {
  2797. // set the stream position to the end of the metafile
  2798. SeekFromStart(stream, startPosition + header.GetMetafileSize());
  2799. return Ok;
  2800. }
  2801. // set the stream position to the start of the metafile
  2802. SeekFromStart(stream, startPosition);
  2803. return status;
  2804. }
  2805. VOID
  2806. GpMetafile::InitStream(
  2807. IStream* stream,
  2808. BOOL tryWmfOnly
  2809. )
  2810. {
  2811. BOOL isCorrupted = FALSE;
  2812. // We just use the stream long enough to create an hEMF
  2813. stream->AddRef();
  2814. if ((GetHeaderAndMetafile(stream, Header, &Hemf, &isCorrupted, tryWmfOnly) == Ok) &&
  2815. (Hemf != NULL))
  2816. {
  2817. State = DoneRecordingMetafileState;
  2818. }
  2819. else if (isCorrupted)
  2820. {
  2821. State = CorruptedMetafileState;
  2822. }
  2823. stream->Release();
  2824. }
  2825. GpStatus
  2826. GetMetafileHeader(
  2827. IStream * stream,
  2828. MetafileHeader & header,
  2829. BOOL tryWmfOnly
  2830. )
  2831. {
  2832. BOOL isCorrupted = FALSE;
  2833. return GetHeaderAndMetafile(stream, header, NULL, &isCorrupted, tryWmfOnly);
  2834. }
  2835. GpStatus
  2836. GetMetafileHeader(
  2837. const WCHAR * filename,
  2838. MetafileHeader & header
  2839. )
  2840. {
  2841. GpStatus status = InvalidParameter;
  2842. ASSERT(filename != NULL);
  2843. if (filename != NULL)
  2844. {
  2845. const WCHAR* ext = UnicodeStringReverseSearch(filename, L'.');
  2846. // Get a stream only long enough to validate the metafile
  2847. IStream * metaStream = CreateStreamOnFile(filename, GENERIC_READ);
  2848. if (metaStream != NULL)
  2849. {
  2850. // apm is for a Placeable Metafile
  2851. BOOL tryWmf = (ext &&
  2852. (UnicodeStringCompareCI(ext, L".WMF") ||
  2853. UnicodeStringCompareCI(ext, L".APM")));
  2854. BOOL isCorrupted = FALSE;
  2855. status = GetHeaderAndMetafile(metaStream, header, NULL, &isCorrupted, tryWmf);
  2856. // if we tried a WMF, but it's not a WMF, then try an EMF
  2857. if ((status != Ok) && tryWmf && !isCorrupted)
  2858. {
  2859. status = GetHeaderAndMetafile(metaStream, header, NULL, &isCorrupted, FALSE);
  2860. }
  2861. metaStream->Release();
  2862. }
  2863. }
  2864. return status;
  2865. }
  2866. VOID
  2867. GpMetafile::InitWmf(
  2868. HMETAFILE hWmf,
  2869. const WmfPlaceableFileHeader * wmfPlaceableFileHeader,
  2870. BOOL deleteWmf
  2871. )
  2872. {
  2873. // See if there is an wmfPlaceableFileHeader we can use
  2874. if ((wmfPlaceableFileHeader != NULL) && (WmfPlaceableHeaderIsValid(wmfPlaceableFileHeader)))
  2875. {
  2876. if (GetMetafileHeader(hWmf, wmfPlaceableFileHeader, Header) == Ok)
  2877. {
  2878. DeleteHemf = (deleteWmf != 0);
  2879. Hemf = (HENHMETAFILE)hWmf;
  2880. State = DoneRecordingMetafileState;
  2881. return;
  2882. }
  2883. else
  2884. {
  2885. // we know it's a WMF, but we couldn't get the header from it
  2886. State = CorruptedMetafileState;
  2887. }
  2888. }
  2889. else // no valid wmfPlaceableFileHeader
  2890. {
  2891. // We can have a null or invalid header since we accept WMF files
  2892. // (by turning them into EMFs).
  2893. UINT size = GetMetaFileBitsEx(hWmf, 0, NULL);
  2894. if (size > 0)
  2895. {
  2896. BYTE * wmfData = (BYTE*) GpMalloc(size);
  2897. if (wmfData != NULL)
  2898. {
  2899. if (GetMetaFileBitsEx(hWmf, size, wmfData) > 0)
  2900. {
  2901. HENHMETAFILE hEmf = GetEmfFromWmfData(hWmf, wmfData, size);
  2902. if (hEmf != NULL)
  2903. {
  2904. BOOL isCorrupted;
  2905. if (GetMetafileHeader(hEmf, Header, &isCorrupted) == Ok)
  2906. {
  2907. // Since we created this EMF we need to delete it afterwards
  2908. DeleteHemf = TRUE;
  2909. Hemf = hEmf;
  2910. State = DoneRecordingMetafileState;
  2911. }
  2912. else
  2913. {
  2914. if (isCorrupted)
  2915. {
  2916. // we know it's a metafile, but we couldn't get the header
  2917. State = CorruptedMetafileState;
  2918. }
  2919. DeleteEnhMetaFile(hEmf);
  2920. }
  2921. }
  2922. }
  2923. GpFree(wmfData);
  2924. }
  2925. }
  2926. }
  2927. if (deleteWmf)
  2928. {
  2929. DeleteMetaFile(hWmf);
  2930. }
  2931. }
  2932. VOID
  2933. GpMetafile::InitEmf(
  2934. HENHMETAFILE hEmf,
  2935. BOOL deleteEmf
  2936. )
  2937. {
  2938. BOOL isCorrupted;
  2939. if (GetMetafileHeader(hEmf, Header, &isCorrupted) == Ok)
  2940. {
  2941. DeleteHemf = (deleteEmf != 0);
  2942. Hemf = hEmf;
  2943. State = DoneRecordingMetafileState;
  2944. return;
  2945. }
  2946. if (deleteEmf)
  2947. {
  2948. DeleteEnhMetaFile(hEmf);
  2949. }
  2950. if (isCorrupted)
  2951. {
  2952. State = CorruptedMetafileState;
  2953. }
  2954. }
  2955. /**************************************************************************\
  2956. *
  2957. * Function Description:
  2958. *
  2959. * GpMetafile constructor for read-only access to a metafile.
  2960. *
  2961. * Arguments:
  2962. *
  2963. * [IN] hWmf - the handle to the metafile to open for playback
  2964. * [IN] wmfPlaceableFileHeader - the Placeable header to give size info about the WMF
  2965. *
  2966. * Return Value:
  2967. *
  2968. * NONE
  2969. *
  2970. * Created:
  2971. *
  2972. * 10/06/1999 DCurtis
  2973. *
  2974. \**************************************************************************/
  2975. GpMetafile::GpMetafile(
  2976. HMETAFILE hWmf,
  2977. const WmfPlaceableFileHeader * wmfPlaceableFileHeader,
  2978. BOOL deleteWmf
  2979. ) : GpImage(ImageTypeMetafile)
  2980. {
  2981. ASSERT(hWmf != NULL);
  2982. InitDefaults();
  2983. if (IsValidMetaFile(hWmf))
  2984. {
  2985. InitWmf(hWmf, wmfPlaceableFileHeader, deleteWmf);
  2986. }
  2987. }
  2988. /**************************************************************************\
  2989. *
  2990. * Function Description:
  2991. *
  2992. * GpMetafile constructor for read-only access to a metafile.
  2993. *
  2994. * Arguments:
  2995. *
  2996. * [IN] hEmf - the handle to the metafile to open for playback
  2997. *
  2998. * Return Value:
  2999. *
  3000. * NONE
  3001. *
  3002. * Created:
  3003. *
  3004. * 10/06/1999 DCurtis
  3005. *
  3006. \**************************************************************************/
  3007. GpMetafile::GpMetafile(
  3008. HENHMETAFILE hEmf,
  3009. BOOL deleteEmf
  3010. ) : GpImage(ImageTypeMetafile)
  3011. {
  3012. ASSERT(hEmf != NULL);
  3013. InitDefaults();
  3014. if (GetObjectTypeInternal(hEmf) == OBJ_ENHMETAFILE)
  3015. {
  3016. InitEmf(hEmf, deleteEmf);
  3017. }
  3018. }
  3019. /**************************************************************************\
  3020. *
  3021. * Function Description:
  3022. *
  3023. * GpMetafile constructor for read-only access to a metafile.
  3024. *
  3025. * Arguments:
  3026. *
  3027. * [IN] filename - the metafile to open for playback
  3028. *
  3029. * Return Value:
  3030. *
  3031. * NONE
  3032. *
  3033. * Created:
  3034. *
  3035. * 6/15/1999 DCurtis
  3036. *
  3037. \**************************************************************************/
  3038. GpMetafile::GpMetafile(
  3039. const WCHAR* filename,
  3040. const WmfPlaceableFileHeader * wmfPlaceableFileHeader
  3041. ) : GpImage(ImageTypeMetafile)
  3042. {
  3043. ASSERT(filename != NULL);
  3044. InitDefaults();
  3045. if ((Filename = UnicodeStringDuplicate(filename)) != NULL)
  3046. {
  3047. const WCHAR* ext = UnicodeStringReverseSearch(filename, L'.');
  3048. // apm is for a Placeable Metafile
  3049. BOOL tryWmf = ((wmfPlaceableFileHeader != NULL) ||
  3050. (ext &&
  3051. (!UnicodeStringCompareCI(ext, L".WMF") ||
  3052. !UnicodeStringCompareCI(ext, L".APM"))));
  3053. BOOL triedEmf = FALSE;
  3054. AnsiStrFromUnicode nameStr(filename);
  3055. // If possible, use the filename to create the metafile handle
  3056. // so that we don't have to load the metafile into memory
  3057. // (GDI uses memory mapped files to access the metafile data).
  3058. if (Globals::IsNt || nameStr.IsValid())
  3059. {
  3060. TryWmf:
  3061. if (tryWmf)
  3062. {
  3063. HMETAFILE hWmf;
  3064. if (Globals::IsNt)
  3065. {
  3066. hWmf = ::GetMetaFileW(filename);
  3067. }
  3068. else
  3069. {
  3070. hWmf = ::GetMetaFileA(nameStr);
  3071. }
  3072. if (hWmf != NULL)
  3073. {
  3074. InitWmf(hWmf, wmfPlaceableFileHeader, TRUE);
  3075. if (IsValid() || IsCorrupted())
  3076. {
  3077. return;
  3078. }
  3079. }
  3080. else // might be a Placeable WMF file
  3081. {
  3082. IStream * metaStream = CreateStreamOnFile(filename, GENERIC_READ);
  3083. if (metaStream != NULL)
  3084. {
  3085. InitStream(metaStream, TRUE /* tryWmfOnly */);
  3086. metaStream->Release();
  3087. if (IsValid() || IsCorrupted())
  3088. {
  3089. return;
  3090. }
  3091. }
  3092. }
  3093. }
  3094. if (!triedEmf)
  3095. {
  3096. triedEmf = TRUE;
  3097. HENHMETAFILE hEmf;
  3098. if (Globals::IsNt)
  3099. {
  3100. hEmf = ::GetEnhMetaFileW(filename);
  3101. }
  3102. else
  3103. {
  3104. hEmf = ::GetEnhMetaFileA(nameStr);
  3105. }
  3106. if (hEmf != NULL)
  3107. {
  3108. InitEmf(hEmf, TRUE);
  3109. if (IsValid() || IsCorrupted())
  3110. {
  3111. return;
  3112. }
  3113. }
  3114. if (!tryWmf)
  3115. {
  3116. tryWmf = TRUE;
  3117. goto TryWmf;
  3118. }
  3119. }
  3120. }
  3121. }
  3122. }
  3123. /**************************************************************************\
  3124. *
  3125. * Function Description:
  3126. *
  3127. * GpMetafile constructor for read-only access to a metafile.
  3128. *
  3129. * Arguments:
  3130. *
  3131. * [IN] stream - the metafile to read for playback
  3132. *
  3133. * Return Value:
  3134. *
  3135. * NONE
  3136. *
  3137. * Created:
  3138. *
  3139. * 6/15/1999 DCurtis
  3140. *
  3141. \**************************************************************************/
  3142. GpMetafile::GpMetafile(
  3143. IStream* stream
  3144. ) : GpImage(ImageTypeMetafile)
  3145. {
  3146. ASSERT(stream != NULL);
  3147. InitDefaults();
  3148. InitStream(stream);
  3149. }
  3150. GpStatus
  3151. GpMetafile::GetHemf(
  3152. HENHMETAFILE * hEmf
  3153. ) const
  3154. {
  3155. if ((State == DoneRecordingMetafileState) ||
  3156. (State == ReadyToPlayMetafileState))
  3157. {
  3158. ASSERT(Hemf != NULL);
  3159. *hEmf = Hemf;
  3160. Hemf = NULL;
  3161. State = InvalidMetafileState;
  3162. return Ok;
  3163. }
  3164. *hEmf = NULL;
  3165. return InvalidParameter;
  3166. }
  3167. GpStatus
  3168. GpMetafile::PrepareToPlay(
  3169. GpGraphics * g,
  3170. GpRecolor * recolor,
  3171. ColorAdjustType adjustType,
  3172. EnumerateMetafileProc enumerateCallback,
  3173. VOID * callbackData,
  3174. DrawImageAbort drawImageCallback,
  3175. VOID* drawImageCallbackData
  3176. ) const
  3177. {
  3178. if (State == DoneRecordingMetafileState)
  3179. {
  3180. ASSERT(Hemf != NULL);
  3181. if (Player == NULL)
  3182. {
  3183. // Create a Player object
  3184. Player = new MetafilePlayer(g, MaxStackSize, recolor, adjustType,
  3185. enumerateCallback, callbackData,
  3186. drawImageCallback,
  3187. drawImageCallbackData
  3188. );
  3189. if (!CheckValid(Player))
  3190. {
  3191. return GenericError;
  3192. }
  3193. }
  3194. State = ReadyToPlayMetafileState;
  3195. return Ok;
  3196. }
  3197. if (State == ReadyToPlayMetafileState)
  3198. {
  3199. ASSERT(Hemf != NULL);
  3200. ASSERT(Player != NULL);
  3201. Player->PrepareToPlay(g, recolor, adjustType, enumerateCallback,
  3202. callbackData,
  3203. drawImageCallback,
  3204. drawImageCallbackData
  3205. );
  3206. return Ok;
  3207. }
  3208. return InvalidParameter;
  3209. }
  3210. GpStatus
  3211. GpMetafile::EnumerateForPlayback(
  3212. const RectF & destRect,
  3213. const RectF & srcRect,
  3214. Unit srcUnit,
  3215. GpGraphics * g,
  3216. EnumerateMetafileProc callback, // if null, just play the metafile
  3217. VOID * callbackData,
  3218. GpRecolor * recolor,
  3219. ColorAdjustType adjustType,
  3220. DrawImageAbort drawImageCallback,
  3221. VOID* drawImageCallbackData
  3222. ) const
  3223. {
  3224. ASSERT (IsValid());
  3225. if ((destRect.Width == 0) || (destRect.Height == 0) ||
  3226. (srcRect.Width == 0) || (srcRect.Height == 0) ||
  3227. (Header.IsEmf() && (Header.EmfHeader.nRecords <= 2)))
  3228. {
  3229. return Ok; // nothing to play
  3230. }
  3231. GpRectF metaSrcRect = srcRect;
  3232. GpRectF metaDestRect = destRect;
  3233. // The metafile player does not handle negative width/height
  3234. // in srcRect and destRect, so handle any negative values
  3235. // by setting up a flipping transform.
  3236. GpMatrix flipMatrix; // starts as identity
  3237. BOOL posWidths;
  3238. BOOL posHeights;
  3239. posWidths = ((metaSrcRect.Width >= 0) && (metaDestRect.Width >= 0));
  3240. posHeights = ((metaSrcRect.Height >= 0) && (metaDestRect.Height >= 0));
  3241. if (!posWidths || !posHeights)
  3242. {
  3243. if (!posWidths)
  3244. {
  3245. if (metaSrcRect.Width < 0)
  3246. {
  3247. if (metaDestRect.Width < 0)
  3248. {
  3249. posWidths = TRUE;
  3250. metaSrcRect.X = metaSrcRect.GetRight();
  3251. metaSrcRect.Width = -(metaSrcRect.Width);
  3252. metaDestRect.X = metaDestRect.GetRight();
  3253. metaDestRect.Width = -(metaDestRect.Width);
  3254. }
  3255. else
  3256. {
  3257. metaSrcRect.X = metaSrcRect.GetRight();
  3258. metaSrcRect.Width = -(metaSrcRect.Width);
  3259. }
  3260. }
  3261. else // metaDestRect.Width < 0
  3262. {
  3263. metaDestRect.X = metaDestRect.GetRight();
  3264. metaDestRect.Width = -(metaDestRect.Width);
  3265. }
  3266. }
  3267. if (!posHeights)
  3268. {
  3269. if (metaSrcRect.Height < 0)
  3270. {
  3271. if (metaDestRect.Height < 0)
  3272. {
  3273. posHeights = TRUE;
  3274. metaSrcRect.Y = metaSrcRect.GetBottom();
  3275. metaSrcRect.Height = -(metaSrcRect.Height);
  3276. metaDestRect.Y = metaDestRect.GetBottom();
  3277. metaDestRect.Height = -(metaDestRect.Height);
  3278. }
  3279. else
  3280. {
  3281. metaSrcRect.Y = metaSrcRect.GetBottom();
  3282. metaSrcRect.Height = -(metaSrcRect.Height);
  3283. }
  3284. }
  3285. else // metaDestRect.Height < 0
  3286. {
  3287. metaDestRect.Y = metaDestRect.GetBottom();
  3288. metaDestRect.Height = -(metaDestRect.Height);
  3289. }
  3290. }
  3291. REAL scaleX = 1.0f;
  3292. REAL scaleY = 1.0f;
  3293. REAL dX = 0.0f;
  3294. REAL dY = 0.0f;
  3295. // Create a matrix that is the equivalent of:
  3296. // 1) translate to the origin
  3297. // 2) do the flip
  3298. // 3) translate back
  3299. if (!posWidths)
  3300. {
  3301. scaleX = -1.0f;
  3302. dX = metaDestRect.X + metaDestRect.GetRight();
  3303. }
  3304. if (!posHeights)
  3305. {
  3306. scaleY = -1.0f;
  3307. dY = metaDestRect.Y + metaDestRect.GetBottom();
  3308. }
  3309. flipMatrix.Translate(dX, dY, MatrixOrderPrepend);
  3310. flipMatrix.Scale(scaleX, scaleY, MatrixOrderPrepend);
  3311. }
  3312. // Note that even though the visibility of the destRect might be
  3313. // fully visible, we should still setup the clipping because:
  3314. // (1) we might do cropping based on the srcRect
  3315. // (2) the frameRect of the metafile might not include all
  3316. // the actual drawing within the metafile.
  3317. GpStatus status = GenericError;
  3318. // Must convert the source rect into UnitPixels (if not already
  3319. // in pixel units), to account for the dpi of the source metafile.
  3320. REAL multiplierX;
  3321. REAL multiplierY;
  3322. GetPixelMultipliers(srcUnit, Header.GetDpiX(), Header.GetDpiY(),
  3323. &multiplierX, &multiplierY);
  3324. GpRectF pixelsSrcRect;
  3325. pixelsSrcRect.X = metaSrcRect.X * multiplierX;
  3326. pixelsSrcRect.Y = metaSrcRect.Y * multiplierY;
  3327. pixelsSrcRect.Width = metaSrcRect.Width * multiplierX;
  3328. pixelsSrcRect.Height = metaSrcRect.Height * multiplierY;
  3329. INT saveId = g->Save();
  3330. if (saveId != 0)
  3331. {
  3332. // We need to take into account the region from the source that we
  3333. // are drawing in order to do that we need to re-translate and
  3334. // rescale and the transform. The clipping will take care of only
  3335. // drawing the region that we are interested in.
  3336. // In order to acheive this we need to translate the dest rect back
  3337. // to the origin. Scale it by the same factor as the scale of the
  3338. // src rect and then translate it back to when it should be which
  3339. // is the scaled version of the left cropping of the src image.
  3340. GpMatrix preFlipPreCropTransform;
  3341. g->GetWorldTransform(preFlipPreCropTransform);
  3342. // apply the flipping transform
  3343. g->MultiplyWorldTransform(flipMatrix, MatrixOrderPrepend);
  3344. BOOL widthsDifferent = (Header.Width != pixelsSrcRect.Width);
  3345. BOOL heightsDifferent = (Header.Height != pixelsSrcRect.Height);
  3346. BOOL cropOrOffset = ((Header.X != pixelsSrcRect.X) ||
  3347. (Header.Y != pixelsSrcRect.Y) ||
  3348. widthsDifferent || heightsDifferent);
  3349. if (cropOrOffset)
  3350. {
  3351. g->TranslateWorldTransform(((((REAL)(Header.X - pixelsSrcRect.X))
  3352. *metaDestRect.Width) /pixelsSrcRect.Width)
  3353. + metaDestRect.X,
  3354. ((((REAL)(Header.Y - pixelsSrcRect.Y))
  3355. *metaDestRect.Height)/pixelsSrcRect.Height)
  3356. + metaDestRect.Y);
  3357. REAL xScale = 1.0f;
  3358. REAL yScale = 1.0f;
  3359. if (widthsDifferent)
  3360. {
  3361. xScale = (REAL) Header.Width / pixelsSrcRect.Width;
  3362. }
  3363. if (heightsDifferent)
  3364. {
  3365. yScale = (REAL) Header.Height / pixelsSrcRect.Height;
  3366. }
  3367. g->ScaleWorldTransform(xScale, yScale);
  3368. g->TranslateWorldTransform(-metaDestRect.X, -metaDestRect.Y);
  3369. }
  3370. // We don't use the deviceRect if we're rendering to a bitmap.
  3371. GpMatrix flipAndCropTransform;
  3372. GpRectF deviceRect = metaDestRect;
  3373. // sets the PreContainerMatrix to the WorldToDevice Transform, which
  3374. // includes the flipping and cropping transforms.
  3375. if ((status = this->PrepareToPlay(g, recolor, adjustType,
  3376. callback, callbackData,
  3377. drawImageCallback,
  3378. drawImageCallbackData)) != Ok)
  3379. {
  3380. goto CleanUp;
  3381. }
  3382. ASSERT(Player != NULL);
  3383. State = PlayingMetafileState;
  3384. BOOL renderToBitmap = FALSE;
  3385. GpMatrix * playMatrix = &(Player->PreContainerMatrix);
  3386. BOOL isTranslateScale = playMatrix->IsTranslateScale();
  3387. // On Win9x and WinNT (except Whistler and beyond), stretchblt calls
  3388. // don't work if there is any flipping.
  3389. // On Win9x text does not work if there is any flipping.
  3390. // On WinNT, bitmap fonts don't work for 90,180,270 degree rotation
  3391. // (but we map all bitmap fonts to true-type fonts anyway).
  3392. if (isTranslateScale)
  3393. {
  3394. // if there is any flipping, render to a bitmap
  3395. if ((playMatrix->GetM11() < 0.0f) ||
  3396. (playMatrix->GetM22() < 0.0f))
  3397. {
  3398. isTranslateScale = FALSE;
  3399. renderToBitmap = TRUE;
  3400. }
  3401. }
  3402. else
  3403. {
  3404. // It's okay to render rotated directly to the HDC on NT,
  3405. // unless the dest is a metafile or the src is a WMF.
  3406. renderToBitmap = (!Globals::IsNt ||
  3407. (g->Type == GpGraphics::GraphicsMetafile) ||
  3408. Header.IsWmf());
  3409. }
  3410. // Save what we have done into flipAndCropTransform. We will prepare the
  3411. // container with this world transform since the precontainerMatrix
  3412. // is only for the Downlevel and it needs that modified transform
  3413. g->GetWorldTransform(flipAndCropTransform);
  3414. // Restore the world transform to it's original self
  3415. // (w/o flipping and cropping transform applied).
  3416. g->SetWorldTransform(preFlipPreCropTransform);
  3417. // When we render to a bitmap, we render the entire metafile to
  3418. // the entire bitmap and then we clip out the cropped part of the
  3419. // metafile from the bitmap. So we have to set the clipping
  3420. // when we render to a bitmap if there is any cropping.
  3421. // It would be nice as an enhancement to just draw to a pre-cropped
  3422. // bitmap instead of clipping out part of the bitmap, but the math
  3423. // for that is tricky.
  3424. if ((!renderToBitmap) || cropOrOffset)
  3425. {
  3426. GpMatrix worldToDeviceTransform;
  3427. g->GetWorldToDeviceTransform(&worldToDeviceTransform);
  3428. if (isTranslateScale)
  3429. {
  3430. worldToDeviceTransform.TransformRect(deviceRect);
  3431. }
  3432. // Don't set the clipping if we're rendering to a bitmap,
  3433. // because the rendering into the bitmap will do the clipping
  3434. // automatically, and if we also clip against the graphics, we
  3435. // sometimes clip too much, which can cause jagged edges on
  3436. // rotated metafiles.
  3437. // Clipping into a metafile causes problems. For example, if
  3438. // we're drawing outside the bounds of the referenece HDC, it
  3439. // works fine, but then when we add clipping into the HDC, it doesn't
  3440. // work anymore -- nothing gets drawn into the metafile, even though
  3441. // everything is within the clipping rect (but the clipping rect is
  3442. // outside the bounds of the reference HDC).
  3443. if (g->Type != GpGraphics::GraphicsMetafile)
  3444. {
  3445. if ((!(renderToBitmap && cropOrOffset)) && isTranslateScale)
  3446. {
  3447. g->SetClip(metaDestRect, CombineModeIntersect);
  3448. }
  3449. else // rendering to a bitmap with cropping or
  3450. // rotating to the screen
  3451. {
  3452. // Since we want the filtered (smooth) edges on the
  3453. // bitmap, we have to add in a little extra room on
  3454. // the edges of our clip rect.
  3455. // On rotations we need to inflate by one pixel also
  3456. // because it seems that GDI doesn't rasterize clipregions
  3457. // the same we that it rasterized rects. Do rects on the
  3458. // edges can have pixels missing. We might be introducing
  3459. // more pixels that should have been clipped out but we
  3460. // can live with that for now.
  3461. GpRectF tmpClipRect = metaDestRect;
  3462. REAL xSize;
  3463. REAL ySize;
  3464. g->GetWorldPixelSize(xSize, ySize);
  3465. // add 1 pixel all the way around
  3466. tmpClipRect.Inflate(xSize, ySize);
  3467. g->SetClip(tmpClipRect, CombineModeIntersect);
  3468. }
  3469. if (isTranslateScale)
  3470. {
  3471. // We need to intersect the destRect with the Visible Clip
  3472. // in order to make sure that we don't draw outside the bounds
  3473. // in Win9x since we can't use a MetaRgn
  3474. GpRectF clipBounds;
  3475. g->GetVisibleClipBounds(clipBounds);
  3476. worldToDeviceTransform.TransformRect(clipBounds);
  3477. GpRectF::Intersect(deviceRect, deviceRect, clipBounds);
  3478. }
  3479. }
  3480. }
  3481. // If we're playing an EMF+ into another metafile, we have to be
  3482. // careful not to double-transform points. The HDC will have
  3483. // the srcRect to destRect transform in it, and the graphics might
  3484. // have a transform too, so we can end up double-transforming the
  3485. // points of any GDI+ records that are in an EMF+ file.
  3486. // One easy way to get around that is that if we are playing an
  3487. // EMF+ dual, we could just play the down-level records (i.e. play it
  3488. // as an EMF, not an EMF+), so that all the records get transformed
  3489. // the same way. But of course, that doesn't work if it's an
  3490. // EMF+ only file. A solution that works for both EMF+ dual and
  3491. // EMF+ only is to force the GDI+ transform to be the identity so that
  3492. // the down-level records that are generated by DriverMeta are in
  3493. // the original coordinate system of the metafile, not in the
  3494. // destination coordinate system (which then get transformed again
  3495. // erroneously).
  3496. if (Header.IsWmf() || Header.IsEmf())
  3497. {
  3498. status = g->EnumEmf(Player, Hemf, metaDestRect, pixelsSrcRect,
  3499. deviceRect, Header.GetType(),
  3500. isTranslateScale, renderToBitmap,
  3501. flipAndCropTransform);
  3502. }
  3503. else
  3504. {
  3505. ASSERT(Header.IsEmfPlus());
  3506. // When playing from a metafile into a metafile, Win9x does NOT
  3507. // allow you to override (reset) the srcRect->destRect metafile
  3508. // transform. So to keep from double transforming the records,
  3509. // we have to set the GDI+ transform to identity, instead of
  3510. // setting the HDC transform to identity as we would typically do.
  3511. // When rendering to a bitmap, we don't have to worry about
  3512. // double-transforming, because we play the metafile to the
  3513. // bitmap HDC, not to the dest metafile hdc, so there won't
  3514. // be a transform on the metafile hdc to mess us up.
  3515. INT containerId;
  3516. if ((g->Type != GpGraphics::GraphicsMetafile) || renderToBitmap)
  3517. {
  3518. // Now apply the flipping matrix.
  3519. // The g->Restore call below will reset the transform.
  3520. g->MultiplyWorldTransform(flipMatrix, MatrixOrderPrepend);
  3521. GpRectF gdiDestRect = metaDestRect;
  3522. // We need to calculate our transform so that the last point in the
  3523. // src maps to the last point in the destination. This is how GDI does
  3524. // it and we also need to do it so that we can play metafile properly
  3525. if (pixelsSrcRect.Width >= 2.0f)
  3526. {
  3527. pixelsSrcRect.Width -= 1.0f;
  3528. }
  3529. if (pixelsSrcRect.Height >= 2.0f)
  3530. {
  3531. pixelsSrcRect.Height -= 1.0f;
  3532. }
  3533. if (gdiDestRect.Width >= 2.0f)
  3534. {
  3535. gdiDestRect.Width -= 1.0f;
  3536. }
  3537. if (gdiDestRect.Height >= 2.0f)
  3538. {
  3539. gdiDestRect.Height -= 1.0f;
  3540. }
  3541. containerId = g->BeginContainer(
  3542. gdiDestRect,
  3543. pixelsSrcRect,
  3544. UnitPixel,
  3545. (REAL)Header.LogicalDpiX,
  3546. (REAL)Header.LogicalDpiY,
  3547. Header.IsDisplay());
  3548. }
  3549. else // we're drawing into a metafile
  3550. {
  3551. containerId = g->BeginContainer(
  3552. TRUE, // force xform to identity
  3553. (REAL)Header.LogicalDpiX,
  3554. (REAL)Header.LogicalDpiY,
  3555. Header.IsDisplay());
  3556. }
  3557. if (containerId != 0)
  3558. {
  3559. // There may be GDI records that we need to play!
  3560. status = g->EnumEmfPlusDual(Player, Hemf, metaDestRect,
  3561. deviceRect, isTranslateScale,
  3562. renderToBitmap);
  3563. g->EndContainer(containerId);
  3564. Player->DonePlaying(); // free up objects created by Player
  3565. }
  3566. // make sure the status reflect the abort state of the player
  3567. ASSERT(!Player->EnumerateAborted || (status == Aborted));
  3568. }
  3569. CleanUp:
  3570. g->Restore(saveId);
  3571. }
  3572. // Don't change the state unless we were playing the metafile
  3573. if (State == PlayingMetafileState)
  3574. {
  3575. State = ReadyToPlayMetafileState;
  3576. }
  3577. return status;
  3578. }
  3579. /**************************************************************************\
  3580. *
  3581. * Function Description:
  3582. *
  3583. * Initialize the metafile object members to their default values.
  3584. *
  3585. * Arguments:
  3586. *
  3587. * NONE
  3588. *
  3589. * Return Value:
  3590. *
  3591. * NONE
  3592. *
  3593. * Created:
  3594. *
  3595. * 6/15/1999 DCurtis
  3596. *
  3597. \**************************************************************************/
  3598. VOID
  3599. GpMetafile::InitDefaults()
  3600. {
  3601. ThreadId = 0;
  3602. State = InvalidMetafileState;
  3603. Filename = NULL;
  3604. Stream = NULL;
  3605. Hemf = NULL;
  3606. MetaGraphics = NULL;
  3607. Player = NULL;
  3608. MaxStackSize = GDIP_SAVE_STACK_SIZE;
  3609. DeleteHemf = TRUE;
  3610. RequestedMetaGraphics = FALSE;
  3611. GpMemset(&Header, 0, sizeof(Header));
  3612. // Set the version for recording. If we're plyaing back,
  3613. // this will get overwritten later.
  3614. Header.Version = EMFPLUS_VERSION;
  3615. }
  3616. GpStatus
  3617. GpMetafile::GetImageInfo(
  3618. ImageInfo * imageInfo
  3619. ) const
  3620. {
  3621. ASSERT(imageInfo != NULL);
  3622. ASSERT(IsValid());
  3623. if ((State == DoneRecordingMetafileState) ||
  3624. (State == ReadyToPlayMetafileState))
  3625. {
  3626. if (Header.IsEmfOrEmfPlus())
  3627. {
  3628. imageInfo->RawDataFormat = IMGFMT_EMF;
  3629. }
  3630. else // Wmf
  3631. {
  3632. imageInfo->RawDataFormat = IMGFMT_WMF;
  3633. }
  3634. imageInfo->PixelFormat = PIXFMT_32BPP_RGB;
  3635. imageInfo->Width = Header.Width;
  3636. imageInfo->Height = Header.Height;
  3637. imageInfo->TileWidth = Header.Width;
  3638. imageInfo->TileHeight = 1;
  3639. imageInfo->Xdpi = Header.DpiX;
  3640. imageInfo->Ydpi = Header.DpiY;
  3641. imageInfo->Flags = SinkFlagsTopDown |
  3642. SinkFlagsFullWidth |
  3643. SinkFlagsScalable |
  3644. SinkFlagsHasAlpha;
  3645. return Ok;
  3646. }
  3647. return InvalidParameter;
  3648. }
  3649. GpImage *
  3650. GpMetafile::Clone() const
  3651. {
  3652. GpMetafile * clonedMetafile = NULL;
  3653. if ((State == DoneRecordingMetafileState) ||
  3654. (State == ReadyToPlayMetafileState))
  3655. {
  3656. if (Header.IsEmfOrEmfPlus())
  3657. {
  3658. HENHMETAFILE hEmf = CopyEnhMetaFileA(Hemf, NULL);
  3659. if (hEmf != NULL)
  3660. {
  3661. clonedMetafile = new GpMetafile(hEmf, TRUE);
  3662. if (clonedMetafile != NULL)
  3663. {
  3664. if (!clonedMetafile->IsValid())
  3665. {
  3666. DeleteEnhMetaFile(hEmf);
  3667. clonedMetafile->Hemf = NULL;
  3668. clonedMetafile->Dispose();
  3669. clonedMetafile = NULL;
  3670. }
  3671. }
  3672. }
  3673. }
  3674. else // Wmf
  3675. {
  3676. HMETAFILE hWmf = CopyMetaFileA((HMETAFILE)Hemf, NULL);
  3677. if (hWmf != NULL)
  3678. {
  3679. WmfPlaceableFileHeader wmfPlaceableFileHeader;
  3680. wmfPlaceableFileHeader.Key = GDIP_WMF_PLACEABLEKEY;
  3681. wmfPlaceableFileHeader.Hmf = 0;
  3682. wmfPlaceableFileHeader.BoundingBox.Left = static_cast<INT16>(Header.X);
  3683. wmfPlaceableFileHeader.BoundingBox.Right = static_cast<INT16>(Header.X + Header.Width);
  3684. wmfPlaceableFileHeader.BoundingBox.Top = static_cast<INT16>(Header.Y);
  3685. wmfPlaceableFileHeader.BoundingBox.Bottom = static_cast<INT16>(Header.Y + Header.Height);
  3686. wmfPlaceableFileHeader.Inch = static_cast<INT16>(GpRound(Header.DpiX));
  3687. wmfPlaceableFileHeader.Reserved = 0;
  3688. wmfPlaceableFileHeader.Checksum = GetWmfPlaceableCheckSum(&wmfPlaceableFileHeader);
  3689. clonedMetafile = new GpMetafile(hWmf, &wmfPlaceableFileHeader, TRUE);
  3690. if (clonedMetafile != NULL)
  3691. {
  3692. if (!clonedMetafile->IsValid())
  3693. {
  3694. DeleteMetaFile(hWmf);
  3695. clonedMetafile->Hemf = NULL;
  3696. clonedMetafile->Dispose();
  3697. clonedMetafile = NULL;
  3698. }
  3699. }
  3700. }
  3701. }
  3702. }
  3703. return clonedMetafile;
  3704. }
  3705. GpImage*
  3706. GpMetafile::CloneColorAdjusted(
  3707. GpRecolor * recolor,
  3708. ColorAdjustType adjustType
  3709. ) const
  3710. {
  3711. ASSERT(recolor != NULL);
  3712. if ((State == DoneRecordingMetafileState) ||
  3713. (State == ReadyToPlayMetafileState))
  3714. {
  3715. GpMetafile* clonedMetafile;
  3716. // FrameRect is Inclusive-Inclusive so subtrace 1 device unit
  3717. GpRectF frameRect((REAL)Header.X, (REAL)Header.Y,
  3718. (REAL)(Header.Width - 1), (REAL)(Header.Height - 1));
  3719. EmfType type;
  3720. if (Header.Type <= MetafileTypeEmf)
  3721. {
  3722. type = EmfTypeEmfOnly;
  3723. }
  3724. else
  3725. {
  3726. // we don't need the down-level dual sections for embedded files
  3727. type = EmfTypeEmfPlusOnly;
  3728. }
  3729. // It doesn't matter if we lose the description string, since this
  3730. // metafile is just being embedded inside another one anyway.
  3731. clonedMetafile = new GpMetafile(Globals::DesktopIc, type,
  3732. &frameRect,MetafileFrameUnitPixel,NULL);
  3733. if ((clonedMetafile != NULL) &&
  3734. (clonedMetafile->IsValid()))
  3735. {
  3736. GpStatus status;
  3737. GpPageUnit srcUnit;
  3738. GpRectF srcRect;
  3739. GpGraphics * g = clonedMetafile->GetGraphicsContext();
  3740. ASSERT (g != NULL);
  3741. this->GetBounds(&srcRect, &srcUnit);
  3742. // We pass Inclusive-Exclusive bounds to play so add 1 device
  3743. // unit to the framerect
  3744. frameRect.Width++;
  3745. frameRect.Height++;
  3746. status = this->Play(frameRect, srcRect, srcUnit, g, recolor, adjustType);
  3747. delete g;
  3748. if ((status == Ok) &&
  3749. (clonedMetafile->State == DoneRecordingMetafileState))
  3750. {
  3751. return clonedMetafile;
  3752. }
  3753. }
  3754. delete clonedMetafile;
  3755. }
  3756. return NULL;
  3757. }
  3758. GpStatus
  3759. GpMetafile::ColorAdjust(
  3760. GpRecolor * recolor,
  3761. ColorAdjustType adjustType
  3762. )
  3763. {
  3764. ASSERT(recolor != NULL);
  3765. GpMetafile * clone;
  3766. if (DeleteHemf &&
  3767. ((clone = (GpMetafile *)CloneColorAdjusted(recolor, adjustType)) != NULL))
  3768. {
  3769. CleanUp();
  3770. InitDefaults();
  3771. if (GetMetafileHeader(clone->Hemf, Header) == Ok)
  3772. {
  3773. Hemf = clone->Hemf;
  3774. DeleteHemf = TRUE;
  3775. State = DoneRecordingMetafileState;
  3776. clone->DeleteHemf = FALSE;
  3777. delete clone;
  3778. return Ok;
  3779. }
  3780. }
  3781. return GenericError;
  3782. }
  3783. VOID
  3784. GpMetafile::Dispose()
  3785. {
  3786. delete this;
  3787. }
  3788. class RemoveDualRecords
  3789. {
  3790. public:
  3791. BYTE * MetaData;
  3792. INT Size;
  3793. INT NumRecords;
  3794. BOOL GetGdiRecords;
  3795. RemoveDualRecords()
  3796. {
  3797. Init();
  3798. }
  3799. VOID Init()
  3800. {
  3801. MetaData = NULL;
  3802. Size = 0;
  3803. NumRecords = 0;
  3804. GetGdiRecords = TRUE; // so we write the EMR_HEADER record
  3805. }
  3806. VOID GetRecord(CONST ENHMETARECORD * emfRecord)
  3807. {
  3808. UINT recordSize = emfRecord->nSize;
  3809. if (MetaData != NULL)
  3810. {
  3811. GpMemcpy(MetaData, emfRecord, recordSize);
  3812. MetaData += recordSize;
  3813. }
  3814. Size += recordSize;
  3815. NumRecords++;
  3816. }
  3817. };
  3818. extern "C"
  3819. int CALLBACK
  3820. EnumEmfRemoveDualRecords(
  3821. HDC hdc, // should be NULL
  3822. HANDLETABLE FAR * gdiHandleTable,
  3823. CONST ENHMETARECORD * emfRecord,
  3824. int numHandles,
  3825. LPARAM removeDualRecords
  3826. )
  3827. {
  3828. if ((emfRecord != NULL) && (emfRecord->nSize >= sizeof(EMR)) &&
  3829. (removeDualRecords != NULL))
  3830. {
  3831. if (IsEmfPlusRecord(emfRecord))
  3832. {
  3833. // See if the last record of this set of EMF+ records is a GetDC
  3834. // record. If it is, then we know to play the next set of
  3835. // GDI records that we encounter.
  3836. // I prefer not to have to parse through all these records,
  3837. // but there is always the slight possibility that this will
  3838. // result in a false positive. But the worst thing that can
  3839. // happen is that we write a little too much data to the stream.
  3840. EmfPlusRecord * lastRecord;
  3841. lastRecord = (EmfPlusRecord *)(((BYTE *)emfRecord) + emfRecord->nSize -
  3842. sizeof(EmfPlusRecord));
  3843. ((RemoveDualRecords *)removeDualRecords)->GetGdiRecords =
  3844. ((lastRecord->Type == EmfPlusRecordTypeGetDC) &&
  3845. (lastRecord->Size == sizeof(EmfPlusRecord)) &&
  3846. (lastRecord->DataSize == 0));
  3847. }
  3848. else if ((emfRecord->iType != EMR_EOF) && // Write EOF record
  3849. (!(((RemoveDualRecords *)removeDualRecords)->GetGdiRecords)))
  3850. {
  3851. return 1; // skip this GDI record
  3852. }
  3853. ((RemoveDualRecords *)removeDualRecords)->GetRecord(emfRecord);
  3854. }
  3855. else
  3856. {
  3857. WARNING(("Bad Enumeration Parameter"));
  3858. }
  3859. return 1;
  3860. }
  3861. extern "C"
  3862. int CALLBACK
  3863. EnumEmfToStream(
  3864. HDC hdc, // handle to device context
  3865. HANDLETABLE FAR * gdiHandleTable, // pointer to metafile handle table
  3866. CONST ENHMETARECORD * emfRecord, // pointer to metafile record
  3867. int numHandles, // count of objects
  3868. LPARAM stream // pointer to optional data
  3869. )
  3870. {
  3871. if ((emfRecord != NULL) && (emfRecord->nSize >= sizeof(EMR)) &&
  3872. (stream != NULL))
  3873. {
  3874. ((IStream *)stream)->Write(emfRecord, emfRecord->nSize, NULL);
  3875. }
  3876. else
  3877. {
  3878. WARNING(("Bad Enumeration Parameter"));
  3879. }
  3880. return 1;
  3881. }
  3882. class MetafileData : public ObjectTypeData
  3883. {
  3884. public:
  3885. INT32 MetaType;
  3886. INT32 MetaDataSize;
  3887. };
  3888. /**************************************************************************\
  3889. *
  3890. * Function Description:
  3891. *
  3892. * Get the metafile data.
  3893. *
  3894. * Arguments:
  3895. *
  3896. * [IN] dataBuffer - fill this buffer with the data
  3897. * [IN/OUT] size - IN - size of buffer; OUT - number bytes written
  3898. *
  3899. * Return Value:
  3900. *
  3901. * GpStatus - Ok or error code
  3902. *
  3903. * Created:
  3904. *
  3905. * 9/13/1999 DCurtis
  3906. *
  3907. \**************************************************************************/
  3908. GpStatus
  3909. GpMetafile::GetData(
  3910. IStream * stream
  3911. ) const
  3912. {
  3913. ASSERT (stream != NULL);
  3914. if ((State != DoneRecordingMetafileState) &&
  3915. (State != ReadyToPlayMetafileState))
  3916. {
  3917. WARNING(("Wrong State To GetData"));
  3918. return WrongState;
  3919. }
  3920. ASSERT(Hemf != NULL);
  3921. MetafileData metafileData;
  3922. metafileData.Type = ImageTypeMetafile;
  3923. if (Header.IsWmf())
  3924. {
  3925. INT wmfDataSize = GetMetaFileBitsEx((HMETAFILE)Hemf, 0, NULL);
  3926. if (wmfDataSize <= 0)
  3927. {
  3928. WARNING(("Empty WMF"));
  3929. return Win32Error;
  3930. }
  3931. BYTE * wmfData = (BYTE *)GpMalloc(wmfDataSize);
  3932. if (wmfData == NULL)
  3933. {
  3934. return OutOfMemory;
  3935. }
  3936. if (GetMetaFileBitsEx((HMETAFILE)Hemf, wmfDataSize, wmfData) == 0)
  3937. {
  3938. WARNING(("Problem retrieving WMF Data"));
  3939. GpFree(wmfData);
  3940. return Win32Error;
  3941. }
  3942. // We don't save MetafileTypeWmf -- we convert it to the Placeable type
  3943. metafileData.MetaType = MetafileTypeWmfPlaceable;
  3944. metafileData.MetaDataSize = wmfDataSize;
  3945. stream->Write(&metafileData, sizeof(metafileData), NULL);
  3946. ASSERT(sizeof(WmfPlaceableFileHeader) == 22);
  3947. #define PLACEABLE_BUFFER_SIZE (sizeof(WmfPlaceableFileHeader) + 2)
  3948. BYTE placeableBuffer[PLACEABLE_BUFFER_SIZE];
  3949. WmfPlaceableFileHeader * wmfPlaceableFileHeader = (WmfPlaceableFileHeader *)placeableBuffer;
  3950. REAL aveDpi;
  3951. // set pad word to 0
  3952. *((INT16 *)(placeableBuffer + sizeof(WmfPlaceableFileHeader))) = 0;
  3953. aveDpi = (Header.GetDpiX() + Header.GetDpiY()) / 2.0f;
  3954. wmfPlaceableFileHeader->Key = GDIP_WMF_PLACEABLEKEY;
  3955. wmfPlaceableFileHeader->Hmf = 0;
  3956. wmfPlaceableFileHeader->BoundingBox.Left = static_cast<INT16>(Header.X);
  3957. wmfPlaceableFileHeader->BoundingBox.Top = static_cast<INT16>(Header.Y);
  3958. wmfPlaceableFileHeader->BoundingBox.Right = static_cast<INT16>(Header.X + Header.Width);
  3959. wmfPlaceableFileHeader->BoundingBox.Bottom = static_cast<INT16>(Header.Y + Header.Height);
  3960. wmfPlaceableFileHeader->Inch = static_cast<INT16>(GpRound(aveDpi));
  3961. wmfPlaceableFileHeader->Reserved = 0;
  3962. wmfPlaceableFileHeader->Checksum = GetWmfPlaceableCheckSum(wmfPlaceableFileHeader);
  3963. stream->Write(placeableBuffer, PLACEABLE_BUFFER_SIZE, NULL);
  3964. stream->Write(wmfData, wmfDataSize, NULL);
  3965. GpFree(wmfData);
  3966. // align
  3967. if ((wmfDataSize & 0x03) != 0)
  3968. {
  3969. INT pad = 0;
  3970. stream->Write(&pad, 4 - (wmfDataSize & 0x03), NULL);
  3971. }
  3972. }
  3973. else if (!Header.IsEmfPlusDual())
  3974. {
  3975. INT emfDataSize = GetEnhMetaFileBits(Hemf, 0, NULL);
  3976. if (emfDataSize <= 0)
  3977. {
  3978. WARNING(("Empty EMF"));
  3979. return Win32Error;
  3980. }
  3981. metafileData.MetaType = Header.GetType();
  3982. metafileData.MetaDataSize = emfDataSize;
  3983. stream->Write(&metafileData, sizeof(metafileData), NULL);
  3984. if (!::EnumEnhMetaFile(NULL, Hemf, EnumEmfToStream, stream, NULL))
  3985. {
  3986. WARNING(("Problem retrieving EMF Data"));
  3987. return Win32Error;
  3988. }
  3989. }
  3990. else // it is EMF+ Dual. Remove the dual records for embedding.
  3991. {
  3992. RemoveDualRecords removeDualRecords;
  3993. // First, figure out how big a buffer we need to allocate
  3994. if (!::EnumEnhMetaFile(NULL, Hemf, EnumEmfRemoveDualRecords,
  3995. &removeDualRecords, NULL))
  3996. {
  3997. WARNING(("Problem retrieving EMF Data"));
  3998. return Win32Error;
  3999. }
  4000. INT emfDataSize = removeDualRecords.Size;
  4001. BYTE * emfData = (BYTE *)GpMalloc(emfDataSize);
  4002. if (emfData == NULL)
  4003. {
  4004. return OutOfMemory;
  4005. }
  4006. removeDualRecords.Init();
  4007. removeDualRecords.MetaData = emfData;
  4008. if (!::EnumEnhMetaFile(NULL, Hemf, EnumEmfRemoveDualRecords,
  4009. &removeDualRecords, NULL))
  4010. {
  4011. WARNING(("Problem retrieving EMF Data"));
  4012. GpFree(emfData);
  4013. return Win32Error;
  4014. }
  4015. // make sure we get the same value back the 2nd time
  4016. ASSERT(emfDataSize == removeDualRecords.Size);
  4017. // We convert MetafileTypeEmfPlusDual into MetafileTypeEmfPlusOnly
  4018. metafileData.MetaType = MetafileTypeEmfPlusOnly;
  4019. metafileData.MetaDataSize = removeDualRecords.Size;
  4020. stream->Write(&metafileData, sizeof(metafileData), NULL);
  4021. ((ENHMETAHEADER3 *)emfData)->nBytes = removeDualRecords.Size;
  4022. ((ENHMETAHEADER3 *)emfData)->nRecords = removeDualRecords.NumRecords;
  4023. stream->Write(emfData, removeDualRecords.Size, NULL);
  4024. GpFree(emfData);
  4025. }
  4026. return Ok;
  4027. }
  4028. UINT
  4029. GpMetafile::GetDataSize() const
  4030. {
  4031. if ((State != DoneRecordingMetafileState) &&
  4032. (State != ReadyToPlayMetafileState))
  4033. {
  4034. WARNING(("Wrong State To GetDataSize"));
  4035. return 0;
  4036. }
  4037. ASSERT(Hemf != NULL);
  4038. UINT dataSize = sizeof(MetafileData);
  4039. if (Header.IsWmf())
  4040. {
  4041. INT wmfDataSize = GetMetaFileBitsEx((HMETAFILE)Hemf, 0, NULL);
  4042. if (wmfDataSize <= 0)
  4043. {
  4044. WARNING(("Empty WMF"));
  4045. return 0;
  4046. }
  4047. // add aligned size of the placeable header and aligned wmf size
  4048. dataSize += 24 + ((wmfDataSize + 3) & ~3);
  4049. }
  4050. else if (!Header.IsEmfPlusDual())
  4051. {
  4052. INT emfDataSize = GetEnhMetaFileBits(Hemf, 0, NULL);
  4053. if (emfDataSize <= 0)
  4054. {
  4055. WARNING(("Empty EMF"));
  4056. return 0;
  4057. }
  4058. dataSize += emfDataSize;
  4059. }
  4060. else // it is EMF+ Dual. Remove the dual records for embedding.
  4061. {
  4062. RemoveDualRecords removeDualRecords;
  4063. if (!::EnumEnhMetaFile(NULL, Hemf, EnumEmfRemoveDualRecords,
  4064. &removeDualRecords, NULL))
  4065. {
  4066. WARNING(("Problem retrieving EMF Data"));
  4067. return 0;
  4068. }
  4069. dataSize += removeDualRecords.Size;
  4070. }
  4071. return dataSize;
  4072. }
  4073. /**************************************************************************\
  4074. *
  4075. * Function Description:
  4076. *
  4077. * Read the metafile object from memory.
  4078. *
  4079. * Arguments:
  4080. *
  4081. * [IN] data - the data to set the metafile with
  4082. * [IN] size - the size of the data
  4083. *
  4084. * Return Value:
  4085. *
  4086. * GpStatus - Ok or failure status
  4087. *
  4088. * Created:
  4089. *
  4090. * 4/26/1999 DCurtis
  4091. *
  4092. \**************************************************************************/
  4093. GpStatus
  4094. GpMetafile::SetData(
  4095. const BYTE * dataBuffer,
  4096. UINT size
  4097. )
  4098. {
  4099. ASSERT ((GpImageType)(((MetafileData *)dataBuffer)->Type) == ImageTypeMetafile);
  4100. InitDefaults();
  4101. if (dataBuffer == NULL)
  4102. {
  4103. WARNING(("dataBuffer is NULL"));
  4104. return InvalidParameter;
  4105. }
  4106. if (size < sizeof(MetafileData))
  4107. {
  4108. WARNING(("size too small"));
  4109. return InvalidParameter;
  4110. }
  4111. const MetafileData * metaData;
  4112. metaData = reinterpret_cast<const MetafileData *>(dataBuffer);
  4113. if (!metaData->MajorVersionMatches())
  4114. {
  4115. WARNING(("Version number mismatch"));
  4116. return InvalidParameter;
  4117. }
  4118. dataBuffer += sizeof(MetafileData);
  4119. size -= sizeof(MetafileData);
  4120. MetafileType type = (MetafileType)metaData->MetaType;
  4121. UINT metaDataSize = metaData->MetaDataSize;
  4122. if (type == MetafileTypeWmfPlaceable)
  4123. {
  4124. HMETAFILE hWmf;
  4125. if (size < (metaDataSize + 24))
  4126. {
  4127. WARNING(("size too small"));
  4128. return InvalidParameter;
  4129. }
  4130. hWmf = SetMetaFileBitsEx(metaDataSize, dataBuffer + 24);
  4131. if (hWmf != NULL)
  4132. {
  4133. if (GetMetafileHeader(hWmf, (WmfPlaceableFileHeader*)dataBuffer, Header) == Ok)
  4134. {
  4135. Hemf = (HENHMETAFILE)hWmf;
  4136. State = DoneRecordingMetafileState;
  4137. return Ok;
  4138. }
  4139. DeleteMetaFile(hWmf);
  4140. }
  4141. }
  4142. else
  4143. {
  4144. // We'll let the object think it's dual, even if we've removed
  4145. // all the dual records. It shouldn't hurt anything.
  4146. HENHMETAFILE hEmf;
  4147. if (size < metaDataSize)
  4148. {
  4149. WARNING(("size too small"));
  4150. return InvalidParameter;
  4151. }
  4152. hEmf = SetEnhMetaFileBits(metaDataSize, dataBuffer);
  4153. if (hEmf != NULL)
  4154. {
  4155. BOOL isCorrupted;
  4156. if (GetMetafileHeader(hEmf, Header, &isCorrupted) == Ok)
  4157. {
  4158. Hemf = hEmf;
  4159. State = DoneRecordingMetafileState;
  4160. return Ok;
  4161. }
  4162. if (isCorrupted)
  4163. {
  4164. State = CorruptedMetafileState;
  4165. }
  4166. DeleteEnhMetaFile(hEmf);
  4167. }
  4168. }
  4169. return GenericError;
  4170. }
  4171. class CommentEPR : public EmfPlusRecordPlay
  4172. {
  4173. public:
  4174. VOID Play(
  4175. MetafilePlayer * player,
  4176. EmfPlusRecordType recordType,
  4177. UINT flags,
  4178. UINT dataSize
  4179. ) const
  4180. {
  4181. ASSERT(recordType == EmfPlusRecordTypeComment);
  4182. return;
  4183. }
  4184. };
  4185. class GetDCEPR : public EmfPlusRecordPlay
  4186. {
  4187. public:
  4188. VOID Play(
  4189. MetafilePlayer * player,
  4190. EmfPlusRecordType recordType,
  4191. UINT flags,
  4192. UINT dataSize
  4193. ) const
  4194. {
  4195. ASSERT(recordType == EmfPlusRecordTypeGetDC);
  4196. // Flag that the next down-level records should be played.
  4197. #if 0
  4198. // This is now done in the enumerator, so that it will happen
  4199. // for enumeration as well as playback.
  4200. player->PlayEMFRecords = TRUE;
  4201. #endif
  4202. }
  4203. };
  4204. #define EMFPLUS_MAJORVERSION(v) ((v) & 0xFFFF0000)
  4205. #define EMFPLUS_MINORVERSION(v) ((v) & 0x0000FFFF)
  4206. #define EMF_SKIP_ALL_MULTIFORMAT_SECTIONS 0x7FFFFFFF
  4207. #define MULTIFORMATSTARTEPR_MINSIZE (sizeof(UINT32) + sizeof(UINT32))
  4208. // Note: nesting multiformat records does NOT work.
  4209. class MultiFormatStartEPR : public EmfPlusRecordPlay
  4210. {
  4211. protected:
  4212. UINT32 NumSections;
  4213. UINT32 Version[1];
  4214. public:
  4215. VOID Play(
  4216. MetafilePlayer * player,
  4217. EmfPlusRecordType recordType,
  4218. UINT flags,
  4219. UINT dataSize
  4220. ) const
  4221. {
  4222. ASSERT(recordType == EmfPlusRecordTypeMultiFormatStart);
  4223. if (dataSize < MULTIFORMATSTARTEPR_MINSIZE)
  4224. {
  4225. WARNING(("MultiFormatStartEPR::Play dataSize is too small"));
  4226. return;
  4227. }
  4228. UINT sectionToPlay = EMF_SKIP_ALL_MULTIFORMAT_SECTIONS;
  4229. if (NumSections > 0)
  4230. {
  4231. if (dataSize < MULTIFORMATSTARTEPR_MINSIZE + ((NumSections - 1) * sizeof(UINT32)))
  4232. {
  4233. WARNING(("MultiFormatStartEPR::Play dataSize is too small"));
  4234. return;
  4235. }
  4236. if ((Version[0] == EMFPLUS_VERSION) || (NumSections == 1))
  4237. {
  4238. sectionToPlay = 1; // start counting from 1, not 0
  4239. }
  4240. else
  4241. {
  4242. UINT playVersion = 0;
  4243. UINT curVersion;
  4244. // The multiformat section must match the major version.
  4245. // The first format whose minor version <= the current
  4246. // minor version is the one we play. If we don't find
  4247. // one of those, then we play the one whose minor version
  4248. // is closest to the current minor version.
  4249. for (UINT i = 0; i < NumSections; i++)
  4250. {
  4251. curVersion = Version[i];
  4252. if (EMFPLUS_MAJORVERSION(curVersion) ==
  4253. EMFPLUS_MAJORVERSION(EMFPLUS_VERSION))
  4254. {
  4255. if (EMFPLUS_MINORVERSION(curVersion) <=
  4256. EMFPLUS_MINORVERSION(EMFPLUS_VERSION))
  4257. {
  4258. sectionToPlay = i + 1;
  4259. break;
  4260. }
  4261. else if ((playVersion == 0) ||
  4262. (EMFPLUS_MINORVERSION(curVersion) <
  4263. EMFPLUS_MINORVERSION(playVersion)))
  4264. {
  4265. playVersion = curVersion;
  4266. sectionToPlay = i + 1;
  4267. }
  4268. }
  4269. }
  4270. }
  4271. }
  4272. player->MultiFormatSection = sectionToPlay;
  4273. player->CurFormatSection = 0;
  4274. player->PlayMultiFormatSection = FALSE;
  4275. }
  4276. };
  4277. class MultiFormatSectionEPR : public EmfPlusRecordPlay
  4278. {
  4279. public:
  4280. VOID Play(
  4281. MetafilePlayer * player,
  4282. EmfPlusRecordType recordType,
  4283. UINT flags,
  4284. UINT dataSize
  4285. ) const
  4286. {
  4287. ASSERT(recordType == EmfPlusRecordTypeMultiFormatSection);
  4288. if (player->MultiFormatSection != 0)
  4289. {
  4290. player->PlayMultiFormatSection =
  4291. (++(player->CurFormatSection) == player->MultiFormatSection);
  4292. }
  4293. }
  4294. };
  4295. class MultiFormatEndEPR : public EmfPlusRecordPlay
  4296. {
  4297. public:
  4298. VOID Play(
  4299. MetafilePlayer * player,
  4300. EmfPlusRecordType recordType,
  4301. UINT flags,
  4302. UINT dataSize
  4303. ) const
  4304. {
  4305. ASSERT(recordType == EmfPlusRecordTypeMultiFormatEnd);
  4306. player->MultiFormatSection = 0;
  4307. player->CurFormatSection = 0;
  4308. player->PlayMultiFormatSection = TRUE;
  4309. }
  4310. };
  4311. class SetAntiAliasModeEPR : public EmfPlusRecordPlay
  4312. {
  4313. public:
  4314. VOID Play(
  4315. MetafilePlayer * player,
  4316. EmfPlusRecordType recordType,
  4317. UINT flags,
  4318. UINT dataSize
  4319. ) const
  4320. {
  4321. ASSERT(recordType == EmfPlusRecordTypeSetAntiAliasMode);
  4322. player->Graphics->SetAntiAliasMode(GetAntiAliasMode(flags));
  4323. }
  4324. };
  4325. class SetTextRenderingHintEPR : public EmfPlusRecordPlay
  4326. {
  4327. public:
  4328. VOID Play(
  4329. MetafilePlayer * player,
  4330. EmfPlusRecordType recordType,
  4331. UINT flags,
  4332. UINT dataSize
  4333. ) const
  4334. {
  4335. ASSERT(recordType == EmfPlusRecordTypeSetTextRenderingHint);
  4336. player->Graphics->SetTextRenderingHint(GetTextRenderingHint(flags));
  4337. }
  4338. };
  4339. class SetTextContrastEPR : public EmfPlusRecordPlay
  4340. {
  4341. public:
  4342. VOID Play(
  4343. MetafilePlayer * player,
  4344. EmfPlusRecordType recordType,
  4345. UINT flags,
  4346. UINT dataSize
  4347. ) const
  4348. {
  4349. ASSERT(recordType == EmfPlusRecordTypeSetTextContrast);
  4350. player->Graphics->SetTextContrast(GetTextContrast(flags));
  4351. }
  4352. };
  4353. class SetInterpolationModeEPR : public EmfPlusRecordPlay
  4354. {
  4355. public:
  4356. VOID Play(
  4357. MetafilePlayer * player,
  4358. EmfPlusRecordType recordType,
  4359. UINT flags,
  4360. UINT dataSize
  4361. ) const
  4362. {
  4363. ASSERT(recordType == EmfPlusRecordTypeSetInterpolationMode);
  4364. player->Graphics->SetInterpolationMode(GetInterpolationMode(flags));
  4365. }
  4366. };
  4367. class SetPixelOffsetModeEPR : public EmfPlusRecordPlay
  4368. {
  4369. public:
  4370. VOID Play(
  4371. MetafilePlayer * player,
  4372. EmfPlusRecordType recordType,
  4373. UINT flags,
  4374. UINT dataSize
  4375. ) const
  4376. {
  4377. ASSERT(recordType == EmfPlusRecordTypeSetPixelOffsetMode);
  4378. player->Graphics->SetPixelOffsetMode(GetPixelOffsetMode(flags));
  4379. }
  4380. };
  4381. class SetCompositingModeEPR : public EmfPlusRecordPlay
  4382. {
  4383. public:
  4384. VOID Play(
  4385. MetafilePlayer * player,
  4386. EmfPlusRecordType recordType,
  4387. UINT flags,
  4388. UINT dataSize
  4389. ) const
  4390. {
  4391. ASSERT(recordType == EmfPlusRecordTypeSetCompositingMode);
  4392. player->Graphics->SetCompositingMode(GetCompositingMode(flags));
  4393. }
  4394. };
  4395. class SetCompositingQualityEPR : public EmfPlusRecordPlay
  4396. {
  4397. public:
  4398. VOID Play(
  4399. MetafilePlayer * player,
  4400. EmfPlusRecordType recordType,
  4401. UINT flags,
  4402. UINT dataSize
  4403. ) const
  4404. {
  4405. ASSERT(recordType == EmfPlusRecordTypeSetCompositingQuality);
  4406. player->Graphics->SetCompositingQuality(GetCompositingQuality(flags));
  4407. }
  4408. };
  4409. class SetRenderingOriginEPR : public EmfPlusRecordPlay
  4410. {
  4411. INT x;
  4412. INT y;
  4413. public:
  4414. VOID Play(
  4415. MetafilePlayer * player,
  4416. EmfPlusRecordType recordType,
  4417. UINT flags,
  4418. UINT dataSize
  4419. ) const
  4420. {
  4421. ASSERT(recordType == EmfPlusRecordTypeSetRenderingOrigin);
  4422. player->Graphics->SetRenderingOrigin(x, y);
  4423. }
  4424. };
  4425. #define SAVEEPR_MINSIZE (sizeof(UINT32))
  4426. class SaveEPR : public EmfPlusRecordPlay
  4427. {
  4428. protected:
  4429. UINT32 StackIndex;
  4430. public:
  4431. VOID Play(
  4432. MetafilePlayer * player,
  4433. EmfPlusRecordType recordType,
  4434. UINT flags,
  4435. UINT dataSize
  4436. ) const
  4437. {
  4438. ASSERT(recordType == EmfPlusRecordTypeSave);
  4439. if (dataSize < SAVEEPR_MINSIZE)
  4440. {
  4441. WARNING(("SaveEPR::Play dataSize is too small"));
  4442. return;
  4443. }
  4444. player->NewSave(StackIndex, player->Graphics->Save());
  4445. }
  4446. };
  4447. #define RESTOREEPR_MINSIZE (sizeof(UINT32))
  4448. class RestoreEPR : public EmfPlusRecordPlay
  4449. {
  4450. protected:
  4451. UINT32 StackIndex;
  4452. public:
  4453. VOID Play(
  4454. MetafilePlayer * player,
  4455. EmfPlusRecordType recordType,
  4456. UINT flags,
  4457. UINT dataSize
  4458. ) const
  4459. {
  4460. ASSERT(recordType == EmfPlusRecordTypeRestore);
  4461. if (dataSize < RESTOREEPR_MINSIZE)
  4462. {
  4463. WARNING(("RestoreEPR::Play dataSize is too small"));
  4464. return;
  4465. }
  4466. player->Graphics->Restore(player->GetSaveID(StackIndex));
  4467. }
  4468. };
  4469. #define BEGINCONTAINEREPR_MINSIZE (sizeof(GpRectF) + sizeof(GpRectF) + sizeof(UINT32))
  4470. class BeginContainerEPR : public EmfPlusRecordPlay
  4471. {
  4472. protected:
  4473. GpRectF DestRect;
  4474. GpRectF SrcRect;
  4475. UINT32 StackIndex;
  4476. public:
  4477. VOID Play(
  4478. MetafilePlayer * player,
  4479. EmfPlusRecordType recordType,
  4480. UINT flags,
  4481. UINT dataSize
  4482. ) const
  4483. {
  4484. ASSERT(recordType == EmfPlusRecordTypeBeginContainer);
  4485. if (dataSize < BEGINCONTAINEREPR_MINSIZE)
  4486. {
  4487. WARNING(("BeginContainerEPR::Play dataSize is too small"));
  4488. return;
  4489. }
  4490. player->NewSave(StackIndex,
  4491. player->Graphics->BeginContainer(DestRect, SrcRect, GetPageUnit(flags)));
  4492. }
  4493. };
  4494. #define BEGINCONTAINERNOPARAMSEPR_MINSIZE (sizeof(UINT32))
  4495. class BeginContainerNoParamsEPR : public EmfPlusRecordPlay
  4496. {
  4497. protected:
  4498. UINT32 StackIndex;
  4499. public:
  4500. VOID Play(
  4501. MetafilePlayer * player,
  4502. EmfPlusRecordType recordType,
  4503. UINT flags,
  4504. UINT dataSize
  4505. ) const
  4506. {
  4507. ASSERT(recordType == EmfPlusRecordTypeBeginContainerNoParams);
  4508. if (dataSize < BEGINCONTAINERNOPARAMSEPR_MINSIZE)
  4509. {
  4510. WARNING(("BeginContainerNoParamsEPR::Play dataSize is too small"));
  4511. return;
  4512. }
  4513. player->NewSave(StackIndex, player->Graphics->BeginContainer());
  4514. }
  4515. };
  4516. #define ENDCONTAINEREPR_MINSIZE (sizeof(UINT32))
  4517. class EndContainerEPR : public EmfPlusRecordPlay
  4518. {
  4519. protected:
  4520. UINT32 StackIndex;
  4521. public:
  4522. VOID Play(
  4523. MetafilePlayer * player,
  4524. EmfPlusRecordType recordType,
  4525. UINT flags,
  4526. UINT dataSize
  4527. ) const
  4528. {
  4529. ASSERT(recordType == EmfPlusRecordTypeEndContainer);
  4530. if (dataSize < ENDCONTAINEREPR_MINSIZE)
  4531. {
  4532. WARNING(("EndContainerEPR::Play dataSize is too small"));
  4533. return;
  4534. }
  4535. player->Graphics->EndContainer(player->GetSaveID(StackIndex));
  4536. }
  4537. };
  4538. #define SETWORLDTRANSFORMEPR_MINSIZE GDIP_MATRIX_SIZE
  4539. class SetWorldTransformEPR : public EmfPlusRecordPlay
  4540. {
  4541. protected:
  4542. REAL MatrixData[6];
  4543. public:
  4544. VOID Play(
  4545. MetafilePlayer * player,
  4546. EmfPlusRecordType recordType,
  4547. UINT flags,
  4548. UINT dataSize
  4549. ) const
  4550. {
  4551. ASSERT(recordType == EmfPlusRecordTypeSetWorldTransform);
  4552. if (dataSize < SETWORLDTRANSFORMEPR_MINSIZE)
  4553. {
  4554. WARNING(("SetWorldTransformEPR::Play dataSize is too small"));
  4555. return;
  4556. }
  4557. GpMatrix matrix(MatrixData[0], MatrixData[1],
  4558. MatrixData[2], MatrixData[3],
  4559. MatrixData[4], MatrixData[5]);
  4560. player->Graphics->SetWorldTransform(matrix);
  4561. }
  4562. };
  4563. class ResetWorldTransformEPR : public EmfPlusRecordPlay
  4564. {
  4565. public:
  4566. VOID Play(
  4567. MetafilePlayer * player,
  4568. EmfPlusRecordType recordType,
  4569. UINT flags,
  4570. UINT dataSize
  4571. ) const
  4572. {
  4573. ASSERT(recordType == EmfPlusRecordTypeResetWorldTransform);
  4574. player->Graphics->ResetWorldTransform();
  4575. }
  4576. };
  4577. #define MULTIPLYWORLDTRANSFORMEPR_MINSIZE GDIP_MATRIX_SIZE
  4578. class MultiplyWorldTransformEPR : public EmfPlusRecordPlay
  4579. {
  4580. protected:
  4581. REAL MatrixData[6];
  4582. public:
  4583. VOID Play(
  4584. MetafilePlayer * player,
  4585. EmfPlusRecordType recordType,
  4586. UINT flags,
  4587. UINT dataSize
  4588. ) const
  4589. {
  4590. ASSERT(recordType == EmfPlusRecordTypeMultiplyWorldTransform);
  4591. if (dataSize < MULTIPLYWORLDTRANSFORMEPR_MINSIZE)
  4592. {
  4593. WARNING(("MultiplyWorldTransformEPR::Play dataSize is too small"));
  4594. return;
  4595. }
  4596. GpMatrix matrix(MatrixData[0], MatrixData[1],
  4597. MatrixData[2], MatrixData[3],
  4598. MatrixData[4], MatrixData[5]);
  4599. player->Graphics->MultiplyWorldTransform(matrix, GetMatrixOrder(flags));
  4600. }
  4601. };
  4602. #define TRANSLATEWORLDTRANSFORMEPR_MINSIZE (sizeof(REAL) + sizeof(REAL))
  4603. class TranslateWorldTransformEPR : public EmfPlusRecordPlay
  4604. {
  4605. protected:
  4606. REAL Dx;
  4607. REAL Dy;
  4608. public:
  4609. VOID Play(
  4610. MetafilePlayer * player,
  4611. EmfPlusRecordType recordType,
  4612. UINT flags,
  4613. UINT dataSize
  4614. ) const
  4615. {
  4616. ASSERT(recordType == EmfPlusRecordTypeTranslateWorldTransform);
  4617. if (dataSize < TRANSLATEWORLDTRANSFORMEPR_MINSIZE)
  4618. {
  4619. WARNING(("TranslateWorldTransformEPR::Play dataSize is too small"));
  4620. return;
  4621. }
  4622. player->Graphics->TranslateWorldTransform(Dx, Dy, GetMatrixOrder(flags));
  4623. }
  4624. };
  4625. #define SCALEWORLDTRANSFORMEPR_MINSIZE (sizeof(REAL) + sizeof(REAL))
  4626. class ScaleWorldTransformEPR : public EmfPlusRecordPlay
  4627. {
  4628. protected:
  4629. REAL Sx;
  4630. REAL Sy;
  4631. public:
  4632. VOID Play(
  4633. MetafilePlayer * player,
  4634. EmfPlusRecordType recordType,
  4635. UINT flags,
  4636. UINT dataSize
  4637. ) const
  4638. {
  4639. ASSERT(recordType == EmfPlusRecordTypeScaleWorldTransform);
  4640. if (dataSize < SCALEWORLDTRANSFORMEPR_MINSIZE)
  4641. {
  4642. WARNING(("ScaleWorldTransformEPR::Play dataSize is too small"));
  4643. return;
  4644. }
  4645. player->Graphics->ScaleWorldTransform(Sx, Sy, GetMatrixOrder(flags));
  4646. }
  4647. };
  4648. #define ROTATEWORLDTRANSFORMEPR_MINSIZE (sizeof(REAL))
  4649. class RotateWorldTransformEPR : public EmfPlusRecordPlay
  4650. {
  4651. protected:
  4652. REAL Angle;
  4653. public:
  4654. VOID Play(
  4655. MetafilePlayer * player,
  4656. EmfPlusRecordType recordType,
  4657. UINT flags,
  4658. UINT dataSize
  4659. ) const
  4660. {
  4661. ASSERT(recordType == EmfPlusRecordTypeRotateWorldTransform);
  4662. if (dataSize < ROTATEWORLDTRANSFORMEPR_MINSIZE)
  4663. {
  4664. WARNING(("RotateWorldTransformEPR::Play dataSize is too small"));
  4665. return;
  4666. }
  4667. player->Graphics->RotateWorldTransform(Angle, GetMatrixOrder(flags));
  4668. }
  4669. };
  4670. #define SETPAGETRANSFORMEPR_MINSIZE (sizeof(REAL))
  4671. class SetPageTransformEPR : public EmfPlusRecordPlay
  4672. {
  4673. protected:
  4674. REAL Scale;
  4675. public:
  4676. VOID Play(
  4677. MetafilePlayer * player,
  4678. EmfPlusRecordType recordType,
  4679. UINT flags,
  4680. UINT dataSize
  4681. ) const
  4682. {
  4683. ASSERT(recordType == EmfPlusRecordTypeSetPageTransform);
  4684. if (dataSize < SETPAGETRANSFORMEPR_MINSIZE)
  4685. {
  4686. WARNING(("SetPageTransformEPR::Play dataSize is too small"));
  4687. return;
  4688. }
  4689. player->Graphics->SetPageTransform(GetPageUnit(flags), Scale);
  4690. }
  4691. };
  4692. class ResetClipEPR : public EmfPlusRecordPlay
  4693. {
  4694. public:
  4695. VOID Play(
  4696. MetafilePlayer * player,
  4697. EmfPlusRecordType recordType,
  4698. UINT flags,
  4699. UINT dataSize
  4700. ) const
  4701. {
  4702. ASSERT(recordType == EmfPlusRecordTypeResetClip);
  4703. player->Graphics->ResetClip();
  4704. }
  4705. };
  4706. #define SETCLIPRECTEPR_MINSIZE (sizeof(GpRectF))
  4707. class SetClipRectEPR : public EmfPlusRecordPlay
  4708. {
  4709. protected:
  4710. GpRectF ClipRect; // !!! Handle 16-bit rect
  4711. public:
  4712. VOID Play(
  4713. MetafilePlayer * player,
  4714. EmfPlusRecordType recordType,
  4715. UINT flags,
  4716. UINT dataSize
  4717. ) const
  4718. {
  4719. ASSERT(recordType == EmfPlusRecordTypeSetClipRect);
  4720. if (dataSize < SETCLIPRECTEPR_MINSIZE)
  4721. {
  4722. WARNING(("SetClipRectEPR::Play dataSize is too small"));
  4723. return;
  4724. }
  4725. player->Graphics->SetClip(ClipRect, GetCombineMode(flags));
  4726. }
  4727. };
  4728. class SetClipPathEPR : public EmfPlusRecordPlay
  4729. {
  4730. public:
  4731. VOID Play(
  4732. MetafilePlayer * player,
  4733. EmfPlusRecordType recordType,
  4734. UINT flags,
  4735. UINT dataSize
  4736. ) const
  4737. {
  4738. ASSERT(recordType == EmfPlusRecordTypeSetClipPath);
  4739. GpPath *path = (GpPath *)player->GetObject(GetMetaObjectId(flags), ObjectTypePath);
  4740. if (path != NULL)
  4741. {
  4742. player->Graphics->SetClip(path, GetCombineMode(flags), GetIsDevicePath(flags));
  4743. }
  4744. }
  4745. };
  4746. class SetClipRegionEPR : public EmfPlusRecordPlay
  4747. {
  4748. public:
  4749. VOID Play(
  4750. MetafilePlayer * player,
  4751. EmfPlusRecordType recordType,
  4752. UINT flags,
  4753. UINT dataSize
  4754. ) const
  4755. {
  4756. ASSERT(recordType == EmfPlusRecordTypeSetClipRegion);
  4757. GpRegion *region = (GpRegion *)player->GetObject(GetMetaObjectId(flags), ObjectTypeRegion);
  4758. if (region != NULL)
  4759. {
  4760. player->Graphics->SetClip(region, GetCombineMode(flags));
  4761. }
  4762. }
  4763. };
  4764. #define OFFSETCLIPEPR_MINSIZE (sizeof(REAL) + sizeof(REAL))
  4765. class OffsetClipEPR : public EmfPlusRecordPlay
  4766. {
  4767. protected:
  4768. REAL Dx;
  4769. REAL Dy;
  4770. public:
  4771. VOID Play(
  4772. MetafilePlayer * player,
  4773. EmfPlusRecordType recordType,
  4774. UINT flags,
  4775. UINT dataSize
  4776. ) const
  4777. {
  4778. ASSERT(recordType == EmfPlusRecordTypeOffsetClip);
  4779. if (dataSize < OFFSETCLIPEPR_MINSIZE)
  4780. {
  4781. WARNING(("OffsetClipEPR::Play dataSize is too small"));
  4782. return;
  4783. }
  4784. player->Graphics->OffsetClip(Dx, Dy);
  4785. }
  4786. };
  4787. #define OBJECTEPR_MINSIZE (sizeof(UINT32))
  4788. class ObjectEPR : public EmfPlusRecordPlay
  4789. {
  4790. protected:
  4791. BYTE ObjectData[1];
  4792. public:
  4793. VOID Play(
  4794. MetafilePlayer * player,
  4795. EmfPlusRecordType recordType,
  4796. UINT flags,
  4797. UINT dataSize
  4798. ) const
  4799. {
  4800. if (dataSize < OBJECTEPR_MINSIZE)
  4801. {
  4802. WARNING(("ObjectEPR::Play dataSize is too small"));
  4803. return;
  4804. }
  4805. player->AddObject(flags, ObjectData, dataSize);
  4806. }
  4807. };
  4808. #define CLEAREPR_MINSIZE (sizeof(UINT32))
  4809. class ClearEPR : public EmfPlusBoundsRecord
  4810. {
  4811. protected:
  4812. ARGB Color;
  4813. public:
  4814. VOID Play(
  4815. MetafilePlayer * player,
  4816. EmfPlusRecordType recordType,
  4817. UINT flags,
  4818. UINT dataSize
  4819. ) const
  4820. {
  4821. ASSERT(recordType == EmfPlusRecordTypeClear);
  4822. if (dataSize < CLEAREPR_MINSIZE)
  4823. {
  4824. WARNING(("ClearEPR::Play dataSize is too small"));
  4825. return;
  4826. }
  4827. GpColor color;
  4828. color.SetColor(Color);
  4829. player->Graphics->Clear(color);
  4830. }
  4831. };
  4832. #define FILLRECTSEPR_MINSIZE (sizeof(UINT32) + sizeof(UINT32))
  4833. class FillRectsEPR : public EmfPlusBoundsRecord
  4834. {
  4835. protected:
  4836. UINT32 BrushValue;
  4837. UINT32 Count;
  4838. BYTE RectData[1]; // GpRect16 or GpRectF
  4839. public:
  4840. VOID Play(
  4841. MetafilePlayer * player,
  4842. EmfPlusRecordType recordType,
  4843. UINT flags,
  4844. UINT dataSize
  4845. ) const
  4846. {
  4847. ASSERT(recordType == EmfPlusRecordTypeFillRects);
  4848. if (dataSize < FILLRECTSEPR_MINSIZE)
  4849. {
  4850. WARNING(("FillRectsEPR::Play dataSize is too small"));
  4851. return;
  4852. }
  4853. GpBrush * brush = player->GetBrush(BrushValue, flags);
  4854. GpRectF * rects = player->GetRects(RectData, dataSize - FILLRECTSEPR_MINSIZE, Count, flags);
  4855. if (rects != NULL)
  4856. {
  4857. if (brush != NULL)
  4858. {
  4859. player->Graphics->FillRects(brush, rects, Count);
  4860. }
  4861. player->FreePointsBuffer();
  4862. }
  4863. }
  4864. };
  4865. #define DRAWRECTSEPR_MINSIZE (sizeof(UINT32))
  4866. class DrawRectsEPR : public EmfPlusBoundsRecord
  4867. {
  4868. protected:
  4869. UINT32 Count;
  4870. BYTE RectData[1]; // GpRect16 or GpRectF
  4871. public:
  4872. VOID Play(
  4873. MetafilePlayer * player,
  4874. EmfPlusRecordType recordType,
  4875. UINT flags,
  4876. UINT dataSize
  4877. ) const
  4878. {
  4879. ASSERT(recordType == EmfPlusRecordTypeDrawRects);
  4880. if (dataSize < DRAWRECTSEPR_MINSIZE)
  4881. {
  4882. WARNING(("DrawRectsEPR::Play dataSize is too small"));
  4883. return;
  4884. }
  4885. GpPen * pen = (GpPen *)player->GetObject(GetMetaObjectId(flags), ObjectTypePen);
  4886. GpRectF * rects = player->GetRects(RectData, dataSize - DRAWRECTSEPR_MINSIZE, Count, flags);
  4887. if (rects != NULL)
  4888. {
  4889. if (pen != NULL)
  4890. {
  4891. player->Graphics->DrawRects(pen, rects, Count);
  4892. }
  4893. player->FreePointsBuffer();
  4894. }
  4895. }
  4896. };
  4897. #define FILLPOLYGONEPR_MINSIZE (sizeof(UINT32) + sizeof(UINT32))
  4898. class FillPolygonEPR : public EmfPlusBoundsRecord
  4899. {
  4900. protected:
  4901. UINT32 BrushValue;
  4902. UINT32 Count;
  4903. BYTE PointData[1]; // GpPoint16 or GpPointF
  4904. public:
  4905. VOID Play(
  4906. MetafilePlayer * player,
  4907. EmfPlusRecordType recordType,
  4908. UINT flags,
  4909. UINT dataSize
  4910. ) const
  4911. {
  4912. ASSERT(recordType == EmfPlusRecordTypeFillPolygon);
  4913. if (dataSize < FILLPOLYGONEPR_MINSIZE)
  4914. {
  4915. WARNING(("FillPolygonEPR::Play dataSize is too small"));
  4916. return;
  4917. }
  4918. GpBrush * brush = player->GetBrush(BrushValue, flags);
  4919. GpPointF * points = player->GetPoints(PointData, dataSize - FILLPOLYGONEPR_MINSIZE, Count, flags);
  4920. if (points != NULL)
  4921. {
  4922. if (brush != NULL)
  4923. {
  4924. player->Graphics->FillPolygon(brush, points, Count, GetFillMode(flags));
  4925. }
  4926. player->FreePointsBuffer();
  4927. }
  4928. }
  4929. };
  4930. #define DRAWLINESEPR_MINSIZE (sizeof(UINT32))
  4931. class DrawLinesEPR : public EmfPlusBoundsRecord
  4932. {
  4933. protected:
  4934. UINT32 Count;
  4935. BYTE PointData[1]; // GpPoint16 or GpPointF
  4936. public:
  4937. VOID Play(
  4938. MetafilePlayer * player,
  4939. EmfPlusRecordType recordType,
  4940. UINT flags,
  4941. UINT dataSize
  4942. ) const
  4943. {
  4944. ASSERT(recordType == EmfPlusRecordTypeDrawLines);
  4945. if (dataSize < DRAWLINESEPR_MINSIZE)
  4946. {
  4947. WARNING(("DrawLinesEPR::Play dataSize is too small"));
  4948. return;
  4949. }
  4950. GpPen * pen = (GpPen *)player->GetObject(GetMetaObjectId(flags), ObjectTypePen);
  4951. GpPointF * points = player->GetPoints(PointData, dataSize - DRAWLINESEPR_MINSIZE, Count, flags);
  4952. if (points != NULL)
  4953. {
  4954. if (pen != NULL)
  4955. {
  4956. player->Graphics->DrawLines(pen, points, Count, IsClosed(flags));
  4957. }
  4958. player->FreePointsBuffer();
  4959. }
  4960. }
  4961. };
  4962. #define FILLELLIPSEEPR_MINSIZE (sizeof(UINT32))
  4963. class FillEllipseEPR : public EmfPlusBoundsRecord
  4964. {
  4965. protected:
  4966. UINT32 BrushValue;
  4967. BYTE RectData[1]; // GpRect16 or GpRectF
  4968. public:
  4969. VOID Play(
  4970. MetafilePlayer * player,
  4971. EmfPlusRecordType recordType,
  4972. UINT flags,
  4973. UINT dataSize
  4974. ) const
  4975. {
  4976. ASSERT(recordType == EmfPlusRecordTypeFillEllipse);
  4977. if (dataSize < FILLELLIPSEEPR_MINSIZE)
  4978. {
  4979. WARNING(("FillEllipseEPR::Play dataSize is too small"));
  4980. return;
  4981. }
  4982. GpBrush * brush = player->GetBrush(BrushValue, flags);
  4983. GpRectF * rect = player->GetRects(RectData, dataSize - FILLELLIPSEEPR_MINSIZE, 1, flags);
  4984. if (rect != NULL)
  4985. {
  4986. if (brush != NULL)
  4987. {
  4988. player->Graphics->FillEllipse(brush, *rect);
  4989. }
  4990. player->FreePointsBuffer();
  4991. }
  4992. }
  4993. };
  4994. class DrawEllipseEPR : public EmfPlusBoundsRecord
  4995. {
  4996. protected:
  4997. BYTE RectData[1]; // GpRect16 or GpRectF
  4998. public:
  4999. VOID Play(
  5000. MetafilePlayer * player,
  5001. EmfPlusRecordType recordType,
  5002. UINT flags,
  5003. UINT dataSize
  5004. ) const
  5005. {
  5006. ASSERT(recordType == EmfPlusRecordTypeDrawEllipse);
  5007. GpPen * pen = (GpPen *)player->GetObject(GetMetaObjectId(flags), ObjectTypePen);
  5008. GpRectF * rect = player->GetRects(RectData, dataSize, 1, flags);
  5009. if (rect != NULL)
  5010. {
  5011. if (pen != NULL)
  5012. {
  5013. player->Graphics->DrawEllipse(pen, *rect);
  5014. }
  5015. player->FreePointsBuffer();
  5016. }
  5017. }
  5018. };
  5019. #define FILLPIEEPR_MINSIZE (sizeof(UINT32) + sizeof(REAL) + sizeof(REAL))
  5020. class FillPieEPR : public EmfPlusBoundsRecord
  5021. {
  5022. protected:
  5023. UINT32 BrushValue;
  5024. REAL StartAngle;
  5025. REAL SweepAngle;
  5026. BYTE RectData[1]; // GpRect16 or GpRectF
  5027. public:
  5028. VOID Play(
  5029. MetafilePlayer * player,
  5030. EmfPlusRecordType recordType,
  5031. UINT flags,
  5032. UINT dataSize
  5033. ) const
  5034. {
  5035. ASSERT(recordType == EmfPlusRecordTypeFillPie);
  5036. if (dataSize < FILLPIEEPR_MINSIZE)
  5037. {
  5038. WARNING(("FillPieEPR::Play dataSize is too small"));
  5039. return;
  5040. }
  5041. GpBrush * brush = player->GetBrush(BrushValue, flags);
  5042. GpRectF * rect = player->GetRects(RectData, dataSize - FILLPIEEPR_MINSIZE, 1, flags);
  5043. if (rect != NULL)
  5044. {
  5045. if (brush != NULL)
  5046. {
  5047. player->Graphics->FillPie(brush, *rect, StartAngle, SweepAngle);
  5048. }
  5049. player->FreePointsBuffer();
  5050. }
  5051. }
  5052. };
  5053. #define DRAWPIEEPR_MINSIZE (sizeof(REAL) + sizeof(REAL))
  5054. class DrawPieEPR : public EmfPlusBoundsRecord
  5055. {
  5056. protected:
  5057. REAL StartAngle;
  5058. REAL SweepAngle;
  5059. BYTE RectData[1]; // GpRect16 or GpRectF
  5060. public:
  5061. VOID Play(
  5062. MetafilePlayer * player,
  5063. EmfPlusRecordType recordType,
  5064. UINT flags,
  5065. UINT dataSize
  5066. ) const
  5067. {
  5068. ASSERT(recordType == EmfPlusRecordTypeDrawPie);
  5069. if (dataSize < DRAWPIEEPR_MINSIZE)
  5070. {
  5071. WARNING(("DrawPieEPR::Play dataSize is too small"));
  5072. return;
  5073. }
  5074. GpPen * pen = (GpPen *)player->GetObject(GetMetaObjectId(flags), ObjectTypePen);
  5075. GpRectF * rect = player->GetRects(RectData, dataSize - DRAWPIEEPR_MINSIZE, 1, flags);
  5076. if (rect != NULL)
  5077. {
  5078. if (pen != NULL)
  5079. {
  5080. player->Graphics->DrawPie(pen, *rect, StartAngle, SweepAngle);
  5081. }
  5082. player->FreePointsBuffer();
  5083. }
  5084. }
  5085. };
  5086. #define DRAWARCEPR_MINSIZE (sizeof(REAL) + sizeof(REAL))
  5087. class DrawArcEPR : public EmfPlusBoundsRecord
  5088. {
  5089. protected:
  5090. REAL StartAngle;
  5091. REAL SweepAngle;
  5092. BYTE RectData[1]; // GpRect16 or GpRectF
  5093. public:
  5094. VOID Play(
  5095. MetafilePlayer * player,
  5096. EmfPlusRecordType recordType,
  5097. UINT flags,
  5098. UINT dataSize
  5099. ) const
  5100. {
  5101. ASSERT(recordType == EmfPlusRecordTypeDrawArc);
  5102. if (dataSize < DRAWARCEPR_MINSIZE)
  5103. {
  5104. WARNING(("DrawArcEPR::Play dataSize is too small"));
  5105. return;
  5106. }
  5107. GpPen * pen = (GpPen *)player->GetObject(GetMetaObjectId(flags), ObjectTypePen);
  5108. GpRectF * rect = player->GetRects(RectData, dataSize - DRAWARCEPR_MINSIZE, 1, flags);
  5109. if (rect != NULL)
  5110. {
  5111. if (pen != NULL)
  5112. {
  5113. player->Graphics->DrawArc(pen, *rect, StartAngle, SweepAngle);
  5114. }
  5115. player->FreePointsBuffer();
  5116. }
  5117. }
  5118. };
  5119. #define FILLREGIONEPR_MINSIZE (sizeof(UINT32))
  5120. class FillRegionEPR : public EmfPlusBoundsRecord
  5121. {
  5122. protected:
  5123. UINT32 BrushValue;
  5124. public:
  5125. VOID Play(
  5126. MetafilePlayer * player,
  5127. EmfPlusRecordType recordType,
  5128. UINT flags,
  5129. UINT dataSize
  5130. ) const
  5131. {
  5132. ASSERT(recordType == EmfPlusRecordTypeFillRegion);
  5133. if (dataSize < FILLREGIONEPR_MINSIZE)
  5134. {
  5135. WARNING(("FillRegionEPR::Play dataSize is too small"));
  5136. return;
  5137. }
  5138. GpBrush * brush = player->GetBrush(BrushValue, flags);
  5139. GpRegion * region = (GpRegion *)player->GetObject(GetMetaObjectId(flags), ObjectTypeRegion);
  5140. if ((brush != NULL) && (region != NULL))
  5141. {
  5142. player->Graphics->FillRegion(brush, region);
  5143. }
  5144. }
  5145. };
  5146. #define FILLPATHEPR_MINSIZE (sizeof(UINT32))
  5147. class FillPathEPR : public EmfPlusBoundsRecord
  5148. {
  5149. protected:
  5150. UINT32 BrushValue;
  5151. public:
  5152. VOID Play(
  5153. MetafilePlayer * player,
  5154. EmfPlusRecordType recordType,
  5155. UINT flags,
  5156. UINT dataSize
  5157. ) const
  5158. {
  5159. ASSERT(recordType == EmfPlusRecordTypeFillPath);
  5160. if (dataSize < FILLPATHEPR_MINSIZE)
  5161. {
  5162. WARNING(("FillPathEPR::Play dataSize is too small"));
  5163. return;
  5164. }
  5165. GpBrush * brush = player->GetBrush(BrushValue, flags);
  5166. GpPath * path = (GpPath *)player->GetObject(GetMetaObjectId(flags), ObjectTypePath);
  5167. if ((brush != NULL) && (path != NULL))
  5168. {
  5169. player->Graphics->FillPath(brush, path);
  5170. }
  5171. }
  5172. };
  5173. #define DRAWPATHEPR_MINSIZE (sizeof(UINT32))
  5174. class DrawPathEPR : public EmfPlusBoundsRecord
  5175. {
  5176. protected:
  5177. UINT32 PenId;
  5178. public:
  5179. VOID Play(
  5180. MetafilePlayer * player,
  5181. EmfPlusRecordType recordType,
  5182. UINT flags,
  5183. UINT dataSize
  5184. ) const
  5185. {
  5186. ASSERT(recordType == EmfPlusRecordTypeDrawPath);
  5187. if (dataSize < DRAWPATHEPR_MINSIZE)
  5188. {
  5189. WARNING(("DrawPathEPR::Play dataSize is too small"));
  5190. return;
  5191. }
  5192. GpPen * pen = (GpPen *)player->GetObject(PenId, ObjectTypePen);
  5193. GpPath * path = (GpPath *)player->GetObject(GetMetaObjectId(flags), ObjectTypePath);
  5194. if ((pen != NULL) && (path != NULL))
  5195. {
  5196. player->Graphics->DrawPath(pen, path);
  5197. }
  5198. }
  5199. };
  5200. #define FILLCLOSEDCURVEEPR_MINSIZE (sizeof(UINT32) + sizeof(REAL) + sizeof(UINT32))
  5201. class FillClosedCurveEPR : public EmfPlusBoundsRecord
  5202. {
  5203. protected:
  5204. UINT32 BrushValue;
  5205. REAL Tension;
  5206. UINT32 Count;
  5207. BYTE PointData[1]; // GpPoint16 or GpPointF
  5208. public:
  5209. VOID Play(
  5210. MetafilePlayer * player,
  5211. EmfPlusRecordType recordType,
  5212. UINT flags,
  5213. UINT dataSize
  5214. ) const
  5215. {
  5216. ASSERT(recordType == EmfPlusRecordTypeFillClosedCurve);
  5217. if (dataSize < FILLCLOSEDCURVEEPR_MINSIZE)
  5218. {
  5219. WARNING(("FillClosedCurveEPR::Play dataSize is too small"));
  5220. return;
  5221. }
  5222. GpBrush * brush = player->GetBrush(BrushValue, flags);
  5223. GpPointF * points = player->GetPoints(PointData, dataSize - FILLCLOSEDCURVEEPR_MINSIZE, Count, flags);
  5224. if (points != NULL)
  5225. {
  5226. if (brush != NULL)
  5227. {
  5228. player->Graphics->FillClosedCurve(brush, points, Count,Tension,GetFillMode(flags));
  5229. }
  5230. player->FreePointsBuffer();
  5231. }
  5232. }
  5233. };
  5234. #define DRAWCLOSEDCURVEEPR_MINSIZE (sizeof(REAL) + sizeof(UINT32))
  5235. class DrawClosedCurveEPR : public EmfPlusBoundsRecord
  5236. {
  5237. protected:
  5238. REAL Tension;
  5239. UINT32 Count;
  5240. BYTE PointData[1]; // GpPoint16 or GpPointF
  5241. public:
  5242. VOID Play(
  5243. MetafilePlayer * player,
  5244. EmfPlusRecordType recordType,
  5245. UINT flags,
  5246. UINT dataSize
  5247. ) const
  5248. {
  5249. ASSERT(recordType == EmfPlusRecordTypeDrawClosedCurve);
  5250. if (dataSize < DRAWCLOSEDCURVEEPR_MINSIZE)
  5251. {
  5252. WARNING(("DrawClosedCurveEPR::Play dataSize is too small"));
  5253. return;
  5254. }
  5255. GpPen * pen = (GpPen *)player->GetObject(GetMetaObjectId(flags), ObjectTypePen);
  5256. GpPointF * points = player->GetPoints(PointData, dataSize - DRAWCLOSEDCURVEEPR_MINSIZE, Count, flags);
  5257. if (points != NULL)
  5258. {
  5259. if (pen != NULL)
  5260. {
  5261. player->Graphics->DrawClosedCurve(pen, points, Count, Tension);
  5262. }
  5263. player->FreePointsBuffer();
  5264. }
  5265. }
  5266. };
  5267. #define DRAWCURVEEPR_MINSIZE (sizeof(REAL) + sizeof(INT32) + sizeof(UINT32) + sizeof(UINT32))
  5268. class DrawCurveEPR : public EmfPlusBoundsRecord
  5269. {
  5270. protected:
  5271. REAL Tension;
  5272. INT32 Offset;
  5273. UINT32 NumSegments;
  5274. UINT32 Count;
  5275. BYTE PointData[1]; // GpPoint16 or GpPointF
  5276. public:
  5277. VOID Play(
  5278. MetafilePlayer * player,
  5279. EmfPlusRecordType recordType,
  5280. UINT flags,
  5281. UINT dataSize
  5282. ) const
  5283. {
  5284. ASSERT(recordType == EmfPlusRecordTypeDrawCurve);
  5285. if (dataSize < DRAWCURVEEPR_MINSIZE)
  5286. {
  5287. WARNING(("DrawCurveEPR::Play dataSize is too small"));
  5288. return;
  5289. }
  5290. GpPen * pen = (GpPen *)player->GetObject(GetMetaObjectId(flags), ObjectTypePen);
  5291. GpPointF * points = player->GetPoints(PointData, dataSize - DRAWCURVEEPR_MINSIZE, Count, flags);
  5292. if (points != NULL)
  5293. {
  5294. if (pen != NULL)
  5295. {
  5296. player->Graphics->DrawCurve(pen, points, Count, Tension, Offset, NumSegments);
  5297. }
  5298. player->FreePointsBuffer();
  5299. }
  5300. }
  5301. };
  5302. #define DRAWBEZIERSEPR_MINSIZE (sizeof(UINT32))
  5303. class DrawBeziersEPR : public EmfPlusBoundsRecord
  5304. {
  5305. protected:
  5306. UINT32 Count;
  5307. BYTE PointData[1]; // GpPoint16 or GpPointF
  5308. public:
  5309. VOID Play(
  5310. MetafilePlayer * player,
  5311. EmfPlusRecordType recordType,
  5312. UINT flags,
  5313. UINT dataSize
  5314. ) const
  5315. {
  5316. ASSERT(recordType == EmfPlusRecordTypeDrawBeziers);
  5317. if (dataSize < DRAWBEZIERSEPR_MINSIZE)
  5318. {
  5319. WARNING(("DrawBeziersEPR::Play dataSize is too small"));
  5320. return;
  5321. }
  5322. GpPen * pen = (GpPen *)player->GetObject(GetMetaObjectId(flags), ObjectTypePen);
  5323. GpPointF * points = player->GetPoints(PointData, dataSize - DRAWBEZIERSEPR_MINSIZE, Count, flags);
  5324. if (points != NULL)
  5325. {
  5326. if (pen != NULL)
  5327. {
  5328. player->Graphics->DrawBeziers(pen, points, Count);
  5329. }
  5330. player->FreePointsBuffer();
  5331. }
  5332. }
  5333. };
  5334. #define DRAWIMAGEEPR_MINSIZE (sizeof(INT32) + sizeof(GpRectF))
  5335. class DrawImageEPR : public EmfPlusBoundsRecord
  5336. {
  5337. protected:
  5338. UINT32 ImageAttributesId;
  5339. INT32 SrcUnit;
  5340. GpRectF SrcRect;
  5341. BYTE RectData[1]; // GpRect16 or GpRectF
  5342. public:
  5343. VOID Play(
  5344. MetafilePlayer * player,
  5345. EmfPlusRecordType recordType,
  5346. UINT flags,
  5347. UINT dataSize
  5348. ) const
  5349. {
  5350. ASSERT(recordType == EmfPlusRecordTypeDrawImage);
  5351. if (dataSize < DRAWIMAGEEPR_MINSIZE)
  5352. {
  5353. WARNING(("DrawImageEPR::Play dataSize is too small"));
  5354. return;
  5355. }
  5356. GpImage *image = (GpImage *)player->GetObject(GetMetaObjectId(flags), ObjectTypeImage);
  5357. GpRectF *destRect = player->GetRects(RectData, dataSize - DRAWIMAGEEPR_MINSIZE, 1, flags);
  5358. GpImageAttributes *imageAttributes =
  5359. (GpImageAttributes *)player->GetObject(
  5360. ImageAttributesId,
  5361. ObjectTypeImageAttributes
  5362. );
  5363. if ( (image != NULL) && (NULL != destRect) )
  5364. {
  5365. GpStatus status = player->Graphics->DrawImage(
  5366. image,
  5367. *destRect,
  5368. SrcRect,
  5369. static_cast<GpPageUnit>(SrcUnit),
  5370. imageAttributes,
  5371. player->DrawImageCallback,
  5372. player->DrawImageCallbackData
  5373. );
  5374. if (status == Aborted)
  5375. {
  5376. // stop enumerating records
  5377. player->EnumerateAborted = TRUE;
  5378. }
  5379. }
  5380. }
  5381. };
  5382. #define DRAWIMAGEPOINTSEPR_MINSIZE (sizeof(INT32) + sizeof(GpRectF) + sizeof(UINT32))
  5383. class DrawImagePointsEPR : public EmfPlusBoundsRecord
  5384. {
  5385. protected:
  5386. UINT32 ImageAttributesId;
  5387. INT32 SrcUnit;
  5388. GpRectF SrcRect;
  5389. UINT32 Count;
  5390. BYTE PointData[1]; // GpPoint16 or GpPointF
  5391. public:
  5392. VOID Play(
  5393. MetafilePlayer * player,
  5394. EmfPlusRecordType recordType,
  5395. UINT flags,
  5396. UINT dataSize
  5397. ) const
  5398. {
  5399. ASSERT(recordType == EmfPlusRecordTypeDrawImagePoints);
  5400. if (dataSize < DRAWIMAGEPOINTSEPR_MINSIZE)
  5401. {
  5402. WARNING(("DrawImagePointsEPR::Play dataSize is too small"));
  5403. return;
  5404. }
  5405. GpImage *image = (GpImage *)player->GetObject(GetMetaObjectId(flags), ObjectTypeImage);
  5406. GpPointF *destPoints = player->GetPoints(PointData, dataSize - DRAWIMAGEPOINTSEPR_MINSIZE, Count, flags);
  5407. GpImageAttributes *imageAttributes =
  5408. (GpImageAttributes *)player->GetObject(
  5409. ImageAttributesId,
  5410. ObjectTypeImageAttributes
  5411. );
  5412. if (destPoints != NULL)
  5413. {
  5414. if (image != NULL)
  5415. {
  5416. GpStatus status = player->Graphics->DrawImage(
  5417. image,
  5418. destPoints,
  5419. Count,
  5420. SrcRect,
  5421. static_cast<GpPageUnit>(SrcUnit),
  5422. imageAttributes,
  5423. player->DrawImageCallback,
  5424. player->DrawImageCallbackData
  5425. );
  5426. if (status == Aborted)
  5427. {
  5428. // stop enumerating records
  5429. player->EnumerateAborted = TRUE;
  5430. }
  5431. }
  5432. player->FreePointsBuffer();
  5433. }
  5434. }
  5435. };
  5436. #define DRAWSTRINGEPR_MINSIZE (sizeof(UINT32) + sizeof(UINT32) + sizeof(UINT32) + sizeof(GpRectF))
  5437. class DrawStringEPR : public EmfPlusBoundsRecord
  5438. {
  5439. protected:
  5440. UINT32 BrushValue;
  5441. UINT32 FormatId;
  5442. UINT32 Length;
  5443. GpRectF LayoutRect;
  5444. BYTE StringData[1];
  5445. public:
  5446. VOID Play(
  5447. MetafilePlayer * player,
  5448. EmfPlusRecordType recordType,
  5449. UINT flags,
  5450. UINT dataSize
  5451. ) const
  5452. {
  5453. ASSERT(recordType == EmfPlusRecordTypeDrawString);
  5454. if (dataSize < DRAWSTRINGEPR_MINSIZE)
  5455. {
  5456. WARNING(("DrawStringEPR::Play dataSize is too small"));
  5457. return;
  5458. }
  5459. GlobalTextLock lock;
  5460. GpBrush * brush = player->GetBrush(BrushValue, flags);
  5461. GpFont * font = (GpFont *)player->GetObject(GetMetaObjectId(flags), ObjectTypeFont);
  5462. // Optional parameter - can return NULL.
  5463. GpStringFormat *format = (GpStringFormat *)player->GetObject(
  5464. FormatId,
  5465. ObjectTypeStringFormat
  5466. );
  5467. if (Length > 0)
  5468. {
  5469. if (dataSize >= (DRAWSTRINGEPR_MINSIZE + (Length * sizeof(WCHAR))))
  5470. {
  5471. if ((brush != NULL) && (font != NULL))
  5472. {
  5473. // !!! TODO:
  5474. // Determine whether the string is compressed or not.
  5475. // If so, decompress it.
  5476. player->Graphics->DrawString(
  5477. (WCHAR *)StringData,
  5478. Length,
  5479. font,
  5480. &LayoutRect,
  5481. format,
  5482. brush
  5483. );
  5484. }
  5485. }
  5486. else
  5487. {
  5488. WARNING(("DrawStringEPR::Play dataSize is too small"));
  5489. return;
  5490. }
  5491. player->FreePointsBuffer();
  5492. }
  5493. }
  5494. };
  5495. #define DRAWDRIVERSTRINGEPR_MINSIZE (sizeof(UINT32) + sizeof(INT) + sizeof(UINT32) + sizeof(UINT32))
  5496. class DrawDriverStringEPR : public EmfPlusBoundsRecord
  5497. {
  5498. protected:
  5499. UINT32 BrushValue;
  5500. INT ApiFlags;
  5501. UINT32 MatrixPresent;
  5502. UINT32 GlyphCount;
  5503. BYTE Data[1];
  5504. public:
  5505. VOID Play(
  5506. MetafilePlayer * player,
  5507. EmfPlusRecordType recordType,
  5508. UINT flags,
  5509. UINT dataSize
  5510. ) const
  5511. {
  5512. ASSERT(recordType == EmfPlusRecordTypeDrawDriverString);
  5513. if (dataSize < DRAWDRIVERSTRINGEPR_MINSIZE)
  5514. {
  5515. WARNING(("DrawDriverStringEPR::Play dataSize is too small"));
  5516. return;
  5517. }
  5518. GlobalTextLock lock;
  5519. GpBrush * brush = player->GetBrush(BrushValue, flags);
  5520. GpFont * font = (GpFont *)player->GetObject(GetMetaObjectId(flags), ObjectTypeFont);
  5521. if (GlyphCount > 0)
  5522. {
  5523. UINT requiredSize = DRAWDRIVERSTRINGEPR_MINSIZE +
  5524. (GlyphCount * sizeof(WCHAR)) +
  5525. (GlyphCount * sizeof(PointF));
  5526. if (dataSize >= requiredSize)
  5527. {
  5528. if ((brush != NULL) && (font != NULL))
  5529. {
  5530. WCHAR *text = (WCHAR *) Data;
  5531. PointF *positions = (PointF *) (Data + (GlyphCount * sizeof(WCHAR)));
  5532. if (MatrixPresent > 0)
  5533. {
  5534. if (dataSize < requiredSize + GDIP_MATRIX_SIZE)
  5535. {
  5536. WARNING(("DrawDriverStringEPR::Play dataSize is too small"));
  5537. return;
  5538. }
  5539. REAL *matrixData = (REAL *)((BYTE *) ((BYTE *)positions) +
  5540. (GlyphCount * sizeof(PointF)));
  5541. GpMatrix matrix(matrixData);
  5542. player->Graphics->DrawDriverString(
  5543. (unsigned short *)text,
  5544. GlyphCount,
  5545. font,
  5546. brush,
  5547. positions,
  5548. ApiFlags | DriverStringOptionsMetaPlay,
  5549. &matrix);
  5550. }
  5551. else
  5552. {
  5553. player->Graphics->DrawDriverString(
  5554. (unsigned short *)text,
  5555. GlyphCount,
  5556. font,
  5557. brush,
  5558. positions,
  5559. ApiFlags,
  5560. NULL);
  5561. }
  5562. }
  5563. }
  5564. else
  5565. {
  5566. WARNING(("DrawDriverStringEPR::Play dataSize is too small"));
  5567. return;
  5568. }
  5569. player->FreePointsBuffer();
  5570. }
  5571. }
  5572. };
  5573. // The order of these methods must exactly match
  5574. // the order of the enums of the record numbers.
  5575. PLAYRECORDFUNC RecordPlayFuncs[EmfPlusRecordTypeMax - EmfPlusRecordTypeMin + 1] = {
  5576. (PLAYRECORDFUNC)&EmfPlusHeaderRecord::Play, // Header
  5577. (PLAYRECORDFUNC)&EmfPlusRecordPlay::Play, // EndOfFile
  5578. (PLAYRECORDFUNC)&CommentEPR::Play,
  5579. (PLAYRECORDFUNC)&GetDCEPR::Play,
  5580. (PLAYRECORDFUNC)&MultiFormatStartEPR::Play,
  5581. (PLAYRECORDFUNC)&MultiFormatSectionEPR::Play,
  5582. (PLAYRECORDFUNC)&MultiFormatEndEPR::Play,
  5583. // For all persistent objects
  5584. (PLAYRECORDFUNC)&ObjectEPR::Play,
  5585. // Drawing Records
  5586. (PLAYRECORDFUNC)&ClearEPR::Play,
  5587. (PLAYRECORDFUNC)&FillRectsEPR::Play,
  5588. (PLAYRECORDFUNC)&DrawRectsEPR::Play,
  5589. (PLAYRECORDFUNC)&FillPolygonEPR::Play,
  5590. (PLAYRECORDFUNC)&DrawLinesEPR::Play,
  5591. (PLAYRECORDFUNC)&FillEllipseEPR::Play,
  5592. (PLAYRECORDFUNC)&DrawEllipseEPR::Play,
  5593. (PLAYRECORDFUNC)&FillPieEPR::Play,
  5594. (PLAYRECORDFUNC)&DrawPieEPR::Play,
  5595. (PLAYRECORDFUNC)&DrawArcEPR::Play,
  5596. (PLAYRECORDFUNC)&FillRegionEPR::Play,
  5597. (PLAYRECORDFUNC)&FillPathEPR::Play,
  5598. (PLAYRECORDFUNC)&DrawPathEPR::Play,
  5599. (PLAYRECORDFUNC)&FillClosedCurveEPR::Play,
  5600. (PLAYRECORDFUNC)&DrawClosedCurveEPR::Play,
  5601. (PLAYRECORDFUNC)&DrawCurveEPR::Play,
  5602. (PLAYRECORDFUNC)&DrawBeziersEPR::Play,
  5603. (PLAYRECORDFUNC)&DrawImageEPR::Play,
  5604. (PLAYRECORDFUNC)&DrawImagePointsEPR::Play,
  5605. (PLAYRECORDFUNC)&DrawStringEPR::Play,
  5606. // Graphics State Records
  5607. (PLAYRECORDFUNC)&SetRenderingOriginEPR::Play,
  5608. (PLAYRECORDFUNC)&SetAntiAliasModeEPR::Play,
  5609. (PLAYRECORDFUNC)&SetTextRenderingHintEPR::Play,
  5610. (PLAYRECORDFUNC)&SetTextContrastEPR::Play,
  5611. (PLAYRECORDFUNC)&SetInterpolationModeEPR::Play,
  5612. (PLAYRECORDFUNC)&SetPixelOffsetModeEPR::Play,
  5613. (PLAYRECORDFUNC)&SetCompositingModeEPR::Play,
  5614. (PLAYRECORDFUNC)&SetCompositingQualityEPR::Play,
  5615. (PLAYRECORDFUNC)&SaveEPR::Play,
  5616. (PLAYRECORDFUNC)&RestoreEPR::Play,
  5617. (PLAYRECORDFUNC)&BeginContainerEPR::Play,
  5618. (PLAYRECORDFUNC)&BeginContainerNoParamsEPR::Play,
  5619. (PLAYRECORDFUNC)&EndContainerEPR::Play,
  5620. (PLAYRECORDFUNC)&SetWorldTransformEPR::Play,
  5621. (PLAYRECORDFUNC)&ResetWorldTransformEPR::Play,
  5622. (PLAYRECORDFUNC)&MultiplyWorldTransformEPR::Play,
  5623. (PLAYRECORDFUNC)&TranslateWorldTransformEPR::Play,
  5624. (PLAYRECORDFUNC)&ScaleWorldTransformEPR::Play,
  5625. (PLAYRECORDFUNC)&RotateWorldTransformEPR::Play,
  5626. (PLAYRECORDFUNC)&SetPageTransformEPR::Play,
  5627. (PLAYRECORDFUNC)&ResetClipEPR::Play,
  5628. (PLAYRECORDFUNC)&SetClipRectEPR::Play,
  5629. (PLAYRECORDFUNC)&SetClipPathEPR::Play,
  5630. (PLAYRECORDFUNC)&SetClipRegionEPR::Play,
  5631. (PLAYRECORDFUNC)&OffsetClipEPR::Play,
  5632. (PLAYRECORDFUNC)&DrawDriverStringEPR::Play,
  5633. // New record types must be added here (at the end) -- do not add above,
  5634. // since that will invalidate previous metafiles!
  5635. };
  5636. HENHMETAFILE
  5637. GetEmf(
  5638. const WCHAR * fileName,
  5639. MetafileType type
  5640. )
  5641. {
  5642. HENHMETAFILE hEmf = NULL;
  5643. if (type == MetafileTypeWmfPlaceable)
  5644. {
  5645. IStream * wmfStream;
  5646. IStream * memStream;
  5647. wmfStream = CreateStreamOnFile(fileName, GENERIC_READ);
  5648. if (wmfStream != NULL)
  5649. {
  5650. STATSTG statstg;
  5651. HRESULT hResult;
  5652. hResult = wmfStream->Stat(&statstg, STATFLAG_NONAME);
  5653. if (!HResultSuccess(hResult))
  5654. {
  5655. wmfStream->Release();
  5656. return hEmf;
  5657. }
  5658. INT size = (INT)(statstg.cbSize.QuadPart - sizeof(WmfPlaceableFileHeader));
  5659. if (SeekFromStart(wmfStream, sizeof(WmfPlaceableFileHeader)))
  5660. {
  5661. HGLOBAL hGlobal;
  5662. hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, size);
  5663. if (hGlobal != NULL)
  5664. {
  5665. hResult = CreateStreamOnHGlobal(hGlobal, TRUE, &memStream);
  5666. if (HResultSuccess(hResult) && (memStream != NULL))
  5667. {
  5668. if (CopyStream(wmfStream, memStream, size))
  5669. {
  5670. BYTE * wmfData = (BYTE *)GlobalLock(hGlobal);
  5671. if (wmfData != NULL)
  5672. {
  5673. hEmf = (HENHMETAFILE)
  5674. SetMetaFileBitsEx(size, wmfData);
  5675. GlobalUnlock(hGlobal);
  5676. }
  5677. }
  5678. memStream->Release();
  5679. }
  5680. else
  5681. {
  5682. GlobalFree(hGlobal);
  5683. }
  5684. }
  5685. }
  5686. wmfStream->Release();
  5687. }
  5688. }
  5689. else
  5690. {
  5691. if (Globals::IsNt)
  5692. {
  5693. hEmf = GetEnhMetaFileW(fileName);
  5694. }
  5695. else // Windows 9x - non-Unicode
  5696. {
  5697. AnsiStrFromUnicode nameStr(fileName);
  5698. if (nameStr.IsValid())
  5699. {
  5700. hEmf = GetEnhMetaFileA(nameStr);
  5701. }
  5702. }
  5703. }
  5704. return hEmf;
  5705. }
  5706. #if 0 // don't need this right now
  5707. WCHAR *
  5708. GetTemporaryFilename()
  5709. {
  5710. if (Globals::IsNt)
  5711. {
  5712. WCHAR pathBuffer[MAX_PATH + 1];
  5713. WCHAR fileBuffer[MAX_PATH + 12 + 1]; // 12 for filename itself
  5714. UINT len = GetTempPathW(MAX_PATH, pathBuffer);
  5715. if ((len == 0) || (len > MAX_PATH))
  5716. {
  5717. pathBuffer[0] = L'.';
  5718. pathBuffer[1] = L'\0';
  5719. }
  5720. if (GetTempFileNameW(pathBuffer, L"Emp", 0, fileBuffer) == 0)
  5721. {
  5722. return NULL;
  5723. }
  5724. return UnicodeStringDuplicate(fileBuffer);
  5725. }
  5726. else // Windows 9x - non-Unicode
  5727. {
  5728. CHAR pathBuffer[MAX_PATH + 1];
  5729. CHAR fileBuffer[MAX_PATH + 12 + 1]; // 12 for filename itself
  5730. UINT len = GetTempPathA(MAX_PATH, pathBuffer);
  5731. if ((len == 0) || (len > MAX_PATH))
  5732. {
  5733. pathBuffer[0] = '.';
  5734. pathBuffer[1] = '\0';
  5735. }
  5736. if (GetTempFileNameA(pathBuffer, "Emp", 0, fileBuffer) == 0)
  5737. {
  5738. return NULL;
  5739. }
  5740. len = (strlen(fileBuffer) + 1) * sizeof(WCHAR);
  5741. WCHAR * filename = (WCHAR *)GpMalloc(len);
  5742. if (filename != NULL)
  5743. {
  5744. if (AnsiToUnicodeStr(fileBuffer, filename, len))
  5745. {
  5746. return filename;
  5747. }
  5748. GpFree(filename);
  5749. }
  5750. return NULL;
  5751. }
  5752. }
  5753. #endif
  5754. // For now, don't handle a source rect
  5755. GpBitmap *
  5756. GpMetafile::GetBitmap(
  5757. INT width,
  5758. INT height,
  5759. const GpImageAttributes * imageAttributes
  5760. )
  5761. {
  5762. GpRectF srcRect;
  5763. GpPageUnit srcUnit;
  5764. this->GetBounds(&srcRect, &srcUnit);
  5765. ASSERT(srcUnit == UnitPixel);
  5766. // Determine what size to make the bitmap.
  5767. if ((width <= 0) || (height <= 0))
  5768. {
  5769. if (this->IsEmfOrEmfPlus())
  5770. {
  5771. width = GpRound(srcRect.Width);
  5772. height = GpRound(srcRect.Height);
  5773. }
  5774. else // must be a WMF
  5775. {
  5776. // Convert size to use the dpi of this display.
  5777. // This is somewhat of a hack, but what else could I do,
  5778. // since I don't know where this brush will be used?
  5779. REAL srcDpiX;
  5780. REAL srcDpiY;
  5781. REAL destDpiX = Globals::DesktopDpiX; // guess
  5782. REAL destDpiY = Globals::DesktopDpiY;
  5783. this->GetResolution(&srcDpiX, &srcDpiY);
  5784. if ((srcDpiX <= 0) || (srcDpiY <= 0))
  5785. {
  5786. WARNING(("bad dpi for WMF"));
  5787. return NULL;
  5788. }
  5789. width = GpRound((srcRect.Width / srcDpiX) * destDpiX);
  5790. height = GpRound((srcRect.Height / srcDpiY) * destDpiY);
  5791. }
  5792. if ((width <= 0) || (height <= 0))
  5793. {
  5794. WARNING(("bad size for metafile"));
  5795. return NULL;
  5796. }
  5797. }
  5798. GpBitmap * bitmapImage = new GpBitmap(width, height, PIXFMT_32BPP_ARGB);
  5799. if (bitmapImage != NULL)
  5800. {
  5801. if (bitmapImage->IsValid())
  5802. {
  5803. GpGraphics * graphics = bitmapImage->GetGraphicsContext();
  5804. if (graphics != NULL)
  5805. {
  5806. if (graphics->IsValid())
  5807. {
  5808. // we have to lock the graphics so the driver doesn't assert
  5809. GpLock * lockGraphics = new GpLock(graphics->GetObjectLock());
  5810. if (lockGraphics != NULL)
  5811. {
  5812. ASSERT(lockGraphics->IsValid());
  5813. // now draw the metafile into the bitmap image
  5814. GpRectF destRect(0.0f, 0.0f, (REAL)width, (REAL)height);
  5815. // We don't want to interpolate the bitmaps in WMFs
  5816. // and EMFs when converting them to a texture.
  5817. graphics->SetInterpolationMode(InterpolationModeNearestNeighbor);
  5818. GpStatus status;
  5819. status = graphics->DrawImage(
  5820. this,
  5821. destRect,
  5822. srcRect,
  5823. srcUnit,
  5824. imageAttributes);
  5825. // have to delete the lock before deleting the graphics
  5826. delete lockGraphics;
  5827. if (status == Ok)
  5828. {
  5829. delete graphics;
  5830. return bitmapImage;
  5831. }
  5832. WARNING(("DrawImage failed"));
  5833. }
  5834. else
  5835. {
  5836. WARNING(("Could not create graphics lock"));
  5837. }
  5838. }
  5839. else
  5840. {
  5841. WARNING(("graphics from bitmap image not valid"));
  5842. }
  5843. delete graphics;
  5844. }
  5845. else
  5846. {
  5847. WARNING(("could not create graphics from bitmap image"));
  5848. }
  5849. }
  5850. else
  5851. {
  5852. WARNING(("bitmap image is not valid"));
  5853. }
  5854. bitmapImage->Dispose();
  5855. }
  5856. else
  5857. {
  5858. WARNING(("could not create bitmap image"));
  5859. }
  5860. return NULL;
  5861. }