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.

1829 lines
58 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 2000 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * MetaEmf.cpp
  8. *
  9. * Abstract:
  10. *
  11. * Methods for playing and recoloring an EMF.
  12. *
  13. * Created:
  14. *
  15. * 1/6/2000 DCurtis
  16. *
  17. \**************************************************************************/
  18. #include "Precomp.hpp"
  19. #include "MetaWmf.hpp"
  20. //----------------------------------------------------------------------------
  21. // File format signatures for Office Art data.
  22. //------------------------------------------------------------------- JohnBo
  23. #define msoszOfficeSignature "MSOFFICE"
  24. #define msocbOfficeSignature 8
  25. #define msoszOfficeAuthentication "9.0"
  26. #define msocbOfficeAuthentication 3
  27. #define msoszOfficeIdent msoszOfficeSignature msoszOfficeAuthentication
  28. #define msocbOfficeIdent (msocbOfficeSignature+msocbOfficeAuthentication)
  29. #define msoszOAPNGChunk "msOA"
  30. #define msocbOAPNGChunk 4
  31. #define msoszOADataHeader msoszOAPNGChunk msoszOfficeIdent
  32. #define msocbOADataHeader (msocbOAPNGChunk+msocbOfficeIdent)
  33. #define msoszOAKind "OA"
  34. #define msocbOAKind 2
  35. /* This defines an OZ chunk, like OA but Zlib compressed. */
  36. #define msoszOZPNGChunk "msOZ"
  37. #define msocbOZPNGChunk 4
  38. #define msoszOZDataHeader msoszOZPNGChunk msoszOfficeIdent
  39. #define msocbOZDataHeader (msocbOZPNGChunk+msocbOfficeIdent)
  40. // These are needed for IA64 compatibility with X86
  41. // Since we are reading this record from a stream, on IA64
  42. // The EXTLOGPEN structure has a ULONG_PTR member which is not the same size
  43. // on IA64 and X86. Since all output to files will keep the X86 format we need
  44. // to make sure that we can read this format in IA64, so we make it compatible
  45. // by changing the ULONG_PTR to a ULONG (32bit). The packing of the structure
  46. // will them be the same and the members will be at the same offset
  47. typedef struct tagEXTLOGPEN32 {
  48. DWORD elpPenStyle;
  49. DWORD elpWidth;
  50. UINT elpBrushStyle;
  51. COLORREF elpColor;
  52. ULONG elpHatch;
  53. DWORD elpNumEntries;
  54. DWORD elpStyleEntry[1];
  55. } EXTLOGPEN32, *PEXTLOGPEN32;
  56. typedef struct tagEMREXTCREATEPEN32
  57. {
  58. EMR emr;
  59. DWORD ihPen; // Pen handle index
  60. DWORD offBmi; // Offset to the BITMAPINFO structure if any
  61. DWORD cbBmi; // Size of the BITMAPINFO structure if any
  62. // The bitmap info is followed by the bitmap
  63. // bits to form a packed DIB.
  64. DWORD offBits; // Offset to the brush bitmap bits if any
  65. DWORD cbBits; // Size of the brush bitmap bits if any
  66. EXTLOGPEN32 elp; // The extended pen with the style array.
  67. } EMREXTCREATEPEN32, *PEMREXTCREATEPEN32;
  68. typedef struct tagEMRRCLBOUNDS
  69. {
  70. EMR emr;
  71. RECTL rclBounds;
  72. } EMRRCLBOUNDS, *PEMRRCLBOUNDS;
  73. typedef struct EMROFFICECOMMENT
  74. {
  75. EMR emr;
  76. DWORD cbData; // Size of following fields and data
  77. DWORD ident; // GDICOMMENT_IDENTIFIER
  78. DWORD iComment; // Comment type e.g. GDICOMMENT_WINDOWS_METAFILE
  79. } EMROFFICECOMMENT, *PEMROFFICECOMMENT;
  80. RecolorStockObject RecolorStockObjectList[NUM_STOCK_RECOLOR_OBJS] =
  81. {
  82. { WHITE_BRUSH, (COLORREF)RGB(0xFF, 0xFF, 0xFF), TRUE },
  83. { LTGRAY_BRUSH, (COLORREF)RGB(0xC0, 0xC0, 0xC0), TRUE },
  84. { GRAY_BRUSH, (COLORREF)RGB(0x80, 0x80, 0x80), TRUE },
  85. { DKGRAY_BRUSH, (COLORREF)RGB(0x40, 0x40 ,0x40), TRUE },
  86. { BLACK_BRUSH, (COLORREF)RGB(0, 0, 0), TRUE },
  87. { WHITE_PEN, (COLORREF)RGB(0xFF, 0xFF, 0xFF), FALSE },
  88. { BLACK_PEN, (COLORREF)RGB(0, 0 ,0), FALSE }
  89. };
  90. inline static RGBQUAD *
  91. GetDibColorTable(
  92. BITMAPINFOHEADER * dibInfo
  93. )
  94. {
  95. return ( RGBQUAD *)(((BYTE *)dibInfo) + dibInfo->biSize);
  96. }
  97. BOOL
  98. EmfEnumState::CreateCopyOfCurrentRecord()
  99. {
  100. if (ModifiedRecordSize > 0)
  101. {
  102. // We already made a modified record. Don't do it again.
  103. ASSERT(ModifiedRecord != NULL);
  104. return TRUE;
  105. }
  106. INT size = this->GetCurrentRecordSize();
  107. if (CreateRecordToModify(size))
  108. {
  109. ENHMETARECORD * modifiedRecord = (ENHMETARECORD *)ModifiedRecord;
  110. modifiedRecord->iType = RecordType;
  111. modifiedRecord->nSize = size;
  112. if (RecordDataSize > 0)
  113. {
  114. GpMemcpy(modifiedRecord->dParm, RecordData, RecordDataSize);
  115. }
  116. return TRUE;
  117. }
  118. WARNING(("Failed to create copy of current record"));
  119. return FALSE;
  120. }
  121. BOOL
  122. EmfEnumState::CreateAndPlayOutputDIBRecord(
  123. HDC hdc,
  124. const RECTL * bounds,
  125. INT dstX,
  126. INT dstY,
  127. INT dstWidth,
  128. INT dstHeight,
  129. INT srcX,
  130. INT srcY,
  131. INT srcWidth,
  132. INT srcHeight,
  133. UNALIGNED BITMAPINFOHEADER * dibInfo,
  134. BYTE * bits, // if NULL, this is a packed DIB
  135. UINT usage,
  136. DWORD rop
  137. )
  138. {
  139. ASSERT(!Globals::IsNt);
  140. INT bitsSize = GetDibBitsSize(dibInfo);
  141. UINT sizePalEntries;
  142. if (GetDibNumPalEntries(FALSE,
  143. dibInfo->biSize,
  144. dibInfo->biBitCount,
  145. dibInfo->biCompression,
  146. dibInfo->biClrUsed,
  147. &sizePalEntries))
  148. {
  149. // We need to get the palette size that corresponds to the type
  150. // If we have a DIB_PAL_COLORS then each entry is 16bits
  151. sizePalEntries *= ((usage == DIB_PAL_COLORS)?2:sizeof(RGBQUAD));
  152. }
  153. else
  154. {
  155. sizePalEntries = 0 ;
  156. }
  157. // We need at least a BITMAPINFO structure in there, but if there is a
  158. // palette, calculate the full size of the structure including the
  159. // palette
  160. INT bitmapHeaderSize = sizeof(BITMAPINFOHEADER) + sizePalEntries;
  161. INT size = sizeof(EMRSTRETCHDIBITS) + bitmapHeaderSize + bitsSize ;
  162. // We cannot use the CreateRecordToModify because the record has already
  163. // been modified
  164. size = (size + 3) & ~3;
  165. EMRSTRETCHDIBITS* emrStretchDIBits = (EMRSTRETCHDIBITS*) GpMalloc(size);
  166. if (emrStretchDIBits != NULL)
  167. {
  168. emrStretchDIBits->emr.iType = EmfRecordTypeStretchDIBits;
  169. emrStretchDIBits->emr.nSize = size;
  170. emrStretchDIBits->rclBounds = *bounds;
  171. emrStretchDIBits->xDest = dstX;
  172. emrStretchDIBits->yDest = dstY;
  173. emrStretchDIBits->xSrc = srcX;
  174. emrStretchDIBits->ySrc = srcY;
  175. emrStretchDIBits->cxSrc = srcWidth;
  176. emrStretchDIBits->cySrc = srcHeight;
  177. emrStretchDIBits->offBmiSrc = sizeof(EMRSTRETCHDIBITS);
  178. emrStretchDIBits->cbBmiSrc = bitmapHeaderSize;
  179. emrStretchDIBits->offBitsSrc = emrStretchDIBits->offBmiSrc + emrStretchDIBits->cbBmiSrc;
  180. emrStretchDIBits->cbBitsSrc = bitsSize;
  181. emrStretchDIBits->iUsageSrc = usage;
  182. emrStretchDIBits->dwRop = rop;
  183. emrStretchDIBits->cxDest = dstWidth;
  184. emrStretchDIBits->cyDest = dstHeight;
  185. GpMemcpy((BYTE*)emrStretchDIBits + emrStretchDIBits->offBmiSrc, dibInfo, emrStretchDIBits->cbBmiSrc);
  186. GpMemcpy((BYTE*)emrStretchDIBits + emrStretchDIBits->offBitsSrc, bits, emrStretchDIBits->cbBitsSrc);
  187. ::PlayEnhMetaFileRecord(hdc, HandleTable, (ENHMETARECORD *)emrStretchDIBits, NumObjects);
  188. GpFree(emrStretchDIBits);
  189. return TRUE;
  190. }
  191. return FALSE;
  192. }
  193. BITMAPINFOHEADER *
  194. EmfEnumState::CreateModifiedDib(
  195. BITMAPINFOHEADER * srcDibInfo,
  196. BYTE * srcBits,
  197. UINT & usage,
  198. DWORD rop
  199. )
  200. {
  201. BITMAPINFOHEADER * dstDibInfo = NULL;
  202. UINT numPalEntries;
  203. UINT dibBitsSize;
  204. if ((srcDibInfo->biSize >= sizeof(BITMAPINFOHEADER)) &&
  205. GetDibNumPalEntries(FALSE,
  206. srcDibInfo->biSize,
  207. srcDibInfo->biBitCount,
  208. srcDibInfo->biCompression,
  209. srcDibInfo->biClrUsed,
  210. &numPalEntries) &&
  211. ((dibBitsSize = GetDibBitsSize(srcDibInfo)) > 0))
  212. {
  213. if (numPalEntries == 2 && rop != SRCCOPY)
  214. {
  215. DWORD *rgb = (DWORD*) GetDibColorTable(srcDibInfo);
  216. if (rgb[0] == 0x00000000 && rgb[1] == 0x00FFFFFF)
  217. {
  218. return dstDibInfo;
  219. }
  220. }
  221. // We need to pass in to ModifyDib the old Usage value because we haven't modified
  222. // the bitmap yet. Once we do then we will return the new usage of the palette.
  223. UINT oldUsage = usage;
  224. INT dstDibSize = GetModifiedDibSize(srcDibInfo, numPalEntries, dibBitsSize, usage);
  225. if ((dstDibSize > 0) && CreateRecordToModify(dstDibSize))
  226. {
  227. dstDibInfo = (BITMAPINFOHEADER *)ModifiedRecord;
  228. ModifyDib(oldUsage, srcDibInfo, srcBits, dstDibInfo,
  229. numPalEntries, dibBitsSize, ColorAdjustTypeBitmap);
  230. }
  231. }
  232. return dstDibInfo;
  233. }
  234. VOID
  235. EmfEnumState::BitBlt(
  236. )
  237. {
  238. const EMRBITBLT * bitBltRecord = (const EMRBITBLT *)GetPartialRecord();
  239. DWORD rop = bitBltRecord->dwRop;
  240. // If No-Op ROP, do nothing; just return
  241. if ((rop & 0xFFFF0000) == (GDIP_NOOP_ROP3 & 0xFFFF0000))
  242. {
  243. return;
  244. }
  245. // On NT4, PATCOPYs fail to draw correctly if there is a skew/rotate
  246. // in the matrix. So use a rectangle call instead.
  247. if ((rop == PATCOPY) && Globals::IsNt && (Globals::OsVer.dwMajorVersion <= 4))
  248. {
  249. XFORM xform;
  250. if (::GetWorldTransform(Hdc, &xform) &&
  251. ((xform.eM12 != 0.0f) || (xform.eM21 != 0.0f)))
  252. {
  253. HPEN hPenOld = (HPEN)::SelectObject(Hdc, ::GetStockObject(NULL_PEN));
  254. DWORD dcRop = ::GetROP2(Hdc);
  255. if (dcRop != R2_COPYPEN)
  256. {
  257. ::SetROP2(Hdc, R2_COPYPEN);
  258. }
  259. ::Rectangle(Hdc, bitBltRecord->xDest, bitBltRecord->yDest,
  260. bitBltRecord->xDest + bitBltRecord->cxDest,
  261. bitBltRecord->yDest + bitBltRecord->cyDest);
  262. ::SelectObject(Hdc, hPenOld);
  263. if (dcRop != R2_COPYPEN)
  264. {
  265. ::SetROP2(Hdc, dcRop);
  266. }
  267. return;
  268. }
  269. }
  270. if (rop != SRCCOPY &&
  271. rop != NOTSRCCOPY &&
  272. rop != PATCOPY &&
  273. rop != BLACKNESS &&
  274. rop != WHITENESS)
  275. {
  276. RopUsed = TRUE;
  277. }
  278. if ((bitBltRecord->cbBitsSrc > 0) &&
  279. (bitBltRecord->cbBmiSrc > 0) &&
  280. IsSourceInRop3(rop))
  281. {
  282. // Should we modify the dib if it is monochrome?
  283. // What if there is a non-identity transform for the src DC?
  284. UINT usage = bitBltRecord->iUsageSrc;
  285. BITMAPINFOHEADER * srcDibInfo = (BITMAPINFOHEADER *)(((BYTE *)bitBltRecord) + bitBltRecord->offBmiSrc);
  286. BYTE * srcBits = ((BYTE *)bitBltRecord) + bitBltRecord->offBitsSrc;
  287. BITMAPINFOHEADER * dstDibInfo = CreateModifiedDib(srcDibInfo, srcBits, usage, rop);
  288. if (dstDibInfo != NULL)
  289. {
  290. srcDibInfo = dstDibInfo;
  291. srcBits = NULL;
  292. }
  293. if (SrcCopyOnly && rop != SRCCOPY)
  294. {
  295. rop = SRCCOPY;
  296. }
  297. OutputDIB(Hdc,
  298. &bitBltRecord->rclBounds,
  299. bitBltRecord->xDest, bitBltRecord->yDest,
  300. bitBltRecord->cxDest, bitBltRecord->cyDest,
  301. bitBltRecord->xSrc, bitBltRecord->ySrc,
  302. bitBltRecord->cxDest, bitBltRecord->cyDest,
  303. srcDibInfo, srcBits, usage, rop, FALSE);
  304. }
  305. else
  306. {
  307. if (SrcCopyOnly && rop != PATCOPY && !IsSourceInRop3(rop) && CreateCopyOfCurrentRecord())
  308. {
  309. EMRBITBLT * newBitBltRecord = (EMRBITBLT *) ModifiedEmfRecord;
  310. newBitBltRecord->dwRop = PATCOPY;
  311. }
  312. ResetRecordBounds();
  313. this->PlayRecord();
  314. }
  315. }
  316. VOID
  317. EmfEnumState::StretchBlt(
  318. )
  319. {
  320. const EMRSTRETCHBLT * stretchBltRecord = (const EMRSTRETCHBLT *)GetPartialRecord();
  321. DWORD rop = stretchBltRecord->dwRop;
  322. // If No-Op ROP, do nothing; just return
  323. if ((rop & 0xFFFF0000) == (GDIP_NOOP_ROP3 & 0xFFFF0000))
  324. {
  325. return;
  326. }
  327. if (rop != SRCCOPY &&
  328. rop != NOTSRCCOPY &&
  329. rop != PATCOPY &&
  330. rop != BLACKNESS &&
  331. rop != WHITENESS)
  332. {
  333. RopUsed = TRUE;
  334. }
  335. if ((stretchBltRecord->cbBitsSrc > 0) &&
  336. (stretchBltRecord->cbBmiSrc > 0) &&
  337. IsSourceInRop3(rop))
  338. {
  339. // Should we modify the dib if it is monochrome?
  340. // What if there is a non-identity transform for the src DC?
  341. UINT usage = stretchBltRecord->iUsageSrc;
  342. BITMAPINFOHEADER * srcDibInfo = (BITMAPINFOHEADER *)(((BYTE *)stretchBltRecord) + stretchBltRecord->offBmiSrc);
  343. BYTE * srcBits = ((BYTE *)stretchBltRecord) + stretchBltRecord->offBitsSrc;
  344. BITMAPINFOHEADER * dstDibInfo = CreateModifiedDib(srcDibInfo, srcBits, usage, rop);
  345. if (SrcCopyOnly && rop != SRCCOPY)
  346. {
  347. rop = SRCCOPY;
  348. }
  349. ASSERT(sizeof(XFORM) == sizeof(REAL)*6);
  350. GpMatrix xForm((REAL*) &(stretchBltRecord->xformSrc));
  351. if (dstDibInfo != NULL)
  352. {
  353. srcDibInfo = dstDibInfo;
  354. srcBits = NULL;
  355. }
  356. GpRectF srcRect((REAL)stretchBltRecord->xSrc,
  357. (REAL)stretchBltRecord->ySrc,
  358. (REAL)stretchBltRecord->cxSrc,
  359. (REAL)stretchBltRecord->cySrc);
  360. if (!xForm.IsIdentity())
  361. {
  362. // We cannot use TransformRect, because the output rect will always
  363. // have a positive Width and Height which we don't want
  364. GpPointF points[2];
  365. points[0] = GpPointF(srcRect.X, srcRect.Y);
  366. points[1] = GpPointF(srcRect.GetRight(), srcRect.GetBottom());
  367. xForm.Transform(points, 2);
  368. srcRect.X = points[0].X;
  369. srcRect.Y = points[0].Y;
  370. srcRect.Width = points[1].X - points[0].X;
  371. srcRect.Height = points[1].Y - points[0].Y;
  372. }
  373. // StretchBlt takes as parameters the top left corner of the dest
  374. // whereas StretchDIBits takes the offset in the source image.
  375. // For bottom up dibs those are not the same and we need to offset
  376. // the srcrect's Y coodinate by the difference
  377. if (srcDibInfo->biHeight > 0 &&
  378. srcRect.Height < srcDibInfo->biHeight)
  379. {
  380. srcRect.Y = srcDibInfo->biHeight - srcRect.Height - srcRect.Y;
  381. }
  382. OutputDIB(Hdc,
  383. &stretchBltRecord->rclBounds,
  384. stretchBltRecord->xDest, stretchBltRecord->yDest,
  385. stretchBltRecord->cxDest, stretchBltRecord->cyDest,
  386. GpRound(srcRect.X), GpRound(srcRect.Y),
  387. GpRound(srcRect.Width), GpRound(srcRect.Height),
  388. srcDibInfo, srcBits, usage, rop, FALSE);
  389. }
  390. else
  391. {
  392. if (SrcCopyOnly && rop != PATCOPY && !IsSourceInRop3(rop) && CreateCopyOfCurrentRecord())
  393. {
  394. EMRSTRETCHBLT * stretchBltRecord = (EMRSTRETCHBLT *)ModifiedEmfRecord;
  395. stretchBltRecord->dwRop = PATCOPY;
  396. }
  397. ResetRecordBounds();
  398. this->PlayRecord();
  399. }
  400. }
  401. VOID
  402. EmfEnumState::StretchDIBits(
  403. )
  404. {
  405. const EMRSTRETCHDIBITS * stretchDIBitsRecord = (const EMRSTRETCHDIBITS *)GetPartialRecord();
  406. DWORD rop = stretchDIBitsRecord->dwRop;
  407. // If No-Op ROP, do nothing; just return
  408. if ((rop & 0xFFFF0000) == (GDIP_NOOP_ROP3 & 0xFFFF0000))
  409. {
  410. return;
  411. }
  412. if (rop != SRCCOPY &&
  413. rop != NOTSRCCOPY &&
  414. rop != PATCOPY &&
  415. rop != BLACKNESS &&
  416. rop != WHITENESS)
  417. {
  418. RopUsed = TRUE;
  419. }
  420. if ((stretchDIBitsRecord->cbBitsSrc > 0) &&
  421. (stretchDIBitsRecord->cbBmiSrc > 0) &&
  422. IsSourceInRop3(rop))
  423. {
  424. UINT usage = stretchDIBitsRecord->iUsageSrc;
  425. BITMAPINFOHEADER * srcDibInfo = (BITMAPINFOHEADER *)(((BYTE *)stretchDIBitsRecord) + stretchDIBitsRecord->offBmiSrc);
  426. BYTE * srcBits = ((BYTE *)stretchDIBitsRecord) + stretchDIBitsRecord->offBitsSrc;
  427. BITMAPINFOHEADER * dstDibInfo = CreateModifiedDib(srcDibInfo, srcBits, usage, rop);
  428. if (dstDibInfo != NULL)
  429. {
  430. srcDibInfo = dstDibInfo;
  431. srcBits = NULL;
  432. }
  433. if (SrcCopyOnly && rop != SRCCOPY)
  434. {
  435. rop = SRCCOPY;
  436. }
  437. OutputDIB(Hdc,
  438. &stretchDIBitsRecord->rclBounds,
  439. stretchDIBitsRecord->xDest, stretchDIBitsRecord->yDest,
  440. stretchDIBitsRecord->cxDest, stretchDIBitsRecord->cyDest,
  441. stretchDIBitsRecord->xSrc, stretchDIBitsRecord->ySrc,
  442. stretchDIBitsRecord->cxSrc, stretchDIBitsRecord->cySrc,
  443. srcDibInfo, srcBits, usage, rop, FALSE);
  444. }
  445. else
  446. {
  447. if (SrcCopyOnly && rop != PATCOPY && !IsSourceInRop3(rop) && CreateCopyOfCurrentRecord())
  448. {
  449. EMRSTRETCHDIBITS* stretchDIBitsRecord = (EMRSTRETCHDIBITS *)ModifiedEmfRecord;
  450. stretchDIBitsRecord->dwRop = PATCOPY;
  451. }
  452. ResetRecordBounds();
  453. this->PlayRecord();
  454. }
  455. }
  456. VOID
  457. EmfEnumState::SetDIBitsToDevice(
  458. )
  459. {
  460. // !!! to do
  461. // In SetDIBitsToDevice, the destination width and height
  462. // are in device units but in StretchDIBits, they are in world units.
  463. // Plus, the DIB header is for the entire DIB, but only part of the
  464. // DIB may be here (based on the number of scans).
  465. // So this record requires special handling if we are to process it.
  466. ResetRecordBounds();
  467. this->PlayRecord();
  468. }
  469. VOID
  470. EmfEnumState::CreateDibPatternBrushPt(
  471. )
  472. {
  473. const EMRCREATEDIBPATTERNBRUSHPT * brushRecord = (const EMRCREATEDIBPATTERNBRUSHPT *)GetPartialRecord();
  474. INT objectIndex = brushRecord->ihBrush;
  475. if (ValidObjectIndex(objectIndex) && (HandleTable != NULL))
  476. {
  477. UINT usage = brushRecord->iUsage;
  478. BITMAPINFOHEADER * srcDibInfo = (BITMAPINFOHEADER *)(((UNALIGNED BYTE *)brushRecord) + brushRecord->offBmi);
  479. BITMAPINFOHEADER * dstDibInfo = CreateModifiedDib(srcDibInfo, NULL, usage, SRCCOPY);
  480. if (dstDibInfo != NULL)
  481. {
  482. HandleTable->objectHandle[objectIndex] =
  483. CreateDIBPatternBrushPt((BITMAPINFO *)dstDibInfo, usage);
  484. return;
  485. }
  486. }
  487. this->PlayRecord();
  488. }
  489. inline static BOOL
  490. IsOfficeArtData(
  491. UINT recordSize,
  492. const EMRGDICOMMENT * commentRecord
  493. )
  494. {
  495. return ((recordSize >= (12 + 4 + msocbOADataHeader)) &&
  496. (commentRecord->cbData >= (msocbOADataHeader + 4)) &&
  497. ((GpMemcmp(commentRecord->Data, msoszOADataHeader, msocbOADataHeader) == 0) ||
  498. (GpMemcmp(commentRecord->Data, msoszOZDataHeader, msocbOZDataHeader) == 0)));
  499. }
  500. inline static const EMROFFICECOMMENT *
  501. GetEmfComment(
  502. const BYTE * emfRecord,
  503. ULONG signature,
  504. UINT kind
  505. )
  506. {
  507. const EMROFFICECOMMENT * emfComment = (const EMROFFICECOMMENT*)(emfRecord);
  508. if ((emfComment->ident == signature) && (emfComment->iComment == kind))
  509. {
  510. return emfComment;
  511. }
  512. return NULL;
  513. }
  514. VOID
  515. EmfEnumState::GdiComment(
  516. )
  517. {
  518. // Skip Office Art data when playing into another metafile
  519. if (IsMetafile() &&
  520. IsOfficeArtData(
  521. GetCurrentRecordSize(),
  522. (const EMRGDICOMMENT *)GetPartialRecord()))
  523. {
  524. return;
  525. }
  526. if (IsPostscript())
  527. {
  528. if (GetEmfComment((BYTE*)CurrentEmfRecord, msosignature, msocommentBeginSrcCopy))
  529. {
  530. SrcCopyOnly = TRUE;
  531. return;
  532. }
  533. if (GetEmfComment((BYTE*)CurrentEmfRecord, msosignature, msocommentEndSrcCopy))
  534. {
  535. SrcCopyOnly = FALSE;
  536. return;
  537. }
  538. }
  539. this->PlayRecord();
  540. }
  541. BOOL
  542. IsPenCosmetic(
  543. HDC hdc,
  544. int penWidth
  545. )
  546. {
  547. penWidth <<= 7;
  548. INT newPenWidth = penWidth;
  549. POINT points[2];
  550. points[0].x = 0;
  551. points[0].y = 0;
  552. points[1].x = 1 << 7;
  553. points[1].y = 0;
  554. if (::DPtoLP(hdc, points, 2))
  555. {
  556. newPenWidth = points[1].x - points[0].x;
  557. if (newPenWidth < 0)
  558. {
  559. newPenWidth = -newPenWidth;
  560. }
  561. }
  562. return (penWidth <= newPenWidth);
  563. }
  564. VOID
  565. EmfEnumState::CreatePen(
  566. )
  567. {
  568. const EMRCREATEPEN * penRecord = (const EMRCREATEPEN *)GetPartialRecord();
  569. DWORD oldStyle = penRecord->lopn.lopnStyle;
  570. if (oldStyle == PS_NULL)
  571. {
  572. this->PlayRecord();
  573. }
  574. else if (IsMetafile())
  575. {
  576. ModifyRecordColor(4, ColorAdjustTypePen);
  577. this->PlayRecord();
  578. }
  579. else
  580. {
  581. INT objectIndex = penRecord->ihPen;
  582. if (ValidObjectIndex(objectIndex) && (HandleTable != NULL))
  583. {
  584. LOGBRUSH logBrush;
  585. logBrush.lbStyle = PS_SOLID;
  586. logBrush.lbColor = ModifyColor(penRecord->lopn.lopnColor, ColorAdjustTypePen);
  587. logBrush.lbHatch = 0;
  588. INT penWidth = penRecord->lopn.lopnWidth.x;
  589. DWORD style;
  590. if (!Globals::IsNt && !IsMetafile())
  591. {
  592. //IsPenCosmetic is gonna call DPtoLP... Make sure to invalidate
  593. //the transform before
  594. CreateAndPlayCommentRecord();
  595. }
  596. if (IsPenCosmetic(Hdc, penWidth))
  597. {
  598. switch (oldStyle)
  599. {
  600. case PS_SOLID:
  601. case PS_DASH: // on Win9x, cosmetic only
  602. case PS_DOT: // on Win9x, cosmetic only
  603. case PS_DASHDOT: // on Win9x, cosmetic only
  604. case PS_DASHDOTDOT: // on Win9x, cosmetic only
  605. break;
  606. case PS_ALTERNATE: // cosmetic only, NT only
  607. if (Globals::IsNt)
  608. {
  609. break;
  610. }
  611. // FALLTHRU
  612. case PS_USERSTYLE: // NT only
  613. case PS_INSIDEFRAME: // geometric only
  614. default:
  615. oldStyle = PS_SOLID;
  616. break;
  617. }
  618. penWidth = 1;
  619. style = PS_COSMETIC | oldStyle;
  620. }
  621. else
  622. {
  623. switch (oldStyle)
  624. {
  625. case PS_SOLID:
  626. case PS_INSIDEFRAME: // geometric only
  627. break;
  628. case PS_DASH: // on Win9x, cosmetic only
  629. case PS_DOT: // on Win9x, cosmetic only
  630. case PS_DASHDOT: // on Win9x, cosmetic only
  631. case PS_DASHDOTDOT: // on Win9x, cosmetic only
  632. if (Globals::IsNt)
  633. {
  634. break;
  635. }
  636. // FALLTHRU
  637. case PS_ALTERNATE: // cosmetic only, NT only
  638. case PS_USERSTYLE: // NT only
  639. default:
  640. oldStyle = PS_SOLID;
  641. break;
  642. }
  643. style = PS_GEOMETRIC | oldStyle | PS_ENDCAP_ROUND | PS_JOIN_ROUND;
  644. }
  645. HandleTable->objectHandle[objectIndex] = ::ExtCreatePen(style, penWidth, &logBrush, 0, NULL);
  646. }
  647. }
  648. }
  649. HFONT CreateTrueTypeFont(
  650. HFONT hFont
  651. )
  652. {
  653. if (hFont)
  654. {
  655. if (Globals::IsNt)
  656. {
  657. LOGFONT logFont;
  658. if (GetObject(hFont, sizeof(logFont), &logFont) > 0)
  659. {
  660. logFont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
  661. return CreateFontIndirect(&logFont);
  662. }
  663. else
  664. {
  665. WARNING1("GetObject for hFont failed");
  666. }
  667. }
  668. else
  669. {
  670. LOGFONTA logFont;
  671. if (GetObjectA(hFont, sizeof(logFont), &logFont) > 0)
  672. {
  673. logFont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
  674. // We have a bug in Win9x that the OUT_TT_ONLY_PRECIS flag is
  675. // not always respected so if the font name is MS SANS SERIF
  676. // change it to Times New Roman
  677. if (lstrcmpiA(logFont.lfFaceName, "MS SANS SERIF") == 0)
  678. {
  679. GpMemcpy(logFont.lfFaceName, "Times New Roman", sizeof("Times New Roman"));
  680. }
  681. return CreateFontIndirectA(&logFont);
  682. }
  683. else
  684. {
  685. WARNING1("GetObject for hFont failed");
  686. }
  687. }
  688. }
  689. else
  690. {
  691. WARNING1("NULL hFont");
  692. }
  693. return NULL;
  694. }
  695. VOID
  696. EmfEnumState::ExtCreateFontIndirect(
  697. )
  698. {
  699. const EMREXTCREATEFONTINDIRECTW * fontRecord = (const EMREXTCREATEFONTINDIRECTW *)GetPartialRecord();
  700. BOOL recordCopied = FALSE;
  701. if (!Globals::IsNt)
  702. {
  703. // We have a bug in Win9x that the OUT_TT_ONLY_PRECIS flag is
  704. // not always respected so if the font name is MS SANS SERIF
  705. // change it to Times New Roman
  706. if (UnicodeStringCompareCI(fontRecord->elfw.elfFullName, L"MS SANS SERIF") == 0)
  707. {
  708. if (CreateCopyOfCurrentRecord())
  709. {
  710. GpMemcpy(((EMREXTCREATEFONTINDIRECTW *)ModifiedEmfRecord)->elfw.elfFullName,
  711. L"Times New Roman", sizeof(L"Times New Roman"));
  712. recordCopied = TRUE;
  713. }
  714. }
  715. }
  716. if (fontRecord->elfw.elfLogFont.lfOutPrecision != OUT_TT_ONLY_PRECIS)
  717. {
  718. if (recordCopied || CreateCopyOfCurrentRecord())
  719. // Instruct GDI to use only True Type fonts, since bitmap fonts
  720. // are not scalable.
  721. {
  722. ((EMREXTCREATEFONTINDIRECTW *)ModifiedEmfRecord)->elfw.elfLogFont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
  723. }
  724. }
  725. this->PlayRecord();
  726. }
  727. VOID
  728. EmfEnumState::SelectObject(
  729. )
  730. {
  731. const EMRSELECTOBJECT * selectRecord = (const EMRSELECTOBJECT *)GetPartialRecord();
  732. DWORD handleIndex = selectRecord->ihObject;
  733. // See if we're selecting in a stock font
  734. if ((handleIndex & ENHMETA_STOCK_OBJECT) != 0)
  735. {
  736. handleIndex &= (~ENHMETA_STOCK_OBJECT);
  737. // handleIndex >= (WHITE_BRUSH==0) && <= BLACK_PEN
  738. if ((handleIndex <= BLACK_PEN) && (Recolor != NULL))
  739. {
  740. union {
  741. LOGBRUSH lb;
  742. LOGPEN lp;
  743. };
  744. RecolorStockObject* stockObj;
  745. int i;
  746. for (stockObj = &RecolorStockObjectList[0],
  747. i = 0;
  748. i < NUM_STOCK_RECOLOR_OBJS;
  749. i++,
  750. stockObj++)
  751. {
  752. if (stockObj->Handle == handleIndex)
  753. {
  754. // Already have a cached recolored handle lying around.
  755. HGDIOBJ stockHandle = RecoloredStockHandle[i];
  756. if (stockHandle == NULL)
  757. {
  758. // No cached recolored stock object handle, recreate
  759. // one here.
  760. COLORREF newColor;
  761. if (stockObj->Brush)
  762. {
  763. newColor = ModifyColor(stockObj->Color, ColorAdjustTypeBrush);
  764. lb.lbStyle = BS_SOLID;
  765. lb.lbColor = newColor;
  766. lb.lbHatch = 0;
  767. stockHandle = ::CreateBrushIndirect(&lb);
  768. RecoloredStockHandle[i] = stockHandle;
  769. }
  770. else
  771. {
  772. newColor = ModifyColor(stockObj->Color, ColorAdjustTypePen);
  773. lp.lopnStyle = PS_SOLID;
  774. lp.lopnWidth.x = 1;
  775. lp.lopnWidth.y = 0;
  776. lb.lbColor = newColor;
  777. stockHandle = ::CreatePenIndirect(&lp);
  778. RecoloredStockHandle[i] = stockHandle;
  779. }
  780. }
  781. if (stockHandle != NULL)
  782. {
  783. ::SelectObject(Hdc, stockHandle);
  784. return;
  785. }
  786. }
  787. }
  788. }
  789. else if ((handleIndex >= OEM_FIXED_FONT) &&
  790. (handleIndex <= DEFAULT_GUI_FONT))
  791. {
  792. // It is a stock font -- create a true type font, instead of
  793. // using the stock font directly to guarantee that we don't
  794. // use bitmap fonts which don't scale well.
  795. HFONT hFont = StockFonts[handleIndex - OEM_FIXED_FONT];
  796. if (hFont == NULL)
  797. {
  798. hFont = CreateTrueTypeFont((HFONT)GetStockObject(handleIndex));
  799. StockFonts[handleIndex - OEM_FIXED_FONT] = hFont;
  800. }
  801. if (hFont != NULL)
  802. {
  803. ::SelectObject(Hdc, hFont);
  804. return;
  805. }
  806. }
  807. }
  808. this->PlayRecord();
  809. // In case we select a region, intersect with the destrect
  810. if (!Globals::IsNt)
  811. {
  812. if (((handleIndex & ENHMETA_STOCK_OBJECT) == 0) &&
  813. (GetObjectTypeInternal((*HandleTable).objectHandle[handleIndex]) == OBJ_REGION))
  814. {
  815. this->IntersectDestRect();
  816. }
  817. }
  818. }
  819. VOID
  820. EmfEnumState::ExtCreatePen(
  821. )
  822. {
  823. const EMREXTCREATEPEN32 * penRecord = (const EMREXTCREATEPEN32 *)GetPartialRecord();
  824. UINT brushStyle = penRecord->elp.elpBrushStyle;
  825. if (brushStyle != BS_HOLLOW)
  826. {
  827. if (IsMetafile())
  828. {
  829. if ((brushStyle == BS_SOLID) || (brushStyle == BS_HATCHED))
  830. {
  831. ModifyRecordColor(8, ColorAdjustTypePen);
  832. }
  833. // else don't worry about recoloring pattern brushes for now
  834. this->PlayRecord();
  835. return;
  836. }
  837. INT objectIndex = penRecord->ihPen;
  838. if (ValidObjectIndex(objectIndex) && (HandleTable != NULL))
  839. {
  840. if (!Globals::IsNt && !IsMetafile())
  841. {
  842. //IsPenCosmetic is gonna call DPtoLP... Make sure to invalidate
  843. //the transform before
  844. CreateAndPlayCommentRecord();
  845. }
  846. DWORD penWidth = penRecord->elp.elpWidth;
  847. BOOL isCosmetic = IsPenCosmetic(Hdc, penWidth);
  848. DWORD oldStyle = penRecord->elp.elpPenStyle;
  849. if (!Globals::IsNt)
  850. {
  851. DWORD style;
  852. if (isCosmetic)
  853. {
  854. oldStyle &= PS_STYLE_MASK;
  855. switch (oldStyle)
  856. {
  857. case PS_SOLID:
  858. case PS_DASH: // on Win9x, cosmetic only
  859. case PS_DOT: // on Win9x, cosmetic only
  860. case PS_DASHDOT: // on Win9x, cosmetic only
  861. case PS_DASHDOTDOT: // on Win9x, cosmetic only
  862. break;
  863. case PS_ALTERNATE: // cosmetic only, NT only
  864. case PS_USERSTYLE: // NT only
  865. case PS_INSIDEFRAME: // geometric only
  866. default:
  867. oldStyle = PS_SOLID;
  868. break;
  869. }
  870. penWidth = 1;
  871. style = PS_COSMETIC | oldStyle;
  872. }
  873. else
  874. {
  875. oldStyle &= (~PS_TYPE_MASK);
  876. switch (oldStyle & PS_STYLE_MASK)
  877. {
  878. case PS_SOLID:
  879. case PS_INSIDEFRAME: // geometric only
  880. break;
  881. case PS_DASH: // on Win9x, cosmetic only
  882. case PS_DOT: // on Win9x, cosmetic only
  883. case PS_DASHDOT: // on Win9x, cosmetic only
  884. case PS_DASHDOTDOT: // on Win9x, cosmetic only
  885. case PS_ALTERNATE: // cosmetic only, NT only
  886. case PS_USERSTYLE: // NT only
  887. default:
  888. oldStyle = (oldStyle & (~PS_STYLE_MASK)) | PS_SOLID;
  889. break;
  890. }
  891. style = PS_GEOMETRIC | oldStyle;
  892. }
  893. COLORREF color = RGB(0,0,0);
  894. if ((brushStyle == BS_SOLID) || (brushStyle == BS_HATCHED))
  895. {
  896. color = penRecord->elp.elpColor;
  897. }
  898. color = ModifyColor(color, ColorAdjustTypePen);
  899. // Only solid brushes are supported on Win9x
  900. LOGBRUSH logBrush;
  901. logBrush.lbStyle = PS_SOLID;
  902. logBrush.lbColor = color;
  903. logBrush.lbHatch = 0;
  904. HandleTable->objectHandle[objectIndex] = ::ExtCreatePen(style, penWidth, &logBrush, 0, NULL);
  905. return;
  906. }
  907. // else it is NT
  908. if ((brushStyle == BS_SOLID) || (brushStyle == BS_HATCHED))
  909. {
  910. ModifyRecordColor(8, ColorAdjustTypePen);
  911. }
  912. // else don't worry about recoloring pattern brushes for now
  913. if (isCosmetic && CreateCopyOfCurrentRecord())
  914. {
  915. oldStyle &= PS_STYLE_MASK;
  916. if (oldStyle == PS_INSIDEFRAME) // geometric only
  917. {
  918. oldStyle = PS_SOLID;
  919. }
  920. ((EMREXTCREATEPEN32 *)ModifiedEmfRecord)->elp.elpPenStyle = PS_COSMETIC | oldStyle;
  921. ((EMREXTCREATEPEN32 *)ModifiedEmfRecord)->elp.elpWidth = 1;
  922. }
  923. }
  924. }
  925. this->PlayRecord();
  926. }
  927. VOID
  928. EmfEnumState::CreateBrushIndirect(
  929. )
  930. {
  931. const EMRCREATEBRUSHINDIRECT * brushRecord = (const EMRCREATEBRUSHINDIRECT *)GetPartialRecord();
  932. if (brushRecord->lb.lbStyle != BS_HOLLOW)
  933. {
  934. ModifyRecordColor(2, ColorAdjustTypeBrush);
  935. if (ModifiedEmfRecord != NULL)
  936. {
  937. brushRecord = (const EMRCREATEBRUSHINDIRECT *)ModifiedEmfRecord;
  938. }
  939. // See if we need to halftone the color. We do if it is a solid
  940. // color, and we have a halftone palette, and the color is not
  941. // an exact match in the palette.
  942. COLORREF color;
  943. if (IsHalftonePalette && (brushRecord->lb.lbStyle == BS_SOLID) &&
  944. (((color = brushRecord->lb.lbColor) & 0x02000000) == 0))
  945. {
  946. // create a halftone brush, instead of a solid brush
  947. INT objectIndex = brushRecord->ihBrush;
  948. if (ValidObjectIndex(objectIndex) && (HandleTable != NULL))
  949. {
  950. BYTE dib[sizeof(BITMAPINFOHEADER) + // DIB 8 bpp header
  951. (8 * sizeof(RGBQUAD)) + // DIB 8 colors
  952. (8* 8)]; // DIB 8x8 pixels
  953. HalftoneColorRef_216(color, dib);
  954. HandleTable->objectHandle[objectIndex] =
  955. CreateDIBPatternBrushPt(dib, DIB_RGB_COLORS);
  956. return;
  957. }
  958. }
  959. }
  960. this->PlayRecord();
  961. }
  962. BOOL
  963. EmfEnumState::PlayRecord(
  964. )
  965. {
  966. const ENHMETARECORD * recordToPlay = ModifiedEmfRecord;
  967. // See if we've modified the record
  968. if (recordToPlay == NULL)
  969. {
  970. // We haven't. See if we have a valid current record
  971. if (CurrentEmfRecord != NULL)
  972. {
  973. recordToPlay = CurrentEmfRecord;
  974. }
  975. else
  976. {
  977. // we don't so we have to create one
  978. if (!CreateCopyOfCurrentRecord())
  979. {
  980. return FALSE;
  981. }
  982. recordToPlay = ModifiedEmfRecord;
  983. }
  984. }
  985. return PlayEnhMetaFileRecord(Hdc, HandleTable, recordToPlay, NumObjects);
  986. }
  987. VOID
  988. EmfEnumState::RestoreHdc(
  989. )
  990. {
  991. LONG relativeCount = ((const EMRRESTOREDC *)GetPartialRecord())->iRelative;
  992. if (SaveDcCount < 0)
  993. {
  994. if (relativeCount >= SaveDcCount)
  995. {
  996. if (relativeCount >= 0)
  997. {
  998. // Modify the record
  999. CreateCopyOfCurrentRecord(); // guaranteed to succeed
  1000. relativeCount = -1;
  1001. ((EMRRESTOREDC *)ModifiedEmfRecord)->iRelative = -1;
  1002. }
  1003. }
  1004. else
  1005. {
  1006. // Modify the record
  1007. CreateCopyOfCurrentRecord(); // guaranteed to succeed
  1008. relativeCount = SaveDcCount;
  1009. ((EMRRESTOREDC *)ModifiedEmfRecord)->iRelative = relativeCount;
  1010. }
  1011. SaveDcCount -= relativeCount;
  1012. this->PlayRecord();
  1013. }
  1014. else
  1015. {
  1016. WARNING(("RestoreDC not matched to a SaveDC"));
  1017. }
  1018. }
  1019. VOID
  1020. EmfEnumState::ModifyRecordColor(
  1021. INT paramIndex,
  1022. ColorAdjustType adjustType
  1023. )
  1024. {
  1025. COLORREF origColor = ((COLORREF *)RecordData)[paramIndex];
  1026. COLORREF modifiedColor = ModifyColor(origColor, adjustType);
  1027. if (modifiedColor != origColor)
  1028. {
  1029. if (CreateCopyOfCurrentRecord())
  1030. {
  1031. *((COLORREF*)&(ModifiedEmfRecord->dParm[paramIndex])) = modifiedColor;
  1032. }
  1033. }
  1034. }
  1035. VOID
  1036. EmfEnumState::ExtEscape(
  1037. )
  1038. {
  1039. if (IsPostscriptPrinter())
  1040. {
  1041. // Bug #98743 (Windows Bugs) Gdiplus must overcome GDI limitation
  1042. // with POSTSCRIPT_INJECTION. Comments from Rammanohar Arumugam:
  1043. //
  1044. // Being in xx-centric mode means POSTSCRIPT_DATA won't work. I
  1045. // take that to mean that PlayMetaFileRecord only works in
  1046. // compatibility mode.
  1047. //
  1048. // GdiPlus will check for the printer mode. In GDI-centric and
  1049. // Postscript-centric mode, it will not do PlayMetaFileRecord for
  1050. // any record that has POSTSCRIPT_DATA. Instead, it will output
  1051. // the postscript data through a PASSTHRU (for GDI-centric mode)
  1052. // or a POSTSCRIPT_PASSTHRU (for Postscript-Centric mode).
  1053. //
  1054. // You can find out the mode by querying the escape support.
  1055. // 1. Query for POSTSCRIPT_INJECTION support. If not supported,
  1056. // it's compat mode. If supported, find out the mode by doing step 2/3
  1057. // 2. Query for PASSTHROUGH support. If supported, it's GDI-centric.
  1058. // 3. Query for POSTSCRIPT_PASSTHROUGH support. If supported, it's PS-centric.
  1059. PEMREXTESCAPE escRecord = (PEMREXTESCAPE) RecordData;
  1060. // EMR emr;
  1061. // INT iEscape; // Escape code
  1062. // INT cbEscData; // Size of escape data
  1063. // BYTE EscData[1]; // Escape data
  1064. if (escRecord->iEscape == POSTSCRIPT_DATA)
  1065. {
  1066. if (Globals::IsNt)
  1067. {
  1068. DWORD EscapeValue = POSTSCRIPT_IDENTIFY;
  1069. if (::ExtEscape(Hdc,
  1070. QUERYESCSUPPORT,
  1071. sizeof(DWORD),
  1072. (LPSTR)&EscapeValue,
  1073. 0,
  1074. NULL) <= 0)
  1075. {
  1076. // POSTSCRIPT_IDENTITY is not supported if the mode has
  1077. // been set because it can only be set once.
  1078. EscapeValue = POSTSCRIPT_PASSTHROUGH;
  1079. if (::ExtEscape(Hdc,
  1080. QUERYESCSUPPORT,
  1081. sizeof(DWORD),
  1082. (LPSTR)&EscapeValue,
  1083. 0,
  1084. NULL) <= 0)
  1085. {
  1086. // GDI-centric mode
  1087. if (CreateCopyOfCurrentRecord())
  1088. {
  1089. ((EMREXTESCAPE *)ModifiedEmfRecord)->iEscape = PASSTHROUGH;
  1090. }
  1091. }
  1092. else
  1093. {
  1094. // PS-centric mode
  1095. if (CreateCopyOfCurrentRecord())
  1096. {
  1097. ((EMREXTESCAPE *)ModifiedEmfRecord)->iEscape = POSTSCRIPT_PASSTHROUGH;
  1098. }
  1099. }
  1100. this->PlayRecord();
  1101. return;
  1102. }
  1103. else
  1104. {
  1105. // compatibility mode uses POSTSCRIPT_DATA
  1106. }
  1107. }
  1108. else
  1109. {
  1110. // Win98 doesn't distinguish between GDI & compatibility mode
  1111. if (CreateCopyOfCurrentRecord())
  1112. {
  1113. ((EMREXTESCAPE *)ModifiedEmfRecord)->iEscape = PASSTHROUGH;
  1114. }
  1115. }
  1116. }
  1117. }
  1118. this->PlayRecord();
  1119. }
  1120. EmfEnumState::EmfEnumState(
  1121. HDC hdc,
  1122. HENHMETAFILE hEmf,
  1123. const RECT * dest,
  1124. const RECT * deviceRect,
  1125. BOOL externalEnumeration,
  1126. InterpolationMode interpolation,
  1127. DpContext * context,
  1128. GpRecolor * recolor,
  1129. ColorAdjustType adjustType
  1130. )
  1131. : MfEnumState(hdc, externalEnumeration, interpolation,
  1132. recolor, adjustType, deviceRect, context)
  1133. {
  1134. if (IsValid())
  1135. {
  1136. ClipRgn = NULL;
  1137. Palette = NULL;
  1138. BrushOrg.x = 0;
  1139. BrushOrg.y = 0;
  1140. // Bug 166280 from Office:
  1141. // PROBLEM: If the DC has any clipping region in it, EnumEnhMetaFile
  1142. // will create a region before calling the EnumProc for the
  1143. // first time. And, this region is not deleted and cannot be
  1144. // recovered through RestoreDC. (Only on Win9x)
  1145. // FIX: Before calling EnumEnhMetafile, save the clipping region
  1146. // and set the Clipping region to NULL. Select the saved
  1147. // clipping region in the CallBack at EMR_HEADER.
  1148. // We will not do this on Metafile DC. Put clipping region
  1149. // records in Metafile may cause other rendering problems.
  1150. if (!Globals::IsNt && !IsMetafile())
  1151. {
  1152. HRGN clipRgn = ::CreateRectRgn(0,0,0,0);
  1153. if (clipRgn != NULL)
  1154. {
  1155. switch (::GetClipRgn(hdc, clipRgn))
  1156. {
  1157. case -1: // error
  1158. case 0: // no initial clip region
  1159. ::DeleteObject(clipRgn);
  1160. break;
  1161. case 1: // has initial clip region
  1162. ::SelectClipRgn(hdc, NULL);
  1163. ClipRgn = clipRgn;
  1164. break;
  1165. }
  1166. }
  1167. }
  1168. // Bug 160932 from Office: Redraw problems with EMFs
  1169. // The fix is to make the drawing independent of where
  1170. // the EMF is drawn - this can be done easily by setting the
  1171. // brush origin before the first record is played (in the
  1172. // record callback proc) to a value which is the top left of the
  1173. // output rectangle of the EMF in device coordinates (i.e. LPtoDP of
  1174. // the logical coordinate top left).
  1175. BrushOrg.x = dest->left;
  1176. BrushOrg.y = dest->top;
  1177. LPtoDP(hdc, &BrushOrg, 1);
  1178. // EnumEnhMetafile selects in the DEFAULT_PALETTE, but we may need
  1179. // another palette to remain selected in (for halftoning, etc.)
  1180. // so save the current palette and select it back in when the
  1181. // header record is received.
  1182. HPALETTE hpal = (HPALETTE)GetCurrentObject(hdc, OBJ_PAL);
  1183. if (hpal != (HPALETTE)GetStockObject(DEFAULT_PALETTE))
  1184. {
  1185. Palette = hpal;
  1186. }
  1187. BkColor = ::GetBkColor(hdc);
  1188. TextColor = ::GetTextColor(hdc);
  1189. }
  1190. }
  1191. VOID
  1192. EmfEnumState::Header(
  1193. )
  1194. {
  1195. ::SetBrushOrgEx(Hdc, BrushOrg.x, BrushOrg.y, NULL);
  1196. if (ClipRgn != (HRGN)0)
  1197. {
  1198. ::SelectClipRgn(Hdc, ClipRgn);
  1199. ::DeleteObject(ClipRgn);
  1200. ClipRgn = NULL;
  1201. }
  1202. if (Palette != NULL)
  1203. {
  1204. ::SelectPalette(Hdc, Palette, TRUE);
  1205. }
  1206. // Bitmap fonts are not good for playing metafiles because they
  1207. // don't scale well, so use a true type font instead as the default font.
  1208. HFONT hFont = CreateTrueTypeFont((HFONT)GetCurrentObject(Hdc, OBJ_FONT));
  1209. if (hFont != NULL)
  1210. {
  1211. DefaultFont = hFont;
  1212. ::SelectObject(Hdc, hFont);
  1213. }
  1214. this->PlayRecord();
  1215. }
  1216. VOID
  1217. EmfEnumState::SelectPalette(INT objectIndex)
  1218. {
  1219. if (objectIndex == (ENHMETA_STOCK_OBJECT | DEFAULT_PALETTE))
  1220. {
  1221. CurrentPalette = (HPALETTE)::GetStockObject(DEFAULT_PALETTE);
  1222. }
  1223. else
  1224. {
  1225. MfEnumState::SelectPalette(objectIndex);
  1226. }
  1227. }
  1228. VOID
  1229. EmfEnumState::IntersectDestRect()
  1230. {
  1231. if (!IsMetafile())
  1232. {
  1233. // Make the transform the identity
  1234. POINT windowOrg;
  1235. SIZE windowExt;
  1236. POINT viewportOrg;
  1237. SIZE viewportExt;
  1238. ::SetViewportOrgEx(Hdc, 0, 0, &viewportOrg);
  1239. ::SetViewportExtEx(Hdc, 1, 1, &viewportExt);
  1240. ::SetWindowOrgEx(Hdc, 0, 0, &windowOrg);
  1241. ::SetWindowExtEx(Hdc, 1, 1, &windowExt);
  1242. // We are always in device units
  1243. ::IntersectClipRect(Hdc, DestRectDevice.left, DestRectDevice.top,
  1244. DestRectDevice.right, DestRectDevice.bottom);
  1245. // Restore the transform
  1246. ::SetViewportOrgEx(Hdc, viewportOrg.x, viewportOrg.y, NULL);
  1247. ::SetViewportExtEx(Hdc, viewportExt.cx, viewportExt.cy, NULL);
  1248. ::SetWindowOrgEx(Hdc, windowOrg.x, windowOrg.y, NULL);
  1249. ::SetWindowExtEx(Hdc, windowExt.cx, windowExt.cy, NULL);
  1250. }
  1251. }
  1252. VOID EmfEnumState::SetROP2()
  1253. {
  1254. DWORD dwROP = ((const EMRSETROP2 *)GetPartialRecord())->iMode;
  1255. if (dwROP != R2_BLACK &&
  1256. dwROP != R2_COPYPEN &&
  1257. dwROP != R2_NOTCOPYPEN &&
  1258. dwROP != R2_WHITE )
  1259. {
  1260. RopUsed = TRUE;
  1261. }
  1262. this->PlayRecord();
  1263. }
  1264. VOID EmfEnumState::ExtTextOutW()
  1265. {
  1266. if (!this->PlayRecord())
  1267. {
  1268. BYTE* emrTextOut = (BYTE*) GetPartialRecord();
  1269. if(CreateCopyOfCurrentRecord())
  1270. {
  1271. // !!! Shouldn't this use the offset in the record?
  1272. BYTE * ptr = emrTextOut + sizeof(EMREXTTEXTOUTW);
  1273. AnsiStrFromUnicode ansistr((WCHAR*)ptr);
  1274. INT len = strlen(ansistr);
  1275. // Don't forget to copy the NULL byte
  1276. GpMemcpy((BYTE*)ModifiedEmfRecord + sizeof(EMREXTTEXTOUTW), (char*)ansistr, len+1);
  1277. EMREXTTEXTOUTA *record = (EMREXTTEXTOUTA*) ModifiedEmfRecord;
  1278. record->emr.iType = EmfRecordTypeExtTextOutA;
  1279. // Keep the size of the record intact because of the spacing vector
  1280. this->PlayRecord();
  1281. }
  1282. }
  1283. }
  1284. VOID EmfEnumState::Rectangle()
  1285. {
  1286. // On NT convert the rectangle call to a polygon call because rectangle
  1287. // seem to have a special case that can draw outside of the metafile
  1288. // bounds. GDI seems to Ceil the coordinates instead of rounding them for
  1289. // rectangles.
  1290. if (!Globals::IsNt || IsMetafile())
  1291. {
  1292. this->PlayRecord();
  1293. return;
  1294. }
  1295. const EMRRECTANGLE *emrRect = (const EMRRECTANGLE*) GetPartialRecord();
  1296. POINT points[4] = {emrRect->rclBox.left, emrRect->rclBox.top,
  1297. emrRect->rclBox.right, emrRect->rclBox.top,
  1298. emrRect->rclBox.right, emrRect->rclBox.bottom,
  1299. emrRect->rclBox.left, emrRect->rclBox.bottom};
  1300. ::Polygon(Hdc, points, 4);
  1301. return;
  1302. }
  1303. BOOL
  1304. EmfEnumState::ProcessRecord(
  1305. EmfPlusRecordType recordType,
  1306. UINT recordDataSize,
  1307. const BYTE * recordData
  1308. )
  1309. {
  1310. BOOL forceCallback = FALSE;
  1311. // See if we're doing enumeration for an external app
  1312. if (ExternalEnumeration)
  1313. {
  1314. if (recordData == NULL)
  1315. {
  1316. recordDataSize = 0;
  1317. }
  1318. else if (recordDataSize == 0)
  1319. {
  1320. recordData = NULL;
  1321. }
  1322. // See if the app changed the record at all.
  1323. if ((recordType != RecordType) ||
  1324. (recordDataSize != RecordDataSize) ||
  1325. ((recordDataSize > 0) &&
  1326. ((CurrentEmfRecord == NULL) ||
  1327. (recordData != (const BYTE *)(const BYTE *)CurrentEmfRecord->dParm))))
  1328. {
  1329. // Yes, we need to override what happened in StartRecord
  1330. CurrentEmfRecord = NULL;
  1331. RecordType = recordType;
  1332. RecordData = recordData;
  1333. RecordDataSize = recordDataSize;
  1334. }
  1335. }
  1336. GDIP_TRY
  1337. switch (recordType)
  1338. {
  1339. case EmfRecordTypeHeader:
  1340. this->Header();
  1341. break;
  1342. #if 0
  1343. // Do we really need to do anything for PolyPolygon records?
  1344. // If so, why not for PolyPolyline too?
  1345. case EmfRecordTypePolyPolygon:
  1346. this->PolyPolygon();
  1347. break;
  1348. case EmfRecordTypePolyPolygon16:
  1349. this->PolyPolygon16();
  1350. break;
  1351. #endif
  1352. case EmfRecordTypeExtEscape:
  1353. this->ExtEscape();
  1354. break;
  1355. case EmfRecordTypeSetPixelV:
  1356. this->SetPixelV();
  1357. break;
  1358. case EmfRecordTypeSetTextColor:
  1359. this->SetTextColor();
  1360. break;
  1361. case EmfRecordTypeSetBkColor:
  1362. this->SetBkColor();
  1363. break;
  1364. case EmfRecordTypeSetMetaRgn:
  1365. // Office Bug 154881. Win9x doesn't handle MetaRgn correctly.
  1366. if (Globals::IsNt)
  1367. {
  1368. this->PlayRecord();
  1369. }
  1370. break;
  1371. case EmfRecordTypeSaveDC:
  1372. this->SaveHdc();
  1373. break;
  1374. case EmfRecordTypeRestoreDC:
  1375. this->RestoreHdc();
  1376. break;
  1377. case EmfRecordTypeCreatePen:
  1378. this->CreatePen();
  1379. break;
  1380. case EmfRecordTypeCreateBrushIndirect:
  1381. this->CreateBrushIndirect();
  1382. break;
  1383. case EmfRecordTypeSelectPalette:
  1384. // We don't select in any palettes when playing the metafile,
  1385. // because we don't want to invalidate our halftoning palette.
  1386. // Keep track of the palette so we can map from PALETTEINDEXes
  1387. // to RGB values.
  1388. this->SelectPalette(((UINT32 *)recordData)[0]);
  1389. break;
  1390. case EmfRecordTypeRealizePalette:
  1391. // We don't want to invalidate our halftoning palette by realizing one
  1392. // from a metafile.
  1393. break;
  1394. case EmfRecordTypeExtFloodFill:
  1395. this->ExtFloodFill();
  1396. break;
  1397. case EmfRecordTypeGdiComment:
  1398. this->GdiComment();
  1399. break;
  1400. case EmfRecordTypeBitBlt:
  1401. this->BitBlt();
  1402. forceCallback = TRUE;
  1403. break;
  1404. case EmfRecordTypeStretchBlt:
  1405. this->StretchBlt();
  1406. forceCallback = TRUE;
  1407. break;
  1408. case EmfRecordTypeMaskBlt:
  1409. this->MaskBlt();
  1410. forceCallback = TRUE;
  1411. break;
  1412. case EmfRecordTypePlgBlt:
  1413. this->PlgBlt();
  1414. forceCallback = TRUE;
  1415. break;
  1416. case EmfRecordTypeSetDIBitsToDevice:
  1417. this->SetDIBitsToDevice();
  1418. forceCallback = TRUE;
  1419. break;
  1420. case EmfRecordTypeStretchDIBits:
  1421. this->StretchDIBits();
  1422. forceCallback = TRUE;
  1423. break;
  1424. // case EMR_CREATEMONOBRUSH:
  1425. // A monochrome brush uses the text color and the background color,
  1426. // so we shouldn't need to make any changes to the brush itself.
  1427. case EmfRecordTypeCreateDIBPatternBrushPt:
  1428. this->CreateDibPatternBrushPt();
  1429. break;
  1430. case EmfRecordTypeExtCreatePen:
  1431. this->ExtCreatePen();
  1432. break;
  1433. case EmfRecordTypeSetICMMode:
  1434. case EmfRecordTypeCreateColorSpace:
  1435. case EmfRecordTypeSetColorSpace:
  1436. case EmfRecordTypeDeleteColorSpace:
  1437. case EmfRecordTypeSetICMProfileA:
  1438. case EmfRecordTypeSetICMProfileW:
  1439. case EmfRecordTypeCreateColorSpaceW:
  1440. if (Globals::IsNt ||
  1441. (!this->IsScreen() && !this->IsBitmap()))
  1442. {
  1443. this->PlayRecord();
  1444. }
  1445. // else skip the record
  1446. break;
  1447. case EmfRecordTypeAlphaBlend:
  1448. this->AlphaBlend();
  1449. forceCallback = TRUE;
  1450. break;
  1451. case EmfRecordTypeTransparentBlt:
  1452. this->TransparentBlt();
  1453. forceCallback = TRUE;
  1454. break;
  1455. case EmfRecordTypeGradientFill:
  1456. this->GradientFill();
  1457. forceCallback = TRUE;
  1458. break;
  1459. case EmfRecordTypeExtCreateFontIndirect:
  1460. this->ExtCreateFontIndirect();
  1461. break;
  1462. case EmfRecordTypeSelectObject:
  1463. this->SelectObject();
  1464. break;
  1465. case EmfRecordTypeSelectClipPath:
  1466. case EmfRecordTypeExtSelectClipRgn:
  1467. case EmfRecordTypeOffsetClipRgn:
  1468. this->PlayRecord();
  1469. if (!Globals::IsNt)
  1470. {
  1471. this->IntersectDestRect();
  1472. }
  1473. break;
  1474. case EmfRecordTypeSetROP2:
  1475. this->SetROP2();
  1476. break;
  1477. case EmfRecordTypeFillRgn:
  1478. case EmfRecordTypeFrameRgn:
  1479. case EmfRecordTypeInvertRgn:
  1480. case EmfRecordTypePaintRgn:
  1481. this->ResetRecordBounds();
  1482. this->PlayRecord();
  1483. break;
  1484. case EmfRecordTypeExtTextOutW:
  1485. this->ExtTextOutW();
  1486. break;
  1487. case EmfRecordTypeRectangle:
  1488. this->Rectangle();
  1489. break;
  1490. case EmfRecordTypeSetMapMode:
  1491. case EmfRecordTypeSetViewportExtEx:
  1492. case EmfRecordTypeSetViewportOrgEx:
  1493. case EmfRecordTypeSetWindowExtEx:
  1494. case EmfRecordTypeSetWindowOrgEx:
  1495. case EmfRecordTypePolyBezier:
  1496. case EmfRecordTypePolygon:
  1497. case EmfRecordTypePolyline:
  1498. case EmfRecordTypePolyBezierTo:
  1499. case EmfRecordTypePolyLineTo:
  1500. case EmfRecordTypePolyPolyline:
  1501. case EmfRecordTypePolyPolygon:
  1502. case EmfRecordTypeSetBrushOrgEx:
  1503. case EmfRecordTypeEOF:
  1504. case EmfRecordTypeSetMapperFlags:
  1505. case EmfRecordTypeSetBkMode:
  1506. case EmfRecordTypeSetPolyFillMode:
  1507. case EmfRecordTypeSetStretchBltMode:
  1508. case EmfRecordTypeSetTextAlign:
  1509. case EmfRecordTypeSetColorAdjustment:
  1510. case EmfRecordTypeMoveToEx:
  1511. case EmfRecordTypeExcludeClipRect:
  1512. case EmfRecordTypeIntersectClipRect:
  1513. case EmfRecordTypeScaleViewportExtEx:
  1514. case EmfRecordTypeScaleWindowExtEx:
  1515. case EmfRecordTypeSetWorldTransform:
  1516. case EmfRecordTypeModifyWorldTransform:
  1517. case EmfRecordTypeDeleteObject:
  1518. case EmfRecordTypeAngleArc:
  1519. case EmfRecordTypeEllipse:
  1520. case EmfRecordTypeRoundRect:
  1521. case EmfRecordTypeArc:
  1522. case EmfRecordTypeChord:
  1523. case EmfRecordTypePie:
  1524. case EmfRecordTypeCreatePalette:
  1525. case EmfRecordTypeSetPaletteEntries:
  1526. case EmfRecordTypeResizePalette:
  1527. case EmfRecordTypeLineTo:
  1528. case EmfRecordTypeArcTo:
  1529. case EmfRecordTypePolyDraw:
  1530. case EmfRecordTypeSetArcDirection:
  1531. case EmfRecordTypeSetMiterLimit:
  1532. case EmfRecordTypeBeginPath:
  1533. case EmfRecordTypeEndPath:
  1534. case EmfRecordTypeCloseFigure:
  1535. case EmfRecordTypeFillPath:
  1536. case EmfRecordTypeStrokeAndFillPath:
  1537. case EmfRecordTypeStrokePath:
  1538. case EmfRecordTypeFlattenPath:
  1539. case EmfRecordTypeWidenPath:
  1540. case EmfRecordTypeAbortPath:
  1541. case EmfRecordTypeReserved_069:
  1542. case EmfRecordTypeExtTextOutA:
  1543. case EmfRecordTypePolyBezier16:
  1544. case EmfRecordTypePolygon16:
  1545. case EmfRecordTypePolyline16:
  1546. case EmfRecordTypePolyBezierTo16:
  1547. case EmfRecordTypePolylineTo16:
  1548. case EmfRecordTypePolyPolyline16:
  1549. case EmfRecordTypePolyPolygon16:
  1550. case EmfRecordTypePolyDraw16:
  1551. case EmfRecordTypeCreateMonoBrush:
  1552. case EmfRecordTypePolyTextOutA:
  1553. case EmfRecordTypePolyTextOutW:
  1554. case EmfRecordTypeGLSRecord:
  1555. case EmfRecordTypeGLSBoundedRecord:
  1556. case EmfRecordTypePixelFormat:
  1557. case EmfRecordTypeDrawEscape:
  1558. case EmfRecordTypeStartDoc:
  1559. case EmfRecordTypeSmallTextOut:
  1560. case EmfRecordTypeForceUFIMapping:
  1561. case EmfRecordTypeNamedEscape:
  1562. case EmfRecordTypeColorCorrectPalette:
  1563. case EmfRecordTypeSetLayout:
  1564. case EmfRecordTypeReserved_117:
  1565. case EmfRecordTypeSetLinkedUFIs:
  1566. case EmfRecordTypeSetTextJustification:
  1567. case EmfRecordTypeColorMatchToTargetW:
  1568. // Play the current record.
  1569. // Even if it fails, we keep playing the rest of the metafile.
  1570. this->PlayRecord();
  1571. break;
  1572. default:
  1573. // unknown record -- ignore it
  1574. WARNING1("Unknown EMF Record");
  1575. break;
  1576. }
  1577. GDIP_CATCH
  1578. forceCallback = TRUE;
  1579. GDIP_ENDCATCH
  1580. return forceCallback;
  1581. }
  1582. VOID EmfEnumState::ResetRecordBounds()
  1583. {
  1584. if (Globals::IsNt && IsMetafile())
  1585. {
  1586. if (ModifiedEmfRecord == NULL)
  1587. {
  1588. CreateCopyOfCurrentRecord();
  1589. }
  1590. // In case the previous call failed
  1591. if (ModifiedEmfRecord != NULL)
  1592. {
  1593. RECTL rect = {INT_MIN, INT_MIN, INT_MAX, INT_MAX};
  1594. EMRRCLBOUNDS *record = (EMRRCLBOUNDS*) ModifiedEmfRecord;
  1595. record->rclBounds = rect;
  1596. }
  1597. }
  1598. }