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.

3449 lines
108 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1999 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * MetaWmf.cpp
  8. *
  9. * Abstract:
  10. *
  11. * Methods for playing and recoloring a WMF.
  12. *
  13. * Created:
  14. *
  15. * 12/13/1999 DCurtis
  16. *
  17. \**************************************************************************/
  18. #include "Precomp.hpp"
  19. #include "MetaWmf.hpp"
  20. #ifndef BI_CMYK // from wingdip.h
  21. #define BI_CMYK 10L
  22. #define BI_CMYKRLE8 11L
  23. #define BI_CMYKRLE4 12L
  24. #endif
  25. inline static BOOL
  26. IsDwordAligned(
  27. VOID * pointer
  28. )
  29. {
  30. return (((ULONG_PTR)pointer & (sizeof(DWORD) - 1)) == 0);
  31. }
  32. inline static BOOL
  33. IsPostscriptPrinter(
  34. HDC hdc
  35. )
  36. {
  37. // It is a PostScript printer if POSTSCRIPT_PASSTHROUGH or
  38. // POSTSCRIPT_IGNORE is available
  39. int iWant1 = POSTSCRIPT_PASSTHROUGH;
  40. int iWant2 = POSTSCRIPT_IGNORE;
  41. return ((Escape(hdc, QUERYESCSUPPORT, sizeof(iWant1), (LPCSTR)&iWant1, NULL) != 0) ||
  42. (Escape(hdc, QUERYESCSUPPORT, sizeof(iWant2), (LPCSTR)&iWant2, NULL) != 0));
  43. }
  44. // Some escapes apparently cause NT 3.51 to crash, so skip them
  45. inline static BOOL
  46. SkipEscape(
  47. INT escapeCode
  48. )
  49. {
  50. switch (escapeCode)
  51. {
  52. case GETPHYSPAGESIZE: // 12
  53. case GETPRINTINGOFFSET: // 13
  54. case GETSCALINGFACTOR: // 14
  55. case BEGIN_PATH: // 4096
  56. case CLIP_TO_PATH: // 4097
  57. case END_PATH: // 4098
  58. return TRUE;
  59. default:
  60. return FALSE;
  61. }
  62. }
  63. inline static BOOL
  64. IsOfficeArtData(
  65. UINT recordSize,
  66. const WORD * recordData
  67. )
  68. {
  69. return (recordData[0] == MFCOMMENT) &&
  70. (recordSize > 16) &&
  71. ((INT)recordSize >= (recordData[1] + 10)) &&
  72. (GpMemcmp(recordData + 2, "TNPPOA", 6) == 0);
  73. }
  74. // The structure which defines the contents of a comment for a WMF or PICT,
  75. // for an EMF use GdiComment() and the "approved" format (see the Win32
  76. // documentation) - this basically is the same except that it has a 4 byte
  77. // kind field. For a PICT this is the format of an ApplicationComment (kind
  78. // 100).
  79. #pragma pack(push, GDIP_pack, 2)
  80. typedef struct
  81. {
  82. ULONG Signature; // Identifes the comment writer.
  83. USHORT Kind; // Type of comment (writer specific)
  84. // Comment data follows here.
  85. } WmfComment;
  86. typedef struct
  87. {
  88. WORD lbStyle;
  89. COLORREF lbColor;
  90. SHORT lbHatch;
  91. } LOGBRUSH16;
  92. typedef struct
  93. {
  94. WORD lopnStyle;
  95. POINTS lopnWidth;
  96. COLORREF lopnColor;
  97. } LOGPEN16;
  98. typedef struct
  99. {
  100. SHORT bmType;
  101. SHORT bmWidth;
  102. SHORT bmHeight;
  103. SHORT bmWidthBytes;
  104. BYTE bmPlanes;
  105. BYTE bmBitsPixel;
  106. LPBYTE bmBits;
  107. } BITMAP16;
  108. typedef struct tagLOGFONT16
  109. {
  110. SHORT lfHeight;
  111. SHORT lfWidth;
  112. SHORT lfEscapement;
  113. SHORT lfOrientation;
  114. SHORT lfWeight;
  115. BYTE lfItalic;
  116. BYTE lfUnderline;
  117. BYTE lfStrikeOut;
  118. BYTE lfCharSet;
  119. BYTE lfOutPrecision;
  120. BYTE lfClipPrecision;
  121. BYTE lfQuality;
  122. BYTE lfPitchAndFamily;
  123. BYTE lfFaceName[LF_FACESIZE];
  124. } LOGFONT16;
  125. #pragma pack(pop, GDIP_pack)
  126. inline static const WmfComment UNALIGNED *
  127. GetWmfComment(
  128. const WORD * recordData,
  129. ULONG signature,
  130. UINT kind
  131. )
  132. {
  133. // Assumes you've already checked that
  134. // (wmfCommentRecord->rdFunction == META_ESCAPE &&
  135. // wmfCommentRecord->rdParm[0] == MFCOMMENT)
  136. const WmfComment UNALIGNED * wmfComment = (const WmfComment UNALIGNED *)&(recordData[2]);
  137. if ((wmfComment->Signature == signature) && (wmfComment->Kind == kind))
  138. {
  139. return wmfComment;
  140. }
  141. return NULL;
  142. }
  143. inline static INT
  144. GetDibByteWidth(
  145. INT biWidth,
  146. INT biPlanes,
  147. INT biBitCount
  148. )
  149. {
  150. return (((biWidth * biPlanes * biBitCount) + 31) & ~31) / 8;
  151. }
  152. inline static RGBQUAD UNALIGNED *
  153. GetDibColorTable(
  154. BITMAPINFOHEADER UNALIGNED * dibInfo
  155. )
  156. {
  157. return (RGBQUAD UNALIGNED *)(((BYTE *)dibInfo) + dibInfo->biSize);
  158. }
  159. static BYTE *
  160. GetDibBits(
  161. BITMAPINFOHEADER UNALIGNED * dibInfo,
  162. UINT numPalEntries,
  163. UINT usage
  164. )
  165. {
  166. ASSERT(dibInfo->biSize >= sizeof(BITMAPINFOHEADER));
  167. INT colorSize = 0;
  168. if (numPalEntries > 0)
  169. {
  170. if ((usage == DIB_PAL_COLORS) &&
  171. (dibInfo->biCompression != BI_BITFIELDS) &&
  172. (dibInfo->biCompression != BI_CMYK))
  173. {
  174. // Make sure it is aligned
  175. colorSize = ((numPalEntries * sizeof(INT16)) + 3) & ~3;
  176. }
  177. else
  178. {
  179. colorSize = numPalEntries * sizeof(RGBQUAD);
  180. }
  181. }
  182. return ((BYTE *)GetDibColorTable(dibInfo)) + colorSize;
  183. }
  184. UINT
  185. GetDibBitsSize(
  186. BITMAPINFOHEADER UNALIGNED * dibInfo
  187. )
  188. {
  189. // Check for PM-style DIB
  190. if (dibInfo->biSize >= sizeof(BITMAPINFOHEADER))
  191. {
  192. // not a core header
  193. if (dibInfo->biWidth > 0) // can't handle negative width
  194. {
  195. if ((dibInfo->biCompression == BI_RGB) ||
  196. (dibInfo->biCompression == BI_BITFIELDS) ||
  197. (dibInfo->biCompression == BI_CMYK))
  198. {
  199. INT posHeight = dibInfo->biHeight;
  200. if (posHeight < 0)
  201. {
  202. posHeight = -posHeight;
  203. }
  204. return posHeight *
  205. GetDibByteWidth(dibInfo->biWidth, dibInfo->biPlanes,
  206. dibInfo->biBitCount);
  207. }
  208. return dibInfo->biSizeImage;
  209. }
  210. WARNING(("0 or negative DIB width"));
  211. return 0;
  212. }
  213. else // it is a PM-style DIB
  214. {
  215. BITMAPCOREHEADER UNALIGNED * coreDibInfo = (BITMAPCOREHEADER UNALIGNED *)dibInfo;
  216. // width and height must be > 0 for COREINFO dibs
  217. if ((coreDibInfo->bcWidth > 0) &&
  218. (coreDibInfo->bcHeight > 0))
  219. {
  220. return coreDibInfo->bcHeight *
  221. GetDibByteWidth(coreDibInfo->bcWidth,coreDibInfo->bcPlanes,
  222. coreDibInfo->bcBitCount);
  223. }
  224. WARNING(("0 or negative DIB width or height"));
  225. return 0;
  226. }
  227. }
  228. BOOL
  229. GetDibNumPalEntries(
  230. BOOL isWmfDib,
  231. UINT biSize,
  232. UINT biBitCount,
  233. UINT biCompression,
  234. UINT biClrUsed,
  235. UINT * numPalEntries
  236. )
  237. {
  238. UINT maxPalEntries = 0;
  239. // Dibs in a WMF always have the bitfields for 16 and 32-bpp dibs.
  240. if (((biBitCount == 16) || (biBitCount == 32)) && isWmfDib)
  241. {
  242. biCompression = BI_BITFIELDS;
  243. }
  244. switch (biCompression)
  245. {
  246. case BI_BITFIELDS:
  247. //
  248. // Handle 16 and 32 bit per pel bitmaps.
  249. //
  250. switch (biBitCount)
  251. {
  252. case 16:
  253. case 32:
  254. break;
  255. default:
  256. WARNING(("BI_BITFIELDS not Valid for this biBitCount"));
  257. return FALSE;
  258. }
  259. if (biSize <= sizeof(BITMAPINFOHEADER))
  260. {
  261. biClrUsed = maxPalEntries = 3;
  262. }
  263. else
  264. {
  265. //
  266. // masks are part of BITMAPV4 and greater
  267. //
  268. biClrUsed = maxPalEntries = 0;
  269. }
  270. break;
  271. case BI_RGB:
  272. switch (biBitCount)
  273. {
  274. case 1:
  275. case 4:
  276. case 8:
  277. maxPalEntries = 1 << biBitCount;
  278. break;
  279. default:
  280. maxPalEntries = 0;
  281. switch (biBitCount)
  282. {
  283. case 16:
  284. case 24:
  285. case 32:
  286. break;
  287. default:
  288. WARNING(("Invalid biBitCount in BI_RGB"));
  289. return FALSE;
  290. }
  291. }
  292. break;
  293. case BI_CMYK:
  294. switch (biBitCount)
  295. {
  296. case 1:
  297. case 4:
  298. case 8:
  299. maxPalEntries = 1 << biBitCount;
  300. break;
  301. case 32:
  302. maxPalEntries = 0;
  303. break;
  304. default:
  305. WARNING(("Invalid biBitCount in BI_CMYK"));
  306. return FALSE;
  307. }
  308. break;
  309. case BI_RLE4:
  310. case BI_CMYKRLE4:
  311. if (biBitCount != 4)
  312. {
  313. WARNING(("Invalid biBitCount in BI_RLE4"));
  314. return FALSE;
  315. }
  316. maxPalEntries = 16;
  317. break;
  318. case BI_RLE8:
  319. case BI_CMYKRLE8:
  320. if (biBitCount != 8)
  321. {
  322. WARNING(("Invalid biBitCount in BI_RLE8"));
  323. return FALSE;
  324. }
  325. maxPalEntries = 256;
  326. break;
  327. case BI_JPEG:
  328. case BI_PNG:
  329. maxPalEntries = 0;
  330. break;
  331. default:
  332. WARNING(("Invalid biCompression"));
  333. return FALSE;
  334. }
  335. if (biClrUsed != 0)
  336. {
  337. if (biClrUsed <= maxPalEntries)
  338. {
  339. maxPalEntries = biClrUsed;
  340. }
  341. }
  342. *numPalEntries = maxPalEntries;
  343. return TRUE;
  344. }
  345. GdipHdcType
  346. GetHdcType(
  347. HDC hdc
  348. )
  349. {
  350. GdipHdcType hdcType = UnknownHdc;
  351. UINT dcType = GetDCType(hdc);
  352. switch (dcType)
  353. {
  354. case OBJ_DC:
  355. {
  356. INT technology = GetDeviceCaps(hdc, TECHNOLOGY);
  357. if (technology == DT_RASDISPLAY)
  358. {
  359. hdcType = ScreenHdc;
  360. }
  361. else if (technology == DT_RASPRINTER)
  362. {
  363. if (IsPostscriptPrinter(hdc))
  364. {
  365. hdcType = PostscriptPrinterHdc;
  366. }
  367. else
  368. {
  369. hdcType = PrinterHdc;
  370. }
  371. }
  372. else
  373. {
  374. WARNING(("Unknown HDC technology!"));
  375. }
  376. }
  377. break;
  378. case OBJ_MEMDC:
  379. hdcType = BitmapHdc;
  380. break;
  381. case OBJ_ENHMETADC:
  382. // When metafile spooling, the printer DC will be of type
  383. // OBJ_ENHMETADC on Win9x and NT4 (but not NT5 due to a fix
  384. // to NT bug 98810). We need to do some more work to figure
  385. // out whether it's really a printer DC or a true metafile
  386. // DC:
  387. if (Globals::GdiIsMetaPrintDCFunction(hdc))
  388. {
  389. if (IsPostscriptPrinter(hdc))
  390. {
  391. hdcType = PostscriptPrinterHdc;
  392. }
  393. else
  394. {
  395. hdcType = PrinterHdc;
  396. }
  397. }
  398. else
  399. {
  400. hdcType = EmfHdc;
  401. }
  402. break;
  403. case OBJ_METADC:
  404. hdcType = WmfHdc;
  405. break;
  406. default:
  407. WARNING(("Unknown HDC type!"));
  408. break;
  409. }
  410. return hdcType;
  411. }
  412. DWORD
  413. GetHdcBitmapBitsPixel(
  414. HDC hdc
  415. )
  416. {
  417. // This function returns the number of bits per pixel for a bitmap DC.
  418. // On error, 0 is returned.
  419. ASSERT(GetDCType(hdc) == OBJ_MEMDC);
  420. HBITMAP hbm = (HBITMAP) GetCurrentObject(hdc, OBJ_BITMAP);
  421. if (hbm)
  422. {
  423. BITMAP bm;
  424. if (GetObjectA(hbm, sizeof(bm), &bm) >= sizeof(BITMAP))
  425. {
  426. return bm.bmBitsPixel;
  427. }
  428. }
  429. return 0;
  430. }
  431. MfEnumState::MfEnumState(
  432. HDC hdc,
  433. BOOL externalEnumeration,
  434. InterpolationMode interpolation,
  435. GpRecolor * recolor,
  436. ColorAdjustType adjustType,
  437. const RECT * deviceRect,
  438. DpContext * context
  439. )
  440. {
  441. HdcType = GetHdcType(hdc);
  442. Hdc = hdc;
  443. HandleTable = NULL;
  444. NumObjects = 0;
  445. CurrentPalette = (HPALETTE)::GetStockObject(DEFAULT_PALETTE);
  446. SizeAllocedRecord = 0;
  447. ModifiedRecordSize = 0;
  448. SaveDcCount = 0;
  449. BytesEnumerated = 0;
  450. ExternalEnumeration = externalEnumeration;
  451. Recolor = recolor;
  452. AdjustType = adjustType;
  453. CurrentRecord = NULL;
  454. ModifiedRecord = NULL;
  455. AllocedRecord = NULL;
  456. Interpolation = interpolation;
  457. SaveDcVal = SaveDC(hdc);
  458. FsmState = MfFsmStart;
  459. GdiCentricMode = FALSE;
  460. SoftekFilter = FALSE;
  461. DefaultFont = NULL;
  462. RopUsed = FALSE;
  463. Context = context;
  464. SrcCopyOnly = FALSE;
  465. GpMemset(StockFonts, 0, sizeof(StockFonts[0]) * NUM_STOCK_FONTS);
  466. GpMemset(RecoloredStockHandle, 0, sizeof(HGDIOBJ) * NUM_STOCK_RECOLOR_OBJS);
  467. // See if we should halftone solid colors
  468. if ((IsScreen() && (::GetDeviceCaps(hdc, BITSPIXEL) == 8)) ||
  469. (IsBitmap() && (GetHdcBitmapBitsPixel(hdc) == 8)))
  470. {
  471. Is8Bpp = TRUE;
  472. EpPaletteMap paletteMap(hdc);
  473. IsHalftonePalette = (paletteMap.IsValid() && (!paletteMap.IsVGAOnly()));
  474. }
  475. else
  476. {
  477. Is8Bpp = FALSE;
  478. IsHalftonePalette = FALSE;
  479. }
  480. // Since the transform can change as we are playing the metafile
  481. // convert the destrect into DeviceUnits. We will make sure to have an
  482. // identity matrix when we apply it.
  483. DestRectDevice = *deviceRect;
  484. }
  485. MfEnumState::~MfEnumState()
  486. {
  487. // Delete all the true type fonts we created (first make sure they
  488. // are not selected into the Hdc.
  489. ::SelectObject(Hdc, GetStockObject(SYSTEM_FONT));
  490. if (DefaultFont)
  491. {
  492. DeleteObject(DefaultFont);
  493. }
  494. for (int i = 0; i < NUM_STOCK_FONTS; i++)
  495. {
  496. if (StockFonts[i] != NULL)
  497. {
  498. DeleteObject(StockFonts[i]);
  499. }
  500. }
  501. // Not necessary to delete NULL_BRUSH, NULL_PEN into HDC. The subclasses
  502. // restore DC state which should dissolve any selections of these pen/brushes.
  503. for (int i = 0; i < NUM_STOCK_RECOLOR_OBJS; i++)
  504. {
  505. if (RecoloredStockHandle[i] != NULL)
  506. {
  507. DeleteObject(RecoloredStockHandle[i]);
  508. }
  509. }
  510. }
  511. WmfEnumState::WmfEnumState(
  512. HDC hdc,
  513. HMETAFILE hWmf,
  514. BOOL externalEnumeration,
  515. InterpolationMode interpolation,
  516. const RECT * dstRect,
  517. const RECT * deviceRect,
  518. DpContext * context,
  519. GpRecolor * recolor,
  520. ColorAdjustType adjustType
  521. )
  522. : MfEnumState(hdc, externalEnumeration, interpolation,
  523. recolor, adjustType, deviceRect, context)
  524. {
  525. if (IsValid())
  526. {
  527. IgnorePostscript = FALSE;
  528. BytesEnumerated = sizeof(METAHEADER); // in WMF enumeration, we don't get header
  529. MetafileSize = GetMetaFileBitsEx(hWmf, 0, NULL);
  530. FirstViewportExt = TRUE;
  531. FirstViewportOrg = TRUE;
  532. IsFirstRecord = TRUE;
  533. // The bad thing about this is that if the metafile is being recolored,
  534. // the default pen, brush, text color, and background colors have NOT
  535. // been recolored. So let's hope they're not really used.
  536. HpenSave = (HPEN) ::SelectObject(hdc, GetStockObject(BLACK_PEN));
  537. HbrushSave = (HBRUSH)::SelectObject(hdc, GetStockObject(WHITE_BRUSH));
  538. if (!Globals::IsNt)
  539. {
  540. HpaletteSave = (HPALETTE)GetCurrentObject(hdc, OBJ_PAL);
  541. HfontSave = (HFONT) GetCurrentObject(hdc, OBJ_FONT);
  542. HbitmapSave = (HBITMAP) GetCurrentObject(hdc, OBJ_BITMAP);
  543. HregionSave = (HRGN) GetCurrentObject(hdc, OBJ_REGION);
  544. }
  545. else
  546. {
  547. HpaletteSave = NULL;
  548. HfontSave = NULL;
  549. HbitmapSave = NULL;
  550. HregionSave = NULL;
  551. }
  552. // Make sure a few default values are set in the hdc
  553. ::SetTextAlign(hdc, 0);
  554. ::SetTextJustification(hdc, 0, 0);
  555. ::SetTextColor(hdc, RGB(0,0,0));
  556. TextColor = RGB(0,0,0);
  557. ::SetBkColor(hdc, RGB(255,255,255));
  558. BkColor = RGB(255,255,255);
  559. ::SetROP2(hdc, R2_COPYPEN);
  560. DstViewportOrg.x = dstRect->left;
  561. DstViewportOrg.y = dstRect->top;
  562. DstViewportExt.cx = dstRect->right - DstViewportOrg.x;
  563. DstViewportExt.cy = dstRect->bottom - DstViewportOrg.y;
  564. }
  565. }
  566. WmfEnumState::~WmfEnumState()
  567. {
  568. // Turn POSTSCRIPT_IGNORE back off if we need to.
  569. if (IsPostscriptPrinter() && IgnorePostscript)
  570. {
  571. WORD wOn = FALSE;
  572. ::Escape(Hdc, POSTSCRIPT_IGNORE, sizeof(wOn), (LPCSTR)&wOn, NULL);
  573. }
  574. // According to Office GEL, SaveDC/RestoreDC doesn't always restore
  575. // the brush and the pen correctly, so we have to do that ourselves.
  576. ::SelectObject(Hdc, HbrushSave);
  577. ::SelectObject(Hdc, HpenSave);
  578. GpFree(AllocedRecord);
  579. if (IsMetafile())
  580. {
  581. // Account for unbalanced SaveDC/RestoreDC pairs and
  582. // restore to the saveDC state
  583. ::RestoreDC(Hdc, SaveDcCount - 1);
  584. }
  585. else
  586. {
  587. ::RestoreDC(Hdc, SaveDcVal);
  588. }
  589. }
  590. VOID
  591. WmfEnumState::EndRecord(
  592. )
  593. {
  594. // We rely on the number of bytes enumerated to determine if
  595. // this is the last record of the WMF.
  596. if ((MetafileSize - BytesEnumerated) < SIZEOF_METARECORDHEADER)
  597. {
  598. if (!Globals::IsNt)
  599. {
  600. // GDI won't delete objects that are still selected, so
  601. // select out all WMF objects before proceeding.
  602. ::SelectObject(Hdc, HpenSave);
  603. ::SelectObject(Hdc, HbrushSave);
  604. ::SelectObject(Hdc, HpaletteSave);
  605. ::SelectObject(Hdc, HfontSave);
  606. ::SelectObject(Hdc, HbitmapSave);
  607. ::SelectObject(Hdc, HregionSave);
  608. INT i;
  609. HANDLE handle;
  610. if (HandleTable != NULL)
  611. {
  612. for (i = 0; i < NumObjects; i++)
  613. {
  614. if ((handle = HandleTable->objectHandle[i]) != NULL)
  615. {
  616. ::DeleteObject(handle);
  617. HandleTable->objectHandle[i] = NULL;
  618. }
  619. }
  620. }
  621. }
  622. }
  623. }
  624. BOOL
  625. WmfEnumState::PlayRecord(
  626. )
  627. {
  628. const METARECORD * recordToPlay = ModifiedWmfRecord;
  629. // See if we've modified the record
  630. if (recordToPlay == NULL)
  631. {
  632. // We haven't. See if we have a valid current record
  633. if (CurrentWmfRecord != NULL)
  634. {
  635. recordToPlay = CurrentWmfRecord;
  636. }
  637. else
  638. {
  639. // we don't so we have to create one
  640. if (!CreateCopyOfCurrentRecord())
  641. {
  642. return FALSE;
  643. }
  644. recordToPlay = ModifiedWmfRecord;
  645. }
  646. }
  647. return PlayMetaFileRecord(Hdc, HandleTable, (METARECORD *)recordToPlay, NumObjects);
  648. }
  649. INT
  650. MfEnumState::GetModifiedDibSize(
  651. BITMAPINFOHEADER UNALIGNED * dibInfo,
  652. UINT numPalEntries,
  653. UINT dibBitsSize,
  654. UINT & usage
  655. )
  656. {
  657. ASSERT(dibInfo->biSize >= sizeof(BITMAPINFOHEADER));
  658. INT byteWidth;
  659. INT bitCount = dibInfo->biBitCount;
  660. if ((usage == DIB_PAL_COLORS) &&
  661. ((bitCount > 8) || (dibInfo->biCompression == BI_BITFIELDS)))
  662. {
  663. usage = DIB_RGB_COLORS;
  664. }
  665. if ((Recolor != NULL) || (usage == DIB_PAL_COLORS))
  666. {
  667. INT biSize = dibInfo->biSize;
  668. if (bitCount > 8)
  669. {
  670. if ((dibInfo->biCompression != BI_RGB) &&
  671. (dibInfo->biCompression != BI_BITFIELDS))
  672. {
  673. return 0; // don't handle compressed images
  674. }
  675. ASSERT((bitCount == 16) || (bitCount == 24) || (bitCount == 32));
  676. INT posHeight = dibInfo->biHeight;
  677. if (posHeight < 0)
  678. {
  679. posHeight = -posHeight;
  680. }
  681. // We have to recolor the object, so we will convert it to a
  682. // 24 bit image and send it down.
  683. // Even if we have less then 256 pixels, it's not worth palettizing
  684. // anymore because the palette will be the size of the image anyway
  685. // make sure that the bitmap is width is aligned
  686. // PERF: We could create a GpBitmap from the bitmap and recolor the
  687. // GpBitmap
  688. dibBitsSize = posHeight * (((dibInfo->biWidth * 3) + 3) & ~3);
  689. numPalEntries = 0;
  690. biSize = sizeof(BITMAPINFOHEADER);
  691. }
  692. else if ((numPalEntries == 0) ||
  693. (dibInfo->biCompression == BI_CMYK) ||
  694. (dibInfo->biCompression == BI_CMYKRLE4) ||
  695. (dibInfo->biCompression == BI_CMYKRLE8))
  696. {
  697. return 0; // don't handle CMYK images
  698. }
  699. usage = DIB_RGB_COLORS;
  700. return biSize + (numPalEntries * sizeof(RGBQUAD)) + dibBitsSize;
  701. }
  702. return 0; // no modifications needed
  703. }
  704. inline static INT
  705. GetMaskShift(
  706. INT maskValue
  707. )
  708. {
  709. ASSERT (maskValue != 0);
  710. INT shift = 0;
  711. while (((maskValue & 1) == 0) && (shift < 24))
  712. {
  713. shift++;
  714. maskValue >>= 1;
  715. }
  716. return shift;
  717. }
  718. inline static INT
  719. GetNumMaskBits(
  720. INT maskValue
  721. )
  722. {
  723. ASSERT ((maskValue & 1) != 0);
  724. INT numBits = 0;
  725. while ((maskValue & 1) != 0)
  726. {
  727. numBits++;
  728. maskValue >>= 1;
  729. }
  730. return numBits;
  731. }
  732. VOID
  733. MfEnumState::Modify16BppDib(
  734. INT width,
  735. INT posHeight,
  736. BYTE * srcPixels,
  737. DWORD UNALIGNED * bitFields,
  738. BYTE * dstPixels,
  739. ColorAdjustType adjustType
  740. )
  741. {
  742. INT rMask = 0x00007C00; // same as GDI default
  743. INT gMask = 0x000003E0;
  744. INT bMask = 0x0000001F;
  745. INT rMaskShift = 10;
  746. INT gMaskShift = 5;
  747. INT bMaskShift = 0;
  748. INT rNumBits = 5;
  749. INT gNumBits = 5;
  750. INT bNumBits = 5;
  751. INT rRightShift = 2;
  752. INT gRightShift = 2;
  753. INT bRightShift = 2;
  754. if (bitFields != NULL)
  755. {
  756. rMask = (INT)((WORD)(*bitFields++));
  757. gMask = (INT)((WORD)(*bitFields++));
  758. bMask = (INT)((WORD)(*bitFields));
  759. rMaskShift = GetMaskShift(rMask);
  760. gMaskShift = GetMaskShift(gMask);
  761. bMaskShift = GetMaskShift(bMask);
  762. rNumBits = GetNumMaskBits(rMask >> rMaskShift);
  763. gNumBits = GetNumMaskBits(gMask >> gMaskShift);
  764. bNumBits = GetNumMaskBits(bMask >> bMaskShift);
  765. rRightShift = (rNumBits << 1) - 8;
  766. gRightShift = (gNumBits << 1) - 8;
  767. bRightShift = (bNumBits << 1) - 8;
  768. }
  769. INT palIndex = 0;
  770. INT pixel;
  771. INT r, g, b;
  772. COLORREF color;
  773. INT w, h;
  774. INT srcByteWidth = ((width * 2) + 3) & (~3);
  775. INT dstByteWidth = ((width * 3) + 3) & (~3);
  776. for (h = 0; h < posHeight; h++)
  777. {
  778. for (w = 0; w < width; w++)
  779. {
  780. pixel = (INT)(((INT16 *)srcPixels)[w]);
  781. r = (pixel & rMask) >> rMaskShift;
  782. r = (r | (r << rNumBits)) >> rRightShift;
  783. g = (pixel & gMask) >> gMaskShift;
  784. g = (g | (g << gNumBits)) >> gRightShift;
  785. b = (pixel & bMask) >> bMaskShift;
  786. b = (b | (b << bNumBits)) >> bRightShift;
  787. color = ModifyColor(RGB(r, g, b), adjustType);
  788. dstPixels[3*w + 2] = GetRValue(color);
  789. dstPixels[3*w + 1] = GetGValue(color);
  790. dstPixels[3*w] = GetBValue(color);
  791. }
  792. srcPixels += srcByteWidth;
  793. dstPixels += dstByteWidth;
  794. }
  795. }
  796. inline static INT
  797. Get24BppColorIndex(
  798. INT maskValue
  799. )
  800. {
  801. switch(GetMaskShift(maskValue))
  802. {
  803. default:
  804. WARNING(("Invalid BitFields Mask"));
  805. // FALLTHRU
  806. case 0:
  807. return 0;
  808. case 8:
  809. return 1;
  810. case 16:
  811. return 2;
  812. }
  813. }
  814. VOID
  815. MfEnumState::Modify24BppDib(
  816. INT width,
  817. INT posHeight,
  818. BYTE * srcPixels,
  819. DWORD UNALIGNED * bitFields,
  820. BYTE * dstPixels,
  821. ColorAdjustType adjustType
  822. )
  823. {
  824. INT rIndex = 2;
  825. INT gIndex = 1;
  826. INT bIndex = 0;
  827. if (bitFields != NULL)
  828. {
  829. INT rMask = (INT)((*bitFields++));
  830. INT gMask = (INT)((*bitFields++));
  831. INT bMask = (INT)((*bitFields));
  832. rIndex = Get24BppColorIndex(rMask);
  833. gIndex = Get24BppColorIndex(gMask);
  834. bIndex = Get24BppColorIndex(bMask);
  835. }
  836. INT palIndex = 0;
  837. INT r, g, b;
  838. COLORREF color;
  839. INT w, h;
  840. INT srcByteWidth = ((width * 3) + 3) & (~3);
  841. INT dstByteWidth = ((width * 3) + 3) & (~3);
  842. BYTE * srcRaster = srcPixels;
  843. for (h = 0; h < posHeight; h++)
  844. {
  845. srcPixels = srcRaster;
  846. for (w = 0; w < width; w++)
  847. {
  848. r = srcPixels[rIndex];
  849. g = srcPixels[gIndex];
  850. b = srcPixels[bIndex];
  851. srcPixels += 3;
  852. color = ModifyColor(RGB(r, g, b), adjustType);
  853. dstPixels[3*w + 2] = GetRValue(color);
  854. dstPixels[3*w + 1] = GetGValue(color);
  855. dstPixels[3*w] = GetBValue(color);
  856. }
  857. srcRaster += srcByteWidth;
  858. dstPixels += dstByteWidth;
  859. }
  860. }
  861. inline static INT
  862. Get32BppColorIndex(
  863. INT maskValue
  864. )
  865. {
  866. switch(GetMaskShift(maskValue))
  867. {
  868. default:
  869. WARNING(("Invalid BitFields Mask"));
  870. // FALLTHRU
  871. case 0:
  872. return 0;
  873. case 8:
  874. return 1;
  875. case 16:
  876. return 2;
  877. case 24:
  878. return 3;
  879. }
  880. }
  881. VOID
  882. MfEnumState::Modify32BppDib(
  883. INT width,
  884. INT posHeight,
  885. BYTE * srcPixels,
  886. DWORD UNALIGNED * bitFields,
  887. BYTE * dstPixels,
  888. ColorAdjustType adjustType
  889. )
  890. {
  891. INT rIndex = 2;
  892. INT gIndex = 1;
  893. INT bIndex = 0;
  894. if (bitFields != NULL)
  895. {
  896. INT rMask = (INT)((*bitFields++));
  897. INT gMask = (INT)((*bitFields++));
  898. INT bMask = (INT)((*bitFields));
  899. rIndex = Get32BppColorIndex(rMask);
  900. gIndex = Get32BppColorIndex(gMask);
  901. bIndex = Get32BppColorIndex(bMask);
  902. }
  903. INT palIndex = 0;
  904. INT r, g, b;
  905. COLORREF color;
  906. INT w, h;
  907. INT dstByteWidth = ((width * 3) + 3) & (~3);
  908. for (h = 0; h < posHeight; h++)
  909. {
  910. for (w = 0; w < width; w++)
  911. {
  912. r = srcPixels[rIndex];
  913. g = srcPixels[gIndex];
  914. b = srcPixels[bIndex];
  915. srcPixels += 4;
  916. color = ModifyColor(RGB(r, g, b), adjustType);
  917. dstPixels[3*w + 2] = GetRValue(color);
  918. dstPixels[3*w + 1] = GetGValue(color);
  919. dstPixels[3*w] = GetBValue(color);
  920. }
  921. dstPixels += dstByteWidth;
  922. }
  923. }
  924. VOID
  925. MfEnumState::ModifyDib(
  926. UINT usage,
  927. BITMAPINFOHEADER UNALIGNED * srcDibInfo,
  928. BYTE * srcBits, // if NULL, it's a packed DIB
  929. BITMAPINFOHEADER UNALIGNED * dstDibInfo,
  930. UINT numPalEntries,
  931. UINT srcDibBitsSize,
  932. ColorAdjustType adjustType
  933. )
  934. {
  935. INT srcBitCount = srcDibInfo->biBitCount;
  936. BYTE * srcPixels = srcBits;
  937. COLORREF color;
  938. if (srcBitCount <= 8)
  939. {
  940. GpMemcpy(dstDibInfo, srcDibInfo, srcDibInfo->biSize);
  941. RGBQUAD UNALIGNED * srcRgb = GetDibColorTable(srcDibInfo);
  942. RGBQUAD UNALIGNED * dstRgb = GetDibColorTable(dstDibInfo);
  943. dstDibInfo->biClrUsed = numPalEntries;
  944. if ((usage == DIB_PAL_COLORS) &&
  945. (dstDibInfo->biCompression != BI_BITFIELDS))
  946. {
  947. WORD * srcPal = (WORD *)srcRgb;
  948. if (srcPixels == NULL)
  949. {
  950. srcPixels = (BYTE *)(srcPal + ((numPalEntries + 1) & ~1)); // align
  951. }
  952. // Copy the Dib pixel data
  953. GpMemcpy(dstRgb + numPalEntries, srcPixels, srcDibBitsSize);
  954. // Modify the palette colors
  955. while (numPalEntries--)
  956. {
  957. color = ModifyColor(*srcPal++ | 0x01000000, adjustType);
  958. dstRgb->rgbRed = GetRValue(color);
  959. dstRgb->rgbGreen = GetGValue(color);
  960. dstRgb->rgbBlue = GetBValue(color);
  961. dstRgb->rgbReserved = 0;
  962. dstRgb++;
  963. }
  964. }
  965. else
  966. {
  967. if (srcPixels == NULL)
  968. {
  969. srcPixels = (BYTE *)(srcRgb + numPalEntries);
  970. }
  971. // Copy the Dib pixel data
  972. GpMemcpy(dstRgb + numPalEntries, srcPixels, srcDibBitsSize);
  973. // Modify the palette colors
  974. while (numPalEntries--)
  975. {
  976. color = ModifyColor(RGB(srcRgb->rgbRed, srcRgb->rgbGreen, srcRgb->rgbBlue), adjustType);
  977. dstRgb->rgbRed = GetRValue(color);
  978. dstRgb->rgbGreen = GetGValue(color);
  979. dstRgb->rgbBlue = GetBValue(color);
  980. dstRgb->rgbReserved = 0;
  981. dstRgb++;
  982. srcRgb++;
  983. }
  984. }
  985. }
  986. else // Recolor the bitmap. There is no need to palettize the image since
  987. // the palette will be as big as the image
  988. {
  989. INT posHeight = srcDibInfo->biHeight;
  990. if (posHeight < 0)
  991. {
  992. posHeight = -posHeight;
  993. }
  994. ASSERT((srcDibInfo->biCompression == BI_RGB) ||
  995. (srcDibInfo->biCompression == BI_BITFIELDS));
  996. GpMemset(dstDibInfo, 0, sizeof(BITMAPINFOHEADER));
  997. dstDibInfo->biSize = sizeof(BITMAPINFOHEADER);
  998. dstDibInfo->biWidth = srcDibInfo->biWidth;
  999. dstDibInfo->biHeight = srcDibInfo->biHeight;
  1000. dstDibInfo->biPlanes = 1;
  1001. dstDibInfo->biBitCount = 24;
  1002. BYTE * dstPixels = GetDibBits(dstDibInfo,0,0);
  1003. DWORD UNALIGNED * bitFields = NULL;
  1004. if (srcPixels == NULL)
  1005. {
  1006. srcPixels = (BYTE *)GetDibBits(srcDibInfo, numPalEntries, usage);
  1007. }
  1008. dstDibInfo->biClrUsed = 0;
  1009. dstDibInfo->biClrImportant = 0;
  1010. if (numPalEntries == 3)
  1011. {
  1012. ASSERT((srcBitCount == 16) || (srcBitCount == 32));
  1013. bitFields = (DWORD*) GetDibColorTable(srcDibInfo);
  1014. if ((bitFields[0] == 0) ||
  1015. (bitFields[1] == 0) ||
  1016. (bitFields[2] == 0))
  1017. {
  1018. bitFields = NULL;
  1019. }
  1020. }
  1021. else if (srcDibInfo->biSize >= sizeof(BITMAPV4HEADER))
  1022. {
  1023. BITMAPV4HEADER * srcHeaderV4 = (BITMAPV4HEADER *)srcDibInfo;
  1024. if ((srcHeaderV4->bV4RedMask != 0) &&
  1025. (srcHeaderV4->bV4GreenMask != 0) &&
  1026. (srcHeaderV4->bV4BlueMask != 0))
  1027. {
  1028. bitFields = &(srcHeaderV4->bV4RedMask);
  1029. }
  1030. }
  1031. switch (srcBitCount)
  1032. {
  1033. case 16:
  1034. Modify16BppDib(srcDibInfo->biWidth, posHeight, srcPixels,
  1035. bitFields, dstPixels, adjustType);
  1036. break;
  1037. case 24:
  1038. Modify24BppDib(srcDibInfo->biWidth, posHeight, srcPixels,
  1039. bitFields, dstPixels, adjustType);
  1040. break;
  1041. case 32:
  1042. Modify32BppDib(srcDibInfo->biWidth, posHeight, srcPixels,
  1043. bitFields, dstPixels, adjustType);
  1044. break;
  1045. }
  1046. }
  1047. }
  1048. VOID
  1049. WmfEnumState::DibCreatePatternBrush(
  1050. )
  1051. {
  1052. INT style = (INT)((INT16)(((WORD *)RecordData)[0]));
  1053. UINT usage = (UINT)((UINT16)(((WORD *)RecordData)[1]));
  1054. BITMAPINFOHEADER UNALIGNED * srcDibInfo = (BITMAPINFOHEADER UNALIGNED *)(&(((WORD *)RecordData)[2]));
  1055. UINT numPalEntries;
  1056. // Pattern brush should mean that it is a monochrome DIB
  1057. if (style == BS_PATTERN)
  1058. {
  1059. if (Recolor != NULL)
  1060. {
  1061. DWORD UNALIGNED * rgb = (DWORD UNALIGNED *)GetDibColorTable(srcDibInfo);
  1062. // See if it is a monochrome pattern brush. If it is, then
  1063. // the text color will be used for 0 bits and the background
  1064. // color will be used for 1 bits. These colors are already
  1065. // modified by their respective records, so there is no need
  1066. // to do anything here.
  1067. // If it is not a monochrome pattern brush, just create a
  1068. // solid black brush.
  1069. if ((usage != DIB_RGB_COLORS) ||
  1070. (srcDibInfo->biSize < sizeof(BITMAPINFOHEADER)) ||
  1071. !GetDibNumPalEntries(TRUE,
  1072. srcDibInfo->biSize,
  1073. srcDibInfo->biBitCount,
  1074. srcDibInfo->biCompression,
  1075. srcDibInfo->biClrUsed,
  1076. &numPalEntries) ||
  1077. (numPalEntries != 2) ||
  1078. (srcDibInfo->biBitCount != 1) || (srcDibInfo->biPlanes != 1) ||
  1079. (rgb[0] != 0x00000000) || (rgb[1] != 0x00FFFFFF))
  1080. {
  1081. // This shouldn't happen, at least not if recorded on NT
  1082. WARNING(("Non-monochrome pattern brush"));
  1083. MakeSolidBlackBrush();
  1084. }
  1085. }
  1086. }
  1087. else
  1088. {
  1089. UINT dibBitsSize;
  1090. if ((srcDibInfo->biSize >= sizeof(BITMAPINFOHEADER)) &&
  1091. GetDibNumPalEntries(TRUE,
  1092. srcDibInfo->biSize,
  1093. srcDibInfo->biBitCount,
  1094. srcDibInfo->biCompression,
  1095. srcDibInfo->biClrUsed,
  1096. &numPalEntries) &&
  1097. ((dibBitsSize = GetDibBitsSize(srcDibInfo)) > 0))
  1098. {
  1099. UINT oldUsage = usage;
  1100. INT dstDibSize = GetModifiedDibSize(srcDibInfo, numPalEntries, dibBitsSize, usage);
  1101. if (dstDibSize > 0)
  1102. {
  1103. INT size = SIZEOF_METARECORDHEADER + (2 * sizeof(WORD)) + dstDibSize;
  1104. CreateRecordToModify(size);
  1105. ModifiedWmfRecord->rdSize = size / 2;
  1106. ModifiedWmfRecord->rdFunction = META_DIBCREATEPATTERNBRUSH;
  1107. ModifiedWmfRecord->rdParm[0] = BS_DIBPATTERN;
  1108. ModifiedWmfRecord->rdParm[1] = DIB_RGB_COLORS;
  1109. ModifyDib(oldUsage, srcDibInfo, NULL,
  1110. (BITMAPINFOHEADER UNALIGNED *)(&(ModifiedWmfRecord->rdParm[2])),
  1111. numPalEntries, dibBitsSize, ColorAdjustTypeBrush);
  1112. }
  1113. }
  1114. }
  1115. this->PlayRecord();
  1116. }
  1117. // This record is obsolete, because it uses a compatible bitmap
  1118. // instead of a DIB. It has a BITMAP16 structure that is
  1119. // used to call CreateBitmapIndirect. That HBITMAP is, in turn,
  1120. // used to call CreatePatternBrush. If this record is present,
  1121. // it is likely that the bitmap is monochrome, in which case
  1122. // the TextColor and the BkColor will be used, and these colors
  1123. // already get modified by their respective records.
  1124. VOID
  1125. WmfEnumState::CreatePatternBrush(
  1126. )
  1127. {
  1128. WARNING(("Obsolete META_CREATEPATTERNBRUSH record"));
  1129. BITMAP16 UNALIGNED * bitmap = (BITMAP16 UNALIGNED *)RecordData;
  1130. if (bitmap->bmBitsPixel != 1)
  1131. {
  1132. WARNING(("Non-monochrome pattern brush"));
  1133. MakeSolidBlackBrush();
  1134. }
  1135. this->PlayRecord();
  1136. }
  1137. VOID
  1138. WmfEnumState::CreatePenIndirect(
  1139. )
  1140. {
  1141. LOGPEN16 UNALIGNED * logPen = (LOGPEN16 UNALIGNED *)RecordData;
  1142. switch (logPen->lopnStyle)
  1143. {
  1144. default:
  1145. WARNING(("Unrecognized Pen Style"));
  1146. case PS_NULL:
  1147. break; // leave the pen alone
  1148. case PS_SOLID:
  1149. case PS_INSIDEFRAME:
  1150. case PS_DASH:
  1151. case PS_DOT:
  1152. case PS_DASHDOT:
  1153. case PS_DASHDOTDOT:
  1154. ModifyRecordColor(3, ColorAdjustTypePen);
  1155. break;
  1156. }
  1157. this->PlayRecord();
  1158. }
  1159. VOID
  1160. WmfEnumState::CreateBrushIndirect(
  1161. )
  1162. {
  1163. LOGBRUSH16 UNALIGNED * logBrush = (LOGBRUSH16 UNALIGNED *)RecordData;
  1164. switch (logBrush->lbStyle)
  1165. {
  1166. case BS_SOLID:
  1167. case BS_HATCHED:
  1168. {
  1169. ModifyRecordColor(1, ColorAdjustTypeBrush);
  1170. if (ModifiedWmfRecord != NULL)
  1171. {
  1172. logBrush = (LOGBRUSH16 UNALIGNED *)(ModifiedWmfRecord->rdParm);
  1173. }
  1174. // See if we need to halftone the color. We do if it is a solid
  1175. // color, and we have a halftone palette, and the color is not
  1176. // an exact match in the palette.
  1177. COLORREF color;
  1178. if (IsHalftonePalette && (logBrush->lbStyle == BS_SOLID) &&
  1179. (((color = logBrush->lbColor) & 0x02000000) == 0))
  1180. {
  1181. // create a halftone brush, instead of a solid brush
  1182. INT size = SIZEOF_METARECORDHEADER + (2 * sizeof(WORD)) +
  1183. sizeof(BITMAPINFOHEADER) + // DIB 8 bpp header
  1184. (8 * sizeof(RGBQUAD)) + // DIB 8 colors
  1185. (8 * 8); // DIB 8x8 pixels
  1186. ModifiedRecordSize = 0; // in case we already modified the record
  1187. CreateRecordToModify(size);
  1188. ModifiedWmfRecord->rdSize = size / 2;
  1189. ModifiedWmfRecord->rdFunction = META_DIBCREATEPATTERNBRUSH;
  1190. ModifiedWmfRecord->rdParm[0] = BS_DIBPATTERN;
  1191. ModifiedWmfRecord->rdParm[1] = DIB_RGB_COLORS;
  1192. HalftoneColorRef_216(color, &(ModifiedWmfRecord->rdParm[2]));
  1193. }
  1194. }
  1195. break;
  1196. case BS_HOLLOW:
  1197. break; // leave the record alone
  1198. default:
  1199. // Looking at the NT source code, there shouldn't be any
  1200. // other brush styles for an indirect brush.
  1201. WARNING(("Brush Style Not Valid"));
  1202. MakeSolidBlackBrush();
  1203. break;
  1204. }
  1205. this->PlayRecord();
  1206. }
  1207. // Also handles StretchBlt.
  1208. // These records are obsolete (when there is a source bitmap) because they
  1209. // have a compatible bitmap instead of a DIB. For that reason, we don't
  1210. // recolor them.
  1211. VOID
  1212. WmfEnumState::BitBlt(
  1213. )
  1214. {
  1215. DWORD rop = *((UNALIGNED DWORD *)RecordData);
  1216. // If No-Op ROP, do nothing; just return
  1217. if ((rop & 0xFFFF0000) == (GDIP_NOOP_ROP3 & 0xFFFF0000))
  1218. {
  1219. return;
  1220. }
  1221. if (!IsMetafile())
  1222. {
  1223. if (IsSourceInRop3(rop))
  1224. {
  1225. WARNING(("Obsolete META_BITBLT/META_STRETCHBLT record"));
  1226. if ((rop != SRCCOPY) && SrcCopyOnly &&
  1227. CreateCopyOfCurrentRecord())
  1228. {
  1229. *((DWORD UNALIGNED *)ModifiedWmfRecord->rdParm) = SRCCOPY;
  1230. }
  1231. }
  1232. else
  1233. {
  1234. if ((rop != PATCOPY) && SrcCopyOnly &&
  1235. CreateCopyOfCurrentRecord())
  1236. {
  1237. *((DWORD UNALIGNED *)ModifiedWmfRecord->rdParm) = PATCOPY;
  1238. }
  1239. }
  1240. }
  1241. this->PlayRecord();
  1242. }
  1243. VOID
  1244. WmfEnumState::Escape(
  1245. )
  1246. {
  1247. INT escapeCode = (INT)((INT16)(((WORD *)RecordData)[0]));
  1248. if (!IsPostscript())
  1249. {
  1250. if (SkipEscape(escapeCode))
  1251. {
  1252. return;
  1253. }
  1254. // Skip Office Art data when playing into another metafile
  1255. if (IsMetafile() &&
  1256. IsOfficeArtData(GetCurrentRecordSize(), (WORD *)RecordData))
  1257. {
  1258. return;
  1259. }
  1260. }
  1261. else // it is postscript
  1262. {
  1263. if (escapeCode == MFCOMMENT)
  1264. {
  1265. if (GetWmfComment((WORD *)RecordData, msosignature, msocommentBeginSrcCopy))
  1266. {
  1267. SrcCopyOnly = TRUE;
  1268. return;
  1269. }
  1270. if (GetWmfComment((WORD *)RecordData, msosignature, msocommentEndSrcCopy))
  1271. {
  1272. SrcCopyOnly = FALSE;
  1273. return;
  1274. }
  1275. }
  1276. if (escapeCode == POSTSCRIPT_DATA)
  1277. {
  1278. // Bug #98743 (Windows Bugs) Gdiplus must overcome GDI limitation
  1279. // with POSTSCRIPT_INJECTION. Comments from Rammanohar Arumugam:
  1280. //
  1281. // Being in xx-centric mode means POSTSCRIPT_DATA won't work. I
  1282. // take that to mean that PlayMetaFileRecord only works in
  1283. // compatibility mode.
  1284. //
  1285. // GdiPlus will check for the printer mode. In GDI-centric and
  1286. // Postscript-centric mode, it will not do PlayMetaFileRecord for
  1287. // any record that has POSTSCRIPT_DATA. Instead, it will output
  1288. // the postscript data through a PASSTHRU (for GDI-centric mode)
  1289. // or a POSTSCRIPT_PASSTHRU (for Postscript-Centric mode).
  1290. //
  1291. // You can find out the mode by querying the escape support.
  1292. // 1. Query for POSTSCRIPT_INJECTION support. If not supported,
  1293. // it's compat mode. If supported, find out the mode by doing step 2/3
  1294. // 2. Query for PASSTHROUGH support. If supported, it's GDI-centric.
  1295. // 3. Query for POSTSCRIPT_PASSTHROUGH support. If supported, it's
  1296. // PS-centric.
  1297. if (Globals::IsNt)
  1298. {
  1299. if (!SoftekFilter)
  1300. {
  1301. // Determine presence of Softek Filter EPS, if so, then
  1302. // we apply workaround patches.
  1303. WORD size = *((WORD*)RecordData);
  1304. LPSTR escape = (LPSTR)(&RecordData[6]);
  1305. const LPSTR softekString = "%MSEPS Preamble [Softek";
  1306. INT softekLen = strlen(softekString);
  1307. if (size >= softekLen)
  1308. {
  1309. SoftekFilter = !GpMemcmp(softekString, escape, softekLen);
  1310. }
  1311. }
  1312. DWORD EscapeValue = POSTSCRIPT_IDENTIFY;
  1313. if (::ExtEscape(Hdc,
  1314. QUERYESCSUPPORT,
  1315. sizeof(DWORD),
  1316. (LPSTR)&EscapeValue,
  1317. 0,
  1318. NULL) <= 0)
  1319. {
  1320. // POSTSCRIPT_IDENTITY is not supported if the mode has
  1321. // been set because it can only be set once.
  1322. EscapeValue = POSTSCRIPT_PASSTHROUGH;
  1323. if (::ExtEscape(Hdc,
  1324. QUERYESCSUPPORT,
  1325. sizeof(DWORD),
  1326. (LPSTR)&EscapeValue,
  1327. 0,
  1328. NULL) <= 0)
  1329. {
  1330. // GDI-centric mode
  1331. if (CreateCopyOfCurrentRecord())
  1332. {
  1333. *((WORD *)ModifiedWmfRecord->rdParm) = PASSTHROUGH;
  1334. }
  1335. GdiCentricMode = TRUE;
  1336. }
  1337. else
  1338. {
  1339. // PS-centric mode
  1340. if (CreateCopyOfCurrentRecord())
  1341. {
  1342. *((WORD *)ModifiedWmfRecord->rdParm) = POSTSCRIPT_PASSTHROUGH;
  1343. }
  1344. }
  1345. this->PlayRecord();
  1346. return;
  1347. }
  1348. else
  1349. {
  1350. // compatibility mode, uses POSTSCRIPT_DATA
  1351. }
  1352. }
  1353. else
  1354. {
  1355. // Win98 doesn't distinguish between GDI & compatibility mode
  1356. if (CreateCopyOfCurrentRecord())
  1357. {
  1358. *((WORD *)ModifiedWmfRecord->rdParm) = PASSTHROUGH;
  1359. }
  1360. }
  1361. }
  1362. }
  1363. // Keep track of the POSTSCRIPT_IGNORE state. If it is still on at
  1364. // the of the metafile, then turn it OFF
  1365. if (escapeCode == POSTSCRIPT_IGNORE && IsPostscript())
  1366. {
  1367. IgnorePostscript = ((WORD *)RecordData)[2] ? TRUE : FALSE;
  1368. }
  1369. this->PlayRecord();
  1370. }
  1371. VOID
  1372. WmfEnumState::Rectangle(
  1373. )
  1374. {
  1375. if (FsmState == MfFsmSetROP)
  1376. {
  1377. // There is a bug using PlayMetaFileRecord on Win2K for this
  1378. // type of escape, we must explicitly call ExtEscape. See bug
  1379. // #98743.
  1380. WORD* rdParm = (WORD*)&(RecordData[0]);
  1381. CHAR postscriptEscape[512];
  1382. RECT rect;
  1383. rect.left = (SHORT)rdParm[3];
  1384. rect.top = (SHORT)rdParm[2];
  1385. rect.right = (SHORT)rdParm[1];
  1386. rect.bottom = (SHORT)rdParm[0];
  1387. if (LPtoDP(Hdc, (POINT*)&rect, 2))
  1388. {
  1389. // Some injected postscript, strangely enough contains the equivalent
  1390. // of a stroke which is erroroneously executed on the current path. In
  1391. // one case, bug #281856 it results in a border about the object. To
  1392. // get around this, we output a 'N' which is newpath operator if it's
  1393. // defined (which should be always.) This, incidently, is done when
  1394. // calling GDI Rectangle() succeeds, it outputs "N x y w h B", so we
  1395. // are doing the equivalent here.
  1396. GpRect clipRect;
  1397. Context->VisibleClip.GetBounds(&clipRect);
  1398. wsprintfA(&postscriptEscape[2],
  1399. "\r\n%d %d %d %d CB\r\n"
  1400. "%s"
  1401. "%d %d %d %d B\r\n",
  1402. clipRect.Width,
  1403. clipRect.Height,
  1404. clipRect.X,
  1405. clipRect.Y,
  1406. Globals::IsNt ? "newpath\r\n" : "",
  1407. rect.right - rect.left,
  1408. rect.bottom - rect.top,
  1409. rect.left,
  1410. rect.top);
  1411. ASSERT(strlen(&postscriptEscape[2]) < 512);
  1412. *(WORD*)(&postscriptEscape[0]) = (WORD)(strlen(&postscriptEscape[2]));
  1413. ::ExtEscape(Hdc,
  1414. PASSTHROUGH,
  1415. *(WORD*)(&postscriptEscape[0]) + sizeof(WORD) + 1,
  1416. (CHAR*)&postscriptEscape[0],
  1417. 0,
  1418. NULL);
  1419. return;
  1420. }
  1421. }
  1422. this->PlayRecord();
  1423. }
  1424. VOID
  1425. WmfEnumState::RestoreHdc(
  1426. )
  1427. {
  1428. INT relativeCount = (INT)((INT16)(((WORD *)RecordData)[0]));
  1429. if (SaveDcCount < 0)
  1430. {
  1431. if (relativeCount >= SaveDcCount)
  1432. {
  1433. if (relativeCount >= 0)
  1434. {
  1435. // Modify the record
  1436. CreateCopyOfCurrentRecord(); // guaranteed to succeed
  1437. relativeCount = -1;
  1438. ModifiedWmfRecord->rdParm[0] = (INT16)(-1);
  1439. }
  1440. }
  1441. else
  1442. {
  1443. // Modify the record
  1444. CreateCopyOfCurrentRecord(); // guaranteed to succeed
  1445. relativeCount = SaveDcCount;
  1446. ModifiedWmfRecord->rdParm[0] = (INT16)(relativeCount);
  1447. }
  1448. SaveDcCount -= relativeCount;
  1449. this->PlayRecord();
  1450. }
  1451. else
  1452. {
  1453. WARNING(("RestoreDC not matched to a SaveDC"));
  1454. }
  1455. }
  1456. // The rop for this command is always SRCCOPY
  1457. VOID
  1458. WmfEnumState::SetDIBitsToDevice(
  1459. )
  1460. {
  1461. // !!!
  1462. // Office doesn't do anything with this record. For now, I don't think
  1463. // I will either. It's a tough one to deal with for a couple reasons:
  1464. // 1st - The xDest and yDest values are in world units, but the
  1465. // width and height values are in device units
  1466. // (unlike StretchDIBits).
  1467. // 2nd - The amount of bits data present may be different than
  1468. // what is in the DIB header (based on the cScanLines param).
  1469. // This makes it harder to deal with as a packed DIB.
  1470. this->PlayRecord();
  1471. }
  1472. VOID
  1473. MfEnumState::SelectPalette(
  1474. INT objectIndex
  1475. )
  1476. {
  1477. // For EMF the check really should be > 0
  1478. if ((objectIndex >= 0) && (objectIndex < NumObjects) && (HandleTable != NULL))
  1479. {
  1480. HGDIOBJ hPal = HandleTable->objectHandle[objectIndex];
  1481. if ((hPal != NULL) && (GetObjectTypeInternal(hPal) == OBJ_PAL))
  1482. {
  1483. CurrentPalette = (HPALETTE)hPal;
  1484. return;
  1485. }
  1486. }
  1487. WARNING(("SelectPalette Failure"));
  1488. }
  1489. inline static VOID
  1490. Point32FromPoint16(
  1491. POINTL * dstPoints,
  1492. POINTS UNALIGNED * srcPoints,
  1493. UINT numPoints
  1494. )
  1495. {
  1496. for (UINT i = 0; i < numPoints; i++, dstPoints++, srcPoints++)
  1497. {
  1498. dstPoints->x = (INT)((INT16)(srcPoints->x));
  1499. dstPoints->y = (INT)((INT16)(srcPoints->y));
  1500. }
  1501. }
  1502. // Apparently there is a bug on Win9x with PolyPolygons, so we
  1503. // parse the record ourselves.
  1504. VOID
  1505. WmfEnumState::PolyPolygon(
  1506. )
  1507. {
  1508. UINT numPolygons = ((WORD *)RecordData)[0];
  1509. UINT numPoints = 0;
  1510. UINT i;
  1511. for (i = 0; i < numPolygons; i++)
  1512. {
  1513. numPoints += ((LPWORD)&((WORD *)RecordData)[1])[i];
  1514. }
  1515. INT * polyCounts;
  1516. POINTL * points;
  1517. INT size = (numPolygons * sizeof(INT)) +
  1518. (numPoints * sizeof(POINTL));
  1519. if (CreateRecordToModify(size))
  1520. {
  1521. polyCounts = (INT *)ModifiedRecord;
  1522. points = (POINTL *)(polyCounts + numPolygons);
  1523. for (i = 0; i < numPolygons; i++)
  1524. {
  1525. polyCounts[i] = (INT)(UINT)((LPWORD)&((WORD *)RecordData)[1])[i];
  1526. }
  1527. Point32FromPoint16(points,
  1528. (POINTS UNALIGNED *)(((WORD *)RecordData) + numPolygons + 1),
  1529. numPoints);
  1530. ::PolyPolygon(Hdc, (POINT *)points, polyCounts, numPolygons);
  1531. return;
  1532. }
  1533. this->PlayRecord();
  1534. }
  1535. #ifdef NEED_TO_KNOW_IF_BITMAP
  1536. static INT
  1537. GetBppFromMemDC(
  1538. HDC hMemDC
  1539. )
  1540. {
  1541. HBITMAP hBitmap = (HBITMAP)::GetCurrentObject(hMemDC, OBJ_BITMAP);
  1542. BITMAP bitmap;
  1543. if ((hBitmap == NULL) ||
  1544. (::GetObjectA(hBitmap, sizeof(bitmap), &bitmap) == 0))
  1545. {
  1546. WARNING(("Couldn't get Bitmap object"));
  1547. return 0; // error
  1548. }
  1549. if (bitmap.bmPlanes <= 0)
  1550. {
  1551. WARNING(("Bitmap with no planes"));
  1552. bitmap.bmPlanes = 1;
  1553. }
  1554. INT bpp = bitmap.bmPlanes * bitmap.bmBitsPixel;
  1555. if (bpp > 32)
  1556. {
  1557. WARNING(("Bitmap with too many bits"));
  1558. bpp = 32;
  1559. }
  1560. return bpp;
  1561. }
  1562. #endif
  1563. #define GDI_INTERPOLATION_MAX (1 << 23)
  1564. VOID
  1565. MfEnumState::OutputDIB(
  1566. HDC hdc,
  1567. const RECTL * bounds,
  1568. INT dstX,
  1569. INT dstY,
  1570. INT dstWidth,
  1571. INT dstHeight,
  1572. INT srcX,
  1573. INT srcY,
  1574. INT srcWidth,
  1575. INT srcHeight,
  1576. BITMAPINFOHEADER UNALIGNED * dibInfo,
  1577. BYTE * bits, // if NULL, this is a packed DIB
  1578. UINT usage,
  1579. DWORD rop,
  1580. BOOL isWmfDib
  1581. )
  1582. {
  1583. BITMAPINFO dibHeaderBuffer[1]; // To be sure it's aligned for 64Bits
  1584. BOOL restoreColors = FALSE;
  1585. COLORREF oldBkColor;
  1586. COLORREF oldTextColor;
  1587. ASSERT(dibInfo->biSize >= sizeof(BITMAPINFOHEADER));
  1588. if (bits == NULL)
  1589. {
  1590. UINT numPalEntries;
  1591. if (GetDibNumPalEntries(isWmfDib,
  1592. dibInfo->biSize,
  1593. dibInfo->biBitCount,
  1594. dibInfo->biCompression,
  1595. dibInfo->biClrUsed,
  1596. &numPalEntries))
  1597. {
  1598. bits = GetDibBits(dibInfo, numPalEntries, usage);
  1599. }
  1600. else
  1601. {
  1602. WARNING(("GetDibNumPalEntries failure"));
  1603. return;
  1604. }
  1605. }
  1606. INT posDstWidth = dstWidth;
  1607. if (posDstWidth < 0)
  1608. {
  1609. posDstWidth = -posDstWidth;
  1610. }
  1611. INT posDstHeight = dstHeight;
  1612. if (posDstHeight < 0)
  1613. {
  1614. posDstHeight = -posDstHeight;
  1615. }
  1616. INT stretchBltMode = HALFTONE;
  1617. GpBitmap * destBitmap = NULL;
  1618. POINT destPoints[3];
  1619. BitmapData bmpData;
  1620. BitmapData * bmpDataPtr = NULL;
  1621. HBITMAP hBitmap = NULL;
  1622. BYTE * bmpBits = NULL;
  1623. BITMAPINFO * dibBmpInfo = NULL;
  1624. BOOL deleteDIBSection = FALSE;
  1625. // Don't use GDI+ stretching for a mask
  1626. // Make this the first thing so that we are sure that they are set
  1627. if ((dibInfo->biBitCount == 1) && (rop != SRCCOPY))
  1628. {
  1629. oldBkColor = ::SetBkColor(hdc, BkColor);
  1630. oldTextColor = ::SetTextColor(hdc, TextColor);
  1631. restoreColors = TRUE;
  1632. goto DoGdiStretch;
  1633. }
  1634. // On Win9x we need to create an play a comment record so that the transform
  1635. // gets invalidated and recalculated
  1636. if (!Globals::IsNt && !IsMetafile())
  1637. {
  1638. CreateAndPlayCommentRecord();
  1639. }
  1640. destPoints[0].x = dstX;
  1641. destPoints[0].y = dstY;
  1642. destPoints[1].x = dstX + posDstWidth;
  1643. destPoints[1].y = dstY;
  1644. destPoints[2].x = dstX;
  1645. destPoints[2].y = dstY + posDstHeight;
  1646. if (!::LPtoDP(hdc, destPoints, 3))
  1647. {
  1648. goto DoGdiStretch;
  1649. }
  1650. posDstWidth = ::GetIntDistance(destPoints[0], destPoints[1]);
  1651. posDstHeight = ::GetIntDistance(destPoints[0], destPoints[2]);
  1652. if ((posDstWidth == 0) || (posDstHeight == 0))
  1653. {
  1654. return;
  1655. }
  1656. INT posSrcWidth;
  1657. INT srcWidthSign;
  1658. posSrcWidth = srcWidth;
  1659. srcWidthSign = 1;
  1660. if (posSrcWidth < 0)
  1661. {
  1662. posSrcWidth = -posSrcWidth;
  1663. srcWidthSign = -1;
  1664. }
  1665. INT posSrcHeight;
  1666. INT srcHeightSign;
  1667. posSrcHeight = srcHeight;
  1668. srcHeightSign = 1;
  1669. if (posSrcHeight < 0)
  1670. {
  1671. posSrcHeight = -posSrcHeight;
  1672. srcHeightSign = -1;
  1673. }
  1674. INT posSrcDibWidth;
  1675. posSrcDibWidth = dibInfo->biWidth;
  1676. if (posSrcDibWidth <= 0)
  1677. {
  1678. WARNING(("Bad biWidth value"));
  1679. return; // negative source dib width not allowed
  1680. }
  1681. INT posSrcDibHeight;
  1682. posSrcDibHeight = dibInfo->biHeight;
  1683. if (posSrcDibHeight < 0)
  1684. {
  1685. posSrcDibHeight = -posSrcDibHeight;
  1686. }
  1687. // We can have a negative source Width or height
  1688. // we need to verify that the two corners of the srcRect lie in the
  1689. // bitmap bounds
  1690. if (srcX < 0)
  1691. {
  1692. srcX = 0;
  1693. WARNING(("srcX < 0"));
  1694. }
  1695. if (srcX > posSrcDibWidth)
  1696. {
  1697. WARNING(("Bad srcWidth or srcX value"));
  1698. srcX = posSrcDibWidth;
  1699. }
  1700. if (srcY < 0)
  1701. {
  1702. srcY = 0;
  1703. WARNING(("srcY < 0"));
  1704. }
  1705. if (srcY > posSrcDibHeight)
  1706. {
  1707. WARNING(("Bad srcWidth or srcX value"));
  1708. srcY = posSrcDibHeight;
  1709. }
  1710. INT srcRight;
  1711. srcRight = srcX + srcWidth;
  1712. if (srcRight < 0)
  1713. {
  1714. WARNING(("Bad srcWidth or srcX value"));
  1715. srcWidth = -srcX;
  1716. }
  1717. if(srcRight > posSrcDibWidth)
  1718. {
  1719. WARNING(("Bad srcWidth or srcX value"));
  1720. srcWidth = posSrcDibWidth - srcX;
  1721. }
  1722. INT srcBottom;
  1723. srcBottom = srcY + srcHeight;
  1724. if (srcBottom < 0)
  1725. {
  1726. WARNING(("Bad srcWidth or srcX value"));
  1727. srcHeight = -srcY;
  1728. }
  1729. if (srcBottom > posSrcDibHeight)
  1730. {
  1731. WARNING(("Bad srcWidth or srcX value"));
  1732. srcHeight = posSrcDibHeight - srcY;
  1733. }
  1734. // This also catches the case where
  1735. // (posSrcDibWidth == 0) || (posSrcDibHeight == 0)
  1736. if ((posSrcWidth <= 0) || (posSrcHeight <= 0))
  1737. {
  1738. return;
  1739. }
  1740. // If we are drawing into an 8Bpp surface and we have a different ROP then
  1741. // srcCopy.
  1742. if (Is8Bpp && rop != SRCCOPY)
  1743. {
  1744. BOOL freeDibInfo = FALSE;
  1745. UINT size;
  1746. BITMAPINFO * alignedDibInfo = NULL;
  1747. if (GetDibNumPalEntries(TRUE,
  1748. dibInfo->biSize,
  1749. dibInfo->biBitCount,
  1750. dibInfo->biCompression,
  1751. dibInfo->biClrUsed,
  1752. &size))
  1753. {
  1754. if (IsDwordAligned(dibInfo))
  1755. {
  1756. alignedDibInfo = (BITMAPINFO*) dibInfo;
  1757. }
  1758. else
  1759. {
  1760. // Mutliply the number of entries by the size of each entry
  1761. size *= ((usage==DIB_RGB_COLORS)?sizeof(RGBQUAD):sizeof(WORD));
  1762. // WMF's can't use System Palette
  1763. alignedDibInfo = (BITMAPINFO*) GpMalloc(dibInfo->biSize + size);
  1764. if (alignedDibInfo != NULL)
  1765. {
  1766. memcpy((void*)&alignedDibInfo, dibInfo, dibInfo->biSize + size);
  1767. freeDibInfo = TRUE;
  1768. }
  1769. }
  1770. if (alignedDibInfo != NULL)
  1771. {
  1772. if (GpBitmap::DrawAndHalftoneForStretchBlt(hdc, alignedDibInfo, bits, srcX, srcY,
  1773. posSrcWidth, posSrcHeight,
  1774. posDstWidth, posDstHeight,
  1775. &dibBmpInfo, &bmpBits, &hBitmap,
  1776. Interpolation) == Ok)
  1777. {
  1778. deleteDIBSection = TRUE;
  1779. srcX = 0;
  1780. srcY = 0;
  1781. srcWidth = posDstWidth;
  1782. srcHeight = posDstHeight;
  1783. dibInfo = (BITMAPINFOHEADER*) dibBmpInfo;
  1784. bits = bmpBits;
  1785. if (freeDibInfo)
  1786. {
  1787. GpFree(alignedDibInfo);
  1788. }
  1789. goto DoGdiStretch;
  1790. }
  1791. if (freeDibInfo)
  1792. {
  1793. GpFree(alignedDibInfo);
  1794. }
  1795. }
  1796. }
  1797. }
  1798. // if not stretching, let GDI do the blt
  1799. if ((posSrcWidth == posDstWidth) && (posSrcHeight == posDstHeight))
  1800. {
  1801. goto DoGdiStretch;
  1802. }
  1803. InterpolationMode interpolationMode;
  1804. interpolationMode = Interpolation;
  1805. // if not going to the screen or to a bitmap, use GDI to do the stretch
  1806. // otherwise, use GDI+ to do the stretch (but let GDI do the blt)
  1807. // if going to printer on Win98 and it is RLE8 compressed bitmap, then
  1808. // always decode and blit from GDI+. The reason is that print drivers
  1809. // commonly don't support RLEx encoding and punt to GDI. In this
  1810. // context it creates a compatible printer dc and bitmap and then does a
  1811. // StretchBlt, but it only does this at 1bpp, the result is black and white.
  1812. if ((IsPrinter() && !Globals::IsNt &&
  1813. dibInfo->biCompression == BI_RLE8) ||
  1814. ((IsScreen() || IsBitmap()) &&
  1815. (interpolationMode != InterpolationModeNearestNeighbor) &&
  1816. (posSrcWidth > 1) && (posSrcHeight > 1) &&
  1817. ((posDstWidth * posDstHeight) < GDI_INTERPOLATION_MAX)))
  1818. {
  1819. GpStatus status = GenericError;
  1820. destBitmap = new GpBitmap(posDstWidth, posDstHeight, PIXFMT_24BPP_RGB);
  1821. if (destBitmap != NULL)
  1822. {
  1823. if (destBitmap->IsValid())
  1824. {
  1825. BITMAPINFO * alignedDibInfo = NULL;
  1826. UINT size;
  1827. BOOL freeDibInfo = FALSE;
  1828. if (GetDibNumPalEntries(TRUE,
  1829. dibInfo->biSize,
  1830. dibInfo->biBitCount,
  1831. dibInfo->biCompression,
  1832. dibInfo->biClrUsed,
  1833. &size))
  1834. {
  1835. if (IsDwordAligned(dibInfo))
  1836. {
  1837. alignedDibInfo = (BITMAPINFO*) dibInfo;
  1838. }
  1839. else
  1840. {
  1841. // Mutliply the number of entries by the size of each entry
  1842. size *= ((usage==DIB_RGB_COLORS)?sizeof(RGBQUAD):sizeof(WORD));
  1843. // WMF's can't use System Palette
  1844. alignedDibInfo = (BITMAPINFO*) GpMalloc(dibInfo->biSize + size);
  1845. if (alignedDibInfo != NULL)
  1846. {
  1847. memcpy((void*)&alignedDibInfo, dibInfo, dibInfo->biSize + size);
  1848. freeDibInfo = TRUE;
  1849. }
  1850. }
  1851. if (alignedDibInfo != NULL)
  1852. {
  1853. GpBitmap * srcBitmap = new GpBitmap(alignedDibInfo,
  1854. bits, FALSE);
  1855. if (srcBitmap != NULL)
  1856. {
  1857. if (srcBitmap->IsValid())
  1858. {
  1859. GpGraphics * destGraphics = destBitmap->GetGraphicsContext();
  1860. if (destGraphics != NULL)
  1861. {
  1862. if (destGraphics->IsValid())
  1863. {
  1864. // we have to lock the graphics so the driver doesn't assert
  1865. GpLock lockGraphics(destGraphics->GetObjectLock());
  1866. ASSERT(lockGraphics.IsValid());
  1867. GpRectF dstRect(0.0f, 0.0f, (REAL)posDstWidth, (REAL)posDstHeight);
  1868. GpRectF srcRect;
  1869. // StretchDIBits takes a srcY parameter relative to the lower-left
  1870. // (bottom) corner of the bitmap, not the top-left corner,
  1871. // like DrawImage does
  1872. srcRect.Y = (REAL)(posSrcDibHeight - srcY - srcHeight);
  1873. srcRect.X = (REAL)srcX;
  1874. // !!! We have to subtract one to keep the
  1875. // filter from blending black into the image
  1876. // on the right and bottom.
  1877. srcRect.Width = (REAL)(srcWidth - (srcWidthSign));
  1878. srcRect.Height = (REAL)(srcHeight - (srcHeightSign));
  1879. // don't do any blending as part of the stretch
  1880. destGraphics->SetCompositingMode(CompositingModeSourceCopy);
  1881. destGraphics->SetInterpolationMode(interpolationMode);
  1882. // Set the image attributes to Wrap since we don't want to
  1883. // use black pixels for the edges
  1884. GpImageAttributes imgAttr;
  1885. imgAttr.SetWrapMode(WrapModeTileFlipXY);
  1886. // now draw the source into the dest bitmap
  1887. status = destGraphics->DrawImage(srcBitmap,
  1888. dstRect,
  1889. srcRect,
  1890. UnitPixel,
  1891. &imgAttr);
  1892. }
  1893. else
  1894. {
  1895. WARNING(("destGraphics not valid"));
  1896. }
  1897. delete destGraphics;
  1898. }
  1899. else
  1900. {
  1901. WARNING(("Could not construct destGraphics"));
  1902. }
  1903. }
  1904. else
  1905. {
  1906. WARNING(("srcGraphics not valid"));
  1907. }
  1908. srcBitmap->Dispose(); // doesn't delete the source data
  1909. }
  1910. else
  1911. {
  1912. WARNING(("Could not allocate a new BitmapInfoHeader"));
  1913. }
  1914. if (freeDibInfo)
  1915. {
  1916. GpFree(alignedDibInfo);
  1917. }
  1918. }
  1919. else
  1920. {
  1921. WARNING(("Could not construct srcGraphics"));
  1922. }
  1923. }
  1924. else
  1925. {
  1926. WARNING(("Could not clone the bitmap header"));
  1927. }
  1928. if ((status == Ok) &&
  1929. (destBitmap->LockBits(NULL, IMGLOCK_READ, PIXFMT_24BPP_RGB,
  1930. &bmpData) == Ok))
  1931. {
  1932. ASSERT((bmpData.Stride & 3) == 0);
  1933. GpMemset(dibHeaderBuffer, 0, sizeof(BITMAPINFO));
  1934. bmpDataPtr = &bmpData;
  1935. bits = (BYTE *)bmpData.Scan0;
  1936. srcX = 0;
  1937. srcY = 0;
  1938. srcWidth = posDstWidth;
  1939. srcHeight = posDstHeight;
  1940. usage = DIB_RGB_COLORS;
  1941. dibInfo = (BITMAPINFOHEADER *)dibHeaderBuffer;
  1942. dibInfo->biSize = sizeof(BITMAPINFOHEADER);
  1943. dibInfo->biWidth = posDstWidth;
  1944. dibInfo->biHeight = -posDstHeight;
  1945. dibInfo->biPlanes = 1;
  1946. dibInfo->biBitCount = 24;
  1947. // We don't want to set the StretchBltMode to COLORONCOLOR here
  1948. // because we might draw this into non 8Bpp surface and we still
  1949. // have to halftone in this case
  1950. }
  1951. }
  1952. else
  1953. {
  1954. WARNING(("destBitmap not valid"));
  1955. }
  1956. }
  1957. else
  1958. {
  1959. WARNING(("Could not construct destBitmap"));
  1960. }
  1961. }
  1962. DoGdiStretch:
  1963. // Halftoning on NT4 with 8bpp does not work very well -- it gets
  1964. // the wrong color hue.
  1965. // We cannot halftone to metafile for that same reason
  1966. if ((rop != SRCCOPY) ||
  1967. (Is8Bpp && Globals::IsNt && (Globals::OsVer.dwMajorVersion <= 4)) ||
  1968. IsMetafile())
  1969. {
  1970. // don't let halftoning mess up some kind of masking or other effect
  1971. stretchBltMode = COLORONCOLOR;
  1972. }
  1973. ::SetStretchBltMode(hdc, stretchBltMode);
  1974. // There is a bug in Win9x that some StretchDIBits calls don't work
  1975. // so we need to create an actual StretchDIBits record to play.
  1976. // Also, NT4 postscript printing can't handle anything but SRCCOPY,
  1977. // so change any ROPs that are not source copy.
  1978. BOOL processed = FALSE;
  1979. if (!Globals::IsNt)
  1980. {
  1981. processed = CreateAndPlayOutputDIBRecord(hdc, bounds, dstX, dstY, dstWidth,
  1982. dstHeight, srcX, srcY, srcWidth, srcHeight, dibInfo, bits, usage,
  1983. rop);
  1984. }
  1985. else if (rop != SRCCOPY &&
  1986. Globals::OsVer.dwMajorVersion <= 4 &&
  1987. IsPostscript())
  1988. {
  1989. rop = SRCCOPY;
  1990. }
  1991. // In MSO, at this point they would check if this is NT running
  1992. // on a non-true-color surface. If so, they would set the
  1993. // color adjustment gamma to be 20000. The comment said that
  1994. // this was needed for NT 3.5. I'm assuming we don't need to
  1995. // worry about that anymore.
  1996. if (!processed)
  1997. {
  1998. ::StretchDIBits(hdc,
  1999. dstX, dstY, dstWidth, dstHeight,
  2000. srcX, srcY, srcWidth, srcHeight,
  2001. bits, (BITMAPINFO *)dibInfo, usage, rop);
  2002. }
  2003. if (destBitmap)
  2004. {
  2005. if (bmpDataPtr != NULL)
  2006. {
  2007. destBitmap->UnlockBits(bmpDataPtr);
  2008. }
  2009. destBitmap->Dispose();
  2010. }
  2011. if (restoreColors)
  2012. {
  2013. ::SetBkColor(hdc, oldBkColor);
  2014. ::SetTextColor(hdc, oldTextColor);
  2015. }
  2016. if (deleteDIBSection)
  2017. {
  2018. // This will get rid of the Bitmap and it's bits
  2019. ::DeleteObject(hBitmap);
  2020. GpFree(dibBmpInfo);
  2021. }
  2022. }
  2023. // Also handles META_DIBSTRETCHBLT
  2024. // There is not a usage parameter with these records -- the
  2025. // usage is always DIB_RGB_COLORS.
  2026. VOID
  2027. WmfEnumState::DIBBitBlt(
  2028. )
  2029. {
  2030. DWORD rop = *((DWORD UNALIGNED *)RecordData);
  2031. // If No-Op ROP, do nothing; just return
  2032. if ((rop & 0xFFFF0000) == (GDIP_NOOP_ROP3 & 0xFFFF0000))
  2033. {
  2034. return;
  2035. }
  2036. if (rop != SRCCOPY &&
  2037. rop != NOTSRCCOPY &&
  2038. rop != PATCOPY &&
  2039. rop != BLACKNESS &&
  2040. rop != WHITENESS)
  2041. {
  2042. RopUsed = TRUE;
  2043. }
  2044. INT paramIndex = 7;
  2045. if (RecordType != WmfRecordTypeDIBBitBlt)
  2046. {
  2047. paramIndex = 9; // META_DIBSTRETCHBLT
  2048. }
  2049. INT dibIndex = paramIndex + 1;
  2050. if (!IsSourceInRop3(rop))
  2051. {
  2052. if (((GetCurrentRecordSize() / 2) - 3) ==
  2053. (GDIP_EMFPLUS_RECORD_TO_WMF(RecordType) >> 8))
  2054. {
  2055. paramIndex++;
  2056. }
  2057. INT dstX = (INT)((INT16)((WORD *)RecordData)[paramIndex--]);
  2058. INT dstY = (INT)((INT16)((WORD *)RecordData)[paramIndex--]);
  2059. INT dstWidth = (INT)((INT16)((WORD *)RecordData)[paramIndex--]);
  2060. INT dstHeight = (INT)((INT16)((WORD *)RecordData)[paramIndex]);
  2061. // We know that this call will succeed because we have a 2K buffer
  2062. // by default
  2063. CreateRecordToModify(20);
  2064. // For some strange reason we need to play the record on both
  2065. // Win2K and Win9x. So create a WMF record for PatBlt and play it
  2066. ModifiedWmfRecord->rdFunction = GDIP_EMFPLUS_RECORD_TO_WMF(WmfRecordTypePatBlt);
  2067. ModifiedWmfRecord->rdSize = 10;
  2068. ModifiedWmfRecord->rdParm[5] = (WORD) dstX;
  2069. ModifiedWmfRecord->rdParm[4] = (WORD) dstY;
  2070. ModifiedWmfRecord->rdParm[3] = (WORD) dstWidth;
  2071. ModifiedWmfRecord->rdParm[2] = (WORD) dstHeight;
  2072. if (rop != PATCOPY && SrcCopyOnly)
  2073. {
  2074. *((DWORD*) ModifiedWmfRecord->rdParm) = PATCOPY;
  2075. }
  2076. else
  2077. {
  2078. *((DWORD*) ModifiedWmfRecord->rdParm) = rop;
  2079. }
  2080. // Now play the record (below)
  2081. }
  2082. else
  2083. {
  2084. BITMAPINFOHEADER UNALIGNED * srcDibInfo = (BITMAPINFOHEADER UNALIGNED *)(((WORD *)RecordData) + dibIndex);
  2085. UINT numPalEntries;
  2086. UINT dibBitsSize;
  2087. if ((srcDibInfo->biSize >= sizeof(BITMAPINFOHEADER)) &&
  2088. GetDibNumPalEntries(TRUE,
  2089. srcDibInfo->biSize,
  2090. srcDibInfo->biBitCount,
  2091. srcDibInfo->biCompression,
  2092. srcDibInfo->biClrUsed,
  2093. &numPalEntries) &&
  2094. ((dibBitsSize = GetDibBitsSize(srcDibInfo)) > 0))
  2095. {
  2096. if ((srcDibInfo->biBitCount == 1) && (srcDibInfo->biPlanes == 1))
  2097. {
  2098. DWORD UNALIGNED * rgb = (DWORD UNALIGNED *)GetDibColorTable(srcDibInfo);
  2099. if ((rgb[0] == 0x00000000) &&
  2100. (rgb[1] == 0x00FFFFFF))
  2101. {
  2102. if (SrcCopyOnly && (rop != SRCCOPY) && CreateCopyOfCurrentRecord())
  2103. {
  2104. *((DWORD UNALIGNED *)ModifiedWmfRecord->rdParm) = SRCCOPY;
  2105. goto PlayTheRecord;
  2106. }
  2107. else
  2108. {
  2109. // It is a compatible monochrome bitmap, which means it
  2110. // will use the TextColor and BkColor, so no recoloring
  2111. // is needed. Since we are not using SrcCopy that means
  2112. // that it's a mask
  2113. COLORREF oldBkColor = ::SetBkColor(Hdc, BkColor);
  2114. COLORREF oldTextColor = ::SetTextColor(Hdc, TextColor);
  2115. this->PlayRecord();
  2116. ::SetBkColor(Hdc, oldBkColor);
  2117. ::SetTextColor(Hdc, oldTextColor);
  2118. return;
  2119. }
  2120. }
  2121. }
  2122. UINT usage = DIB_RGB_COLORS;
  2123. INT dstDibSize = GetModifiedDibSize(srcDibInfo, numPalEntries, dibBitsSize, usage);
  2124. if (IsMetafile())
  2125. {
  2126. if (dstDibSize > 0)
  2127. {
  2128. INT size = SIZEOF_METARECORDHEADER + (dibIndex * sizeof(WORD)) + dstDibSize;
  2129. if (CreateRecordToModify(size))
  2130. {
  2131. ModifiedWmfRecord->rdFunction = GDIP_EMFPLUS_RECORD_TO_WMF(RecordType);
  2132. ModifiedWmfRecord->rdSize = size / 2;
  2133. GpMemcpy(ModifiedWmfRecord->rdParm, RecordData, (dibIndex * sizeof(WORD)));
  2134. ModifyDib(DIB_RGB_COLORS, srcDibInfo, NULL,
  2135. (BITMAPINFOHEADER UNALIGNED *)(ModifiedWmfRecord->rdParm + dibIndex),
  2136. numPalEntries, dibBitsSize, ColorAdjustTypeBitmap);
  2137. }
  2138. }
  2139. goto PlayTheRecord;
  2140. }
  2141. // At this point, we are not going to play the record. We're
  2142. // going to call StretchDIBits. One reason is because we want
  2143. // to set the StretchBltMode, which is only used if a stretching
  2144. // method is called.
  2145. // Also, it avoids us doing an allocation/copy and then GDI doing
  2146. // another allocation/copy (GDI has to do this to align the
  2147. // DIB on a DWORD boundary).
  2148. BITMAPINFOHEADER UNALIGNED * dstDibInfo = srcDibInfo;
  2149. if (dstDibSize > 0)
  2150. {
  2151. if (CreateRecordToModify(dstDibSize))
  2152. {
  2153. // ModifiedRecord is Aligned
  2154. dstDibInfo = (BITMAPINFOHEADER UNALIGNED *)ModifiedRecord;
  2155. ModifyDib(DIB_RGB_COLORS, srcDibInfo, NULL, dstDibInfo,
  2156. numPalEntries, dibBitsSize, ColorAdjustTypeBitmap);
  2157. }
  2158. }
  2159. else if (!IsDwordAligned(dstDibInfo))
  2160. {
  2161. // The srcDibInfo may not aligned properly, so we make
  2162. // a copy of it, so that it will be aligned.
  2163. dstDibSize = GetCurrentRecordSize() - (SIZEOF_METARECORDHEADER + (dibIndex * sizeof(WORD)));
  2164. if (CreateRecordToModify(dstDibSize))
  2165. {
  2166. dstDibInfo = (BITMAPINFOHEADER *)ModifiedRecord;
  2167. GpMemcpy(dstDibInfo, srcDibInfo, dstDibSize);
  2168. }
  2169. }
  2170. if (SrcCopyOnly)
  2171. {
  2172. rop = SRCCOPY;
  2173. }
  2174. INT srcX, srcY;
  2175. INT dstX, dstY;
  2176. INT srcWidth, srcHeight;
  2177. INT dstWidth, dstHeight;
  2178. dstX = (INT)((INT16)((WORD *)RecordData)[paramIndex--]);
  2179. dstY = (INT)((INT16)((WORD *)RecordData)[paramIndex--]);
  2180. dstWidth = (INT)((INT16)((WORD *)RecordData)[paramIndex--]);
  2181. dstHeight = (INT)((INT16)((WORD *)RecordData)[paramIndex--]);
  2182. srcX = (INT)((INT16)((WORD *)RecordData)[paramIndex--]);
  2183. srcY = (INT)((INT16)((WORD *)RecordData)[paramIndex--]);
  2184. if (RecordType != WmfRecordTypeDIBBitBlt)
  2185. {
  2186. // META_DIBSTRETCHBLT
  2187. srcWidth = (INT)((INT16)((WORD *)RecordData)[paramIndex--]);
  2188. srcHeight = (INT)((INT16)((WORD *)RecordData)[paramIndex--]);
  2189. }
  2190. else
  2191. {
  2192. srcWidth = dstWidth;
  2193. srcHeight = dstHeight;
  2194. }
  2195. // Need to flip the source y coordinate to call StretchDIBits.
  2196. srcY = dstDibInfo->biHeight - srcY - srcHeight;
  2197. OutputDIB(Hdc,
  2198. NULL,
  2199. dstX, dstY, dstWidth, dstHeight,
  2200. srcX, srcY, srcWidth, srcHeight,
  2201. dstDibInfo, NULL, DIB_RGB_COLORS, rop, TRUE);
  2202. return;
  2203. }
  2204. }
  2205. PlayTheRecord:
  2206. this->PlayRecord();
  2207. }
  2208. VOID
  2209. WmfEnumState::StretchDIBits(
  2210. )
  2211. {
  2212. DWORD rop = *((DWORD UNALIGNED *)RecordData);
  2213. // If No-Op ROP, do nothing; just return
  2214. if ((rop & 0xFFFF0000) == (GDIP_NOOP_ROP3 & 0xFFFF0000))
  2215. {
  2216. return;
  2217. }
  2218. if (rop != SRCCOPY &&
  2219. rop != NOTSRCCOPY &&
  2220. rop != PATCOPY &&
  2221. rop != BLACKNESS &&
  2222. rop != WHITENESS)
  2223. {
  2224. RopUsed = TRUE;
  2225. }
  2226. if (IsSourceInRop3(rop))
  2227. {
  2228. if(((GetCurrentRecordSize() / 2) > (SIZEOF_METARECORDHEADER / sizeof(WORD)) + 11))
  2229. {
  2230. BITMAPINFOHEADER UNALIGNED * srcDibInfo = (BITMAPINFOHEADER UNALIGNED *)(((WORD *)RecordData) + 11);
  2231. UINT numPalEntries;
  2232. UINT dibBitsSize;
  2233. if ((srcDibInfo->biSize >= sizeof(BITMAPINFOHEADER)) &&
  2234. GetDibNumPalEntries(TRUE,
  2235. srcDibInfo->biSize,
  2236. srcDibInfo->biBitCount,
  2237. srcDibInfo->biCompression,
  2238. srcDibInfo->biClrUsed,
  2239. &numPalEntries) &&
  2240. ((dibBitsSize = GetDibBitsSize(srcDibInfo)) > 0))
  2241. {
  2242. UINT usage = ((WORD *)RecordData)[2];
  2243. UINT oldUsage = usage;
  2244. INT dstDibSize = GetModifiedDibSize(srcDibInfo, numPalEntries, dibBitsSize, usage);
  2245. BITMAPINFOHEADER UNALIGNED * dstDibInfo = srcDibInfo;
  2246. if (dstDibSize > 0)
  2247. {
  2248. if ((srcDibInfo->biBitCount == 1) && (srcDibInfo->biPlanes == 1))
  2249. {
  2250. DWORD UNALIGNED * rgb = (DWORD UNALIGNED *)GetDibColorTable(srcDibInfo);
  2251. if ((rgb[0] == 0x00000000) &&
  2252. (rgb[1] == 0x00FFFFFF))
  2253. {
  2254. if (SrcCopyOnly && (rop != SRCCOPY) && CreateCopyOfCurrentRecord())
  2255. {
  2256. *((DWORD UNALIGNED *)ModifiedWmfRecord->rdParm) = SRCCOPY;
  2257. goto PlayTheRecord;
  2258. }
  2259. else
  2260. {
  2261. // It is a compatible monochrome bitmap, which means it
  2262. // will use the TextColor and BkColor, so no recoloring
  2263. // is needed. Since we are not using SrcCopy that means
  2264. // that it's a mask
  2265. COLORREF oldBkColor = ::SetBkColor(Hdc, BkColor);
  2266. COLORREF oldTextColor = ::SetTextColor(Hdc, TextColor);
  2267. this->PlayRecord();
  2268. ::SetBkColor(Hdc, oldBkColor);
  2269. ::SetTextColor(Hdc, oldTextColor);
  2270. return;
  2271. }
  2272. }
  2273. }
  2274. INT size = SIZEOF_METARECORDHEADER + (11 * sizeof(WORD)) + dstDibSize;
  2275. if (CreateRecordToModify(size))
  2276. {
  2277. ModifiedWmfRecord->rdFunction = GDIP_EMFPLUS_RECORD_TO_WMF(RecordType);
  2278. ModifiedWmfRecord->rdSize = size / 2;
  2279. GpMemcpy(ModifiedWmfRecord->rdParm, RecordData, (11 * sizeof(WORD)));
  2280. // This will be aligned.... Do we want to take a chance?
  2281. dstDibInfo = (BITMAPINFOHEADER UNALIGNED *)(ModifiedWmfRecord->rdParm + 11);
  2282. ModifyDib(oldUsage, srcDibInfo, NULL, dstDibInfo,
  2283. numPalEntries, dibBitsSize, ColorAdjustTypeBitmap);
  2284. }
  2285. }
  2286. if (!IsMetafile())
  2287. {
  2288. if ((dstDibInfo == srcDibInfo) && (!IsDwordAligned(dstDibInfo)))
  2289. {
  2290. // The srcDibInfo may not aligned properly, so we make
  2291. // a copy of it, so that it will be aligned.
  2292. dstDibSize = GetCurrentRecordSize() - (SIZEOF_METARECORDHEADER + (11 * sizeof(WORD)));
  2293. if (CreateRecordToModify(dstDibSize))
  2294. {
  2295. dstDibInfo = (BITMAPINFOHEADER UNALIGNED *)ModifiedRecord;
  2296. GpMemcpy(dstDibInfo, srcDibInfo, dstDibSize);
  2297. }
  2298. }
  2299. if (SrcCopyOnly)
  2300. {
  2301. rop = SRCCOPY;
  2302. }
  2303. INT dstX = (INT)((INT16)((WORD *)RecordData)[10]);
  2304. INT dstY = (INT)((INT16)((WORD *)RecordData)[9]);
  2305. INT dstWidth = (INT)((INT16)((WORD *)RecordData)[8]);
  2306. INT dstHeight = (INT)((INT16)((WORD *)RecordData)[7]);
  2307. INT srcX = (INT)((INT16)((WORD *)RecordData)[6]);
  2308. INT srcY = (INT)((INT16)((WORD *)RecordData)[5]);
  2309. INT srcWidth = (INT)((INT16)((WORD *)RecordData)[4]);
  2310. INT srcHeight = (INT)((INT16)((WORD *)RecordData)[3]);
  2311. OutputDIB(Hdc,
  2312. NULL,
  2313. dstX, dstY, dstWidth, dstHeight,
  2314. srcX, srcY, srcWidth, srcHeight,
  2315. dstDibInfo, NULL, usage, rop, TRUE);
  2316. return;
  2317. }
  2318. }
  2319. }
  2320. }
  2321. else // !IsSourceRop3
  2322. {
  2323. if (rop != PATCOPY && SrcCopyOnly && CreateCopyOfCurrentRecord())
  2324. {
  2325. *((DWORD UNALIGNED *)ModifiedWmfRecord->rdParm) = PATCOPY;
  2326. }
  2327. }
  2328. PlayTheRecord:
  2329. this->PlayRecord();
  2330. }
  2331. BOOL
  2332. WmfEnumState::CreateAndPlayOutputDIBRecord(
  2333. HDC hdc,
  2334. const RECTL * bounds,
  2335. INT dstX,
  2336. INT dstY,
  2337. INT dstWidth,
  2338. INT dstHeight,
  2339. INT srcX,
  2340. INT srcY,
  2341. INT srcWidth,
  2342. INT srcHeight,
  2343. BITMAPINFOHEADER UNALIGNED * dibInfo,
  2344. BYTE * bits, // if NULL, this is a packed DIB
  2345. UINT usage,
  2346. DWORD rop
  2347. )
  2348. {
  2349. INT bitsSize = GetDibBitsSize(dibInfo);
  2350. UINT sizePalEntries;
  2351. if (GetDibNumPalEntries(TRUE,
  2352. dibInfo->biSize,
  2353. dibInfo->biBitCount,
  2354. dibInfo->biCompression,
  2355. dibInfo->biClrUsed,
  2356. &sizePalEntries))
  2357. {
  2358. // We need to get the palette size that corresponds to the type
  2359. // If we have a DIB_PAL_COLORS then each entry is 16bits
  2360. sizePalEntries *= ((usage == DIB_PAL_COLORS)?2:sizeof(RGBQUAD));
  2361. }
  2362. else
  2363. {
  2364. sizePalEntries = 0 ;
  2365. }
  2366. // We need at least a BITMAPINFO structure in there, but if there is a
  2367. // palette, calculate the full size of the structure including the
  2368. // palette
  2369. INT bitmapHeaderSize = sizeof(BITMAPINFOHEADER) + sizePalEntries;
  2370. INT size = SIZEOF_METARECORDHEADER + (11 * sizeof(WORD)) + bitmapHeaderSize + bitsSize ;
  2371. // We cannot use the CreateRecordToModify because the record has already
  2372. // been modified
  2373. size = (size + 1) & ~1;
  2374. METARECORD* metaRecord = (METARECORD*) GpMalloc(size);
  2375. if (metaRecord != NULL)
  2376. {
  2377. metaRecord->rdFunction = GDIP_EMFPLUS_RECORD_TO_WMF(WmfRecordTypeStretchDIB);
  2378. metaRecord->rdSize = size / 2;
  2379. metaRecord->rdParm[10] = (WORD) dstX;
  2380. metaRecord->rdParm[9] = (WORD) dstY;
  2381. metaRecord->rdParm[8] = (WORD) dstWidth;
  2382. metaRecord->rdParm[7] = (WORD) dstHeight;
  2383. metaRecord->rdParm[6] = (WORD) srcX;
  2384. metaRecord->rdParm[5] = (WORD) srcY;
  2385. metaRecord->rdParm[4] = (WORD) srcWidth;
  2386. metaRecord->rdParm[3] = (WORD) srcHeight;
  2387. metaRecord->rdParm[2] = (WORD) usage;
  2388. *(DWORD UNALIGNED *)(&(metaRecord->rdParm[0])) = rop;
  2389. GpMemcpy((BYTE*)(&(metaRecord->rdParm[11])), dibInfo, bitmapHeaderSize);
  2390. GpMemcpy((BYTE*)(&(metaRecord->rdParm[11])) + bitmapHeaderSize, bits, bitsSize);
  2391. ::PlayMetaFileRecord(hdc, HandleTable, metaRecord, NumObjects);
  2392. GpFree(metaRecord);
  2393. return TRUE;
  2394. }
  2395. return FALSE;
  2396. }
  2397. VOID
  2398. WmfEnumState::ModifyRecordColor(
  2399. INT paramIndex,
  2400. ColorAdjustType adjustType
  2401. )
  2402. {
  2403. COLORREF origColor = *((COLORREF UNALIGNED *)&(((WORD *)RecordData)[paramIndex]));
  2404. COLORREF modifiedColor = ModifyColor(origColor, adjustType);
  2405. if (modifiedColor != origColor)
  2406. {
  2407. if (CreateCopyOfCurrentRecord())
  2408. {
  2409. *((COLORREF UNALIGNED *)&(ModifiedWmfRecord->rdParm[paramIndex])) = modifiedColor;
  2410. }
  2411. }
  2412. }
  2413. COLORREF
  2414. MfEnumState::ModifyColor(
  2415. COLORREF color,
  2416. ColorAdjustType adjustType
  2417. )
  2418. {
  2419. if (AdjustType != ColorAdjustTypeDefault)
  2420. {
  2421. adjustType = AdjustType;
  2422. }
  2423. switch (color & 0xFF000000)
  2424. {
  2425. case 0x00000000:
  2426. break;
  2427. case 0x01000000: // Palette Index
  2428. {
  2429. PALETTEENTRY palEntry;
  2430. if (::GetPaletteEntries(CurrentPalette, color & 0x000000FF, 1, &palEntry) == 1)
  2431. {
  2432. color = RGB(palEntry.peRed, palEntry.peGreen, palEntry.peBlue);
  2433. }
  2434. else
  2435. {
  2436. color = RGB(0, 0, 0);
  2437. WARNING(("Failed to get palette entry"));
  2438. }
  2439. }
  2440. break;
  2441. case 0x02000000: // Palette RGB
  2442. default:
  2443. color &= 0x00FFFFFF;
  2444. break;
  2445. }
  2446. // Possible perfomance improvement: recolor the SelectedPalette so only
  2447. // RGB values need to be recolored here.
  2448. if (Recolor != NULL)
  2449. {
  2450. Recolor->ColorAdjustCOLORREF(&color, adjustType);
  2451. }
  2452. // Palette RGB values don't get dithered (at least not on NT), so we
  2453. // only want to make it a PaletteRGB value if it is a solid color in
  2454. // the palette.
  2455. if (Is8Bpp)
  2456. {
  2457. COLORREF matchingColor;
  2458. matchingColor = (::GetNearestColor(Hdc, color | 0x02000000) & 0x00FFFFFF);
  2459. // Pens and Text don't get Dithered so match them to the logical palette
  2460. // the other adjustTypes do so they will get halftoned
  2461. if ((matchingColor == color) ||
  2462. (adjustType == ColorAdjustTypePen) ||
  2463. (adjustType == ColorAdjustTypeText))
  2464. {
  2465. return color | 0x02000000;
  2466. }
  2467. }
  2468. return color;
  2469. }
  2470. BOOL
  2471. MfEnumState::CreateRecordToModify(
  2472. INT size
  2473. )
  2474. {
  2475. if (size <= 0)
  2476. {
  2477. size = this->GetCurrentRecordSize();
  2478. }
  2479. // add a little padding to help insure we don't read past the end of the buffer
  2480. size += 16;
  2481. if (ModifiedRecordSize < size)
  2482. {
  2483. ASSERT(ModifiedRecordSize == 0);
  2484. if (size <= GDIP_RECORDBUFFER_SIZE)
  2485. {
  2486. ModifiedRecord = RecordBuffer;
  2487. }
  2488. else if (size <= SizeAllocedRecord)
  2489. {
  2490. ModifiedRecord = AllocedRecord;
  2491. }
  2492. else
  2493. {
  2494. VOID * newRecord;
  2495. INT allocSize;
  2496. // alloc in increments of 1K
  2497. allocSize = (size + 1023) & (~1023);
  2498. ModifiedRecord = NULL;
  2499. newRecord = GpRealloc(AllocedRecord, allocSize);
  2500. if (newRecord != NULL)
  2501. {
  2502. ModifiedRecord = newRecord;
  2503. AllocedRecord = newRecord;
  2504. SizeAllocedRecord = allocSize;
  2505. }
  2506. }
  2507. }
  2508. else
  2509. {
  2510. ASSERT(ModifiedRecord != NULL);
  2511. ASSERT(ModifiedRecordSize == size);
  2512. }
  2513. if (ModifiedRecord != NULL)
  2514. {
  2515. ModifiedRecordSize = size;
  2516. return TRUE;
  2517. }
  2518. WARNING(("Failed to create ModifiedRecord"));
  2519. return FALSE;
  2520. }
  2521. BOOL
  2522. WmfEnumState::CreateCopyOfCurrentRecord()
  2523. {
  2524. if (ModifiedRecordSize > 0)
  2525. {
  2526. // We already made a modified record. Don't do it again.
  2527. ASSERT(ModifiedRecord != NULL);
  2528. return TRUE;
  2529. }
  2530. INT size = this->GetCurrentRecordSize();
  2531. if (CreateRecordToModify(size))
  2532. {
  2533. METARECORD * modifiedRecord = (METARECORD *)ModifiedRecord;
  2534. modifiedRecord->rdFunction = GDIP_EMFPLUS_RECORD_TO_WMF(RecordType);
  2535. modifiedRecord->rdSize = size / 2;
  2536. if (RecordDataSize > 0)
  2537. {
  2538. GpMemcpy(modifiedRecord->rdParm, RecordData, RecordDataSize);
  2539. }
  2540. return TRUE;
  2541. }
  2542. WARNING(("Failed to create copy of current record"));
  2543. return FALSE;
  2544. }
  2545. VOID
  2546. WmfEnumState::MakeSolidBlackBrush()
  2547. {
  2548. INT size = SIZEOF_METARECORDHEADER + sizeof(LOGBRUSH16);
  2549. CreateRecordToModify(size);
  2550. ModifiedWmfRecord->rdSize = size / 2;
  2551. ModifiedWmfRecord->rdFunction = META_CREATEBRUSHINDIRECT;
  2552. LOGBRUSH16 * logBrush = (LOGBRUSH16 *)(ModifiedWmfRecord->rdParm);
  2553. logBrush->lbStyle = BS_SOLID;
  2554. logBrush->lbColor = PALETTERGB(0,0,0);
  2555. logBrush->lbHatch = 0;
  2556. }
  2557. VOID
  2558. WmfEnumState::CalculateViewportMatrix()
  2559. {
  2560. GpRectF destViewport((REAL)DstViewportOrg.x, (REAL)DstViewportOrg.y,
  2561. (REAL)DstViewportExt.cx, (REAL)DstViewportExt.cy);
  2562. GpRectF srcViewport((REAL)ImgViewportOrg.x, (REAL)ImgViewportOrg.y,
  2563. (REAL)ImgViewportExt.cx, (REAL)ImgViewportExt.cy);
  2564. Status status = ViewportXForm.InferAffineMatrix(destViewport, srcViewport);
  2565. if (status != Ok)
  2566. {
  2567. ViewportXForm.Reset();
  2568. }
  2569. }
  2570. VOID
  2571. WmfEnumState::SetViewportOrg()
  2572. {
  2573. // If this is the first SetViewportOrg then we need to save that value and
  2574. // calculate a transform from out viewport to this viewport
  2575. ImgViewportOrg.x = (INT)((INT16)((WORD *)RecordData)[1]);
  2576. ImgViewportOrg.y = (INT)((INT16)((WORD *)RecordData)[0]);
  2577. if (FirstViewportOrg || FirstViewportExt)
  2578. {
  2579. FirstViewportOrg = FALSE;
  2580. // If we have processed the first ViewportExt call then we can calculate
  2581. // the transform from our current viewport to the new viewport
  2582. if (!FirstViewportExt)
  2583. {
  2584. CalculateViewportMatrix();
  2585. }
  2586. }
  2587. else
  2588. {
  2589. // We need to keep the new Viewport origin to be able to calculate
  2590. // the viewport bottom right corner before passing it through a
  2591. // transform
  2592. GpPointF newOrg((REAL) ImgViewportOrg.x,
  2593. (REAL) ImgViewportOrg.y);
  2594. // Transform the new viewport with our viewport transformation
  2595. ViewportXForm.Transform(&newOrg);
  2596. DstViewportOrg.x = GpRound(newOrg.X);
  2597. DstViewportOrg.y = GpRound(newOrg.Y);
  2598. if(CreateRecordToModify())
  2599. {
  2600. ModifiedWmfRecord->rdFunction = CurrentWmfRecord->rdFunction;
  2601. ModifiedWmfRecord->rdSize = CurrentWmfRecord->rdSize;
  2602. ModifiedWmfRecord->rdParm[0] = (WORD)GpRound(newOrg.Y);
  2603. ModifiedWmfRecord->rdParm[1] = (WORD)GpRound(newOrg.X);
  2604. }
  2605. this->PlayRecord();
  2606. }
  2607. }
  2608. VOID
  2609. WmfEnumState::SetViewportExt()
  2610. {
  2611. // If this is the first SetViewportOrg then we need to save that value and
  2612. // calculate a transform from out viewport to this viewport
  2613. ImgViewportExt.cx = (INT)((INT16)((WORD *)RecordData)[1]);
  2614. ImgViewportExt.cy = (INT)((INT16)((WORD *)RecordData)[0]);
  2615. if (FirstViewportOrg || FirstViewportExt)
  2616. {
  2617. FirstViewportExt = FALSE;
  2618. // If we have processed the first ViewportExt call then we can calculate
  2619. // the transform from our current viewport to the new viewport
  2620. if (!FirstViewportOrg)
  2621. {
  2622. CalculateViewportMatrix();
  2623. }
  2624. }
  2625. else
  2626. {
  2627. // We need to transform the point, so add the current origin
  2628. // of the Viewport
  2629. GpPointF newExt((REAL) ImgViewportExt.cx,
  2630. (REAL) ImgViewportExt.cy);
  2631. // Transform the new viewport with our viewport transformation
  2632. ViewportXForm.VectorTransform(&newExt);
  2633. if(CreateRecordToModify())
  2634. {
  2635. ModifiedWmfRecord->rdFunction = CurrentWmfRecord->rdFunction;
  2636. ModifiedWmfRecord->rdSize = CurrentWmfRecord->rdSize;
  2637. ModifiedWmfRecord->rdParm[0] = (WORD)GpRound(newExt.Y);
  2638. ModifiedWmfRecord->rdParm[1] = (WORD)GpRound(newExt.X);
  2639. }
  2640. this->PlayRecord();
  2641. }
  2642. }
  2643. VOID
  2644. WmfEnumState::CreateRegion()
  2645. {
  2646. // Check if the region it too big when mapped to device space.
  2647. if (!Globals::IsNt)
  2648. {
  2649. // There is a bug in Win9x GDI where the code which plays METACREATEREGION doesn't copy the
  2650. // entire region data, it is off by 8 bytes. This seems to have been introduced to allow
  2651. // for compatibility with an older header format, WIN2OBJECT. We get around this by increasing
  2652. // the size of the record by 8 bytes. No other harm done.
  2653. if (CreateCopyOfCurrentRecord())
  2654. {
  2655. // When we create a copy of the record, we add 16 bytes of padding so we know this
  2656. // won't overflow into other memory.
  2657. ModifiedWmfRecord->rdSize += 4;
  2658. }
  2659. }
  2660. this->PlayRecord();
  2661. }
  2662. HFONT CreateTrueTypeFont(
  2663. HFONT hFont
  2664. );
  2665. VOID
  2666. WmfEnumState::CreateFontIndirect(
  2667. )
  2668. {
  2669. LOGFONT16 * logFont = (LOGFONT16 *)RecordData;
  2670. BOOL recordCopied = FALSE;
  2671. if (!Globals::IsNt)
  2672. {
  2673. // We have a bug in Win9x that the OUT_TT_ONLY_PRECIS flag is
  2674. // not always respected so if the font name is MS SANS SERIF
  2675. // change it to Times New Roman
  2676. // Since we don't have a string compare in ASCII do it in UNICODE
  2677. WCHAR faceName[32];
  2678. if (AnsiToUnicodeStr((char*)(logFont->lfFaceName), faceName, sizeof(faceName)/sizeof(WCHAR)) &&
  2679. (UnicodeStringCompareCI(faceName, L"MS SANS SERIF") == 0))
  2680. {
  2681. if (CreateCopyOfCurrentRecord())
  2682. {
  2683. GpMemcpy(((LOGFONT16 *)(ModifiedWmfRecord->rdParm))->lfFaceName,
  2684. "Times New Roman", sizeof("Times New Roman"));
  2685. recordCopied = TRUE;
  2686. }
  2687. }
  2688. }
  2689. if (logFont->lfOutPrecision != OUT_TT_ONLY_PRECIS)
  2690. {
  2691. // Instruct GDI to use only True Type fonts, since bitmap fonts
  2692. // are not scalable.
  2693. if (recordCopied || CreateCopyOfCurrentRecord())
  2694. {
  2695. ((LOGFONT16 *)(ModifiedWmfRecord->rdParm))->lfOutPrecision = OUT_TT_ONLY_PRECIS;
  2696. }
  2697. }
  2698. this->PlayRecord();
  2699. }
  2700. VOID WmfEnumState::SelectObject()
  2701. {
  2702. this->PlayRecord();
  2703. // In case we selected a region on Win9x, we need to intersect
  2704. if (!Globals::IsNt)
  2705. {
  2706. DWORD index = CurrentWmfRecord->rdParm[0];
  2707. if (GetObjectTypeInternal((*HandleTable).objectHandle[index]) == OBJ_REGION)
  2708. {
  2709. this->IntersectDestRect();
  2710. }
  2711. }
  2712. }
  2713. VOID WmfEnumState::IntersectDestRect()
  2714. {
  2715. if (!IsMetafile())
  2716. {
  2717. POINT windowOrg;
  2718. SIZE windowExt;
  2719. ::SetWindowOrgEx(Hdc, DstViewportOrg.x, DstViewportOrg.y, &windowOrg);
  2720. ::SetWindowExtEx(Hdc, DstViewportExt.cx, DstViewportExt.cy, &windowExt);
  2721. // We are always in device units
  2722. ::IntersectClipRect(Hdc, DestRectDevice.left, DestRectDevice.top,
  2723. DestRectDevice.right, DestRectDevice.bottom);
  2724. ::SetWindowOrgEx(Hdc, windowOrg.x, windowOrg.y, NULL);
  2725. ::SetWindowExtEx(Hdc, windowExt.cx, windowExt.cy, NULL);
  2726. }
  2727. }
  2728. VOID WmfEnumState::SetROP2()
  2729. {
  2730. INT rop = (INT)((INT16)(((WORD *)RecordData)[0]));
  2731. if (rop != R2_BLACK &&
  2732. rop != R2_COPYPEN &&
  2733. rop != R2_NOTCOPYPEN &&
  2734. rop != R2_WHITE )
  2735. {
  2736. RopUsed = TRUE;
  2737. }
  2738. this->PlayRecord();
  2739. }
  2740. BOOL
  2741. WmfEnumState::ProcessRecord(
  2742. EmfPlusRecordType recordType,
  2743. UINT recordDataSize,
  2744. const BYTE * recordData
  2745. )
  2746. {
  2747. BOOL forceCallback = FALSE;
  2748. MfFsmState nextState = MfFsmStart;
  2749. if (IsFirstRecord)
  2750. {
  2751. // Bitmap fonts are not good for playing metafiles because they
  2752. // don't scale well, so use a true type font instead as the default font.
  2753. HFONT hFont = CreateTrueTypeFont((HFONT)GetCurrentObject(Hdc, OBJ_FONT));
  2754. if (hFont != NULL)
  2755. {
  2756. DefaultFont = hFont;
  2757. ::SelectObject(Hdc, hFont);
  2758. }
  2759. IsFirstRecord = FALSE;
  2760. }
  2761. // See if we're doing enumeration for an external app
  2762. if (ExternalEnumeration)
  2763. {
  2764. if (recordData == NULL)
  2765. {
  2766. recordDataSize = 0;
  2767. }
  2768. else if (recordDataSize == 0)
  2769. {
  2770. recordData = NULL;
  2771. }
  2772. // make sure it's an EMF enum type
  2773. recordType = GDIP_WMF_RECORD_TO_EMFPLUS(recordType);
  2774. // See if the app changed the record at all.
  2775. if ((recordType != RecordType) ||
  2776. (recordDataSize != RecordDataSize) ||
  2777. ((recordDataSize > 0) &&
  2778. ((CurrentWmfRecord == NULL) ||
  2779. (recordData != (const BYTE *)CurrentWmfRecord->rdParm))))
  2780. {
  2781. // Yes, we need to override what happened in StartRecord
  2782. CurrentWmfRecord = NULL;
  2783. RecordType = recordType;
  2784. RecordData = recordData;
  2785. RecordDataSize = recordDataSize;
  2786. }
  2787. }
  2788. // Ignore all non-escape records if IgnorePostcript is TRUE
  2789. if (recordType == WmfRecordTypeEscape || !IgnorePostscript)
  2790. {
  2791. GDIP_TRY
  2792. switch (recordType)
  2793. {
  2794. // According to NT playback code, this is a EOF record, but it
  2795. // is just skipped by the NT player.
  2796. case GDIP_WMF_RECORD_TO_EMFPLUS(0x0000): // End of metafile record
  2797. break;
  2798. // These records are not played back (at least in Win2000).
  2799. // Apparently they haven't been supported since before Win3.1!
  2800. case WmfRecordTypeSetRelAbs:
  2801. case WmfRecordTypeDrawText:
  2802. case WmfRecordTypeResetDC:
  2803. case WmfRecordTypeStartDoc:
  2804. case WmfRecordTypeStartPage:
  2805. case WmfRecordTypeEndPage:
  2806. case WmfRecordTypeAbortDoc:
  2807. case WmfRecordTypeEndDoc:
  2808. case WmfRecordTypeCreateBrush:
  2809. case WmfRecordTypeCreateBitmapIndirect:
  2810. case WmfRecordTypeCreateBitmap:
  2811. ONCE(WARNING1("Unsupported WMF record"));
  2812. break;
  2813. default:
  2814. // unknown record -- ignore it
  2815. WARNING1("Unknown WMF Record");
  2816. break;
  2817. case WmfRecordTypeSetBkMode:
  2818. case WmfRecordTypeSetMapMode:
  2819. case WmfRecordTypeSetPolyFillMode:
  2820. case WmfRecordTypeSetStretchBltMode:
  2821. case WmfRecordTypeSetTextCharExtra:
  2822. case WmfRecordTypeSetTextJustification:
  2823. case WmfRecordTypeSetWindowOrg:
  2824. case WmfRecordTypeSetWindowExt:
  2825. case WmfRecordTypeOffsetWindowOrg:
  2826. case WmfRecordTypeScaleWindowExt:
  2827. case WmfRecordTypeOffsetViewportOrg:
  2828. case WmfRecordTypeScaleViewportExt:
  2829. case WmfRecordTypeLineTo:
  2830. case WmfRecordTypeMoveTo:
  2831. case WmfRecordTypeExcludeClipRect:
  2832. case WmfRecordTypeIntersectClipRect:
  2833. case WmfRecordTypeArc:
  2834. case WmfRecordTypeEllipse:
  2835. case WmfRecordTypePie:
  2836. case WmfRecordTypeRoundRect:
  2837. case WmfRecordTypePatBlt:
  2838. case WmfRecordTypeTextOut:
  2839. case WmfRecordTypePolygon:
  2840. case WmfRecordTypePolyline:
  2841. case WmfRecordTypeFillRegion:
  2842. case WmfRecordTypeFrameRegion:
  2843. case WmfRecordTypeInvertRegion:
  2844. case WmfRecordTypePaintRegion:
  2845. case WmfRecordTypeSetTextAlign:
  2846. case WmfRecordTypeChord:
  2847. case WmfRecordTypeSetMapperFlags:
  2848. case WmfRecordTypeExtTextOut:
  2849. case WmfRecordTypeAnimatePalette:
  2850. case WmfRecordTypeSetPalEntries:
  2851. case WmfRecordTypeResizePalette:
  2852. case WmfRecordTypeSetLayout:
  2853. case WmfRecordTypeDeleteObject:
  2854. case WmfRecordTypeCreatePalette:
  2855. // Play the current record.
  2856. // Even if it fails, we keep playing the rest of the metafile.
  2857. // There is a case that GdiComment with EPS may fail.
  2858. this->PlayRecord();
  2859. break;
  2860. case WmfRecordTypeCreateRegion:
  2861. this->CreateRegion();
  2862. break;
  2863. case WmfRecordTypeCreateFontIndirect:
  2864. this->CreateFontIndirect();
  2865. break;
  2866. case WmfRecordTypeSetBkColor:
  2867. this->SetBkColor();
  2868. break;
  2869. case WmfRecordTypeSetTextColor:
  2870. this->SetTextColor();
  2871. break;
  2872. case WmfRecordTypeFloodFill:
  2873. this->FloodFill();
  2874. break;
  2875. case WmfRecordTypeExtFloodFill:
  2876. this->ExtFloodFill();
  2877. break;
  2878. case WmfRecordTypeSaveDC:
  2879. this->SaveHdc(); // plays the record
  2880. break;
  2881. case WmfRecordTypeSetPixel:
  2882. this->SetPixel();
  2883. break;
  2884. case WmfRecordTypeDIBCreatePatternBrush:
  2885. this->DibCreatePatternBrush();
  2886. break;
  2887. case WmfRecordTypeCreatePatternBrush: // Obsolete but still played back
  2888. this->CreatePatternBrush();
  2889. break;
  2890. case WmfRecordTypeCreatePenIndirect:
  2891. this->CreatePenIndirect();
  2892. if (FsmState == MfFsmSelectBrush)
  2893. {
  2894. nextState = MfFsmCreatePenIndirect;
  2895. }
  2896. break;
  2897. case WmfRecordTypeCreateBrushIndirect:
  2898. this->CreateBrushIndirect();
  2899. if (FsmState == MfFsmPSData)
  2900. {
  2901. nextState = MfFsmCreateBrushIndirect;
  2902. }
  2903. break;
  2904. case WmfRecordTypeSelectObject:
  2905. // What if we break out of the FSM, we do want to Create the appropriate
  2906. // brush and pens right?!
  2907. if (FsmState == MfFsmCreateBrushIndirect)
  2908. {
  2909. nextState = MfFsmSelectBrush;
  2910. break;
  2911. }
  2912. else if (FsmState == MfFsmSelectBrush ||
  2913. FsmState == MfFsmCreatePenIndirect)
  2914. {
  2915. nextState = MfFsmSelectPen;
  2916. break;
  2917. }
  2918. this->SelectObject();
  2919. break;
  2920. case WmfRecordTypeRectangle:
  2921. this->Rectangle();
  2922. break;
  2923. case WmfRecordTypeSetROP2:
  2924. {
  2925. INT rdParm = (INT)((INT16)(((WORD *)RecordData)[0]));
  2926. if (FsmState == MfFsmSelectPen &&
  2927. (INT)(rdParm == R2_NOP))
  2928. {
  2929. nextState = MfFsmSetROP;
  2930. }
  2931. this->SetROP2();
  2932. }
  2933. break;
  2934. case WmfRecordTypeBitBlt: // Obsolete but still played back
  2935. this->BitBlt();
  2936. forceCallback = TRUE;
  2937. break;
  2938. case WmfRecordTypeStretchBlt: // Obsolete but still played back
  2939. this->StretchBlt();
  2940. forceCallback = TRUE;
  2941. break;
  2942. case WmfRecordTypeEscape:
  2943. {
  2944. INT escapeCode = (INT)((INT16)(((WORD *)RecordData)[0]));
  2945. this->Escape(); // optionally plays the record
  2946. if (FsmState == MfFsmStart && escapeCode == POSTSCRIPT_DATA &&
  2947. Globals::IsNt && IsPostscriptPrinter() &&
  2948. GdiCentricMode && SoftekFilter)
  2949. {
  2950. nextState = MfFsmPSData;
  2951. }
  2952. // Comments do not change the current state
  2953. if (escapeCode == MFCOMMENT)
  2954. {
  2955. nextState = FsmState;
  2956. }
  2957. }
  2958. break;
  2959. case WmfRecordTypeRestoreDC:
  2960. this->RestoreHdc(); // optionally plays the record
  2961. break;
  2962. case WmfRecordTypeSetDIBToDev:
  2963. this->SetDIBitsToDevice();
  2964. forceCallback = TRUE;
  2965. break;
  2966. case WmfRecordTypeSelectPalette:
  2967. // We don't select in any palettes when playing the metafile,
  2968. // because we don't want to invalidate our halftoning palette.
  2969. // Keep track of the palette so we can map from PALETTEINDEXes
  2970. // to RGB values.
  2971. this->SelectPalette((INT)((INT16)(((WORD *)recordData)[0])));
  2972. break;
  2973. case WmfRecordTypeRealizePalette:
  2974. // We don't want to invalidate our halftoning palette by realizing one
  2975. // from a metafile.
  2976. break;
  2977. case WmfRecordTypePolyPolygon:
  2978. this->PolyPolygon();
  2979. break;
  2980. case WmfRecordTypeDIBBitBlt:
  2981. this->DIBBitBlt();
  2982. forceCallback = TRUE;
  2983. break;
  2984. case WmfRecordTypeDIBStretchBlt:
  2985. this->DIBStretchBlt();
  2986. forceCallback = TRUE;
  2987. break;
  2988. case WmfRecordTypeStretchDIB:
  2989. this->StretchDIBits();
  2990. forceCallback = TRUE;
  2991. break;
  2992. case WmfRecordTypeSetViewportOrg:
  2993. this->SetViewportOrg();
  2994. break;
  2995. case WmfRecordTypeSetViewportExt:
  2996. this->SetViewportExt();
  2997. break;
  2998. case WmfRecordTypeSelectClipRegion:
  2999. case WmfRecordTypeOffsetClipRgn:
  3000. this->PlayRecord();
  3001. if (!Globals::IsNt)
  3002. {
  3003. this->IntersectDestRect();
  3004. }
  3005. break;
  3006. }
  3007. GDIP_CATCH
  3008. forceCallback = TRUE;
  3009. GDIP_ENDCATCH
  3010. }
  3011. FsmState = nextState;
  3012. this->EndRecord();
  3013. return forceCallback;
  3014. }