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.

5256 lines
155 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 "..\imaging\api\comutils.hpp"
  20. #define META_FORMAT_ENHANCED 0x10000 // Windows NT format
  21. VOID
  22. FrameToMM100(
  23. const GpRectF * frameRect,
  24. GpPageUnit frameUnit,
  25. GpRectF & frameRectMM100,
  26. REAL dpiX, // only used for pixel case
  27. REAL dpiY
  28. );
  29. /**************************************************************************\
  30. *
  31. * Function Description:
  32. *
  33. * Determine if the REAL points can be converted to GpPoint16 points without
  34. * losing accuracy. If so, then do the conversion, and set the flags to say
  35. * we're using 16-bit points.
  36. *
  37. * Arguments:
  38. *
  39. * [IN] points - the REAL points to try to convert
  40. * [IN] count - the number of points
  41. *
  42. * Return Value:
  43. *
  44. * NONE
  45. *
  46. * Created:
  47. *
  48. * 6/15/1999 DCurtis
  49. *
  50. \**************************************************************************/
  51. MetafilePointData::MetafilePointData(
  52. const GpPointF * points,
  53. INT count
  54. )
  55. {
  56. ASSERT((count > 0) && (points != NULL));
  57. // Assume that the conversion to GpPoint16 will fail
  58. PointData = (BYTE *)points;
  59. PointDataSize = count * sizeof(points[0]);
  60. Flags = 0;
  61. AllocedPoints = NULL;
  62. GpPoint16 * points16 = PointBuffer;
  63. if (count > GDIP_POINTDATA_BUFFERSIZE)
  64. {
  65. AllocedPoints = new GpPoint16[count];
  66. if (AllocedPoints == NULL)
  67. {
  68. return; // live with REAL data
  69. }
  70. points16 = AllocedPoints;
  71. }
  72. GpPoint16 * curPoint16 = points16;
  73. INT i = count;
  74. do
  75. {
  76. curPoint16->X = (INT16)GpRound(points->X);
  77. curPoint16->Y = (INT16)GpRound(points->Y);
  78. if (!IsPoint16Equal(curPoint16, points))
  79. {
  80. return; // the point data doesn't fit in 16 bits per value
  81. }
  82. curPoint16++;
  83. points++;
  84. } while (--i > 0);
  85. // We succeeded in converting the point data to 16 bits per value
  86. PointData = (BYTE *)points16;
  87. PointDataSize = count * sizeof(points16[0]);
  88. Flags = GDIP_EPRFLAGS_COMPRESSED;
  89. }
  90. /**************************************************************************\
  91. *
  92. * Function Description:
  93. *
  94. * Determine if the REAL rects can be converted to GpRect16 points without
  95. * losing accuracy. If so, then do the conversion, and set the flags to say
  96. * we're using 16-bit rects.
  97. *
  98. * Arguments:
  99. *
  100. * [IN] rects - the REAL rects to try to convert
  101. * [IN] count - the number of rects
  102. *
  103. * Return Value:
  104. *
  105. * NONE
  106. *
  107. * Created:
  108. *
  109. * 6/15/1999 DCurtis
  110. *
  111. \**************************************************************************/
  112. MetafileRectData::MetafileRectData(
  113. const GpRectF * rects,
  114. INT count
  115. )
  116. {
  117. ASSERT((count > 0) && (rects != NULL));
  118. // Assume that the conversion to GpRect16 will fail
  119. RectData = (BYTE *)rects;
  120. RectDataSize = count * sizeof(rects[0]);
  121. Flags = 0;
  122. AllocedRects = NULL;
  123. GpRect16 * rects16 = RectBuffer;
  124. if (count > GDIP_RECTDATA_BUFFERSIZE)
  125. {
  126. AllocedRects = new GpRect16[count];
  127. if (AllocedRects == NULL)
  128. {
  129. return; // live with REAL data
  130. }
  131. rects16 = AllocedRects;
  132. }
  133. GpRect16 * curRect16 = rects16;
  134. INT i = count;
  135. do
  136. {
  137. curRect16->X = (INT16)GpRound(rects->X);
  138. curRect16->Y = (INT16)GpRound(rects->Y);
  139. curRect16->Width = (INT16)GpRound(rects->Width);
  140. curRect16->Height = (INT16)GpRound(rects->Height);
  141. if (!IsRect16Equal(curRect16, rects))
  142. {
  143. return; // the rect data doesn't fit in 16 bits per value
  144. }
  145. curRect16++;
  146. rects++;
  147. } while (--i > 0);
  148. // We succeeded in converting the rect data to 16 bits per value
  149. RectData = (BYTE *)rects16;
  150. RectDataSize = count * sizeof(rects16[0]);
  151. Flags = GDIP_EPRFLAGS_COMPRESSED;
  152. }
  153. ///////////////////////////////////////////////////////////////////////////
  154. // classes for handling recording of objects within the metafile
  155. class MetafileRecordObject
  156. {
  157. friend class MetafileRecordObjectList;
  158. protected:
  159. const GpObject * ObjectPointer;
  160. UINT Uid;
  161. ObjectType Type;
  162. UINT Next;
  163. UINT Prev;
  164. public:
  165. MetafileRecordObject()
  166. {
  167. ObjectPointer = NULL;
  168. Uid = 0;
  169. Type = ObjectTypeInvalid;
  170. Next = GDIP_LIST_NIL;
  171. Prev = GDIP_LIST_NIL;
  172. }
  173. const GpObject * GetObject() const
  174. {
  175. return ObjectPointer;
  176. }
  177. UINT GetUid() const
  178. {
  179. return Uid;
  180. }
  181. ObjectType GetType() const
  182. {
  183. return Type;
  184. }
  185. };
  186. class MetafileRecordObjectList
  187. {
  188. protected:
  189. INT Count;
  190. UINT LRU;
  191. UINT MRU;
  192. MetafileRecordObject Objects[GDIP_MAX_OBJECTS];
  193. public:
  194. MetafileRecordObjectList()
  195. {
  196. Count = 0;
  197. LRU = GDIP_LIST_NIL;
  198. MRU = GDIP_LIST_NIL;
  199. }
  200. MetafileRecordObject * GetMetaObject(UINT metaObjectID)
  201. {
  202. ASSERT(metaObjectID < GDIP_MAX_OBJECTS);
  203. return Objects + metaObjectID;
  204. }
  205. // Search through the list, starting at the MRU entry, to see if we
  206. // can find the object. If we do find it, return the index to the
  207. // object in metaObjectId (even if the Uid's don't match). Return
  208. // TRUE only if we found the object and the Uid's match.
  209. BOOL
  210. IsInList(
  211. const GpObject * object,
  212. ObjectType objectType,
  213. UINT32 * metaObjectId
  214. );
  215. #if 0 // not used
  216. VOID
  217. RemoveAt(
  218. UINT32 metaObjectId
  219. );
  220. #endif
  221. // if metaObjectId is GDIP_LIST_NIL, use the next available slot
  222. VOID
  223. InsertAt(
  224. const GpObject * object,
  225. UINT32 * metaObjectId
  226. );
  227. VOID
  228. UpdateMRU(
  229. UINT32 metaObjectId
  230. );
  231. };
  232. // Search through the list, starting at the MRU entry, to see if we
  233. // can find the object. If we do find it, return the index to the
  234. // object in metaObjectId (even if the Uid's don't match). Return
  235. // TRUE only if we found the object and the Uid's match.
  236. BOOL
  237. MetafileRecordObjectList::IsInList(
  238. const GpObject * object,
  239. ObjectType objectType,
  240. UINT32 * metaObjectId
  241. )
  242. {
  243. ASSERT(object != NULL);
  244. ASSERT(metaObjectId != NULL);
  245. BOOL isInList = FALSE;
  246. isInList = FALSE; // indicate object not found
  247. *metaObjectId = GDIP_LIST_NIL; // indicate object not found
  248. if (Count != 0)
  249. {
  250. UINT curIndex;
  251. UINT uid;
  252. curIndex = MRU;
  253. uid = object->GetUid();
  254. do
  255. {
  256. if (Objects[curIndex].ObjectPointer == object)
  257. {
  258. *metaObjectId = curIndex;
  259. isInList = ((Objects[curIndex].Uid == uid) &&
  260. (Objects[curIndex].Type == objectType));
  261. break;
  262. }
  263. curIndex = Objects[curIndex].Prev;
  264. } while (curIndex != GDIP_LIST_NIL);
  265. }
  266. return isInList;
  267. }
  268. #if 0 // not used
  269. // We don't actually remove it from the list, we just put it at the
  270. // front of the LRU so its spot gets used next. So the count stays
  271. // the same.
  272. VOID
  273. MetafileRecordObjectList::RemoveAt(
  274. UINT32 metaObjectId
  275. )
  276. {
  277. ASSERT(metaObjectId < GDIP_MAX_OBJECTS);
  278. MetafileRecordObject * removeObject = Objects + metaObjectId;
  279. ASSERT(Count > 0);
  280. removeObject->ObjectPointer = NULL;
  281. removeObject->Uid = 0;
  282. removeObject->Type = EmfPlusRecordTypeInvalid;
  283. INT removeNext = removeObject->Next;
  284. INT removePrev = removeObject->Prev;
  285. if (removeNext != GDIP_LIST_NIL)
  286. {
  287. Objects[removeNext].Prev = removePrev;
  288. }
  289. else
  290. {
  291. ASSERT(MRU == metaObjectId);
  292. if (removePrev != GDIP_LIST_NIL)
  293. {
  294. MRU = removePrev;
  295. }
  296. }
  297. if (removePrev != GDIP_LIST_NIL)
  298. {
  299. ASSERT(LRU != metaObjectId);
  300. Objects[removePrev].Next = removeNext;
  301. removeObject->Prev = GDIP_LIST_NIL;
  302. removeObject->Next = LRU;
  303. Objects[LRU].Prev = metaObjectId;
  304. LRU = metaObjectId;
  305. }
  306. else
  307. {
  308. ASSERT(LRU == metaObjectId);
  309. }
  310. }
  311. #endif
  312. // Make the specified object the MRU object.
  313. VOID
  314. MetafileRecordObjectList::UpdateMRU(
  315. UINT32 metaObjectId
  316. )
  317. {
  318. if (MRU != metaObjectId)
  319. {
  320. // Now we know there are at least 2 objects
  321. MetafileRecordObject * object = &Objects[metaObjectId];
  322. if (LRU != metaObjectId)
  323. {
  324. Objects[object->Prev].Next = object->Next;
  325. }
  326. else
  327. {
  328. LRU = object->Next;
  329. }
  330. Objects[object->Next].Prev = object->Prev;
  331. object->Prev = MRU;
  332. object->Next = GDIP_LIST_NIL;
  333. Objects[MRU].Next = metaObjectId;
  334. MRU = metaObjectId;
  335. }
  336. }
  337. // if metaObjectId is GDIP_LIST_NIL, use the next available slot
  338. VOID
  339. MetafileRecordObjectList::InsertAt(
  340. const GpObject * object,
  341. UINT32 * metaObjectId
  342. )
  343. {
  344. MetafileRecordObject * newObject;
  345. UINT newIndex = *metaObjectId;
  346. if (newIndex == GDIP_LIST_NIL)
  347. {
  348. if (Count != 0)
  349. {
  350. // use freed object before adding new one
  351. if ((Objects[LRU].ObjectPointer == NULL) ||
  352. (Count == GDIP_MAX_OBJECTS))
  353. {
  354. newIndex = LRU;
  355. UseLRU:
  356. LRU = Objects[newIndex].Next;
  357. Objects[LRU].Prev = GDIP_LIST_NIL;
  358. }
  359. else
  360. {
  361. newIndex = Count++;
  362. }
  363. InsertObject:
  364. Objects[MRU].Next = newIndex;
  365. SetupObject:
  366. *metaObjectId = newIndex;
  367. newObject = &Objects[newIndex];
  368. newObject->Next = GDIP_LIST_NIL;
  369. newObject->Prev = MRU;
  370. MRU = newIndex;
  371. UseMRU:
  372. newObject->ObjectPointer = object;
  373. newObject->Uid = object->GetUid();
  374. newObject->Type = object->GetObjectType();
  375. return;
  376. }
  377. // else first object
  378. newIndex = 0;
  379. LRU = 0;
  380. Count = 1;
  381. goto SetupObject;
  382. }
  383. else // we already know where to put the object
  384. {
  385. ASSERT(Count > 0);
  386. ASSERT(newIndex < GDIP_MAX_OBJECTS);
  387. if (newIndex == MRU)
  388. {
  389. // This covers the case where there is only 1 object
  390. newObject = &Objects[newIndex];
  391. goto UseMRU;
  392. }
  393. // else there must be at least 2 objects
  394. ASSERT(Count > 1);
  395. if (newIndex == LRU)
  396. {
  397. goto UseLRU;
  398. }
  399. // Move middle object to MRU
  400. newObject = &Objects[newIndex];
  401. Objects[newObject->Prev].Next = newObject->Next;
  402. Objects[newObject->Next].Prev = newObject->Prev;
  403. goto InsertObject;
  404. }
  405. }
  406. #define GDIP_MAX_COMMENT_SIZE 65020 // must be <= 65520 for Win9x bug
  407. class EmfPlusCommentStream : public IUnknownBase<IStream>
  408. {
  409. private:
  410. ObjectTag Tag; // Keep this as the 1st value in the object!
  411. protected:
  412. VOID SetValid(BOOL valid)
  413. {
  414. Tag = valid ? ObjectTagEmfPlusCommentStream : ObjectTagInvalid;
  415. }
  416. public:
  417. EmfPlusCommentStream(HDC hdc)
  418. {
  419. ASSERT(hdc != NULL);
  420. MetafileHdc = hdc;
  421. Position = 0; // starts after signature
  422. ((INT32 *)CommentBuffer)[0] = EMFPLUS_SIGNATURE;
  423. RecordDataStart = CommentBuffer + sizeof(INT32);
  424. ContinuingObjectRecord = FALSE;
  425. SetValid(TRUE);
  426. }
  427. ~EmfPlusCommentStream()
  428. {
  429. this->Flush();
  430. }
  431. BOOL IsValid() const
  432. {
  433. ASSERT((Tag == ObjectTagEmfPlusCommentStream) || (Tag == ObjectTagInvalid));
  434. return (Tag == ObjectTagEmfPlusCommentStream);
  435. }
  436. ULONG SpaceLeft() const
  437. {
  438. return (GDIP_MAX_COMMENT_SIZE - Position);
  439. }
  440. VOID
  441. EndObjectRecord()
  442. {
  443. ASSERT ((Position & 0x03) == 0); // records should be 4-byte aligned
  444. if (ContinuingObjectRecord)
  445. {
  446. ContinuingObjectRecord = FALSE;
  447. if (Position > sizeof(EmfPlusContinueObjectRecord))
  448. {
  449. // Fix up the size of the last chunck of this object record
  450. EmfPlusContinueObjectRecord * recordData;
  451. recordData = (EmfPlusContinueObjectRecord *)RecordDataStart;
  452. recordData->Size = Position;
  453. recordData->DataSize = Position - sizeof(EmfPlusRecord);
  454. }
  455. else
  456. {
  457. // The object record ended exacly at the end of the buffer
  458. // and has already been flushed.
  459. Position = 0;
  460. }
  461. }
  462. }
  463. VOID
  464. WriteRecordHeader(
  465. UINT32 dataSize, // size of data (w/o record header)
  466. EmfPlusRecordType type,
  467. INT flags // 16 bits of flags
  468. );
  469. VOID Flush();
  470. HRESULT STDMETHODCALLTYPE Write(
  471. VOID const HUGEP *pv,
  472. ULONG cb,
  473. ULONG *pcbWritten)
  474. {
  475. if (cb == 0)
  476. {
  477. if (pcbWritten != NULL)
  478. {
  479. *pcbWritten = cb;
  480. }
  481. return S_OK;
  482. }
  483. ASSERT (pv != NULL);
  484. if (IsValid())
  485. {
  486. // We've already written the record header; now we're writing
  487. // the record data.
  488. ASSERT(Position >= sizeof(EmfPlusRecord));
  489. ULONG spaceLeft = SpaceLeft();
  490. BYTE * recordData = RecordDataStart + Position;
  491. // We flush as soon as we reach the end. We don't wait for
  492. // the next write call to flush.
  493. ASSERT(spaceLeft > 0);
  494. if (pcbWritten)
  495. {
  496. *pcbWritten = cb;
  497. }
  498. // see if there is enough room for the data
  499. if (cb <= spaceLeft)
  500. {
  501. GpMemcpy(recordData, pv, cb);
  502. Position += cb;
  503. if (Position < GDIP_MAX_COMMENT_SIZE)
  504. {
  505. return S_OK;
  506. }
  507. this->Flush();
  508. if (IsValid())
  509. {
  510. return S_OK;
  511. }
  512. if (pcbWritten)
  513. {
  514. *pcbWritten = 0;
  515. }
  516. return E_FAIL;
  517. }
  518. ASSERT(ContinuingObjectRecord);
  519. LoopStart:
  520. GpMemcpy(recordData, pv, spaceLeft);
  521. Position += spaceLeft;
  522. if (Position == GDIP_MAX_COMMENT_SIZE)
  523. {
  524. this->Flush();
  525. if (!IsValid())
  526. {
  527. if (pcbWritten)
  528. {
  529. *pcbWritten = 0; // not accurate, but who cares!
  530. }
  531. return E_FAIL;
  532. }
  533. }
  534. cb -= spaceLeft;
  535. if (cb == 0)
  536. {
  537. return S_OK;
  538. }
  539. pv = ((BYTE *)pv) + spaceLeft;
  540. recordData = RecordDataStart + sizeof(EmfPlusContinueObjectRecord);
  541. spaceLeft = GDIP_MAX_COMMENT_SIZE-sizeof(EmfPlusContinueObjectRecord);
  542. if (spaceLeft > cb)
  543. {
  544. spaceLeft = cb;
  545. }
  546. goto LoopStart;
  547. }
  548. return E_FAIL;
  549. }
  550. HRESULT STDMETHODCALLTYPE Read(
  551. VOID HUGEP *pv,
  552. ULONG cb,
  553. ULONG *pcbRead)
  554. {
  555. return E_NOTIMPL;
  556. }
  557. HRESULT STDMETHODCALLTYPE Seek(
  558. LARGE_INTEGER dlibMove,
  559. DWORD dwOrigin,
  560. ULARGE_INTEGER *plibNewPosition)
  561. {
  562. return E_NOTIMPL;
  563. }
  564. HRESULT STDMETHODCALLTYPE SetSize(
  565. ULARGE_INTEGER libNewSize)
  566. {
  567. return E_NOTIMPL;
  568. }
  569. HRESULT STDMETHODCALLTYPE CopyTo(
  570. IStream *pstm,
  571. ULARGE_INTEGER cb,
  572. ULARGE_INTEGER *pcbRead,
  573. ULARGE_INTEGER *pcbWritten)
  574. {
  575. return E_NOTIMPL;
  576. }
  577. HRESULT STDMETHODCALLTYPE Commit(
  578. DWORD grfCommitFlags)
  579. {
  580. return E_NOTIMPL;
  581. }
  582. HRESULT STDMETHODCALLTYPE Revert(VOID)
  583. {
  584. return E_NOTIMPL;
  585. }
  586. HRESULT STDMETHODCALLTYPE LockRegion(
  587. ULARGE_INTEGER libOffset,
  588. ULARGE_INTEGER cb,
  589. DWORD dwLockType)
  590. {
  591. return E_NOTIMPL;
  592. }
  593. HRESULT STDMETHODCALLTYPE UnlockRegion(
  594. ULARGE_INTEGER libOffset,
  595. ULARGE_INTEGER cb,
  596. DWORD dwLockType)
  597. {
  598. return E_NOTIMPL;
  599. }
  600. HRESULT STDMETHODCALLTYPE Stat(
  601. STATSTG *pstatstg,
  602. DWORD grfStatFlag)
  603. {
  604. return E_NOTIMPL;
  605. }
  606. HRESULT STDMETHODCALLTYPE Clone(
  607. IStream **ppstm)
  608. {
  609. return E_NOTIMPL;
  610. }
  611. private:
  612. BYTE CommentBuffer[GDIP_MAX_COMMENT_SIZE + sizeof(INT32)];
  613. BYTE * RecordDataStart;
  614. ULONG Position;
  615. HDC MetafileHdc;
  616. BOOL ContinuingObjectRecord;
  617. };
  618. VOID
  619. EmfPlusCommentStream::Flush()
  620. {
  621. ASSERT ((Position & 0x03) == 0); // records should be 4-byte aligned
  622. if (IsValid() && (Position >= sizeof(EmfPlusRecord)))
  623. {
  624. // write the signature as well as the records
  625. SetValid(GdiComment(MetafileHdc, (INT)Position + sizeof(INT32),
  626. CommentBuffer) != 0);
  627. #if DBG
  628. if (!IsValid())
  629. {
  630. WARNING(("Failed to write GdiComment"));
  631. }
  632. #endif
  633. if (!ContinuingObjectRecord)
  634. {
  635. Position = 0;
  636. }
  637. else
  638. {
  639. ASSERT(Position == GDIP_MAX_COMMENT_SIZE);
  640. // Leave the object record header intact for the rest of the
  641. // object data.
  642. Position = sizeof(EmfPlusContinueObjectRecord);
  643. }
  644. }
  645. }
  646. VOID
  647. EmfPlusCommentStream::WriteRecordHeader(
  648. UINT32 dataSize, // size of data (w/o record header)
  649. EmfPlusRecordType type,
  650. INT flags // 16 bits of flags
  651. )
  652. {
  653. ASSERT ((flags & 0xFFFF0000) == 0);
  654. ASSERT (ContinuingObjectRecord == FALSE);
  655. ASSERT ((Position & 0x03) == 0); // records should be 4-byte aligned
  656. ASSERT ((dataSize & 0x03) == 0); // records should be 4-byte aligned
  657. if (IsValid())
  658. {
  659. ULONG spaceLeft = SpaceLeft();
  660. ULONG recordSize = sizeof(EmfPlusRecord) + dataSize;
  661. ASSERT(spaceLeft > 0);
  662. // see if the record fits in the space left
  663. if (recordSize <= spaceLeft)
  664. {
  665. RecordFits:
  666. EmfPlusRecord * recordData;
  667. recordData = (EmfPlusRecord *)(RecordDataStart + Position);
  668. recordData->Type = type;
  669. recordData->Flags = (INT16)flags;
  670. recordData->Size = recordSize;
  671. recordData->DataSize = dataSize;
  672. Position += sizeof(EmfPlusRecord);
  673. if (Position < GDIP_MAX_COMMENT_SIZE)
  674. {
  675. return;
  676. }
  677. ASSERT((recordSize == sizeof(EmfPlusRecord)) && (dataSize == 0));
  678. this->Flush();
  679. return;
  680. }
  681. else // it doesn't fit in the space left
  682. {
  683. // maybe it will fit after flushing the current record buffer
  684. if (spaceLeft < GDIP_MAX_COMMENT_SIZE)
  685. {
  686. this->Flush();
  687. if (!IsValid())
  688. {
  689. return;
  690. }
  691. if (recordSize <= GDIP_MAX_COMMENT_SIZE)
  692. {
  693. goto RecordFits;
  694. }
  695. }
  696. // Now we know the record does not fit in a single comment.
  697. // This better be an object record!
  698. ASSERT(type == EmfPlusRecordTypeObject);
  699. flags |= GDIP_EPRFLAGS_CONTINUEOBJECT;
  700. ContinuingObjectRecord = TRUE;
  701. // We know that Position is 0
  702. EmfPlusContinueObjectRecord * recordData;
  703. recordData = (EmfPlusContinueObjectRecord *)RecordDataStart;
  704. recordData->Type = type;
  705. recordData->Flags = (INT16)flags;
  706. recordData->Size = GDIP_MAX_COMMENT_SIZE;
  707. recordData->DataSize = GDIP_MAX_COMMENT_SIZE - sizeof(EmfPlusRecord);
  708. recordData->TotalObjectSize = dataSize; // size of object data (w/o header size)
  709. Position = sizeof(EmfPlusContinueObjectRecord);
  710. }
  711. }
  712. }
  713. class MetafileRecorder : public IMetafileRecord
  714. {
  715. friend class GpMetafile;
  716. private:
  717. ObjectTag Tag; // Keep this as the 1st value in the object!
  718. protected:
  719. VOID SetValid(BOOL valid)
  720. {
  721. Tag = valid ? ObjectTagMetafileRecorder : ObjectTagInvalid;
  722. }
  723. public:
  724. BOOL WroteFrameRect;
  725. SIZEL Millimeters;
  726. protected:
  727. EmfPlusCommentStream * EmfPlusStream; // memory buffer stream
  728. GpMetafile * Metafile; // being recorded
  729. EmfType Type;
  730. REAL XMinDevice; // device bounds
  731. REAL YMinDevice;
  732. REAL XMaxDevice;
  733. REAL YMaxDevice;
  734. BOOL BoundsInit;
  735. INT NumRecords; // for debugging only
  736. INT MaxStackSize;
  737. HDC MetafileHdc;
  738. DynArrayIA<INT,GDIP_SAVE_STACK_SIZE> SaveRestoreStack;
  739. MetafileRecordObjectList ObjectList;
  740. GpRectF MetafileBounds;
  741. public:
  742. MetafileRecorder(
  743. GpMetafile * metafile,
  744. EmfType type,
  745. HDC metafileHdc,
  746. BOOL wroteFrameRect,
  747. SIZEL & effectiveMillimeters,
  748. GpRectF & metafileBounds
  749. );
  750. ~MetafileRecorder() // called by EndRecording
  751. {
  752. // Release the memory stream for writing the GdiComments
  753. if (EmfPlusStream != NULL)
  754. {
  755. EmfPlusStream->Release();
  756. }
  757. }
  758. BOOL IsValid() const
  759. {
  760. ASSERT((Tag == ObjectTagMetafileRecorder) || (Tag == ObjectTagInvalid));
  761. return (Tag == ObjectTagMetafileRecorder);
  762. }
  763. virtual VOID GetMetafileBounds(GpRect & metafileBounds) const
  764. {
  765. // Use Floor to make sure we don't miss any pixels
  766. metafileBounds.X = GpFloor(MetafileBounds.X);
  767. metafileBounds.Y = GpFloor(MetafileBounds.Y);
  768. metafileBounds.Width = GpCeiling(MetafileBounds.GetRight()) - metafileBounds.X;
  769. metafileBounds.Height = GpCeiling(MetafileBounds.GetBottom()) - metafileBounds.Y;
  770. }
  771. virtual GpStatus
  772. RecordClear(
  773. const GpRectF * deviceBounds,
  774. GpColor color
  775. );
  776. virtual GpStatus
  777. RecordFillRects(
  778. const GpRectF * deviceBounds,
  779. GpBrush * brush,
  780. const GpRectF * rects,
  781. INT count
  782. );
  783. virtual GpStatus
  784. RecordDrawRects(
  785. const GpRectF * deviceBounds,
  786. GpPen * pen,
  787. const GpRectF * rects,
  788. INT count
  789. );
  790. virtual GpStatus
  791. RecordFillPolygon(
  792. const GpRectF * deviceBounds,
  793. GpBrush* brush,
  794. const GpPointF * points,
  795. INT count,
  796. GpFillMode fillMode
  797. );
  798. virtual GpStatus
  799. RecordDrawLines(
  800. const GpRectF * deviceBounds,
  801. GpPen * pen,
  802. const GpPointF * points,
  803. INT count,
  804. BOOL closed
  805. );
  806. virtual GpStatus
  807. RecordFillEllipse(
  808. const GpRectF * deviceBounds,
  809. GpBrush * brush,
  810. const GpRectF & rect
  811. );
  812. virtual GpStatus
  813. RecordDrawEllipse(
  814. const GpRectF * deviceBounds,
  815. GpPen * pen,
  816. const GpRectF & rect
  817. );
  818. virtual GpStatus
  819. RecordFillPie(
  820. const GpRectF * deviceBounds,
  821. GpBrush * brush,
  822. const GpRectF & rect,
  823. REAL startAngle,
  824. REAL sweepAngle
  825. );
  826. virtual GpStatus
  827. RecordDrawPie(
  828. const GpRectF * deviceBounds,
  829. GpPen * pen,
  830. const GpRectF & rect,
  831. REAL startAngle,
  832. REAL sweepAngle
  833. );
  834. virtual GpStatus
  835. RecordDrawArc(
  836. const GpRectF * deviceBounds,
  837. GpPen * pen,
  838. const GpRectF & rect,
  839. REAL startAngle,
  840. REAL sweepAngle
  841. );
  842. virtual GpStatus
  843. RecordFillRegion(
  844. const GpRectF * deviceBounds,
  845. GpBrush * brush,
  846. GpRegion * region
  847. );
  848. virtual GpStatus
  849. RecordFillPath(
  850. const GpRectF * deviceBounds,
  851. const GpBrush * brush,
  852. GpPath * path
  853. );
  854. virtual GpStatus
  855. RecordDrawPath(
  856. const GpRectF * deviceBounds,
  857. GpPen * pen,
  858. GpPath * path
  859. );
  860. virtual GpStatus
  861. RecordFillClosedCurve(
  862. const GpRectF * deviceBounds,
  863. GpBrush * brush,
  864. const GpPointF * points,
  865. INT count,
  866. REAL tension,
  867. GpFillMode fillMode
  868. );
  869. virtual GpStatus
  870. RecordDrawClosedCurve(
  871. const GpRectF * deviceBounds,
  872. GpPen * pen,
  873. const GpPointF * points,
  874. INT count,
  875. REAL tension
  876. );
  877. virtual GpStatus
  878. RecordDrawCurve(
  879. const GpRectF * deviceBounds,
  880. GpPen * pen,
  881. const GpPointF * points,
  882. INT count,
  883. REAL tension,
  884. INT offset,
  885. INT numberOfSegments
  886. );
  887. virtual GpStatus
  888. RecordDrawBeziers(
  889. const GpRectF * deviceBounds,
  890. GpPen * pen,
  891. const GpPointF * points,
  892. INT count
  893. );
  894. virtual GpStatus
  895. RecordDrawImage(
  896. const GpRectF * deviceBounds,
  897. const GpImage * image,
  898. const GpRectF & destRect,
  899. const GpRectF & srcRect,
  900. GpPageUnit srcUnit,
  901. const GpImageAttributes * imageAttributes
  902. );
  903. virtual GpStatus
  904. RecordDrawImage(
  905. const GpRectF * deviceBounds,
  906. const GpImage * image,
  907. const GpPointF * destPoints,
  908. INT count,
  909. const GpRectF & srcRect,
  910. GpPageUnit srcUnit,
  911. const GpImageAttributes * imageAttributes
  912. );
  913. virtual GpStatus
  914. RecordDrawString(
  915. const GpRectF * deviceBounds,
  916. const WCHAR *string,
  917. INT length,
  918. const GpFont *font,
  919. const RectF *layoutRect,
  920. const GpStringFormat *format,
  921. const GpBrush *brush
  922. );
  923. virtual GpStatus
  924. RecordDrawDriverString(
  925. const GpRectF * deviceBounds,
  926. const UINT16 *text,
  927. INT glyphCount,
  928. const GpFont *font,
  929. const GpBrush *brush,
  930. const PointF *positions,
  931. INT flags,
  932. const GpMatrix *matrix
  933. );
  934. virtual GpStatus
  935. RecordSave(
  936. INT gstate
  937. );
  938. virtual GpStatus
  939. RecordRestore(
  940. INT gstate
  941. );
  942. virtual GpStatus
  943. RecordBeginContainer(
  944. const GpRectF & destRect,
  945. const GpRectF & srcRect,
  946. GpPageUnit srcUnit,
  947. INT containerState
  948. );
  949. virtual GpStatus
  950. RecordBeginContainer(
  951. INT containerState
  952. );
  953. virtual GpStatus
  954. RecordEndContainer(
  955. INT containerState
  956. );
  957. virtual GpStatus
  958. RecordSetWorldTransform(
  959. const GpMatrix & matrix
  960. );
  961. virtual GpStatus
  962. RecordResetWorldTransform();
  963. virtual GpStatus
  964. RecordMultiplyWorldTransform(
  965. const GpMatrix & matrix,
  966. GpMatrixOrder order
  967. );
  968. virtual GpStatus
  969. RecordTranslateWorldTransform(
  970. REAL dx,
  971. REAL dy,
  972. GpMatrixOrder order
  973. );
  974. virtual GpStatus
  975. RecordScaleWorldTransform(
  976. REAL sx,
  977. REAL sy,
  978. GpMatrixOrder order
  979. );
  980. virtual GpStatus
  981. RecordRotateWorldTransform(
  982. REAL angle,
  983. GpMatrixOrder order
  984. );
  985. virtual GpStatus
  986. RecordSetPageTransform(
  987. GpPageUnit unit,
  988. REAL scale
  989. );
  990. virtual GpStatus
  991. RecordResetClip();
  992. virtual GpStatus
  993. RecordSetClip(
  994. const GpRectF & rect,
  995. CombineMode combineMode
  996. );
  997. virtual GpStatus
  998. RecordSetClip(
  999. GpRegion * region,
  1000. CombineMode combineMode
  1001. );
  1002. virtual GpStatus
  1003. RecordSetClip(
  1004. GpPath * path,
  1005. CombineMode combineMode,
  1006. BOOL isDevicePath
  1007. );
  1008. virtual GpStatus
  1009. RecordOffsetClip(
  1010. REAL dx,
  1011. REAL dy
  1012. );
  1013. virtual GpStatus
  1014. RecordGetDC();
  1015. virtual GpStatus
  1016. RecordSetAntiAliasMode(
  1017. BOOL newMode
  1018. );
  1019. virtual GpStatus
  1020. RecordSetTextRenderingHint(
  1021. TextRenderingHint newMode
  1022. );
  1023. virtual GpStatus
  1024. RecordSetTextContrast(
  1025. UINT gammaValue
  1026. );
  1027. virtual GpStatus
  1028. RecordSetInterpolationMode(
  1029. InterpolationMode newMode
  1030. );
  1031. virtual GpStatus
  1032. RecordSetPixelOffsetMode(
  1033. PixelOffsetMode newMode
  1034. );
  1035. virtual GpStatus
  1036. RecordSetCompositingMode(
  1037. GpCompositingMode newMode
  1038. );
  1039. virtual GpStatus
  1040. RecordSetCompositingQuality(
  1041. GpCompositingQuality newQuality
  1042. );
  1043. virtual GpStatus
  1044. RecordSetRenderingOrigin(
  1045. INT x,
  1046. INT y
  1047. );
  1048. virtual GpStatus
  1049. RecordComment(
  1050. UINT sizeData,
  1051. const BYTE * data
  1052. );
  1053. virtual VOID
  1054. EndRecording();
  1055. virtual GpStatus
  1056. RecordBackupObject(
  1057. const GpObject * object
  1058. );
  1059. protected:
  1060. GpStatus
  1061. RecordHeader(
  1062. INT logicalDpiX,
  1063. INT logicalDpiY,
  1064. INT emfPlusFlags
  1065. );
  1066. VOID RecordEndOfFile();
  1067. VOID
  1068. WriteObject(
  1069. ObjectType type,
  1070. const GpObject * object,
  1071. UINT32 metaObjectId
  1072. );
  1073. VOID
  1074. RecordObject(
  1075. const GpObject * object,
  1076. UINT32* metaObjectId
  1077. );
  1078. GpStatus
  1079. RecordZeroDataRecord(
  1080. EmfPlusRecordType type,
  1081. INT flags
  1082. );
  1083. VOID
  1084. WriteRecordHeader(
  1085. UINT32 dataSize,
  1086. EmfPlusRecordType type,
  1087. INT flags = 0, // 16 bits of flags
  1088. const GpRectF * deviceBounds = NULL
  1089. );
  1090. // To keep the number of comments low, this only needs to be called
  1091. // when there is a down-level representation of the GDI+ record.
  1092. VOID
  1093. WriteGdiComment()
  1094. {
  1095. // If we're doing dual (which means we're about to write
  1096. // down-level records) then write out the current list
  1097. // of records in the EmfPlusStream buffer.
  1098. if (Type == EmfTypeEmfPlusDual)
  1099. {
  1100. EmfPlusStream->Flush();
  1101. }
  1102. }
  1103. VOID
  1104. GetBrushValueForRecording(
  1105. const GpBrush *brush,
  1106. UINT32 &brushValue,
  1107. INT &flags
  1108. );
  1109. };
  1110. /**************************************************************************\
  1111. *
  1112. * Function Description:
  1113. *
  1114. * Construct a MetafileRecorder object and initialize it.
  1115. *
  1116. * Arguments:
  1117. *
  1118. * [IN] metafile - pointer to the metafile object being recorded
  1119. * [IN] stream - the stream being recorded into (if any)
  1120. * [IN] metafileHdc - handle to metafile DC being recorded into (if any)
  1121. * [IN] dpiX - the horizontal DPI
  1122. * [IN] dpiY - the vertical DPI
  1123. *
  1124. * Return Value:
  1125. *
  1126. * NONE
  1127. *
  1128. * Created:
  1129. *
  1130. * 6/15/1999 DCurtis
  1131. *
  1132. \**************************************************************************/
  1133. MetafileRecorder::MetafileRecorder(
  1134. GpMetafile * metafile,
  1135. EmfType emfType,
  1136. HDC metafileHdc,
  1137. BOOL wroteFrameRect,
  1138. SIZEL & effectiveMillimeters,
  1139. GpRectF & metafileBounds
  1140. )
  1141. {
  1142. SetValid(FALSE);
  1143. Type = emfType;
  1144. Metafile = metafile;
  1145. WroteFrameRect = wroteFrameRect;
  1146. NumRecords = 0; // currently for debugging only
  1147. MaxStackSize = 0;
  1148. MetafileHdc = metafileHdc;
  1149. XMinDevice = FLT_MAX;
  1150. YMinDevice = FLT_MAX;
  1151. XMaxDevice = -FLT_MAX;
  1152. YMaxDevice = -FLT_MAX;
  1153. BoundsInit = FALSE;
  1154. EmfPlusStream = NULL;
  1155. Millimeters = effectiveMillimeters;
  1156. // The metafileBounds are used as the bounds for FillRegion
  1157. // calls when the region has infinite bounds, to keep from
  1158. // exploding the bounds of the metafile.
  1159. MetafileBounds = metafileBounds;
  1160. if (emfType == EmfTypeEmfOnly)
  1161. {
  1162. Metafile->Header.Type = MetafileTypeEmf;
  1163. SetValid(TRUE);
  1164. }
  1165. else
  1166. {
  1167. // gets freed in the destructor
  1168. EmfPlusStream = new EmfPlusCommentStream(metafileHdc);
  1169. if (EmfPlusStream == NULL)
  1170. {
  1171. return;
  1172. }
  1173. SetValid(TRUE);
  1174. INT logicalDpiX = GetDeviceCaps(metafileHdc, LOGPIXELSX);
  1175. INT logicalDpiY = GetDeviceCaps(metafileHdc, LOGPIXELSY);
  1176. INT emfPlusFlags = 0;
  1177. if (GetDeviceCaps(metafileHdc, TECHNOLOGY) == DT_RASDISPLAY)
  1178. {
  1179. emfPlusFlags |= GDIP_EMFPLUSFLAGS_DISPLAY;
  1180. }
  1181. MetafileHeader * header = &(metafile->Header);
  1182. header->EmfPlusHeaderSize = sizeof(EmfPlusRecord) + sizeof(EmfPlusHeaderRecord);
  1183. header->LogicalDpiX = logicalDpiX;
  1184. header->LogicalDpiY = logicalDpiY;
  1185. header->EmfPlusFlags = emfPlusFlags;
  1186. if (emfType == EmfTypeEmfPlusOnly)
  1187. {
  1188. header->Type = MetafileTypeEmfPlusOnly;
  1189. }
  1190. else
  1191. {
  1192. ASSERT(emfType == EmfTypeEmfPlusDual);
  1193. header->Type = MetafileTypeEmfPlusDual;
  1194. }
  1195. if (RecordHeader(logicalDpiX, logicalDpiY, emfPlusFlags) != Ok)
  1196. {
  1197. SetValid(FALSE);
  1198. EmfPlusStream->Release();
  1199. EmfPlusStream = NULL;
  1200. }
  1201. }
  1202. }
  1203. /**************************************************************************\
  1204. *
  1205. * Function Description:
  1206. *
  1207. * IMetafileRecord interface method - RecordClear.
  1208. *
  1209. * Arguments:
  1210. *
  1211. * [IN] deviceBounds - the bounding rect, in device units
  1212. * [IN] color - the clear color
  1213. *
  1214. * Return Value:
  1215. *
  1216. * GpStatus - Ok or failure status
  1217. *
  1218. * Created:
  1219. *
  1220. * 04/28/2000 AGodfrey
  1221. *
  1222. \**************************************************************************/
  1223. GpStatus
  1224. MetafileRecorder::RecordClear(
  1225. const GpRectF * deviceBounds,
  1226. GpColor color
  1227. )
  1228. {
  1229. // If doing down-level only, then EmfPlusStream will be NULL
  1230. if (EmfPlusStream != NULL)
  1231. {
  1232. if (IsValid())
  1233. {
  1234. ASSERT (deviceBounds != NULL);
  1235. ARGB argbColor = color.GetValue();
  1236. UINT32 dataSize = sizeof(argbColor);
  1237. EmfPlusRecordType type = EmfPlusRecordTypeClear;
  1238. INT flags = 0;
  1239. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  1240. WriteInt32(EmfPlusStream, argbColor);
  1241. WriteGdiComment(); // is down-level for this record
  1242. if (EmfPlusStream->IsValid())
  1243. {
  1244. return Ok;
  1245. }
  1246. SetValid(FALSE);
  1247. }
  1248. WARNING(("Failed to write Clear record"));
  1249. return Win32Error;
  1250. }
  1251. return Ok;
  1252. }
  1253. /**************************************************************************\
  1254. *
  1255. * Function Description:
  1256. *
  1257. * IMetafileRecord interface method - RecordFillRects.
  1258. *
  1259. * Arguments:
  1260. *
  1261. * [IN] deviceBounds - the bounding rect, in device units
  1262. * [IN] brush - brush to draw with
  1263. * [IN] rects - rectangles to fill
  1264. * [IN] count - number of rects
  1265. *
  1266. * Return Value:
  1267. *
  1268. * GpStatus - Ok or failure status
  1269. *
  1270. * Created:
  1271. *
  1272. * 6/15/1999 DCurtis
  1273. *
  1274. \**************************************************************************/
  1275. GpStatus
  1276. MetafileRecorder::RecordFillRects(
  1277. const GpRectF * deviceBounds,
  1278. GpBrush * brush,
  1279. const GpRectF * rects,
  1280. INT count
  1281. )
  1282. {
  1283. // If doing down-level only, then EmfPlusStream will be NULL
  1284. if (EmfPlusStream != NULL)
  1285. {
  1286. ASSERT ((deviceBounds != NULL) && (brush != NULL) &&
  1287. (rects != NULL) && (count > 0));
  1288. if (IsValid())
  1289. {
  1290. MetafileRectData rectData(rects, count);
  1291. UINT32 brushValue; // Metafile Brush Id or ARGB value
  1292. UINT32 dataSize = sizeof(brushValue) +
  1293. sizeof(UINT32/* count */) +
  1294. rectData.GetDataSize();
  1295. EmfPlusRecordType type = EmfPlusRecordTypeFillRects;
  1296. INT flags = rectData.GetFlags();
  1297. GetBrushValueForRecording(brush, brushValue, flags);
  1298. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  1299. WriteInt32(EmfPlusStream, brushValue);
  1300. WriteInt32(EmfPlusStream, count);
  1301. rectData.WriteData(EmfPlusStream);
  1302. WriteGdiComment(); // is down-level for this record
  1303. if (EmfPlusStream->IsValid())
  1304. {
  1305. return Ok;
  1306. }
  1307. SetValid(FALSE);
  1308. }
  1309. WARNING(("Failed to write FillRects record"));
  1310. return Win32Error;
  1311. }
  1312. return Ok;
  1313. }
  1314. /**************************************************************************\
  1315. *
  1316. * Function Description:
  1317. *
  1318. * IMetafileRecord interface method - RecordDrawRects.
  1319. *
  1320. * Arguments:
  1321. *
  1322. * [IN] deviceBounds - the bounding rect, in device units
  1323. * [IN] pen - pen to draw with
  1324. * [IN] rects - rectangles to draw
  1325. * [IN] count - number of rects
  1326. *
  1327. * Return Value:
  1328. *
  1329. * GpStatus - Ok or failure status
  1330. *
  1331. * Created:
  1332. *
  1333. * 6/15/1999 DCurtis
  1334. *
  1335. \**************************************************************************/
  1336. GpStatus
  1337. MetafileRecorder::RecordDrawRects(
  1338. const GpRectF * deviceBounds,
  1339. GpPen * pen,
  1340. const GpRectF * rects,
  1341. INT count
  1342. )
  1343. {
  1344. // If doing down-level only, then EmfPlusStream will be NULL
  1345. if (EmfPlusStream != NULL)
  1346. {
  1347. ASSERT ((deviceBounds != NULL) && (pen != NULL) &&
  1348. (rects != NULL) && (count > 0));
  1349. if (IsValid())
  1350. {
  1351. MetafileRectData rectData(rects, count);
  1352. UINT32 metaPenId;
  1353. UINT32 dataSize = sizeof(UINT32/* count */) +
  1354. rectData.GetDataSize();
  1355. EmfPlusRecordType type = EmfPlusRecordTypeDrawRects;
  1356. INT flags = rectData.GetFlags();
  1357. RecordObject(pen, &metaPenId);
  1358. ASSERT((metaPenId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
  1359. flags |= metaPenId;
  1360. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  1361. WriteInt32(EmfPlusStream, count);
  1362. rectData.WriteData(EmfPlusStream);
  1363. WriteGdiComment(); // is down-level for this record
  1364. if (EmfPlusStream->IsValid())
  1365. {
  1366. return Ok;
  1367. }
  1368. SetValid(FALSE);
  1369. }
  1370. WARNING(("Failed to write DrawRects record"));
  1371. return Win32Error;
  1372. }
  1373. return Ok;
  1374. }
  1375. /**************************************************************************\
  1376. *
  1377. * Function Description:
  1378. *
  1379. * IMetafileRecord interface method - RecordFillPolygon.
  1380. *
  1381. * Arguments:
  1382. *
  1383. * [IN] deviceBounds - the bounding rect, in device units
  1384. * [IN] brush - brush to draw with
  1385. * [IN] points - polygon points
  1386. * [IN] count - number of points
  1387. * [IN] fillMode - Alternate or Winding
  1388. *
  1389. * Return Value:
  1390. *
  1391. * GpStatus - Ok or failure status
  1392. *
  1393. * Created:
  1394. *
  1395. * 6/15/1999 DCurtis
  1396. *
  1397. \**************************************************************************/
  1398. GpStatus
  1399. MetafileRecorder::RecordFillPolygon(
  1400. const GpRectF * deviceBounds,
  1401. GpBrush* brush,
  1402. const GpPointF * points,
  1403. INT count,
  1404. GpFillMode fillMode
  1405. )
  1406. {
  1407. // If doing down-level only, then EmfPlusStream will be NULL
  1408. if (EmfPlusStream != NULL)
  1409. {
  1410. ASSERT ((deviceBounds != NULL) && (brush != NULL) &&
  1411. (points != NULL) && (count > 0));
  1412. if (IsValid())
  1413. {
  1414. MetafilePointData pointData(points, count);
  1415. UINT32 brushValue; // Metafile Brush Id or ARGB value
  1416. UINT32 dataSize = sizeof(brushValue) +
  1417. sizeof(UINT32/* count */) +
  1418. pointData.GetDataSize();
  1419. EmfPlusRecordType type = EmfPlusRecordTypeFillPolygon;
  1420. INT flags = pointData.GetFlags();
  1421. GetBrushValueForRecording(brush, brushValue, flags);
  1422. if (fillMode == FillModeWinding)
  1423. {
  1424. flags |= GDIP_EPRFLAGS_WINDINGFILL;
  1425. }
  1426. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  1427. WriteInt32(EmfPlusStream, brushValue);
  1428. WriteInt32(EmfPlusStream, count);
  1429. pointData.WriteData(EmfPlusStream);
  1430. WriteGdiComment(); // is down-level for this record
  1431. if (EmfPlusStream->IsValid())
  1432. {
  1433. return Ok;
  1434. }
  1435. SetValid(FALSE);
  1436. }
  1437. WARNING(("Failed to write FillPolygon record"));
  1438. return Win32Error;
  1439. }
  1440. return Ok;
  1441. }
  1442. /**************************************************************************\
  1443. *
  1444. * Function Description:
  1445. *
  1446. * IMetafileRecord interface method - RecordDrawLines.
  1447. *
  1448. * Arguments:
  1449. *
  1450. * [IN] deviceBounds - the bounding rect, in device units
  1451. * [IN] pen - pen to draw with
  1452. * [IN] points - polyline points
  1453. * [IN] count - number of points
  1454. * [IN] closed - TRUE if closed
  1455. *
  1456. * Return Value:
  1457. *
  1458. * GpStatus - Ok or failure status
  1459. *
  1460. * Created:
  1461. *
  1462. * 6/15/1999 DCurtis
  1463. *
  1464. \**************************************************************************/
  1465. GpStatus
  1466. MetafileRecorder::RecordDrawLines(
  1467. const GpRectF * deviceBounds,
  1468. GpPen * pen,
  1469. const GpPointF * points,
  1470. INT count,
  1471. BOOL closed
  1472. )
  1473. {
  1474. // If doing down-level only, then EmfPlusStream will be NULL
  1475. if (EmfPlusStream != NULL)
  1476. {
  1477. ASSERT ((deviceBounds != NULL) && (pen != NULL) &&
  1478. (points != NULL) && (count > 0));
  1479. if (IsValid())
  1480. {
  1481. MetafilePointData pointData(points, count);
  1482. UINT32 metaPenId;
  1483. UINT32 dataSize = sizeof(UINT32/* count */) +
  1484. pointData.GetDataSize();
  1485. EmfPlusRecordType type = EmfPlusRecordTypeDrawLines;
  1486. INT flags = pointData.GetFlags();
  1487. RecordObject(pen, &metaPenId);
  1488. ASSERT((metaPenId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
  1489. flags |= metaPenId;
  1490. if (closed)
  1491. {
  1492. flags |= GDIP_EPRFLAGS_CLOSED;
  1493. }
  1494. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  1495. WriteInt32(EmfPlusStream, count);
  1496. pointData.WriteData(EmfPlusStream);
  1497. WriteGdiComment(); // is down-level for this record
  1498. if (EmfPlusStream->IsValid())
  1499. {
  1500. return Ok;
  1501. }
  1502. SetValid(FALSE);
  1503. }
  1504. WARNING(("Failed to write DrawLines record"));
  1505. return Win32Error;
  1506. }
  1507. return Ok;
  1508. }
  1509. /**************************************************************************\
  1510. *
  1511. * Function Description:
  1512. *
  1513. * IMetafileRecord interface method - RecordFillEllipse.
  1514. *
  1515. * Arguments:
  1516. *
  1517. * [IN] deviceBounds - the bounding rect, in device units
  1518. * [IN] brush - brush to draw with
  1519. * [IN] rect - bounding rect of ellipse
  1520. *
  1521. * Return Value:
  1522. *
  1523. * GpStatus - Ok or failure status
  1524. *
  1525. * Created:
  1526. *
  1527. * 6/15/1999 DCurtis
  1528. *
  1529. \**************************************************************************/
  1530. GpStatus
  1531. MetafileRecorder::RecordFillEllipse(
  1532. const GpRectF * deviceBounds,
  1533. GpBrush * brush,
  1534. const GpRectF & rect
  1535. )
  1536. {
  1537. // If doing down-level only, then EmfPlusStream will be NULL
  1538. if (EmfPlusStream != NULL)
  1539. {
  1540. ASSERT ((deviceBounds != NULL) && (brush != NULL));
  1541. if (IsValid())
  1542. {
  1543. MetafileRectData rectData(&rect, 1);
  1544. UINT32 brushValue; // Metafile Brush Id or ARGB value
  1545. UINT32 dataSize = sizeof(brushValue) +
  1546. rectData.GetDataSize();
  1547. EmfPlusRecordType type = EmfPlusRecordTypeFillEllipse;
  1548. INT flags = rectData.GetFlags();
  1549. GetBrushValueForRecording(brush, brushValue, flags);
  1550. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  1551. WriteInt32(EmfPlusStream, brushValue);
  1552. rectData.WriteData(EmfPlusStream);
  1553. WriteGdiComment(); // is down-level for this record
  1554. if (EmfPlusStream->IsValid())
  1555. {
  1556. return Ok;
  1557. }
  1558. SetValid(FALSE);
  1559. }
  1560. WARNING(("Failed to write FillEllipse record"));
  1561. return Win32Error;
  1562. }
  1563. return Ok;
  1564. }
  1565. /**************************************************************************\
  1566. *
  1567. * Function Description:
  1568. *
  1569. * IMetafileRecord interface method - RecordDrawEllipse.
  1570. *
  1571. * Arguments:
  1572. *
  1573. * [IN] deviceBounds - the bounding rect, in device units
  1574. * [IN] pen - pen to draw with
  1575. * [IN] rect - bounding rect of ellipse
  1576. *
  1577. * Return Value:
  1578. *
  1579. * GpStatus - Ok or failure status
  1580. *
  1581. * Created:
  1582. *
  1583. * 6/15/1999 DCurtis
  1584. *
  1585. \**************************************************************************/
  1586. GpStatus
  1587. MetafileRecorder::RecordDrawEllipse(
  1588. const GpRectF * deviceBounds,
  1589. GpPen * pen,
  1590. const GpRectF & rect
  1591. )
  1592. {
  1593. // If doing down-level only, then EmfPlusStream will be NULL
  1594. if (EmfPlusStream != NULL)
  1595. {
  1596. ASSERT ((deviceBounds != NULL) && (pen != NULL));
  1597. if (IsValid())
  1598. {
  1599. MetafileRectData rectData(&rect, 1);
  1600. UINT32 metaPenId;
  1601. UINT32 dataSize = rectData.GetDataSize();
  1602. EmfPlusRecordType type = EmfPlusRecordTypeDrawEllipse;
  1603. INT flags = rectData.GetFlags();
  1604. RecordObject(pen, &metaPenId);
  1605. ASSERT((metaPenId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
  1606. flags |= metaPenId;
  1607. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  1608. rectData.WriteData(EmfPlusStream);
  1609. WriteGdiComment(); // is down-level for this record
  1610. if (EmfPlusStream->IsValid())
  1611. {
  1612. return Ok;
  1613. }
  1614. SetValid(FALSE);
  1615. }
  1616. WARNING(("Failed to write DrawEllipse record"));
  1617. return Win32Error;
  1618. }
  1619. return Ok;
  1620. }
  1621. /**************************************************************************\
  1622. *
  1623. * Function Description:
  1624. *
  1625. * IMetafileRecord interface method - RecordFillPie.
  1626. *
  1627. * Arguments:
  1628. *
  1629. * [IN] deviceBounds - the bounding rect, in device units
  1630. * [IN] brush - brush to draw with
  1631. * [IN] rect - bounding rect of ellipse
  1632. * [IN] startAngle - starting angle of pie
  1633. * [IN] sweepAngle - sweep angle of pie
  1634. *
  1635. * Return Value:
  1636. *
  1637. * GpStatus - Ok or failure status
  1638. *
  1639. * Created:
  1640. *
  1641. * 6/15/1999 DCurtis
  1642. *
  1643. \**************************************************************************/
  1644. GpStatus
  1645. MetafileRecorder::RecordFillPie(
  1646. const GpRectF * deviceBounds,
  1647. GpBrush * brush,
  1648. const GpRectF & rect,
  1649. REAL startAngle,
  1650. REAL sweepAngle
  1651. )
  1652. {
  1653. // If doing down-level only, then EmfPlusStream will be NULL
  1654. if (EmfPlusStream != NULL)
  1655. {
  1656. ASSERT ((deviceBounds != NULL) && (brush != NULL));
  1657. if (IsValid())
  1658. {
  1659. MetafileRectData rectData(&rect, 1);
  1660. UINT32 brushValue; // Metafile Brush Id or ARGB value
  1661. UINT32 dataSize = sizeof(brushValue) +
  1662. sizeof(startAngle) +
  1663. sizeof(sweepAngle) +
  1664. rectData.GetDataSize();
  1665. EmfPlusRecordType type = EmfPlusRecordTypeFillPie;
  1666. INT flags = rectData.GetFlags();
  1667. GetBrushValueForRecording(brush, brushValue, flags);
  1668. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  1669. WriteInt32(EmfPlusStream, brushValue);
  1670. WriteReal (EmfPlusStream, startAngle);
  1671. WriteReal (EmfPlusStream, sweepAngle);
  1672. rectData.WriteData(EmfPlusStream);
  1673. WriteGdiComment(); // is down-level for this record
  1674. if (EmfPlusStream->IsValid())
  1675. {
  1676. return Ok;
  1677. }
  1678. SetValid(FALSE);
  1679. }
  1680. WARNING(("Failed to write FillPie record"));
  1681. return Win32Error;
  1682. }
  1683. return Ok;
  1684. }
  1685. /**************************************************************************\
  1686. *
  1687. * Function Description:
  1688. *
  1689. * IMetafileRecord interface method - RecordDrawPie.
  1690. *
  1691. * Arguments:
  1692. *
  1693. * [IN] deviceBounds - the bounding rect, in device units
  1694. * [IN] pen - pen to draw with
  1695. * [IN] rect - bounding rect of ellipse
  1696. * [IN] startAngle - starting angle of pie
  1697. * [IN] sweepAngle - sweep angle of pie
  1698. *
  1699. * Return Value:
  1700. *
  1701. * GpStatus - Ok or failure status
  1702. *
  1703. * Created:
  1704. *
  1705. * 6/15/1999 DCurtis
  1706. *
  1707. \**************************************************************************/
  1708. GpStatus
  1709. MetafileRecorder::RecordDrawPie(
  1710. const GpRectF * deviceBounds,
  1711. GpPen * pen,
  1712. const GpRectF & rect,
  1713. REAL startAngle,
  1714. REAL sweepAngle
  1715. )
  1716. {
  1717. // If doing down-level only, then EmfPlusStream will be NULL
  1718. if (EmfPlusStream != NULL)
  1719. {
  1720. ASSERT ((deviceBounds != NULL) && (pen != NULL));
  1721. if (IsValid())
  1722. {
  1723. MetafileRectData rectData(&rect, 1);
  1724. UINT32 metaPenId;
  1725. UINT32 dataSize = sizeof(startAngle) +
  1726. sizeof(sweepAngle) +
  1727. rectData.GetDataSize();
  1728. EmfPlusRecordType type = EmfPlusRecordTypeDrawPie;
  1729. INT flags = rectData.GetFlags();
  1730. RecordObject(pen, &metaPenId);
  1731. ASSERT((metaPenId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
  1732. flags |= metaPenId;
  1733. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  1734. WriteReal (EmfPlusStream, startAngle);
  1735. WriteReal (EmfPlusStream, sweepAngle);
  1736. rectData.WriteData(EmfPlusStream);
  1737. WriteGdiComment(); // is down-level for this record
  1738. if (EmfPlusStream->IsValid())
  1739. {
  1740. return Ok;
  1741. }
  1742. SetValid(FALSE);
  1743. }
  1744. WARNING(("Failed to write DrawPie record"));
  1745. return Win32Error;
  1746. }
  1747. return Ok;
  1748. }
  1749. /**************************************************************************\
  1750. *
  1751. * Function Description:
  1752. *
  1753. * IMetafileRecord interface method - RecordDrawArc.
  1754. *
  1755. * Arguments:
  1756. *
  1757. * [IN] deviceBounds - the bounding rect, in device units
  1758. * [IN] pen - pen to draw with
  1759. * [IN] rect - bounding rect of ellipse
  1760. * [IN] startAngle - starting angle of arc
  1761. * [IN] sweepAngle - sweep angle of arc
  1762. *
  1763. * Return Value:
  1764. *
  1765. * GpStatus - Ok or failure status
  1766. *
  1767. * Created:
  1768. *
  1769. * 6/15/1999 DCurtis
  1770. *
  1771. \**************************************************************************/
  1772. GpStatus
  1773. MetafileRecorder::RecordDrawArc(
  1774. const GpRectF * deviceBounds,
  1775. GpPen * pen,
  1776. const GpRectF & rect,
  1777. REAL startAngle,
  1778. REAL sweepAngle
  1779. )
  1780. {
  1781. // If doing down-level only, then EmfPlusStream will be NULL
  1782. if (EmfPlusStream != NULL)
  1783. {
  1784. ASSERT ((deviceBounds != NULL) && (pen != NULL));
  1785. if (IsValid())
  1786. {
  1787. MetafileRectData rectData(&rect, 1);
  1788. UINT32 metaPenId;
  1789. UINT32 dataSize = sizeof(startAngle) +
  1790. sizeof(sweepAngle) +
  1791. rectData.GetDataSize();
  1792. EmfPlusRecordType type = EmfPlusRecordTypeDrawArc;
  1793. INT flags = rectData.GetFlags();
  1794. RecordObject(pen, &metaPenId);
  1795. ASSERT((metaPenId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
  1796. flags |= metaPenId;
  1797. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  1798. WriteReal (EmfPlusStream, startAngle);
  1799. WriteReal (EmfPlusStream, sweepAngle);
  1800. rectData.WriteData(EmfPlusStream);
  1801. WriteGdiComment(); // is down-level for this record
  1802. if (EmfPlusStream->IsValid())
  1803. {
  1804. return Ok;
  1805. }
  1806. SetValid(FALSE);
  1807. }
  1808. WARNING(("Failed to write DrawArc record"));
  1809. return Win32Error;
  1810. }
  1811. return Ok;
  1812. }
  1813. /**************************************************************************\
  1814. *
  1815. * Function Description:
  1816. *
  1817. * IMetafileRecord interface method - RecordFillRegion.
  1818. *
  1819. * Arguments:
  1820. *
  1821. * [IN] deviceBounds - the bounding rect, in device units
  1822. * [IN] brush - brush to draw with
  1823. * [IN] region - region to fill
  1824. *
  1825. * Return Value:
  1826. *
  1827. * GpStatus - Ok or failure status
  1828. *
  1829. * Created:
  1830. *
  1831. * 6/15/1999 DCurtis
  1832. *
  1833. \**************************************************************************/
  1834. GpStatus
  1835. MetafileRecorder::RecordFillRegion(
  1836. const GpRectF * deviceBounds,
  1837. GpBrush * brush,
  1838. GpRegion * region
  1839. )
  1840. {
  1841. // The deviceBounds should never be infinite, because they are
  1842. // intersected with the metafileBounds before being passed in.
  1843. // If doing down-level only, then EmfPlusStream will be NULL
  1844. if (EmfPlusStream != NULL)
  1845. {
  1846. ASSERT ((deviceBounds != NULL) && (brush != NULL) && (region != NULL));
  1847. if (IsValid())
  1848. {
  1849. UINT32 metaRegionId;
  1850. UINT32 brushValue; // Metafile Brush Id or ARGB value
  1851. UINT32 dataSize = sizeof(brushValue);
  1852. EmfPlusRecordType type = EmfPlusRecordTypeFillRegion;
  1853. INT flags = 0;
  1854. GetBrushValueForRecording(brush, brushValue, flags);
  1855. RecordObject(region, &metaRegionId);
  1856. ASSERT((metaRegionId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
  1857. flags |= metaRegionId;
  1858. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  1859. WriteInt32(EmfPlusStream, brushValue);
  1860. WriteGdiComment(); // is down-level for this record
  1861. if (EmfPlusStream->IsValid())
  1862. {
  1863. return Ok;
  1864. }
  1865. SetValid(FALSE);
  1866. }
  1867. WARNING(("Failed to write FillRegion record"));
  1868. return Win32Error;
  1869. }
  1870. return Ok;
  1871. }
  1872. /**************************************************************************\
  1873. *
  1874. * Function Description:
  1875. *
  1876. * IMetafileRecord interface method - RecordFillPath.
  1877. *
  1878. * Arguments:
  1879. *
  1880. * [IN] deviceBounds - the bounding rect, in device units
  1881. * [IN] brush - brush to draw with
  1882. * [IN] path - path to fill
  1883. *
  1884. * Return Value:
  1885. *
  1886. * GpStatus - Ok or failure status
  1887. *
  1888. * Created:
  1889. *
  1890. * 6/15/1999 DCurtis
  1891. *
  1892. \**************************************************************************/
  1893. GpStatus
  1894. MetafileRecorder::RecordFillPath(
  1895. const GpRectF * deviceBounds,
  1896. const GpBrush * brush,
  1897. GpPath * path
  1898. )
  1899. {
  1900. // If doing down-level only, then EmfPlusStream will be NULL
  1901. if (EmfPlusStream != NULL)
  1902. {
  1903. ASSERT ((deviceBounds != NULL) && (brush != NULL) && (path != NULL));
  1904. if (IsValid())
  1905. {
  1906. UINT32 metaPathId;
  1907. UINT32 brushValue; // Metafile Brush Id or ARGB value
  1908. UINT32 dataSize = sizeof(brushValue);
  1909. EmfPlusRecordType type = EmfPlusRecordTypeFillPath;
  1910. INT flags = 0;
  1911. GetBrushValueForRecording(brush, brushValue, flags);
  1912. RecordObject(path, &metaPathId);
  1913. ASSERT((metaPathId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
  1914. flags |= metaPathId;
  1915. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  1916. WriteInt32(EmfPlusStream, brushValue);
  1917. WriteGdiComment(); // is down-level for this record
  1918. if (EmfPlusStream->IsValid())
  1919. {
  1920. return Ok;
  1921. }
  1922. SetValid(FALSE);
  1923. }
  1924. WARNING(("Failed to write FillPath record"));
  1925. return Win32Error;
  1926. }
  1927. return Ok;
  1928. }
  1929. /**************************************************************************\
  1930. *
  1931. * Function Description:
  1932. *
  1933. * IMetafileRecord interface method - RecordDrawPath.
  1934. *
  1935. * Arguments:
  1936. *
  1937. * [IN] deviceBounds - the bounding rect, in device units
  1938. * [IN] pen - pen to draw with
  1939. * [IN] path - path to draw
  1940. *
  1941. * Return Value:
  1942. *
  1943. * GpStatus - Ok or failure status
  1944. *
  1945. * Created:
  1946. *
  1947. * 6/15/1999 DCurtis
  1948. *
  1949. \**************************************************************************/
  1950. GpStatus
  1951. MetafileRecorder::RecordDrawPath(
  1952. const GpRectF * deviceBounds,
  1953. GpPen * pen,
  1954. GpPath * path
  1955. )
  1956. {
  1957. // If doing down-level only, then EmfPlusStream will be NULL
  1958. if (EmfPlusStream != NULL)
  1959. {
  1960. ASSERT ((deviceBounds != NULL) && (pen != NULL) && (path != NULL));
  1961. if (IsValid())
  1962. {
  1963. UINT32 metaPathId;
  1964. UINT32 metaPenId;
  1965. UINT32 dataSize = sizeof(metaPenId);
  1966. EmfPlusRecordType type = EmfPlusRecordTypeDrawPath;
  1967. INT flags = 0;
  1968. RecordObject(pen, &metaPenId);
  1969. RecordObject(path, &metaPathId);
  1970. ASSERT((metaPathId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
  1971. flags |= metaPathId;
  1972. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  1973. WriteInt32(EmfPlusStream, metaPenId);
  1974. WriteGdiComment(); // is down-level for this record
  1975. if (EmfPlusStream->IsValid())
  1976. {
  1977. return Ok;
  1978. }
  1979. SetValid(FALSE);
  1980. }
  1981. WARNING(("Failed to write DrawPath record"));
  1982. return Win32Error;
  1983. }
  1984. return Ok;
  1985. }
  1986. /**************************************************************************\
  1987. *
  1988. * Function Description:
  1989. *
  1990. * IMetafileRecord interface method - RecordFillClosedCurve.
  1991. *
  1992. * Arguments:
  1993. *
  1994. * [IN] deviceBounds - the bounding rect, in device units
  1995. * [IN] brush - brush to draw with
  1996. * [IN] points - curve points
  1997. * [IN] count - number of points
  1998. * [IN] tension - how tight to make curve
  1999. * [IN] fillMode - Alternate or Winding
  2000. *
  2001. * Return Value:
  2002. *
  2003. * GpStatus - Ok or failure status
  2004. *
  2005. * Created:
  2006. *
  2007. * 6/15/1999 DCurtis
  2008. *
  2009. \**************************************************************************/
  2010. GpStatus
  2011. MetafileRecorder::RecordFillClosedCurve(
  2012. const GpRectF * deviceBounds,
  2013. GpBrush * brush,
  2014. const GpPointF * points,
  2015. INT count,
  2016. REAL tension,
  2017. GpFillMode fillMode
  2018. )
  2019. {
  2020. // If doing down-level only, then EmfPlusStream will be NULL
  2021. if (EmfPlusStream != NULL)
  2022. {
  2023. ASSERT ((deviceBounds != NULL) && (brush != NULL) &&
  2024. (points != NULL) && (count > 0));
  2025. if (IsValid())
  2026. {
  2027. MetafilePointData pointData(points, count);
  2028. UINT32 brushValue; // Metafile Brush Id or ARGB value
  2029. UINT32 dataSize = sizeof(brushValue) +
  2030. sizeof(tension) +
  2031. sizeof(UINT32 /* count */) +
  2032. pointData.GetDataSize();
  2033. EmfPlusRecordType type = EmfPlusRecordTypeFillClosedCurve;
  2034. INT flags = pointData.GetFlags();
  2035. GetBrushValueForRecording(brush, brushValue, flags);
  2036. if (fillMode == FillModeWinding)
  2037. {
  2038. flags |= GDIP_EPRFLAGS_WINDINGFILL;
  2039. }
  2040. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  2041. WriteInt32(EmfPlusStream, brushValue);
  2042. WriteReal (EmfPlusStream, tension);
  2043. WriteInt32(EmfPlusStream, count);
  2044. pointData.WriteData(EmfPlusStream);
  2045. WriteGdiComment(); // is down-level for this record
  2046. if (EmfPlusStream->IsValid())
  2047. {
  2048. return Ok;
  2049. }
  2050. SetValid(FALSE);
  2051. }
  2052. WARNING(("Failed to write FillClosedCurve record"));
  2053. return Win32Error;
  2054. }
  2055. return Ok;
  2056. }
  2057. /**************************************************************************\
  2058. *
  2059. * Function Description:
  2060. *
  2061. * IMetafileRecord interface method - RecordDrawClosedCurve.
  2062. *
  2063. * Arguments:
  2064. *
  2065. * [IN] deviceBounds - the bounding rect, in device units
  2066. * [IN] pen - pen to draw with
  2067. * [IN] points - curve points
  2068. * [IN] count - number of points
  2069. * [IN] tension - how tight to make curve
  2070. *
  2071. * Return Value:
  2072. *
  2073. * GpStatus - Ok or failure status
  2074. *
  2075. * Created:
  2076. *
  2077. * 6/15/1999 DCurtis
  2078. *
  2079. \**************************************************************************/
  2080. GpStatus
  2081. MetafileRecorder::RecordDrawClosedCurve(
  2082. const GpRectF * deviceBounds,
  2083. GpPen * pen,
  2084. const GpPointF * points,
  2085. INT count,
  2086. REAL tension
  2087. )
  2088. {
  2089. // If doing down-level only, then EmfPlusStream will be NULL
  2090. if (EmfPlusStream != NULL)
  2091. {
  2092. ASSERT ((deviceBounds != NULL) && (pen != NULL) &&
  2093. (points != NULL) && (count > 0));
  2094. if (IsValid())
  2095. {
  2096. MetafilePointData pointData(points, count);
  2097. UINT32 metaPenId;
  2098. UINT32 dataSize = sizeof(tension) +
  2099. sizeof(UINT32/* count */) +
  2100. pointData.GetDataSize();
  2101. EmfPlusRecordType type = EmfPlusRecordTypeDrawClosedCurve;
  2102. INT flags = pointData.GetFlags();
  2103. RecordObject(pen, &metaPenId);
  2104. ASSERT((metaPenId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
  2105. flags |= metaPenId;
  2106. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  2107. WriteReal (EmfPlusStream, tension);
  2108. WriteInt32(EmfPlusStream, count);
  2109. pointData.WriteData(EmfPlusStream);
  2110. WriteGdiComment(); // is down-level for this record
  2111. if (EmfPlusStream->IsValid())
  2112. {
  2113. return Ok;
  2114. }
  2115. SetValid(FALSE);
  2116. }
  2117. WARNING(("Failed to write DrawClosedCurve record"));
  2118. return Win32Error;
  2119. }
  2120. return Ok;
  2121. }
  2122. /**************************************************************************\
  2123. *
  2124. * Function Description:
  2125. *
  2126. * IMetafileRecord interface method - RecordDrawCurve.
  2127. *
  2128. * Arguments:
  2129. *
  2130. * [IN] deviceBounds - the bounding rect, in device units
  2131. * [IN] pen - pen to draw with
  2132. * [IN] points - curve points
  2133. * [IN] count - number of points
  2134. * [IN] tension - how tight to make curve
  2135. * [IN] offset - offset
  2136. * [IN] numberOfSegments - number of segments
  2137. *
  2138. * Return Value:
  2139. *
  2140. * GpStatus - Ok or failure status
  2141. *
  2142. * Created:
  2143. *
  2144. * 6/15/1999 DCurtis
  2145. *
  2146. \**************************************************************************/
  2147. GpStatus
  2148. MetafileRecorder::RecordDrawCurve(
  2149. const GpRectF * deviceBounds,
  2150. GpPen * pen,
  2151. const GpPointF * points,
  2152. INT count,
  2153. REAL tension,
  2154. INT offset,
  2155. INT numberOfSegments
  2156. )
  2157. {
  2158. // If doing down-level only, then EmfPlusStream will be NULL
  2159. if (EmfPlusStream != NULL)
  2160. {
  2161. ASSERT ((deviceBounds != NULL) && (pen != NULL) &&
  2162. (points != NULL) && (count > 0));
  2163. if (IsValid())
  2164. {
  2165. MetafilePointData pointData(points, count);
  2166. UINT32 metaPenId;
  2167. UINT32 dataSize = sizeof(tension) +
  2168. sizeof(INT32 /* offset */) +
  2169. sizeof(UINT32/* numberOfSegments */) +
  2170. sizeof(UINT32/* count */) +
  2171. pointData.GetDataSize();
  2172. EmfPlusRecordType type = EmfPlusRecordTypeDrawCurve;
  2173. INT flags = pointData.GetFlags();
  2174. RecordObject(pen, &metaPenId);
  2175. ASSERT((metaPenId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
  2176. flags |= metaPenId;
  2177. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  2178. WriteReal (EmfPlusStream, tension);
  2179. WriteInt32(EmfPlusStream, offset);
  2180. WriteInt32(EmfPlusStream, numberOfSegments);
  2181. WriteInt32(EmfPlusStream, count);
  2182. pointData.WriteData(EmfPlusStream);
  2183. WriteGdiComment(); // is down-level for this record
  2184. if (EmfPlusStream->IsValid())
  2185. {
  2186. return Ok;
  2187. }
  2188. SetValid(FALSE);
  2189. }
  2190. WARNING(("Failed to write DrawCurve record"));
  2191. return Win32Error;
  2192. }
  2193. return Ok;
  2194. }
  2195. /**************************************************************************\
  2196. *
  2197. * Function Description:
  2198. *
  2199. * IMetafileRecord interface method - RecordDrawBeziers.
  2200. *
  2201. * Arguments:
  2202. *
  2203. * [IN] deviceBounds - the bounding rect, in device units
  2204. * [IN] pen - pen to draw with
  2205. * [IN] points - curve points
  2206. * [IN] count - number of points
  2207. *
  2208. * Return Value:
  2209. *
  2210. * GpStatus - Ok or failure status
  2211. *
  2212. * Created:
  2213. *
  2214. * 6/15/1999 DCurtis
  2215. *
  2216. \**************************************************************************/
  2217. GpStatus
  2218. MetafileRecorder::RecordDrawBeziers(
  2219. const GpRectF * deviceBounds,
  2220. GpPen * pen,
  2221. const GpPointF * points,
  2222. INT count
  2223. )
  2224. {
  2225. // If doing down-level only, then EmfPlusStream will be NULL
  2226. if (EmfPlusStream != NULL)
  2227. {
  2228. ASSERT ((deviceBounds != NULL) && (pen != NULL) &&
  2229. (points != NULL) && (count > 0));
  2230. if (IsValid())
  2231. {
  2232. MetafilePointData pointData(points, count);
  2233. UINT32 metaPenId;
  2234. UINT32 dataSize = sizeof(UINT32/* count */) +
  2235. pointData.GetDataSize();
  2236. EmfPlusRecordType type = EmfPlusRecordTypeDrawBeziers;
  2237. INT flags = pointData.GetFlags();
  2238. RecordObject(pen, &metaPenId);
  2239. ASSERT((metaPenId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
  2240. flags |= metaPenId;
  2241. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  2242. WriteInt32(EmfPlusStream, count);
  2243. pointData.WriteData(EmfPlusStream);
  2244. WriteGdiComment(); // is down-level for this record
  2245. if (EmfPlusStream->IsValid())
  2246. {
  2247. return Ok;
  2248. }
  2249. SetValid(FALSE);
  2250. }
  2251. WARNING(("Failed to write DrawBeziers record"));
  2252. return Win32Error;
  2253. }
  2254. return Ok;
  2255. }
  2256. /**************************************************************************\
  2257. *
  2258. * Function Description:
  2259. *
  2260. * IMetafileRecord interface method - RecordDrawImage.
  2261. *
  2262. * Arguments:
  2263. *
  2264. * [IN] deviceBounds - the bounding rect, in device units
  2265. * [IN] image - image to draw
  2266. * [IN] destRect - where to draw image
  2267. * [IN] srcRect - portion of image to draw
  2268. * [IN] srcUnit - units of srcRect
  2269. *
  2270. * Return Value:
  2271. *
  2272. * GpStatus - Ok or failure status
  2273. *
  2274. * Created:
  2275. *
  2276. * 6/15/1999 DCurtis
  2277. *
  2278. \**************************************************************************/
  2279. GpStatus
  2280. MetafileRecorder::RecordDrawImage(
  2281. const GpRectF * deviceBounds,
  2282. const GpImage * image,
  2283. const GpRectF & destRect,
  2284. const GpRectF & srcRect,
  2285. GpPageUnit srcUnit,
  2286. const GpImageAttributes * imageAttributes
  2287. )
  2288. {
  2289. // If doing down-level only, then EmfPlusStream will be NULL
  2290. if (EmfPlusStream != NULL)
  2291. {
  2292. ASSERT ((deviceBounds != NULL) && (image != NULL));
  2293. if (IsValid())
  2294. {
  2295. MetafileRectData rectData(&destRect, 1);
  2296. UINT32 metaImageId;
  2297. UINT32 metaImageAttributesId;
  2298. UINT32 dataSize = sizeof(INT32) + /* metaImageAttributesId*/
  2299. sizeof(INT32) + /* srcUnit */
  2300. sizeof(srcRect) +
  2301. rectData.GetDataSize();
  2302. EmfPlusRecordType type = EmfPlusRecordTypeDrawImage;
  2303. INT flags = rectData.GetFlags();
  2304. RecordObject(image, &metaImageId);
  2305. ASSERT((metaImageId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
  2306. flags |= metaImageId;
  2307. // Record the imageAttributes;
  2308. // imageAttributes can be NULL
  2309. RecordObject(imageAttributes, &metaImageAttributesId);
  2310. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  2311. WriteInt32(EmfPlusStream, metaImageAttributesId);
  2312. WriteInt32(EmfPlusStream, srcUnit);
  2313. WriteRect (EmfPlusStream, srcRect);
  2314. rectData.WriteData(EmfPlusStream);
  2315. WriteGdiComment(); // is down-level for this record
  2316. if (EmfPlusStream->IsValid())
  2317. {
  2318. return Ok;
  2319. }
  2320. SetValid(FALSE);
  2321. }
  2322. WARNING(("Failed to write DrawImage record"));
  2323. return Win32Error;
  2324. }
  2325. return Ok;
  2326. }
  2327. /**************************************************************************\
  2328. *
  2329. * Function Description:
  2330. *
  2331. * IMetafileRecord interface method - RecordDrawImage.
  2332. *
  2333. * Arguments:
  2334. *
  2335. * [IN] deviceBounds - the bounding rect, in device units
  2336. * [IN] image - image to draw
  2337. * [IN] destPoints - where to draw image
  2338. * [IN] count - number of destPoints
  2339. * [IN] srcRect - portion of image to draw
  2340. * [IN] srcUnit - units of srcRect
  2341. *
  2342. * Return Value:
  2343. *
  2344. * GpStatus - Ok or failure status
  2345. *
  2346. * Created:
  2347. *
  2348. * 6/15/1999 DCurtis
  2349. *
  2350. \**************************************************************************/
  2351. GpStatus
  2352. MetafileRecorder::RecordDrawImage(
  2353. const GpRectF * deviceBounds,
  2354. const GpImage * image,
  2355. const GpPointF * destPoints,
  2356. INT count,
  2357. const GpRectF & srcRect,
  2358. GpPageUnit srcUnit,
  2359. const GpImageAttributes * imageAttributes
  2360. )
  2361. {
  2362. // If doing down-level only, then EmfPlusStream will be NULL
  2363. if (EmfPlusStream != NULL)
  2364. {
  2365. ASSERT ((deviceBounds != NULL) && (image != NULL) &&
  2366. (destPoints != NULL) && (count > 0));
  2367. if (IsValid())
  2368. {
  2369. MetafilePointData pointData(destPoints, count);
  2370. UINT32 metaImageId;
  2371. UINT32 metaImageAttributesId;
  2372. UINT32 dataSize = sizeof(INT32) + /* metaImageAttributesId*/
  2373. sizeof(INT32) + /* srcUnit */
  2374. sizeof(srcRect) +
  2375. sizeof(UINT32) + /* count */
  2376. pointData.GetDataSize();
  2377. EmfPlusRecordType type = EmfPlusRecordTypeDrawImagePoints;
  2378. INT flags = pointData.GetFlags();
  2379. RecordObject(image, &metaImageId);
  2380. ASSERT((metaImageId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
  2381. flags |= metaImageId;
  2382. // Record the imageAttributes;
  2383. // imageAttributes can be NULL
  2384. RecordObject(imageAttributes, &metaImageAttributesId);
  2385. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  2386. WriteInt32(EmfPlusStream, metaImageAttributesId);
  2387. WriteInt32(EmfPlusStream, srcUnit);
  2388. WriteRect (EmfPlusStream, srcRect);
  2389. WriteInt32(EmfPlusStream, count);
  2390. pointData.WriteData(EmfPlusStream);
  2391. WriteGdiComment(); // is down-level for this record
  2392. if (EmfPlusStream->IsValid())
  2393. {
  2394. return Ok;
  2395. }
  2396. SetValid(FALSE);
  2397. }
  2398. WARNING(("Failed to write DrawImagePoints record"));
  2399. return Win32Error;
  2400. }
  2401. return Ok;
  2402. }
  2403. /**************************************************************************\
  2404. *
  2405. * Function Description:
  2406. *
  2407. * IMetafileRecord interface method - RecordDrawString.
  2408. *
  2409. * Arguments:
  2410. *
  2411. * [IN] string - string to draw
  2412. * [IN] length - length of string
  2413. * [IN] font - font to use when drawing string
  2414. * [IN] layoutRect - where to draw the string
  2415. * [IN] format - format
  2416. * [IN] brush - brush to draw with
  2417. *
  2418. * Return Value:
  2419. *
  2420. * GpStatus - Ok or failure status
  2421. *
  2422. * Created:
  2423. *
  2424. * 6/15/1999 DCurtis
  2425. *
  2426. \**************************************************************************/
  2427. GpStatus
  2428. MetafileRecorder::RecordDrawString(
  2429. const GpRectF * deviceBounds,
  2430. const WCHAR *string,
  2431. INT length,
  2432. const GpFont *font,
  2433. const RectF *layoutRect,
  2434. const GpStringFormat *format,
  2435. const GpBrush *brush
  2436. )
  2437. {
  2438. // If doing down-level only, then EmfPlusStream will be NULL
  2439. if (EmfPlusStream != NULL)
  2440. {
  2441. ASSERT (string && font && brush && layoutRect);
  2442. if (length < 0)
  2443. {
  2444. if (length == -1)
  2445. {
  2446. length = 0;
  2447. while (string[length] && (length < INT_MAX))
  2448. {
  2449. length++;
  2450. }
  2451. }
  2452. else
  2453. {
  2454. return InvalidParameter;
  2455. }
  2456. }
  2457. ASSERT (length > 0);
  2458. if (IsValid())
  2459. {
  2460. const BYTE * strData = (BYTE *)string; // BYTE or WCHAR
  2461. INT sizeString = length * sizeof(WCHAR);
  2462. INT flags = 0;
  2463. // !!! TODO:
  2464. // Compress the Unicode string.
  2465. // Use the GDIP_EPRFLAGS_COMPRESSED to indicate that
  2466. // the string has been compressed to ANSI.
  2467. UINT32 metaFontId;
  2468. UINT32 metaFormatId;
  2469. UINT32 brushValue; // Metafile Brush Id or ARGB value
  2470. UINT32 dataSize = sizeof(brushValue) +
  2471. sizeof(metaFormatId) +
  2472. sizeof(INT32 /* len */) +
  2473. sizeof(*layoutRect) +
  2474. sizeString;
  2475. EmfPlusRecordType type = EmfPlusRecordTypeDrawString;
  2476. dataSize = (dataSize + 3) & (~3); // align
  2477. RecordObject(font, &metaFontId);
  2478. ASSERT((metaFontId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
  2479. flags |= metaFontId;
  2480. // the format can be NULL
  2481. RecordObject(format, &metaFormatId);
  2482. GetBrushValueForRecording(brush, brushValue, flags);
  2483. WriteRecordHeader(dataSize, type, flags, deviceBounds);
  2484. WriteInt32(EmfPlusStream, brushValue);
  2485. WriteInt32(EmfPlusStream, metaFormatId);
  2486. WriteInt32(EmfPlusStream, length);
  2487. WriteRect (EmfPlusStream, *layoutRect);
  2488. WriteBytes(EmfPlusStream, strData, sizeString);
  2489. // align
  2490. if ((length & 0x01) != 0)
  2491. {
  2492. length = 0;
  2493. EmfPlusStream->Write(&length, sizeof(WCHAR), NULL);
  2494. }
  2495. WriteGdiComment(); // is down-level for this record
  2496. if (EmfPlusStream->IsValid())
  2497. {
  2498. return Ok;
  2499. }
  2500. SetValid(FALSE);
  2501. }
  2502. WARNING(("Failed to write DrawString record"));
  2503. return Win32Error;
  2504. }
  2505. return Ok;
  2506. }
  2507. /**************************************************************************\
  2508. *
  2509. * Function Description:
  2510. *
  2511. * IMetafileRecord interface method - RecordDrawdriverString.
  2512. *
  2513. * Arguments:
  2514. *
  2515. * [IN] text - string/glyphs
  2516. * [IN] glyphCount - string length
  2517. * [IN] font - font to use when drawing string
  2518. * [IN] brush - brush to draw with
  2519. * [IN] positions - character/glyphs origins
  2520. * [IN] flags - API flags
  2521. * [IN] matrix - transofrmation matrix
  2522. *
  2523. * Return Value:
  2524. *
  2525. * GpStatus - Ok or failure status
  2526. *
  2527. * Created:
  2528. *
  2529. * 7/11/2000 Tarekms
  2530. *
  2531. \**************************************************************************/
  2532. GpStatus
  2533. MetafileRecorder::RecordDrawDriverString(
  2534. const GpRectF *deviceBounds,
  2535. const UINT16 *text,
  2536. INT glyphCount,
  2537. const GpFont *font,
  2538. const GpBrush *brush,
  2539. const PointF *positions,
  2540. INT flags,
  2541. const GpMatrix *matrix
  2542. )
  2543. {
  2544. // If doing down-level only, then EmfPlusStream will be NULL
  2545. if (EmfPlusStream != NULL)
  2546. {
  2547. ASSERT (text && font && brush && positions);
  2548. if (glyphCount <= 0)
  2549. {
  2550. return InvalidParameter;
  2551. }
  2552. if (IsValid())
  2553. {
  2554. const BYTE * textData = (BYTE *)text;
  2555. const BYTE * positionData = (BYTE *)positions;
  2556. INT sizeText = glyphCount * sizeof(UINT16);
  2557. INT sizePositions = glyphCount * sizeof(PointF);
  2558. INT metaFlags = 0;
  2559. UINT32 metaFontId;
  2560. UINT32 brushValue; // Metafile Brush Id or ARGB value
  2561. UINT32 matrixPresent;
  2562. UINT32 dataSize = sizeof(brushValue) + // brush value
  2563. sizeof(flags) + // API flags
  2564. sizeof(matrixPresent)+ // matix prensences
  2565. sizeof(UINT32) + // glyphCoumt
  2566. sizeText + // Text
  2567. sizePositions; // Positions
  2568. if (matrix == NULL)
  2569. {
  2570. matrixPresent = 0;
  2571. }
  2572. else
  2573. {
  2574. matrixPresent = 1;
  2575. dataSize += GDIP_MATRIX_SIZE;
  2576. }
  2577. EmfPlusRecordType type = EmfPlusRecordTypeDrawDriverString;
  2578. dataSize = (dataSize + 3) & (~3); // align
  2579. RecordObject(font, &metaFontId);
  2580. ASSERT((metaFontId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
  2581. metaFlags |= metaFontId;
  2582. GetBrushValueForRecording(brush, brushValue, metaFlags);
  2583. WriteRecordHeader(dataSize, type, metaFlags, deviceBounds);
  2584. WriteInt32(EmfPlusStream, brushValue);
  2585. WriteInt32(EmfPlusStream, flags);
  2586. WriteInt32(EmfPlusStream, matrixPresent);
  2587. WriteInt32(EmfPlusStream, glyphCount);
  2588. WriteBytes(EmfPlusStream, textData, sizeText);
  2589. WriteBytes(EmfPlusStream, positionData, sizePositions);
  2590. if (matrix != NULL)
  2591. {
  2592. WriteMatrix(EmfPlusStream, *matrix);
  2593. }
  2594. // align
  2595. if ((glyphCount & 0x01) != 0)
  2596. {
  2597. sizeText = 0;
  2598. EmfPlusStream->Write(&sizeText, sizeof(WCHAR), NULL);
  2599. }
  2600. WriteGdiComment(); // is down-level for this record
  2601. if (EmfPlusStream->IsValid())
  2602. {
  2603. return Ok;
  2604. }
  2605. SetValid(FALSE);
  2606. }
  2607. WARNING(("Failed to write DrawDriverString record"));
  2608. return Win32Error;
  2609. }
  2610. return Ok;
  2611. }
  2612. /**************************************************************************\
  2613. *
  2614. * Function Description:
  2615. *
  2616. * IMetafileRecord interface method - RecordSave.
  2617. *
  2618. * Arguments:
  2619. *
  2620. * [IN] gstate - the pushed state (restore to state before this)
  2621. *
  2622. * Return Value:
  2623. *
  2624. * NONE
  2625. *
  2626. * Created:
  2627. *
  2628. * 6/15/1999 DCurtis
  2629. *
  2630. \**************************************************************************/
  2631. GpStatus
  2632. MetafileRecorder::RecordSave(
  2633. INT gstate
  2634. )
  2635. {
  2636. // If doing down-level only, then EmfPlusStream will be NULL
  2637. if (EmfPlusStream != NULL)
  2638. {
  2639. if (IsValid())
  2640. {
  2641. UINT32 dataSize = sizeof(UINT32/* index */);
  2642. EmfPlusRecordType type = EmfPlusRecordTypeSave;
  2643. INT index = SaveRestoreStack.GetCount();
  2644. SaveRestoreStack.Add(gstate);
  2645. WriteRecordHeader(dataSize, type);
  2646. WriteInt32(EmfPlusStream, index);
  2647. // WriteGdiComment(); no down-level for this record
  2648. if (EmfPlusStream->IsValid())
  2649. {
  2650. return Ok;
  2651. }
  2652. SetValid(FALSE);
  2653. }
  2654. WARNING(("Failed to write Save record"));
  2655. return Win32Error;
  2656. }
  2657. return Ok;
  2658. }
  2659. /**************************************************************************\
  2660. *
  2661. * Function Description:
  2662. *
  2663. * IMetafileRecord interface method - RecordRestore.
  2664. *
  2665. * Arguments:
  2666. *
  2667. * [IN] gstate - the pushed state (restore to state before this)
  2668. *
  2669. * Return Value:
  2670. *
  2671. * NONE
  2672. *
  2673. * Created:
  2674. *
  2675. * 6/15/1999 DCurtis
  2676. *
  2677. \**************************************************************************/
  2678. GpStatus
  2679. MetafileRecorder::RecordRestore(
  2680. INT gstate
  2681. )
  2682. {
  2683. // If doing down-level only, then EmfPlusStream will be NULL
  2684. if (EmfPlusStream != NULL)
  2685. {
  2686. if (IsValid())
  2687. {
  2688. INT count = SaveRestoreStack.GetCount();
  2689. INT * stack = SaveRestoreStack.GetDataBuffer();
  2690. if ((count > 0) && (stack != NULL))
  2691. {
  2692. UINT32 dataSize = sizeof(UINT32/* index */);
  2693. EmfPlusRecordType type = EmfPlusRecordTypeRestore;
  2694. do
  2695. {
  2696. if (stack[--count] == gstate)
  2697. {
  2698. SaveRestoreStack.SetCount(count);
  2699. WriteRecordHeader(dataSize, type);
  2700. WriteInt32(EmfPlusStream, count);
  2701. // WriteGdiComment(); no down-level for this record
  2702. if (EmfPlusStream->IsValid())
  2703. {
  2704. return Ok;
  2705. }
  2706. SetValid(FALSE);
  2707. break;
  2708. }
  2709. } while (count > 0);
  2710. }
  2711. }
  2712. WARNING(("Failed to write Restore record"));
  2713. return Win32Error;
  2714. }
  2715. return Ok;
  2716. }
  2717. /**************************************************************************\
  2718. *
  2719. * Function Description:
  2720. *
  2721. * IMetafileRecord interface method - RecordBeginContainer.
  2722. *
  2723. * Arguments:
  2724. *
  2725. * [IN] destRect - rect to draw container inside of
  2726. * [IN] srcRect - maps source size to destRect
  2727. * [IN] srcUnit - units of srcRect
  2728. * [IN] containerState - the pushed state (restore to state before this)
  2729. *
  2730. * Return Value:
  2731. *
  2732. * NONE
  2733. *
  2734. * Created:
  2735. *
  2736. * 6/15/1999 DCurtis
  2737. *
  2738. \**************************************************************************/
  2739. GpStatus
  2740. MetafileRecorder::RecordBeginContainer(
  2741. const GpRectF & destRect,
  2742. const GpRectF & srcRect,
  2743. GpPageUnit srcUnit,
  2744. INT containerState
  2745. )
  2746. {
  2747. // If doing down-level only, then EmfPlusStream will be NULL
  2748. if (EmfPlusStream != NULL)
  2749. {
  2750. if (IsValid())
  2751. {
  2752. UINT32 dataSize = GDIP_RECTF_SIZE /* destRect */ +
  2753. GDIP_RECTF_SIZE /* srcRect */ +
  2754. sizeof(UINT32/* index */);
  2755. EmfPlusRecordType type = EmfPlusRecordTypeBeginContainer;
  2756. INT index = SaveRestoreStack.GetCount();
  2757. INT flags = srcUnit;
  2758. ASSERT((flags & (~GDIP_EPRFLAGS_PAGEUNIT)) == 0);
  2759. if (index >= MaxStackSize)
  2760. {
  2761. MaxStackSize = index + 1;
  2762. }
  2763. SaveRestoreStack.Add(containerState);
  2764. WriteRecordHeader(dataSize, type, flags);
  2765. WriteRect(EmfPlusStream, destRect);
  2766. WriteRect(EmfPlusStream, srcRect);
  2767. WriteInt32(EmfPlusStream, index);
  2768. // WriteGdiComment(); no down-level for this record
  2769. if (EmfPlusStream->IsValid())
  2770. {
  2771. return Ok;
  2772. }
  2773. SetValid(FALSE);
  2774. }
  2775. WARNING(("Failed to write BeginContainer record"));
  2776. return Win32Error;
  2777. }
  2778. return Ok;
  2779. }
  2780. /**************************************************************************\
  2781. *
  2782. * Function Description:
  2783. *
  2784. * IMetafileRecord interface method - RecordBeginContainer.
  2785. *
  2786. * Arguments:
  2787. *
  2788. * [IN] containerState - the pushed state (restore to state before this)
  2789. *
  2790. * Return Value:
  2791. *
  2792. * NONE
  2793. *
  2794. * Created:
  2795. *
  2796. * 6/15/1999 DCurtis
  2797. *
  2798. \**************************************************************************/
  2799. GpStatus
  2800. MetafileRecorder::RecordBeginContainer(
  2801. INT containerState
  2802. )
  2803. {
  2804. // If doing down-level only, then EmfPlusStream will be NULL
  2805. if (EmfPlusStream != NULL)
  2806. {
  2807. if (IsValid())
  2808. {
  2809. UINT32 dataSize = sizeof(UINT32/* index */);
  2810. EmfPlusRecordType type = EmfPlusRecordTypeBeginContainerNoParams;
  2811. INT index = SaveRestoreStack.GetCount();
  2812. INT flags = 0;
  2813. if (index >= MaxStackSize)
  2814. {
  2815. MaxStackSize = index + 1;
  2816. }
  2817. SaveRestoreStack.Add(containerState);
  2818. WriteRecordHeader(dataSize, type, flags);
  2819. WriteInt32(EmfPlusStream, index);
  2820. // WriteGdiComment(); no down-level for this record
  2821. if (EmfPlusStream->IsValid())
  2822. {
  2823. return Ok;
  2824. }
  2825. SetValid(FALSE);
  2826. }
  2827. WARNING(("Failed to write BeginContainer record"));
  2828. return Win32Error;
  2829. }
  2830. return Ok;
  2831. }
  2832. /**************************************************************************\
  2833. *
  2834. * Function Description:
  2835. *
  2836. * IMetafileRecord interface method - RecordEndContainer.
  2837. *
  2838. * Arguments:
  2839. *
  2840. * [IN] containerState - the pushed state (restore to state before this)
  2841. *
  2842. * Return Value:
  2843. *
  2844. * NONE
  2845. *
  2846. * Created:
  2847. *
  2848. * 6/15/1999 DCurtis
  2849. *
  2850. \**************************************************************************/
  2851. GpStatus
  2852. MetafileRecorder::RecordEndContainer(
  2853. INT containerState
  2854. )
  2855. {
  2856. // If doing down-level only, then EmfPlusStream will be NULL
  2857. if (EmfPlusStream != NULL)
  2858. {
  2859. if (IsValid())
  2860. {
  2861. INT count = SaveRestoreStack.GetCount();
  2862. INT * stack = SaveRestoreStack.GetDataBuffer();
  2863. if ((count > 0) && (stack != NULL))
  2864. {
  2865. UINT32 dataSize = sizeof(UINT32/* index */);
  2866. EmfPlusRecordType type = EmfPlusRecordTypeEndContainer;
  2867. do
  2868. {
  2869. if (stack[--count] == containerState)
  2870. {
  2871. SaveRestoreStack.SetCount(count);
  2872. WriteRecordHeader(dataSize, type);
  2873. WriteInt32(EmfPlusStream, count);
  2874. // WriteGdiComment(); no down-level for this record
  2875. if (EmfPlusStream->IsValid())
  2876. {
  2877. return Ok;
  2878. }
  2879. SetValid(FALSE);
  2880. break;
  2881. }
  2882. } while (count > 0);
  2883. }
  2884. }
  2885. WARNING(("Failed to write EndContainer record"));
  2886. return Win32Error;
  2887. }
  2888. return Ok;
  2889. }
  2890. /**************************************************************************\
  2891. *
  2892. * Function Description:
  2893. *
  2894. * IMetafileRecord interface method - RecordSetWorldTransform.
  2895. *
  2896. * Arguments:
  2897. *
  2898. * [IN] matrix - matrix to set in graphics
  2899. *
  2900. * Return Value:
  2901. *
  2902. * GpStatus - Ok or failure status
  2903. *
  2904. * Created:
  2905. *
  2906. * 6/15/1999 DCurtis
  2907. *
  2908. \**************************************************************************/
  2909. GpStatus
  2910. MetafileRecorder::RecordSetWorldTransform(
  2911. const GpMatrix & matrix
  2912. )
  2913. {
  2914. // If doing down-level only, then EmfPlusStream will be NULL
  2915. if (EmfPlusStream != NULL)
  2916. {
  2917. if (IsValid())
  2918. {
  2919. UINT32 dataSize = GDIP_MATRIX_SIZE;
  2920. EmfPlusRecordType type = EmfPlusRecordTypeSetWorldTransform;
  2921. WriteRecordHeader(dataSize, type);
  2922. WriteMatrix(EmfPlusStream, matrix);
  2923. // WriteGdiComment(); no down-level for this record
  2924. if (EmfPlusStream->IsValid())
  2925. {
  2926. return Ok;
  2927. }
  2928. SetValid(FALSE);
  2929. }
  2930. WARNING(("Failed to write SetWorldTransform record"));
  2931. return Win32Error;
  2932. }
  2933. return Ok;
  2934. }
  2935. /**************************************************************************\
  2936. *
  2937. * Function Description:
  2938. *
  2939. * IMetafileRecord interface method - RecordResetWorldTransform.
  2940. *
  2941. * Arguments:
  2942. *
  2943. * NONE
  2944. *
  2945. * Return Value:
  2946. *
  2947. * GpStatus - Ok or failure status
  2948. *
  2949. * Created:
  2950. *
  2951. * 6/15/1999 DCurtis
  2952. *
  2953. \**************************************************************************/
  2954. GpStatus
  2955. MetafileRecorder::RecordResetWorldTransform()
  2956. {
  2957. return RecordZeroDataRecord(EmfPlusRecordTypeResetWorldTransform, 0);
  2958. }
  2959. /**************************************************************************\
  2960. *
  2961. * Function Description:
  2962. *
  2963. * IMetafileRecord interface method - RecordMultiplyWorldTransform.
  2964. *
  2965. * Arguments:
  2966. *
  2967. * [IN] matrix - matrix to set in graphics
  2968. * [IN] order - Append or Prepend
  2969. *
  2970. * Return Value:
  2971. *
  2972. * GpStatus - Ok or failure status
  2973. *
  2974. * Created:
  2975. *
  2976. * 6/15/1999 DCurtis
  2977. *
  2978. \**************************************************************************/
  2979. GpStatus
  2980. MetafileRecorder::RecordMultiplyWorldTransform(
  2981. const GpMatrix & matrix,
  2982. GpMatrixOrder order
  2983. )
  2984. {
  2985. // If doing down-level only, then EmfPlusStream will be NULL
  2986. if (EmfPlusStream != NULL)
  2987. {
  2988. if (IsValid())
  2989. {
  2990. UINT32 dataSize = GDIP_MATRIX_SIZE;
  2991. EmfPlusRecordType type = EmfPlusRecordTypeMultiplyWorldTransform;
  2992. INT flags = 0;
  2993. if (order == MatrixOrderAppend)
  2994. {
  2995. flags |= GDIP_EPRFLAGS_APPEND;
  2996. }
  2997. WriteRecordHeader(dataSize, type, flags);
  2998. WriteMatrix(EmfPlusStream, matrix);
  2999. // WriteGdiComment(); no down-level for this record
  3000. if (EmfPlusStream->IsValid())
  3001. {
  3002. return Ok;
  3003. }
  3004. SetValid(FALSE);
  3005. }
  3006. WARNING(("Failed to write MultiplyWorldTransform record"));
  3007. return Win32Error;
  3008. }
  3009. return Ok;
  3010. }
  3011. /**************************************************************************\
  3012. *
  3013. * Function Description:
  3014. *
  3015. * IMetafileRecord interface method - RecordTranslateWorldTransform.
  3016. *
  3017. * Arguments:
  3018. *
  3019. * [IN] dx - x translation
  3020. * [IN] dy - y translation
  3021. * [IN] order - Append or Prepend
  3022. *
  3023. * Return Value:
  3024. *
  3025. * GpStatus - Ok or failure status
  3026. *
  3027. * Created:
  3028. *
  3029. * 6/15/1999 DCurtis
  3030. *
  3031. \**************************************************************************/
  3032. GpStatus
  3033. MetafileRecorder::RecordTranslateWorldTransform(
  3034. REAL dx,
  3035. REAL dy,
  3036. GpMatrixOrder order
  3037. )
  3038. {
  3039. // If doing down-level only, then EmfPlusStream will be NULL
  3040. if (EmfPlusStream != NULL)
  3041. {
  3042. if (IsValid())
  3043. {
  3044. UINT32 dataSize = sizeof(dx) + sizeof(dy);
  3045. EmfPlusRecordType type = EmfPlusRecordTypeTranslateWorldTransform;
  3046. INT flags = 0;
  3047. if (order == MatrixOrderAppend)
  3048. {
  3049. flags |= GDIP_EPRFLAGS_APPEND;
  3050. }
  3051. WriteRecordHeader(dataSize, type, flags);
  3052. WriteReal(EmfPlusStream, dx);
  3053. WriteReal(EmfPlusStream, dy);
  3054. // WriteGdiComment(); no down-level for this record
  3055. if (EmfPlusStream->IsValid())
  3056. {
  3057. return Ok;
  3058. }
  3059. SetValid(FALSE);
  3060. }
  3061. WARNING(("Failed to write TranslateWorldTransform record"));
  3062. return Win32Error;
  3063. }
  3064. return Ok;
  3065. }
  3066. /**************************************************************************\
  3067. *
  3068. * Function Description:
  3069. *
  3070. * IMetafileRecord interface method - RecordScaleWorldTransform.
  3071. *
  3072. * Arguments:
  3073. *
  3074. * [IN] sx - x scale
  3075. * [IN] sy - y scale
  3076. * [IN] order - Append or Prepend
  3077. *
  3078. * Return Value:
  3079. *
  3080. * GpStatus - Ok or failure status
  3081. *
  3082. * Created:
  3083. *
  3084. * 6/15/1999 DCurtis
  3085. *
  3086. \**************************************************************************/
  3087. GpStatus
  3088. MetafileRecorder::RecordScaleWorldTransform(
  3089. REAL sx,
  3090. REAL sy,
  3091. GpMatrixOrder order
  3092. )
  3093. {
  3094. // If doing down-level only, then EmfPlusStream will be NULL
  3095. if (EmfPlusStream != NULL)
  3096. {
  3097. if (IsValid())
  3098. {
  3099. UINT32 dataSize = sizeof(sx) + sizeof(sy);
  3100. EmfPlusRecordType type = EmfPlusRecordTypeScaleWorldTransform;
  3101. INT flags = 0;
  3102. if (order == MatrixOrderAppend)
  3103. {
  3104. flags |= GDIP_EPRFLAGS_APPEND;
  3105. }
  3106. WriteRecordHeader(dataSize, type, flags);
  3107. WriteReal(EmfPlusStream, sx);
  3108. WriteReal(EmfPlusStream, sy);
  3109. // WriteGdiComment(); no down-level for this record
  3110. if (EmfPlusStream->IsValid())
  3111. {
  3112. return Ok;
  3113. }
  3114. SetValid(FALSE);
  3115. }
  3116. WARNING(("Failed to write ScaleWorldTransform record"));
  3117. return Win32Error;
  3118. }
  3119. return Ok;
  3120. }
  3121. /**************************************************************************\
  3122. *
  3123. * Function Description:
  3124. *
  3125. * IMetafileRecord interface method - RecordRotateWorldTransform.
  3126. *
  3127. * Arguments:
  3128. *
  3129. * [IN] angle - rotation angle
  3130. * [IN] order - Append or Prepend
  3131. *
  3132. * Return Value:
  3133. *
  3134. * GpStatus - Ok or failure status
  3135. *
  3136. * Created:
  3137. *
  3138. * 6/15/1999 DCurtis
  3139. *
  3140. \**************************************************************************/
  3141. GpStatus
  3142. MetafileRecorder::RecordRotateWorldTransform(
  3143. REAL angle,
  3144. GpMatrixOrder order
  3145. )
  3146. {
  3147. // If doing down-level only, then EmfPlusStream will be NULL
  3148. if (EmfPlusStream != NULL)
  3149. {
  3150. if (IsValid())
  3151. {
  3152. UINT32 dataSize = sizeof(angle);
  3153. EmfPlusRecordType type = EmfPlusRecordTypeRotateWorldTransform;
  3154. INT flags = 0;
  3155. if (order == MatrixOrderAppend)
  3156. {
  3157. flags |= GDIP_EPRFLAGS_APPEND;
  3158. }
  3159. WriteRecordHeader(dataSize, type, flags);
  3160. WriteReal(EmfPlusStream, angle);
  3161. // WriteGdiComment(); no down-level for this record
  3162. if (EmfPlusStream->IsValid())
  3163. {
  3164. return Ok;
  3165. }
  3166. SetValid(FALSE);
  3167. }
  3168. WARNING(("Failed to write RotateWorldTransform record"));
  3169. return Win32Error;
  3170. }
  3171. return Ok;
  3172. }
  3173. /**************************************************************************\
  3174. *
  3175. * Function Description:
  3176. *
  3177. * IMetafileRecord interface method - RecordSetPageTransform.
  3178. *
  3179. * Arguments:
  3180. *
  3181. * [IN] unit - units to use
  3182. * [IN] scale - scale factor to apply
  3183. *
  3184. * Return Value:
  3185. *
  3186. * GpStatus - Ok or failure status
  3187. *
  3188. * Created:
  3189. *
  3190. * 6/15/1999 DCurtis
  3191. *
  3192. \**************************************************************************/
  3193. GpStatus
  3194. MetafileRecorder::RecordSetPageTransform(
  3195. GpPageUnit unit,
  3196. REAL scale
  3197. )
  3198. {
  3199. // If doing down-level only, then EmfPlusStream will be NULL
  3200. if (EmfPlusStream != NULL)
  3201. {
  3202. if (IsValid())
  3203. {
  3204. UINT32 dataSize = sizeof(scale);
  3205. EmfPlusRecordType type = EmfPlusRecordTypeSetPageTransform;
  3206. INT flags = unit;
  3207. ASSERT((flags & (~GDIP_EPRFLAGS_PAGEUNIT)) == 0);
  3208. WriteRecordHeader(dataSize, type, flags);
  3209. WriteReal(EmfPlusStream, scale);
  3210. // WriteGdiComment(); no down-level for this record
  3211. if (EmfPlusStream->IsValid())
  3212. {
  3213. return Ok;
  3214. }
  3215. SetValid(FALSE);
  3216. }
  3217. WARNING(("Failed to write SetPageTransform record"));
  3218. return Win32Error;
  3219. }
  3220. return Ok;
  3221. }
  3222. /**************************************************************************\
  3223. *
  3224. * Function Description:
  3225. *
  3226. * IMetafileRecord interface method - RecordResetClip.
  3227. *
  3228. * Arguments:
  3229. *
  3230. * NONE
  3231. *
  3232. * Return Value:
  3233. *
  3234. * GpStatus - Ok or failure status
  3235. *
  3236. * Created:
  3237. *
  3238. * 6/15/1999 DCurtis
  3239. *
  3240. \**************************************************************************/
  3241. GpStatus
  3242. MetafileRecorder::RecordResetClip()
  3243. {
  3244. return RecordZeroDataRecord(EmfPlusRecordTypeResetClip, 0);
  3245. }
  3246. /**************************************************************************\
  3247. *
  3248. * Function Description:
  3249. *
  3250. * IMetafileRecord interface method - RecordSetClip.
  3251. *
  3252. * Arguments:
  3253. *
  3254. * [IN] rect - set clipping to this rect
  3255. * [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
  3256. *
  3257. * Return Value:
  3258. *
  3259. * GpStatus - Ok or failure status
  3260. *
  3261. * Created:
  3262. *
  3263. * 6/15/1999 DCurtis
  3264. *
  3265. \**************************************************************************/
  3266. GpStatus
  3267. MetafileRecorder::RecordSetClip(
  3268. const GpRectF & rect,
  3269. CombineMode combineMode
  3270. )
  3271. {
  3272. // If doing down-level only, then EmfPlusStream will be NULL
  3273. if (EmfPlusStream != NULL)
  3274. {
  3275. if (IsValid())
  3276. {
  3277. UINT32 dataSize = GDIP_RECTF_SIZE;
  3278. EmfPlusRecordType type = EmfPlusRecordTypeSetClipRect;
  3279. INT flags = (combineMode << 8);
  3280. ASSERT((flags & (~GDIP_EPRFLAGS_COMBINEMODE)) == 0);
  3281. WriteRecordHeader(dataSize, type, flags);
  3282. WriteRect(EmfPlusStream, rect);
  3283. // WriteGdiComment(); no down-level for this record
  3284. if (EmfPlusStream->IsValid())
  3285. {
  3286. return Ok;
  3287. }
  3288. SetValid(FALSE);
  3289. }
  3290. WARNING(("Failed to write SetClipRect record"));
  3291. return Win32Error;
  3292. }
  3293. return Ok;
  3294. }
  3295. /**************************************************************************\
  3296. *
  3297. * Function Description:
  3298. *
  3299. * IMetafileRecord interface method - RecordSetClip.
  3300. *
  3301. * Arguments:
  3302. *
  3303. * [IN] region - set clipping to this region
  3304. * [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
  3305. *
  3306. * Return Value:
  3307. *
  3308. * GpStatus - Ok or failure status
  3309. *
  3310. * Created:
  3311. *
  3312. * 6/15/1999 DCurtis
  3313. *
  3314. \**************************************************************************/
  3315. GpStatus
  3316. MetafileRecorder::RecordSetClip(
  3317. GpRegion * region,
  3318. CombineMode combineMode
  3319. )
  3320. {
  3321. // If doing down-level only, then EmfPlusStream will be NULL
  3322. if (EmfPlusStream != NULL)
  3323. {
  3324. if (IsValid())
  3325. {
  3326. UINT32 dataSize = 0;
  3327. EmfPlusRecordType type = EmfPlusRecordTypeSetClipRegion;
  3328. INT flags = (combineMode << 8);
  3329. UINT32 metaRegionId;
  3330. ASSERT((flags & (~GDIP_EPRFLAGS_COMBINEMODE)) == 0);
  3331. RecordObject(region, &metaRegionId);
  3332. ASSERT((metaRegionId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
  3333. flags |= metaRegionId;
  3334. WriteRecordHeader(dataSize, type, flags);
  3335. // WriteGdiComment(); no down-level for this record
  3336. if (EmfPlusStream->IsValid())
  3337. {
  3338. return Ok;
  3339. }
  3340. SetValid(FALSE);
  3341. }
  3342. WARNING(("Failed to write SetClipRegion record"));
  3343. return Win32Error;
  3344. }
  3345. return Ok;
  3346. }
  3347. /**************************************************************************\
  3348. *
  3349. * Function Description:
  3350. *
  3351. * IMetafileRecord interface method - RecordSetClip.
  3352. *
  3353. * Arguments:
  3354. *
  3355. * [IN] path - set clipping to this path
  3356. * [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
  3357. * [IN] isDevicePath- if path is already in device units
  3358. *
  3359. * Return Value:
  3360. *
  3361. * GpStatus - Ok or failure status
  3362. *
  3363. * Created:
  3364. *
  3365. * 6/15/1999 DCurtis
  3366. *
  3367. \**************************************************************************/
  3368. GpStatus
  3369. MetafileRecorder::RecordSetClip(
  3370. GpPath * path,
  3371. CombineMode combineMode,
  3372. BOOL isDevicePath
  3373. )
  3374. {
  3375. // If doing down-level only, then EmfPlusStream will be NULL
  3376. if (EmfPlusStream != NULL)
  3377. {
  3378. if (IsValid())
  3379. {
  3380. UINT32 dataSize = 0;
  3381. EmfPlusRecordType type = EmfPlusRecordTypeSetClipPath;
  3382. INT flags = (combineMode << 8);
  3383. UINT32 metaPathId;
  3384. ASSERT((flags & (~GDIP_EPRFLAGS_COMBINEMODE)) == 0);
  3385. RecordObject(path, &metaPathId);
  3386. ASSERT((metaPathId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
  3387. flags |= metaPathId;
  3388. if (isDevicePath)
  3389. {
  3390. flags |= GDIP_EPRFLAGS_ISDEVICEPATH;
  3391. }
  3392. WriteRecordHeader(dataSize, type, flags);
  3393. // WriteGdiComment(); no down-level for this record
  3394. if (EmfPlusStream->IsValid())
  3395. {
  3396. return Ok;
  3397. }
  3398. SetValid(FALSE);
  3399. }
  3400. WARNING(("Failed to write SetClipPath record"));
  3401. return Win32Error;
  3402. }
  3403. return Ok;
  3404. }
  3405. /**************************************************************************\
  3406. *
  3407. * Function Description:
  3408. *
  3409. * IMetafileRecord interface method - RecordOffsetClip.
  3410. *
  3411. * Arguments:
  3412. *
  3413. * [IN] dx - x translation amount
  3414. * [IN] dy - y translation amount
  3415. *
  3416. * Return Value:
  3417. *
  3418. * GpStatus - Ok or failure status
  3419. *
  3420. * Created:
  3421. *
  3422. * 6/15/1999 DCurtis
  3423. *
  3424. \**************************************************************************/
  3425. GpStatus
  3426. MetafileRecorder::RecordOffsetClip(
  3427. REAL dx,
  3428. REAL dy
  3429. )
  3430. {
  3431. // If doing down-level only, then EmfPlusStream will be NULL
  3432. if (EmfPlusStream != NULL)
  3433. {
  3434. if (IsValid())
  3435. {
  3436. UINT32 dataSize = sizeof(dx) + sizeof(dy);
  3437. EmfPlusRecordType type = EmfPlusRecordTypeOffsetClip;
  3438. WriteRecordHeader(dataSize, type);
  3439. WriteReal(EmfPlusStream, dx);
  3440. WriteReal(EmfPlusStream, dy);
  3441. // WriteGdiComment(); no down-level for this record
  3442. if (EmfPlusStream->IsValid())
  3443. {
  3444. return Ok;
  3445. }
  3446. SetValid(FALSE);
  3447. }
  3448. WARNING(("Failed to write OffsetClip record"));
  3449. return Win32Error;
  3450. }
  3451. return Ok;
  3452. }
  3453. /**************************************************************************\
  3454. *
  3455. * Function Description:
  3456. *
  3457. * IMetafileRecord interface method - RecordGetDC.
  3458. *
  3459. * Arguments:
  3460. *
  3461. * NONE
  3462. *
  3463. * Return Value:
  3464. *
  3465. * NONE
  3466. *
  3467. * Created:
  3468. *
  3469. * 6/15/1999 DCurtis
  3470. *
  3471. \**************************************************************************/
  3472. GpStatus
  3473. MetafileRecorder::RecordGetDC()
  3474. {
  3475. // If doing down-level only, then EmfPlusStream will be NULL
  3476. if (EmfPlusStream != NULL)
  3477. {
  3478. GpStatus status = RecordZeroDataRecord(EmfPlusRecordTypeGetDC, 0);
  3479. // WriteGdiComment(); // is down-level for this record
  3480. // WriteGdiComment will only flush if writing EMF+ dual,
  3481. // but for EMF+-only, we also have to flush GetDC records!
  3482. EmfPlusStream->Flush();
  3483. return status;
  3484. }
  3485. return Ok;
  3486. }
  3487. // Write a record with no data besides the EMF+ record header
  3488. GpStatus
  3489. MetafileRecorder::RecordZeroDataRecord(
  3490. EmfPlusRecordType type,
  3491. INT flags
  3492. )
  3493. {
  3494. // If doing down-level only, then EmfPlusStream will be NULL
  3495. if (EmfPlusStream != NULL)
  3496. {
  3497. if (IsValid())
  3498. {
  3499. UINT32 dataSize = 0;
  3500. WriteRecordHeader(dataSize, type, flags);
  3501. // WriteGdiComment(); no down-level for this record
  3502. if (EmfPlusStream->IsValid())
  3503. {
  3504. return Ok;
  3505. }
  3506. SetValid(FALSE);
  3507. }
  3508. WARNING(("Failed to write record"));
  3509. return Win32Error;
  3510. }
  3511. return Ok;
  3512. }
  3513. /**************************************************************************\
  3514. *
  3515. * Function Description:
  3516. *
  3517. * IMetafileRecord interface method - RecordSetAntiAliasMode.
  3518. *
  3519. * Arguments:
  3520. *
  3521. * [IN] newMode - new anti aliasing mode
  3522. *
  3523. * Return Value:
  3524. *
  3525. * NONE
  3526. *
  3527. * Created:
  3528. *
  3529. * 6/15/1999 DCurtis
  3530. *
  3531. \**************************************************************************/
  3532. GpStatus
  3533. MetafileRecorder::RecordSetAntiAliasMode(
  3534. BOOL newMode
  3535. )
  3536. {
  3537. return RecordZeroDataRecord(EmfPlusRecordTypeSetAntiAliasMode,
  3538. newMode ? GDIP_EPRFLAGS_ANTIALIAS : 0);
  3539. }
  3540. /**************************************************************************\
  3541. *
  3542. * Function Description:
  3543. *
  3544. * IMetafileRecord interface method - RecordSetTextRenderingHint.
  3545. *
  3546. * Arguments:
  3547. *
  3548. * [IN] newMode - new rendering hint
  3549. *
  3550. * Return Value:
  3551. *
  3552. * NONE
  3553. *
  3554. * Created:
  3555. *
  3556. *
  3557. \**************************************************************************/
  3558. GpStatus
  3559. MetafileRecorder::RecordSetTextRenderingHint(
  3560. TextRenderingHint newMode
  3561. )
  3562. {
  3563. ASSERT ((newMode & (~GDIP_EPRFLAGS_TEXTRENDERINGHINT)) == 0);
  3564. return RecordZeroDataRecord(EmfPlusRecordTypeSetTextRenderingHint, newMode);
  3565. }
  3566. /**************************************************************************\
  3567. *
  3568. * Function Description:
  3569. *
  3570. * IMetafileRecord interface method - RecordSetTextContrast.
  3571. *
  3572. * Arguments:
  3573. *
  3574. * [IN] gammaValue - new contrast value
  3575. *
  3576. * Return Value:
  3577. *
  3578. * NONE
  3579. *
  3580. * Created:
  3581. *
  3582. *
  3583. \**************************************************************************/
  3584. GpStatus
  3585. MetafileRecorder::RecordSetTextContrast(
  3586. UINT contrast
  3587. )
  3588. {
  3589. ASSERT ((contrast & (~GDIP_EPRFLAGS_CONTRAST)) == 0);
  3590. return RecordZeroDataRecord(EmfPlusRecordTypeSetTextContrast, contrast);
  3591. }
  3592. /**************************************************************************\
  3593. *
  3594. * Function Description:
  3595. *
  3596. * IMetafileRecord interface method - RecordSetInterpolationMode.
  3597. *
  3598. * Arguments:
  3599. *
  3600. * [IN] newMode - new interpolation mode
  3601. *
  3602. * Return Value:
  3603. *
  3604. * NONE
  3605. *
  3606. * Created:
  3607. *
  3608. * 5/1/2000 DCurtis
  3609. *
  3610. \**************************************************************************/
  3611. GpStatus
  3612. MetafileRecorder::RecordSetInterpolationMode(
  3613. InterpolationMode newMode
  3614. )
  3615. {
  3616. ASSERT ((newMode & (~GDIP_EPRFLAGS_INTERPOLATIONMODE)) == 0);
  3617. return RecordZeroDataRecord(EmfPlusRecordTypeSetInterpolationMode, newMode);
  3618. }
  3619. /**************************************************************************\
  3620. *
  3621. * Function Description:
  3622. *
  3623. * IMetafileRecord interface method - RecordSetPixelOffsetMode.
  3624. *
  3625. * Arguments:
  3626. *
  3627. * [IN] newMode - new pixel offset mode
  3628. *
  3629. * Return Value:
  3630. *
  3631. * NONE
  3632. *
  3633. * Created:
  3634. *
  3635. * 5/1/2000 DCurtis
  3636. *
  3637. \**************************************************************************/
  3638. GpStatus
  3639. MetafileRecorder::RecordSetPixelOffsetMode(
  3640. PixelOffsetMode newMode
  3641. )
  3642. {
  3643. ASSERT ((newMode & (~GDIP_EPRFLAGS_PIXELOFFSETMODE)) == 0);
  3644. return RecordZeroDataRecord(EmfPlusRecordTypeSetPixelOffsetMode, newMode);
  3645. }
  3646. /**************************************************************************\
  3647. *
  3648. * Function Description:
  3649. *
  3650. * IMetafileRecord interface method - RecordSetRenderingOrigin.
  3651. *
  3652. * Arguments:
  3653. *
  3654. * [IN] x, y - new rendering origin
  3655. *
  3656. * Return Value:
  3657. *
  3658. * NONE
  3659. *
  3660. * Created:
  3661. *
  3662. * 5/4/2000 asecchia
  3663. *
  3664. \**************************************************************************/
  3665. GpStatus
  3666. MetafileRecorder::RecordSetRenderingOrigin(
  3667. INT x,
  3668. INT y
  3669. )
  3670. {
  3671. // If doing down-level only, then EmfPlusStream will be NULL
  3672. if (EmfPlusStream != NULL)
  3673. {
  3674. if (IsValid())
  3675. {
  3676. UINT32 dataSize = sizeof(x) + sizeof(y);
  3677. EmfPlusRecordType type = EmfPlusRecordTypeSetRenderingOrigin;
  3678. WriteRecordHeader(dataSize, type);
  3679. WriteInt32(EmfPlusStream, x);
  3680. WriteInt32(EmfPlusStream, y);
  3681. if (EmfPlusStream->IsValid())
  3682. {
  3683. return Ok;
  3684. }
  3685. SetValid(FALSE);
  3686. }
  3687. WARNING(("Failed to write SetRenderingOrigin record"));
  3688. return Win32Error;
  3689. }
  3690. return Ok;
  3691. }
  3692. /**************************************************************************\
  3693. *
  3694. * Function Description:
  3695. *
  3696. * IMetafileRecord interface method - RecordSetCompositingMode.
  3697. *
  3698. * Arguments:
  3699. *
  3700. * [IN] newMode - new compositing mode
  3701. *
  3702. * Return Value:
  3703. *
  3704. * NONE
  3705. *
  3706. * Created:
  3707. *
  3708. * 10/11/1999 AGodfrey
  3709. *
  3710. \**************************************************************************/
  3711. GpStatus
  3712. MetafileRecorder::RecordSetCompositingMode(
  3713. GpCompositingMode newMode
  3714. )
  3715. {
  3716. ASSERT ((newMode & (~GDIP_EPRFLAGS_COMPOSITINGMODE)) == 0);
  3717. return RecordZeroDataRecord(EmfPlusRecordTypeSetCompositingMode, newMode);
  3718. }
  3719. /**************************************************************************\
  3720. *
  3721. * Function Description:
  3722. *
  3723. * IMetafileRecord interface method - RecordSetCompositingQuality.
  3724. *
  3725. * Arguments:
  3726. *
  3727. * [IN] newQuality - new quality setting
  3728. *
  3729. * Return Value:
  3730. *
  3731. * NONE
  3732. *
  3733. * Created:
  3734. *
  3735. * 04/22/2000 AGodfrey
  3736. *
  3737. \**************************************************************************/
  3738. GpStatus
  3739. MetafileRecorder::RecordSetCompositingQuality(
  3740. GpCompositingQuality newQuality
  3741. )
  3742. {
  3743. ASSERT ((newQuality & (~GDIP_EPRFLAGS_COMPOSITINGQUALITY)) == 0);
  3744. return RecordZeroDataRecord(EmfPlusRecordTypeSetCompositingQuality, newQuality);
  3745. }
  3746. /**************************************************************************\
  3747. *
  3748. * Function Description:
  3749. *
  3750. * IMetafileRecord interface method - RecordComment.
  3751. *
  3752. * Arguments:
  3753. *
  3754. * [IN] sizeData - number of bytes of data
  3755. * [IN] data - pointer to the data
  3756. *
  3757. * Return Value:
  3758. *
  3759. * GpStatus - Ok or failure status
  3760. *
  3761. * Created:
  3762. *
  3763. * 6/29/1999 DCurtis
  3764. *
  3765. \**************************************************************************/
  3766. GpStatus
  3767. MetafileRecorder::RecordComment(
  3768. UINT sizeData,
  3769. const BYTE * data
  3770. )
  3771. {
  3772. if (IsValid() && (sizeData > 0) && (data != NULL))
  3773. {
  3774. // If doing down-level only, then EmfPlusStream will be NULL
  3775. if (EmfPlusStream != NULL)
  3776. {
  3777. UINT32 dataSize = (sizeData + 3) & (~3);
  3778. EmfPlusRecordType type = EmfPlusRecordTypeComment;
  3779. INT pad = dataSize - sizeData;
  3780. INT flags = pad;
  3781. WriteRecordHeader(dataSize, type, flags);
  3782. WriteBytes(EmfPlusStream, data, sizeData);
  3783. while(pad--)
  3784. {
  3785. WriteByte(EmfPlusStream, 0);
  3786. }
  3787. // WriteGdiComment(); no down-level for this record
  3788. if (EmfPlusStream->IsValid())
  3789. {
  3790. return Ok;
  3791. }
  3792. SetValid(FALSE);
  3793. }
  3794. else if (Type == EmfTypeEmfOnly)
  3795. {
  3796. GdiComment(MetafileHdc, sizeData, data);
  3797. return Ok;
  3798. }
  3799. }
  3800. WARNING(("Failed to write Comment record"));
  3801. return GenericError;
  3802. }
  3803. GpStatus
  3804. MetafileRecorder::RecordHeader(
  3805. INT logicalDpiX,
  3806. INT logicalDpiY,
  3807. INT emfPlusFlags
  3808. )
  3809. {
  3810. // Don't need to check for EmfPlusStream or Valid
  3811. UINT32 dataSize = sizeof(EmfPlusHeaderRecord);
  3812. EmfPlusRecordType type = EmfPlusRecordTypeHeader;
  3813. INT flags = 0;
  3814. if (Type != EmfTypeEmfPlusOnly)
  3815. {
  3816. flags |= GDIP_EPRFLAGS_EMFPLUSDUAL;
  3817. }
  3818. EmfPlusHeaderRecord emfPlusHeader(emfPlusFlags, logicalDpiX, logicalDpiY);
  3819. WriteRecordHeader(dataSize, type, flags);
  3820. WriteBytes(EmfPlusStream, &emfPlusHeader, sizeof(emfPlusHeader));
  3821. // We have to flush the EMF+ header immediately to guarantee that it
  3822. // is the first record in the EMF after the EMF header. Otherwise,
  3823. // CloneColorAdjusted fails, because immediately after the metafile
  3824. // constructor, it calls Play into the new metafile which writes a
  3825. // SaveDC record into the metafile.
  3826. EmfPlusStream->Flush();
  3827. if (EmfPlusStream->IsValid())
  3828. {
  3829. return Ok;
  3830. }
  3831. SetValid(FALSE);
  3832. WARNING(("Failed to write Metafile Header record"));
  3833. return Win32Error;
  3834. }
  3835. VOID
  3836. MetafileRecorder::RecordEndOfFile()
  3837. {
  3838. RecordZeroDataRecord(EmfPlusRecordTypeEndOfFile, 0);
  3839. }
  3840. extern "C"
  3841. int CALLBACK
  3842. EnumEmfToStream(
  3843. HDC hdc,
  3844. HANDLETABLE FAR * gdiHandleTable,
  3845. CONST ENHMETARECORD * emfRecord,
  3846. int numHandles,
  3847. LPARAM stream
  3848. );
  3849. /**************************************************************************\
  3850. *
  3851. * Function Description:
  3852. *
  3853. * IMetafileRecord interface method - EndRecording.
  3854. *
  3855. * Arguments:
  3856. *
  3857. * NONE
  3858. *
  3859. * Return Value:
  3860. *
  3861. * NONE
  3862. *
  3863. * Created:
  3864. *
  3865. * 6/15/1999 DCurtis
  3866. *
  3867. \**************************************************************************/
  3868. VOID
  3869. MetafileRecorder::EndRecording()
  3870. {
  3871. GpMetafile::MetafileState state = GpMetafile::InvalidMetafileState;
  3872. if (IsValid() && (Metafile->State == GpMetafile::RecordingMetafileState))
  3873. {
  3874. INT success = 1; // assume success
  3875. // If doing down-level only, then EmfPlusStream will be NULL
  3876. if (EmfPlusStream != NULL)
  3877. {
  3878. // Force a flush of the Stream buffer to the EMF+ file
  3879. EmfPlusStream->Flush();
  3880. // We put a no-op PatBlt into the metafile to guarantee that
  3881. // the header of the metafile has the same size bounds and
  3882. // frame rect that GDI+ has recorded so that the EMF will
  3883. // play back the same way, whether GDI plays it back or we do.
  3884. // Otherwise, this may not be the case. For example, on a
  3885. // bezier curve, the GDI+ bounds would include the control
  3886. // points, whereas the down-level representation may not.
  3887. // If we haven't written any records to the file, then XMinDevice
  3888. // and other bounds are still initialized at FLT_MAX and can cause
  3889. // an exception. We don't need the empty PatBlt record in that case
  3890. // because we haven't written anything.
  3891. if (BoundsInit != FALSE)
  3892. {
  3893. // Try to match the GDI+ rasterizer
  3894. INT left = RasterizerCeiling(XMinDevice);
  3895. INT top = RasterizerCeiling(YMinDevice);
  3896. INT right = RasterizerCeiling(XMaxDevice); // exclusive
  3897. INT bottom = RasterizerCeiling(YMaxDevice); // exclusive
  3898. // to get the inclusive right and bottom, we'd now
  3899. // have to subtract 1 from each of them
  3900. if ((right > left) && (bottom > top))
  3901. {
  3902. Metafile->MetaGraphics->NoOpPatBlt(left, top, right - left, bottom - top);
  3903. }
  3904. }
  3905. // must be the last record in the file, except the EMF EOF record
  3906. RecordEndOfFile();
  3907. EmfPlusStream->Flush();
  3908. }
  3909. HENHMETAFILE hEmf = CloseEnhMetaFile(MetafileHdc);
  3910. if (hEmf == NULL)
  3911. {
  3912. goto Done;
  3913. }
  3914. // Get the EMF header
  3915. ENHMETAHEADER3 emfHeader;
  3916. if ((GetEnhMetaFileHeader(hEmf, sizeof(emfHeader),
  3917. (ENHMETAHEADER*)(&emfHeader)) <= 0) ||
  3918. !EmfHeaderIsValid(emfHeader))
  3919. {
  3920. DeleteEnhMetaFile(hEmf);
  3921. goto Done;
  3922. }
  3923. #if DBG
  3924. if ((emfHeader.rclBounds.right == -1) &&
  3925. (emfHeader.rclBounds.bottom == -1) &&
  3926. (emfHeader.rclBounds.left == 0) &&
  3927. (emfHeader.rclBounds.top == 0))
  3928. {
  3929. WARNING1("Empty metafile -- no drawing records");
  3930. }
  3931. #endif
  3932. MetafileHeader * header = &Metafile->Header;
  3933. INT32 emfPlusFlags = header->EmfPlusFlags;
  3934. // Save the header and various other info in the Metafile
  3935. Metafile->Hemf = hEmf;
  3936. Metafile->MaxStackSize = MaxStackSize;
  3937. header->EmfPlusFlags = emfPlusFlags;
  3938. header->EmfHeader = emfHeader;
  3939. header->Size = emfHeader.nBytes;
  3940. // Set the bounds in the Metafile header
  3941. {
  3942. REAL multiplierX = header->DpiX / 2540.0f;
  3943. REAL multiplierY = header->DpiY / 2540.0f;
  3944. // The frameRect is inclusive-inclusive, but the bounds in
  3945. // the header is inclusive-exclusive.
  3946. REAL x = (multiplierX * (REAL)(emfHeader.rclFrame.left));
  3947. REAL y = (multiplierY * (REAL)(emfHeader.rclFrame.top));
  3948. REAL w = (multiplierX * (REAL)(emfHeader.rclFrame.right -
  3949. emfHeader.rclFrame.left)) + 1.0f;
  3950. REAL h = (multiplierY * (REAL)(emfHeader.rclFrame.bottom -
  3951. emfHeader.rclFrame.top)) + 1.0f;
  3952. header->X = GpRound(x);
  3953. header->Y = GpRound(y);
  3954. header->Width = GpRound(w);
  3955. header->Height = GpRound(h);
  3956. }
  3957. // The metafile is either supposed to be in memory, in a file,
  3958. // or in a stream.
  3959. // If it goes in a file, we're done unless we need to rewrite
  3960. // any of the header information.
  3961. if (Metafile->Filename != NULL)
  3962. {
  3963. state = GpMetafile::DoneRecordingMetafileState;
  3964. }
  3965. else
  3966. {
  3967. // If it goes in memory, we're done.
  3968. // If it goes in a stream, then we have to write
  3969. // the bits to the stream.
  3970. if (Metafile->Stream != NULL)
  3971. {
  3972. // Write the emf data buffer to the stream,
  3973. // and leave the stream position at the end of the metafile.
  3974. if (!::EnumEnhMetaFile(NULL, hEmf, EnumEmfToStream,
  3975. Metafile->Stream, NULL))
  3976. {
  3977. WARNING(("Problem retrieving EMF Data"));
  3978. DeleteEnhMetaFile(hEmf);
  3979. Metafile->Hemf = NULL;
  3980. goto Done;
  3981. }
  3982. // Don't need the Stream any longer
  3983. Metafile->Stream->Release();
  3984. Metafile->Stream = NULL;
  3985. }
  3986. state = GpMetafile::DoneRecordingMetafileState;
  3987. }
  3988. }
  3989. else
  3990. {
  3991. DeleteEnhMetaFile(CloseEnhMetaFile(MetafileHdc));
  3992. WARNING(("Metafile in wrong state in EndRecording"));
  3993. }
  3994. Done:
  3995. Metafile->MetaGraphics->Metafile = NULL; // Graphics can't point to us anymore
  3996. Metafile->MetaGraphics->SetValid(FALSE); // Don't allow anymore operations on
  3997. // the graphics
  3998. Metafile->MetaGraphics = NULL; // graphics is not valid any more
  3999. Metafile->State = state;
  4000. delete this;
  4001. }
  4002. #if 0
  4003. inline INT
  4004. WriteActualSize(
  4005. IStream * stream,
  4006. LONGLONG & startOfRecord,
  4007. ULONG actualSize
  4008. )
  4009. {
  4010. ASSERT (actualSize > 0);
  4011. // get to size field
  4012. INT success = SeekFromStart(stream, startOfRecord + sizeof(INT32));
  4013. if (success)
  4014. {
  4015. success &= WriteInt32(stream, actualSize);
  4016. }
  4017. // get back to end of record
  4018. success &= SeekFromStart(stream, startOfRecord + actualSize);
  4019. return success;
  4020. }
  4021. #endif
  4022. /**************************************************************************\
  4023. *
  4024. * Function Description:
  4025. *
  4026. * Write an object (pen, brush, image, region, path, font) to metafile by
  4027. * writing its header, calling its serialize method, and then re-writing
  4028. * the size.
  4029. *
  4030. * Arguments:
  4031. *
  4032. * [IN] type - the record type
  4033. * [IN] flags - any flags for the record header
  4034. * [IN] object - pointer to the object to be recorded
  4035. * [IN] metaObjectId - ID to store in file that identifies object
  4036. * [IN] extraData - any extra data to store with object
  4037. * [IN] extraDataSize - size in BYTES of extraData
  4038. *
  4039. * Return Value:
  4040. *
  4041. * INT - 1 if we succeeded, else 0 if we failed
  4042. *
  4043. * Created:
  4044. *
  4045. * 6/15/1999 DCurtis
  4046. *
  4047. \**************************************************************************/
  4048. VOID
  4049. MetafileRecorder::WriteObject(
  4050. ObjectType type,
  4051. const GpObject * object,
  4052. UINT32 metaObjectId
  4053. )
  4054. {
  4055. ULONG objectDataSize = object->GetDataSize();
  4056. INT flags = ((INT)type << 8);
  4057. ASSERT((objectDataSize & 0x03) == 0);
  4058. ASSERT((flags & (~GDIP_EPRFLAGS_OBJECTTYPE)) == 0);
  4059. ASSERT((metaObjectId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
  4060. ASSERT(objectDataSize != 0); // cannot have an empty object
  4061. flags |= metaObjectId;
  4062. WriteRecordHeader(objectDataSize, EmfPlusRecordTypeObject, flags, NULL);
  4063. if (object->GetData(EmfPlusStream) != Ok)
  4064. {
  4065. WARNING(("GetData failed"));
  4066. }
  4067. EmfPlusStream->EndObjectRecord();
  4068. }
  4069. VOID
  4070. MetafileRecorder::RecordObject(
  4071. const GpObject * object,
  4072. UINT32* metaObjectId
  4073. )
  4074. {
  4075. if (object)
  4076. {
  4077. ObjectType type = object->GetObjectType();
  4078. if (ObjectList.IsInList(object, type, metaObjectId))
  4079. {
  4080. ObjectList.UpdateMRU(*metaObjectId);
  4081. }
  4082. else
  4083. {
  4084. ObjectList.InsertAt(object, metaObjectId);
  4085. WriteObject(type, object, *metaObjectId);
  4086. }
  4087. }
  4088. else
  4089. {
  4090. *metaObjectId = GDIP_OBJECTID_NONE;
  4091. }
  4092. }
  4093. // This is for backward compatiblity. If we are using a new object
  4094. // (such as a new kind of brush), then we can record a backup object
  4095. // for down-level apps to use when they see a new object that they
  4096. // don't know how to deal with.
  4097. GpStatus
  4098. MetafileRecorder::RecordBackupObject(
  4099. const GpObject * object
  4100. )
  4101. {
  4102. WriteObject(object->GetObjectType(), object, GDIP_BACKUP_OBJECTID) ;
  4103. return Ok;
  4104. }
  4105. /**************************************************************************\
  4106. *
  4107. * Function Description:
  4108. *
  4109. * Write the initial portion of an EMF+ record. Every EMF+ record contains
  4110. * a size, a type, and some flags. Many also contain a rect that specifies
  4111. * the bounds of a drawing operation in REAL device units.
  4112. *
  4113. * Arguments:
  4114. *
  4115. * [IN] size - the size of the record (excluding the header)
  4116. * [IN] type - the EMF+ record type
  4117. * [IN] flags - any flags that are defined for this record
  4118. * [IN] deviceBounds - bounds of drawing operation, or NULL
  4119. *
  4120. * Return Value:
  4121. *
  4122. * INT - 1 if we succeeded, else 0 if we failed
  4123. *
  4124. * Created:
  4125. *
  4126. * 6/15/1999 DCurtis
  4127. *
  4128. \**************************************************************************/
  4129. VOID
  4130. MetafileRecorder::WriteRecordHeader(
  4131. UINT32 dataSize,
  4132. EmfPlusRecordType type,
  4133. INT flags, // 16 bits of flags
  4134. const GpRectF * deviceBounds
  4135. )
  4136. {
  4137. ASSERT((dataSize & 0x03) == 0);
  4138. EmfPlusStream->WriteRecordHeader(dataSize, type, flags);
  4139. NumRecords++;
  4140. if (deviceBounds != NULL)
  4141. {
  4142. // If the bounds aren't initalized then make sure we have 4 valid
  4143. // coordinates
  4144. ASSERT(BoundsInit ||
  4145. ((deviceBounds->X < XMinDevice) &&
  4146. (deviceBounds->GetRight() > XMaxDevice) &&
  4147. (deviceBounds->Y < YMinDevice) &&
  4148. (deviceBounds->GetBottom() > YMaxDevice)));
  4149. BoundsInit = TRUE;
  4150. // Update the device bounds
  4151. if (deviceBounds->X < XMinDevice)
  4152. {
  4153. XMinDevice = deviceBounds->X;
  4154. }
  4155. if (deviceBounds->GetRight() > XMaxDevice)
  4156. {
  4157. XMaxDevice = deviceBounds->GetRight(); // exclusive
  4158. }
  4159. if (deviceBounds->Y < YMinDevice)
  4160. {
  4161. YMinDevice = deviceBounds->Y;
  4162. }
  4163. if (deviceBounds->GetBottom() > YMaxDevice)
  4164. {
  4165. YMaxDevice = deviceBounds->GetBottom(); // exclusive
  4166. }
  4167. }
  4168. }
  4169. /**************************************************************************\
  4170. *
  4171. * Function Description:
  4172. *
  4173. * If the brush is a 32-bit solid color, then return the solid color as
  4174. * the brush value and set the flags to indicate it's a solid color.
  4175. * Otherwise, record the brush and return the metafile brush id as the
  4176. * brush value.
  4177. *
  4178. * Arguments:
  4179. *
  4180. * [IN] brush - the brush that needs to be recorded
  4181. * [OUT] brushValue - the 32-bit color or metafile brush ID
  4182. * [OUT] flags - set if we're using a solid color
  4183. *
  4184. * Return Value:
  4185. *
  4186. * INT - 1 if we succeeded, else 0 if we failed
  4187. *
  4188. * Created:
  4189. *
  4190. * 6/15/1999 DCurtis
  4191. *
  4192. \**************************************************************************/
  4193. VOID
  4194. MetafileRecorder::GetBrushValueForRecording(
  4195. const GpBrush *brush,
  4196. UINT32 &brushValue,
  4197. INT &flags
  4198. )
  4199. {
  4200. if (brush->GetBrushType() == BrushTypeSolidColor)
  4201. {
  4202. const GpSolidFill * solidBrush = static_cast<const GpSolidFill *>(brush);
  4203. brushValue = solidBrush->GetColor().GetValue();
  4204. flags |= GDIP_EPRFLAGS_SOLIDCOLOR;
  4205. }
  4206. else
  4207. {
  4208. RecordObject(brush, &brushValue);
  4209. }
  4210. }
  4211. /**************************************************************************\
  4212. *
  4213. * Function Description:
  4214. *
  4215. * GpMetafile constructor for write/read access to a metafile. (Write must
  4216. * precede the read.)
  4217. *
  4218. * This version records an EMF+ to memory. The type specifies whether
  4219. * to record dual GDI records or not.
  4220. *
  4221. * If the frameRect is NULL, it will be calculated by accumulating the
  4222. * device bounds of the metafile. Otherwise, the supplied frameRect and
  4223. * corresponding frameUnit will be used to record the frameRect in the
  4224. * metafile header. The frameRect is inclusive-inclusive, which means
  4225. * that the width value is actually 1 less than the actual width.
  4226. * For example, a width of 0 is accepted and really means a width of 1.
  4227. *
  4228. * If the optional description is supplied, it will become part of the
  4229. * EMF header.
  4230. *
  4231. * Arguments:
  4232. *
  4233. * [IN] fileName - where to write the metafile
  4234. * [IN] referenceHdc - an HDC to use as a reference for creating metafile
  4235. * [IN] type - whether to record EMF+-only or EMF+-dual
  4236. * [IN] frameRect - optional frame rect for recording in header
  4237. * [IN] frameUnit - the units of the frameRect
  4238. * [IN] description - optional metafile description
  4239. *
  4240. * Return Value:
  4241. *
  4242. * NONE
  4243. *
  4244. * Created:
  4245. *
  4246. * 6/15/1999 DCurtis
  4247. *
  4248. \**************************************************************************/
  4249. GpMetafile::GpMetafile(
  4250. HDC referenceHdc,
  4251. EmfType type,
  4252. const GpRectF * frameRect, // can be NULL
  4253. MetafileFrameUnit frameUnit, // if NULL frameRect, doesn't matter
  4254. const WCHAR * description // can be NULL
  4255. ) : GpImage(ImageTypeMetafile)
  4256. {
  4257. ASSERT(referenceHdc != NULL);
  4258. InitDefaults();
  4259. if ((referenceHdc != NULL) &&
  4260. InitForRecording(
  4261. referenceHdc,
  4262. type,
  4263. frameRect, // can be NULL
  4264. frameUnit, // if NULL frameRect, doesn't matter
  4265. description // can be NULL
  4266. ))
  4267. {
  4268. State = RecordingMetafileState;
  4269. }
  4270. }
  4271. /**************************************************************************\
  4272. *
  4273. * Function Description:
  4274. *
  4275. * GpMetafile constructor for write/read access to a metafile. (Write must
  4276. * precede the read.)
  4277. *
  4278. * This version records an EMF+ to a file. The type specifies whether
  4279. * to record dual GDI records or not.
  4280. *
  4281. * If the frameRect is NULL, it will be calculated by accumulating the
  4282. * device bounds of the metafile. Otherwise, the supplied frameRect and
  4283. * corresponding frameUnit will be used to record the frameRect in the
  4284. * metafile header. The frameRect is inclusive-inclusive, which means
  4285. * that the width value is actually 1 less than the actual width.
  4286. * For example, a width of 0 is accepted and really means a width of 1.
  4287. *
  4288. * If the optional description is supplied, it will become part of the
  4289. * EMF header.
  4290. *
  4291. * Arguments:
  4292. *
  4293. * [IN] fileName - where to write the metafile
  4294. * [IN] referenceHdc - an HDC to use as a reference for creating metafile
  4295. * [IN] type - whether to record EMF+-only or EMF+-dual
  4296. * [IN] frameRect - optional frame rect for recording in header
  4297. * [IN] frameUnit - the units of the frameRect
  4298. * [IN] description - optional metafile description
  4299. *
  4300. * Return Value:
  4301. *
  4302. * NONE
  4303. *
  4304. * Created:
  4305. *
  4306. * 6/15/1999 DCurtis
  4307. *
  4308. \**************************************************************************/
  4309. GpMetafile::GpMetafile(
  4310. const WCHAR* fileName,
  4311. HDC referenceHdc,
  4312. EmfType type,
  4313. const GpRectF * frameRect, // can be NULL
  4314. MetafileFrameUnit frameUnit, // if NULL frameRect, doesn't matter
  4315. const WCHAR * description // can be NULL
  4316. ) : GpImage(ImageTypeMetafile)
  4317. {
  4318. ASSERT((fileName != NULL) && (referenceHdc != NULL));
  4319. InitDefaults();
  4320. if ((fileName != NULL) && (referenceHdc != NULL) &&
  4321. ((Filename = UnicodeStringDuplicate(fileName)) != NULL) &&
  4322. InitForRecording(
  4323. referenceHdc,
  4324. type,
  4325. frameRect, // can be NULL
  4326. frameUnit, // if NULL frameRect, doesn't matter
  4327. description // can be NULL
  4328. ))
  4329. {
  4330. State = RecordingMetafileState;
  4331. }
  4332. }
  4333. /**************************************************************************\
  4334. *
  4335. * Function Description:
  4336. *
  4337. * GpMetafile constructor for write/read access to a metafile. (Write must
  4338. * precede the read.)
  4339. *
  4340. * This version records an EMF+ to a file. The type specifies whether
  4341. * to record dual GDI records or not.
  4342. *
  4343. * The metafile is first recorded to a temporary file, then it is copied
  4344. * from the file into the stream.
  4345. *
  4346. * If the frameRect is NULL, it will be calculated by accumulating the
  4347. * device bounds of the metafile. Otherwise, the supplied frameRect and
  4348. * corresponding frameUnit will be used to record the frameRect in the
  4349. * metafile header. The frameRect is inclusive-inclusive, which means
  4350. * that the width value is actually 1 less than the actual width.
  4351. * For example, a width of 0 is accepted and really means a width of 1.
  4352. *
  4353. * If the optional description is supplied, it will become part of the
  4354. * EMF header.
  4355. *
  4356. * Arguments:
  4357. *
  4358. * [IN] stream - where to copy the metafile, after it's recorded
  4359. * [IN] referenceHdc - an HDC to use as a reference for creating metafile
  4360. * [IN] type - whether to record EMF+-only or EMF+-dual
  4361. * [IN] frameRect - optional frame rect for recording in header
  4362. * [IN] frameUnit - the units of the frameRect
  4363. * [IN] description - optional metafile description
  4364. *
  4365. * Return Value:
  4366. *
  4367. * NONE
  4368. *
  4369. * Created:
  4370. *
  4371. * 6/15/1999 DCurtis
  4372. *
  4373. \**************************************************************************/
  4374. GpMetafile::GpMetafile(
  4375. IStream * stream,
  4376. HDC referenceHdc,
  4377. EmfType type,
  4378. const GpRectF * frameRect, // can be NULL
  4379. MetafileFrameUnit frameUnit, // if NULL frameRect, doesn't matter
  4380. const WCHAR * description // can be NULL
  4381. ) : GpImage(ImageTypeMetafile)
  4382. {
  4383. ASSERT((stream != NULL) && (referenceHdc != NULL));
  4384. InitDefaults();
  4385. if ((stream != NULL) && (referenceHdc != NULL))
  4386. {
  4387. if (InitForRecording(
  4388. referenceHdc,
  4389. type,
  4390. frameRect, // can be NULL
  4391. frameUnit, // if NULL frameRect, doesn't matter
  4392. description // can be NULL
  4393. ))
  4394. {
  4395. stream->AddRef();
  4396. Stream = stream;
  4397. State = RecordingMetafileState;
  4398. }
  4399. }
  4400. }
  4401. inline HDC CreateEmf(
  4402. HDC referenceHdc,
  4403. const WCHAR * fileName,
  4404. RECT * frameRect
  4405. )
  4406. {
  4407. HDC metafileHdc = NULL;
  4408. if (Globals::IsNt)
  4409. {
  4410. metafileHdc = CreateEnhMetaFileW(referenceHdc, fileName, frameRect, NULL);
  4411. }
  4412. else
  4413. {
  4414. AnsiStrFromUnicode fileBuffer(fileName);
  4415. if (fileBuffer.IsValid())
  4416. {
  4417. metafileHdc = CreateEnhMetaFileA(referenceHdc, fileBuffer, frameRect, NULL);
  4418. }
  4419. }
  4420. return metafileHdc;
  4421. }
  4422. static BOOL
  4423. GetFrameRectInMM100Units(
  4424. HDC hdc,
  4425. const GpRectF * frameRect,
  4426. MetafileFrameUnit frameUnit,
  4427. RECT & rclFrame
  4428. )
  4429. {
  4430. SIZEL szlDevice; // Size of device in pels
  4431. SIZEL szlMillimeters; // Size of device in millimeters
  4432. REAL dpiX;
  4433. REAL dpiY;
  4434. // NOTE: We have to use the szlDevice and szlMillimeters to get
  4435. // the dpi (instead of getting it directly from LOGPIXELSX/Y)
  4436. // so that the frame rect that is calculated for the metafile by GDI
  4437. // matches the one that GDI+ would have calculated. Because it's
  4438. // these 2 metrics that the GDI metafile code uses to get the frame
  4439. // rect from the bounds, not the logical DPI.
  4440. szlDevice.cx = ::GetDeviceCaps(hdc, HORZRES);
  4441. szlDevice.cy = ::GetDeviceCaps(hdc, VERTRES);
  4442. szlMillimeters.cx = ::GetDeviceCaps(hdc, HORZSIZE);
  4443. szlMillimeters.cy = ::GetDeviceCaps(hdc, VERTSIZE);
  4444. if ((szlDevice.cx <= 0) || (szlDevice.cy <= 0) ||
  4445. (szlMillimeters.cx <= 0) || (szlMillimeters.cy <= 0))
  4446. {
  4447. WARNING(("GetDeviceCaps failed"));
  4448. return FALSE;
  4449. }
  4450. // Now get the real DPI, adjusted for the round-off error.
  4451. dpiX = ((REAL)(szlDevice.cx) / (REAL)(szlMillimeters.cx)) * 25.4f;
  4452. dpiY = ((REAL)(szlDevice.cy) / (REAL)(szlMillimeters.cy)) * 25.4f;
  4453. GpRectF frameRectMM100;
  4454. FrameToMM100(frameRect, (GpPageUnit)frameUnit, frameRectMM100,
  4455. dpiX, dpiY);
  4456. rclFrame.left = GpRound(frameRectMM100.X);
  4457. rclFrame.top = GpRound(frameRectMM100.Y);
  4458. rclFrame.right = GpRound(frameRectMM100.GetRight());
  4459. rclFrame.bottom = GpRound(frameRectMM100.GetBottom());
  4460. // Make sure the .01MM frameRect is valid
  4461. // It's okay for left == right, because the frameRect
  4462. // is inclusive-inclusive.
  4463. if ((rclFrame.left > rclFrame.right) ||
  4464. (rclFrame.top > rclFrame.bottom))
  4465. {
  4466. WARNING(("Invalid GDI frameRect"));
  4467. return FALSE;
  4468. }
  4469. return TRUE;
  4470. }
  4471. /**************************************************************************\
  4472. *
  4473. * Function Description:
  4474. *
  4475. * Convert a frameRect in any units, to a frame rect that is in .01 MM units.
  4476. *
  4477. * Arguments:
  4478. *
  4479. * [IN] frameRect - the source frameRect
  4480. * [IN] frameUnit - the units of the source frameRect
  4481. * [OUT] frameRectMM100 - the frameRect in inch units
  4482. * [IN] dpiX - the horizontal DPI
  4483. * [IN] dpiY - the vertical DPI
  4484. *
  4485. * Return Value:
  4486. *
  4487. * NONE
  4488. *
  4489. * Created:
  4490. *
  4491. * 6/15/1999 DCurtis
  4492. *
  4493. \**************************************************************************/
  4494. static VOID
  4495. FrameToMM100(
  4496. const GpRectF * frameRect,
  4497. GpPageUnit frameUnit,
  4498. GpRectF & frameRectMM100,
  4499. REAL dpiX, // only used for pixel case
  4500. REAL dpiY
  4501. )
  4502. {
  4503. REAL pixelsToMM100X = (2540.0f / dpiX);
  4504. REAL pixelsToMM100Y = (2540.0f / dpiY);
  4505. // The GDI frameRect has right and bottom values that are
  4506. // inclusive, whereas the GDI+ frameRect has GetRight() and
  4507. // GetBottom() values that are exclusive (because GDI+ rects
  4508. // are specified with width/height, not right/bottom. To convert
  4509. // from the GDI+ value to the GDI value, we have to subtract 1 pixel.
  4510. // This means that we first convert the units to pixel units, then
  4511. // subtract one, then convert to MM100 units.
  4512. switch (frameUnit)
  4513. {
  4514. default:
  4515. ASSERT(0);
  4516. // FALLTHRU
  4517. case UnitPixel: // Each unit represents one device pixel.
  4518. frameRectMM100.X = frameRect->X * pixelsToMM100X;
  4519. frameRectMM100.Y = frameRect->Y * pixelsToMM100Y;
  4520. frameRectMM100.Width = frameRect->Width;
  4521. frameRectMM100.Height = frameRect->Height;
  4522. break;
  4523. case UnitPoint: // Each unit represents 1/72 inch.
  4524. frameRectMM100.X = frameRect->X * (2540.0f / 72.0f);
  4525. frameRectMM100.Y = frameRect->Y * (2540.0f / 72.0f);
  4526. frameRectMM100.Width = frameRect->Width * (dpiX / 72.0f);
  4527. frameRectMM100.Height = frameRect->Height * (dpiY / 72.0f);
  4528. break;
  4529. case UnitInch: // Each unit represents 1 inch.
  4530. frameRectMM100.X = frameRect->X * 2540.0f;
  4531. frameRectMM100.Y = frameRect->Y * 2540.0f;
  4532. frameRectMM100.Width = frameRect->Width * dpiX;
  4533. frameRectMM100.Height = frameRect->Height * dpiY;
  4534. break;
  4535. case UnitDocument: // Each unit represents 1/300 inch.
  4536. frameRectMM100.X = frameRect->X * (2540.0f / 300.0f);
  4537. frameRectMM100.Y = frameRect->Y * (2540.0f / 300.0f);
  4538. frameRectMM100.Width = frameRect->Width * (dpiX / 300.0f);
  4539. frameRectMM100.Height = frameRect->Height * (dpiY / 300.0f);
  4540. break;
  4541. case UnitMillimeter: // Each unit represents 1 millimeter.
  4542. // One Millimeter is 0.03937 inches
  4543. // One Inch is 25.4 millimeters
  4544. frameRectMM100.X = frameRect->X * (100.0f);
  4545. frameRectMM100.Y = frameRect->Y * (100.0f);
  4546. frameRectMM100.Width = frameRect->Width * (dpiX / 25.4f);
  4547. frameRectMM100.Height = frameRect->Height * (dpiY / 25.4f);
  4548. break;
  4549. }
  4550. frameRectMM100.Width = (frameRectMM100.Width - 1.0f) * pixelsToMM100X;
  4551. frameRectMM100.Height = (frameRectMM100.Height - 1.0f) * pixelsToMM100Y;
  4552. }
  4553. BOOL
  4554. GpMetafile::InitForRecording(
  4555. HDC referenceHdc,
  4556. EmfType type,
  4557. const GpRectF * frameRect, // can be NULL
  4558. MetafileFrameUnit frameUnit, // if NULL frameRect, doesn't matter
  4559. const WCHAR * description // can be NULL
  4560. )
  4561. {
  4562. RECT * frameRectParam = NULL;
  4563. RECT rclFrame;
  4564. if (frameRect != NULL)
  4565. {
  4566. // Validate the frameRect
  4567. // 0 is allowed, since the frameRect is inclusive-inclusive, which
  4568. // means that a width of 0 is actually a width of 1
  4569. if ((frameRect->Width < 0.0f) || (frameRect->Height < 0.0f))
  4570. {
  4571. WARNING(("Invalid frameRect"));
  4572. return FALSE;
  4573. }
  4574. if (frameUnit == MetafileFrameUnitGdi)
  4575. {
  4576. // Typically, the GDI+ frameRect is inclusive/exclusive
  4577. // as far as the GetLeft()/GetRight() values go, but the
  4578. // MetafileFrameUnitGdi unit is a special type of unit
  4579. // that specifies compatibility with GDI which is
  4580. // inclusive/inclusive, so we don't do any adjustment
  4581. // on those values at all -- we just assume they are ready
  4582. // to pass directly to GDI.
  4583. rclFrame.left = GpRound(frameRect->X);
  4584. rclFrame.top = GpRound(frameRect->Y);
  4585. rclFrame.right = GpRound(frameRect->GetRight());
  4586. rclFrame.bottom = GpRound(frameRect->GetBottom());
  4587. // Make sure the .01MM frameRect is valid
  4588. // It's okay for left == right, because the GDI frameRect
  4589. // is inclusive-inclusive.
  4590. if ((rclFrame.left > rclFrame.right) ||
  4591. (rclFrame.top > rclFrame.bottom))
  4592. {
  4593. WARNING(("Invalid GDI frameRect"));
  4594. return FALSE;
  4595. }
  4596. }
  4597. else
  4598. {
  4599. if (!GetFrameRectInMM100Units(referenceHdc, frameRect, frameUnit, rclFrame))
  4600. {
  4601. return FALSE;
  4602. }
  4603. }
  4604. frameRectParam = &rclFrame;
  4605. }
  4606. HDC metafileHdc;
  4607. // Now create the metafile HDC
  4608. // Note that FileName might be NULL
  4609. metafileHdc = CreateEmf(referenceHdc, Filename, frameRectParam);
  4610. if (metafileHdc == NULL)
  4611. {
  4612. return FALSE; // failed
  4613. }
  4614. // Now get the dpi based on the metafileHdc (which could be different
  4615. // than the referenceHdc).
  4616. SIZEL szlDevice; // Size of metafile device in pels
  4617. SIZEL szlMillimeters; // Size of metafile device in millimeters
  4618. GpRectF metafileBounds;
  4619. // NOTE: We have to use the szlDevice and szlMillimeters to get
  4620. // the dpi (instead of getting it directly from LOGPIXELSX/Y)
  4621. // so that the frame rect that is calculated for the metafile by GDI
  4622. // matches the one that GDI+ would have calculated. Because it's
  4623. // these 2 metrics that the GDI metafile code uses to get the frame
  4624. // rect from the bounds, not the logical DPI.
  4625. szlDevice.cx = ::GetDeviceCaps(metafileHdc, HORZRES);
  4626. szlDevice.cy = ::GetDeviceCaps(metafileHdc, VERTRES);
  4627. szlMillimeters.cx = ::GetDeviceCaps(metafileHdc, HORZSIZE);
  4628. szlMillimeters.cy = ::GetDeviceCaps(metafileHdc, VERTSIZE);
  4629. if ((szlDevice.cx <= 0) || (szlDevice.cy <= 0) ||
  4630. (szlMillimeters.cx <= 0) || (szlMillimeters.cy <= 0))
  4631. {
  4632. WARNING(("GetDeviceCaps failed"));
  4633. goto ErrorExit;
  4634. }
  4635. REAL dpiX;
  4636. REAL dpiY;
  4637. REAL dpmmX = (REAL)(szlDevice.cx) / (REAL)(szlMillimeters.cx);
  4638. REAL dpmmY = (REAL)(szlDevice.cy) / (REAL)(szlMillimeters.cy);
  4639. // Now get the real DPI, adjusted for the round-off error.
  4640. dpiX = dpmmX * 25.4f;
  4641. dpiY = dpmmY * 25.4f;
  4642. // Set the DPI in the metafile
  4643. this->Header.DpiX = dpiX;
  4644. this->Header.DpiY = dpiY;
  4645. // NOTE: On Win9x there are some hi-res printer drivers that use a
  4646. // different resolution for the metafileHdc than they do for the
  4647. // referenceHdc (Probably to avoid overflow.) The problem with that
  4648. // is, that the differing resolutions make it impossible for us to
  4649. // know which frameRect to use, because we don't know for certain
  4650. // what DPI the application is going to assume to do its drawing --
  4651. // whether the metafile resolution or the printer resolution. In any
  4652. // case, it's a safe bet that the original frameRect is wrong.
  4653. if (!Globals::IsNt && (frameRectParam != NULL) &&
  4654. (::GetDeviceCaps(metafileHdc, LOGPIXELSX) != ::GetDeviceCaps(referenceHdc, LOGPIXELSX)))
  4655. {
  4656. frameRectParam = NULL; // give up on the frameRect
  4657. // Now recreate the metafile HDC
  4658. ::DeleteEnhMetaFile(::CloseEnhMetaFile(metafileHdc));
  4659. metafileHdc = CreateEmf(referenceHdc, Filename, frameRectParam);
  4660. if (metafileHdc == NULL)
  4661. {
  4662. return FALSE; // failed
  4663. }
  4664. }
  4665. // The metafileBounds are used as the bounds for FillRegion
  4666. // calls when the region has infinite bounds, to keep from
  4667. // exploding the bounds of the metafile.
  4668. if (frameRectParam != NULL)
  4669. {
  4670. dpmmX *= 0.01f;
  4671. dpmmY *= 0.01f;
  4672. metafileBounds.X = rclFrame.left * dpmmX;
  4673. metafileBounds.Y = rclFrame.top * dpmmY;
  4674. metafileBounds.Width = (rclFrame.right - rclFrame.left) * dpmmX;
  4675. metafileBounds.Height = (rclFrame.bottom - rclFrame.top) * dpmmY;
  4676. }
  4677. else
  4678. {
  4679. metafileBounds.X = 0.0f;
  4680. metafileBounds.Y = 0.0f;
  4681. metafileBounds.Width = (REAL)szlDevice.cx - 1; // metafile bounds are inclusive
  4682. metafileBounds.Height = (REAL)szlDevice.cy - 1;
  4683. }
  4684. // Now create the recorder object
  4685. MetafileRecorder * recorder = new MetafileRecorder(
  4686. this,
  4687. type,
  4688. metafileHdc,
  4689. (frameRectParam != NULL),
  4690. szlMillimeters,
  4691. metafileBounds);
  4692. if (CheckValid(recorder))
  4693. {
  4694. MetaGraphics = GpGraphics::GetForMetafile(recorder, type, metafileHdc);
  4695. if (MetaGraphics != NULL)
  4696. {
  4697. if (MetaGraphics->IsValid())
  4698. {
  4699. return TRUE;
  4700. }
  4701. recorder->SetValid(FALSE);// so we don't record stuff in EndRecording
  4702. delete MetaGraphics; // calls EndRecording which deletes recorder
  4703. MetaGraphics = NULL;
  4704. }
  4705. else
  4706. {
  4707. delete recorder;
  4708. }
  4709. }
  4710. ErrorExit:
  4711. DeleteEnhMetaFile(CloseEnhMetaFile(metafileHdc));
  4712. return FALSE;
  4713. }
  4714. // Returns NULL if the metafile was opened for reading or if already got
  4715. // the context for writing.
  4716. GpGraphics *
  4717. GpMetafile::GetGraphicsContext()
  4718. {
  4719. if (!RequestedMetaGraphics)
  4720. {
  4721. RequestedMetaGraphics = TRUE;
  4722. return MetaGraphics;
  4723. }
  4724. WARNING(("Requesting MetaGraphics more than once"));
  4725. return NULL;
  4726. }
  4727. GpStatus
  4728. GpMetafile::SetDownLevelRasterizationLimit(
  4729. UINT metafileRasterizationLimitDpi
  4730. )
  4731. {
  4732. ASSERT(IsValid());
  4733. // 0 means restore it to the default value; otherwise, the minumum is 10 dpi
  4734. if ((metafileRasterizationLimitDpi == 0) || (metafileRasterizationLimitDpi >= 10))
  4735. {
  4736. if ((State == GpMetafile::RecordingMetafileState) &&
  4737. (MetaGraphics != NULL))
  4738. {
  4739. MetaGraphics->Context->SetMetafileDownLevelRasterizationLimit(metafileRasterizationLimitDpi);
  4740. return Ok;
  4741. }
  4742. WARNING1("Metafile in Wrong State for this operation");
  4743. return WrongState;
  4744. }
  4745. WARNING1("rasterizationDpiLimit is non-zero but too small");
  4746. return InvalidParameter;
  4747. }
  4748. GpStatus
  4749. GpMetafile::GetDownLevelRasterizationLimit(
  4750. UINT * metafileRasterizationLimitDpi
  4751. ) const
  4752. {
  4753. ASSERT(metafileRasterizationLimitDpi != NULL);
  4754. ASSERT(IsValid());
  4755. if ((State == GpMetafile::RecordingMetafileState) &&
  4756. (MetaGraphics != NULL))
  4757. {
  4758. *metafileRasterizationLimitDpi = MetaGraphics->Context->GetMetafileDownLevelRasterizationLimit();
  4759. return Ok;
  4760. }
  4761. WARNING1("Metafile in Wrong State for this operation");
  4762. return WrongState;
  4763. }