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.

783 lines
24 KiB

  1. /*****************************************************************************
  2. *
  3. * paths - Entry points for Win32 to Win 16 converter
  4. *
  5. * Date: 7/1/91
  6. * Author: Jeffrey Newman (c-jeffn)
  7. *
  8. * Copyright 1991 Microsoft Corp
  9. *****************************************************************************/
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. #pragma pack(2)
  13. typedef struct PathInfo16
  14. {
  15. WORD RenderMode;
  16. BYTE FillMode;
  17. BYTE BkMode;
  18. LOGPEN16 Pen;
  19. LOGBRUSH16 Brush;
  20. DWORD BkColor;
  21. } PathInfo16;
  22. #pragma pack()
  23. BOOL GdipFlattenGdiPath(PLOCALDC, LPVOID*, INT*);
  24. /****************************************************************************
  25. * GillesK 2001/02/12
  26. * Convert a PolyPolygon call to multiple Polygons calls.
  27. * PolyPolygons cannot be used for Postscript paths. So we need to convert
  28. * them to Polygon calls and wrap a Postscipt BeginPath/EndPath sequence
  29. * around each polygon
  30. ****************************************************************************/
  31. BOOL ConvertPolyPolygonToPolygons(
  32. PLOCALDC pLocalDC,
  33. PPOINTL pptl,
  34. PDWORD pcptl,
  35. DWORD cptl,
  36. DWORD ccptl,
  37. BOOL transform
  38. )
  39. {
  40. PathInfo16 pathInfo16 = { 0, 1, TRANSPARENT,
  41. { PS_NULL, {0,0}, RGB(0, 0, 0)},
  42. {BS_HOLLOW, RGB(0, 0, 0), 0},
  43. RGB(0, 0, 0) } ;
  44. DWORD polyCount;
  45. BOOL b = TRUE; // In case there are 0 polygons
  46. PPOINTL buffer = NULL;
  47. PPOINTS shortBuffer = NULL;
  48. WORD wEscape;
  49. // Convert the points from POINTL to POINTS
  50. buffer = (PPOINTL) LocalAlloc(LMEM_FIXED, cptl * sizeof(POINTL));
  51. if (buffer == NULL)
  52. {
  53. return FALSE;
  54. }
  55. RtlCopyMemory(buffer, pptl, cptl*sizeof(POINTL));
  56. if (transform)
  57. {
  58. b = bXformRWorldToPPage(pLocalDC, buffer, cptl);
  59. if (b == FALSE)
  60. goto exitFreeMem;
  61. }
  62. vCompressPoints(buffer, cptl) ;
  63. shortBuffer = (PPOINTS) buffer;
  64. // For each polygon in the polycount, we do a BeginPath, and EndPath
  65. for (polyCount = 0; polyCount < ccptl; shortBuffer += pcptl[polyCount], polyCount++)
  66. {
  67. // Emit the Postscript escape to End the Path
  68. if(!bEmitWin16Escape(pLocalDC, BEGIN_PATH, 0, NULL, NULL))
  69. goto exitFreeMem;
  70. // Call the Win16 routine to emit the poly to the metafile.
  71. b = bEmitWin16Poly(pLocalDC, (LPPOINTS) shortBuffer, (SHORT) pcptl[polyCount],
  72. META_POLYGON) ;
  73. // Emit the Postscript escape to End the Path
  74. if(!bEmitWin16Escape(pLocalDC, END_PATH, sizeof(pathInfo16), (LPSTR)&pathInfo16, NULL))
  75. goto exitFreeMem;
  76. // If the bEmitWin16Poly has failed, we at least want to end the path
  77. if (!b)
  78. {
  79. goto exitFreeMem;
  80. }
  81. }
  82. exitFreeMem:
  83. if (buffer != NULL)
  84. {
  85. LocalFree((HLOCAL) buffer);
  86. }
  87. return b;
  88. }
  89. BOOL ConvertPathToPSClipPath(PLOCALDC pLocalDC, BOOL psOnly)
  90. {
  91. INT ihW32Br;
  92. LONG lhpn32 = pLocalDC->lhpn32;
  93. LONG lhbr32 = pLocalDC->lhbr32;
  94. WORD wEscape;
  95. if( pLocalDC->iROP == R2_NOTCOPYPEN )
  96. {
  97. ihW32Br = WHITE_BRUSH | ENHMETA_STOCK_OBJECT ;
  98. }
  99. else
  100. {
  101. ihW32Br = BLACK_BRUSH | ENHMETA_STOCK_OBJECT ;
  102. }
  103. // Emit the Postscript escape to ignore the pen change
  104. wEscape = STARTPSIGNORE ;
  105. if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL))
  106. return FALSE ;
  107. if (DoSelectObject(pLocalDC, ihW32Br))
  108. {
  109. // Do it to the helper DC.
  110. DWORD oldRop = SetROP2(pLocalDC->hdcHelper, R2_COPYPEN);
  111. // Emit the Win16 metafile drawing order.
  112. if (!bEmitWin16SetROP2(pLocalDC, LOWORD(R2_COPYPEN)))
  113. return FALSE;
  114. wEscape = ENDPSIGNORE ;
  115. if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL))
  116. return FALSE ;
  117. // If we only want the path in PS then we need to save the previous one
  118. if (psOnly)
  119. {
  120. wEscape = CLIP_SAVE ;
  121. if(!bEmitWin16Escape(pLocalDC, CLIP_TO_PATH, sizeof(wEscape), (LPSTR)&wEscape, NULL))
  122. return FALSE ;
  123. }
  124. if(!DoRenderPath(pLocalDC, EMR_FILLPATH, psOnly)) // We need to fill the path with black
  125. return FALSE;
  126. if(pLocalDC->pbLastSelectClip == pLocalDC->pbRecord || psOnly)
  127. {
  128. wEscape = CLIP_INCLUSIVE;
  129. if(!bEmitWin16Escape(pLocalDC, CLIP_TO_PATH, sizeof(wEscape), (LPSTR)&wEscape, NULL))
  130. return FALSE;
  131. }
  132. // Emit the Postscript escape to ignore the pen change
  133. wEscape = STARTPSIGNORE ;
  134. if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL))
  135. return FALSE ;
  136. if(!DoSelectObject(pLocalDC, lhbr32))
  137. return FALSE;
  138. // Do it to the helper DC.
  139. SetROP2(pLocalDC->hdcHelper, oldRop);
  140. // Emit the Win16 metafile drawing order.
  141. if (!bEmitWin16SetROP2(pLocalDC, LOWORD(oldRop)))
  142. return FALSE;
  143. wEscape = ENDPSIGNORE ;
  144. if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL))
  145. return FALSE ;
  146. }
  147. return TRUE ;
  148. }
  149. /***************************************************************************
  150. * BeginPath - Win32 to Win16 Metafile Converter Entry Point
  151. **************************************************************************/
  152. BOOL WINAPI DoBeginPath
  153. (
  154. PLOCALDC pLocalDC
  155. )
  156. {
  157. BOOL b ;
  158. // Set the global flag telling all all the geometric
  159. // rendering routines that we are accumulating drawing orders
  160. // for the path.
  161. pLocalDC->flags |= RECORDING_PATH ;
  162. // Tell the helper DC we are begining the path accumulation.
  163. b = BeginPath(pLocalDC->hdcHelper) ;
  164. // Save the position of the path if we haven't started the XOR passes
  165. if (pLocalDC->flags & INCLUDE_W32MF_XORPATH)
  166. {
  167. if(pLocalDC->iXORPass == NOTXORPASS)
  168. {
  169. pLocalDC->pbChange = (PBYTE) pLocalDC->pbRecord ;
  170. pLocalDC->lholdp32 = pLocalDC->lhpn32 ;
  171. pLocalDC->lholdbr32 = pLocalDC->lhbr32;
  172. }
  173. }
  174. ASSERTGDI((b == TRUE), "MF3216: DoBeginPath, BeginPath failed\n") ;
  175. return (b) ;
  176. }
  177. /***************************************************************************
  178. * EndPath - Win32 to Win16 Metafile Converter Entry Point
  179. **************************************************************************/
  180. BOOL WINAPI DoEndPath
  181. (
  182. PLOCALDC pLocalDC
  183. )
  184. {
  185. BOOL b ;
  186. // Reset the global flag, turning off the path accumulation.
  187. pLocalDC->flags &= ~RECORDING_PATH ;
  188. b = EndPath(pLocalDC->hdcHelper) ;
  189. ASSERTGDI((b == TRUE), "MF3216: DoEndPath, EndPath failed\n") ;
  190. return (b) ;
  191. }
  192. /***************************************************************************
  193. * WidenPath - Win32 to Win16 Metafile Converter Entry Point
  194. **************************************************************************/
  195. BOOL WINAPI DoWidenPath
  196. (
  197. PLOCALDC pLocalDC
  198. )
  199. {
  200. BOOL b ;
  201. b = WidenPath(pLocalDC->hdcHelper) ;
  202. ASSERTGDI((b == TRUE), "MF3216: DoWidenPath, WidenPath failed\n") ;
  203. return (b) ;
  204. }
  205. /***************************************************************************
  206. * SelectClipPath - Win32 to Win16 Metafile Converter Entry Point
  207. *
  208. * History:
  209. * Tue Apr 07 17:05:37 1992 -by- Hock San Lee [hockl]
  210. * Wrote it.
  211. **************************************************************************/
  212. BOOL WINAPI DoSelectClipPath(PLOCALDC pLocalDC, INT iMode)
  213. {
  214. INT iROP2 ;
  215. BOOL bRet = TRUE;
  216. WORD wEscape;
  217. PathInfo16 pathInfo16 = { 0, 1, 1,
  218. { PS_NULL, {0,0}, 0},
  219. {BS_NULL, 0, 0},
  220. 0 } ;
  221. BOOL bNoClipping = bNoDCRgn(pLocalDC, DCRGN_CLIP);
  222. BOOL bIgnorePS = FALSE;
  223. // Since we cannot do any other operations then an OR with multiple clipping regions
  224. // Only do the XOR if we are with a RGN_OR
  225. if ((iMode == RGN_COPY || iMode == RGN_AND ||
  226. (iMode == RGN_OR && bNoClipping)) &&
  227. (pLocalDC->flags & INCLUDE_W32MF_XORPATH))
  228. {
  229. if (pLocalDC->iXORPass == NOTXORPASS )
  230. {
  231. pLocalDC->iXORPass = DRAWXORPASS ;
  232. pLocalDC->iXORPassDCLevel = pLocalDC->iLevel ;
  233. iROP2 = GetROP2( pLocalDC->hdcHelper ) ;
  234. if( iROP2 == R2_COPYPEN || iROP2 == R2_NOTCOPYPEN )
  235. {
  236. if(!DoSaveDC(pLocalDC))
  237. return FALSE;
  238. pLocalDC->iROP = iROP2;
  239. // Emit the Postscript escape to ignore the XOR
  240. wEscape = STARTPSIGNORE ;
  241. if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL))
  242. return FALSE ;
  243. // Do it to the helper DC.
  244. SetROP2(pLocalDC->hdcHelper, R2_XORPEN);
  245. // Emit the Win16 metafile drawing order.
  246. if (!bEmitWin16SetROP2(pLocalDC, LOWORD(R2_XORPEN)))
  247. return FALSE;
  248. MoveToEx( pLocalDC->hdcHelper, 0, 0, &(pLocalDC->pOldPosition ) ) ;
  249. MoveToEx( pLocalDC->hdcHelper, pLocalDC->pOldPosition.x, pLocalDC->pOldPosition.y, NULL );
  250. // Save this record number. When we pass again the last one will be the one that send the
  251. // Postscript clip path.
  252. pLocalDC->pbLastSelectClip = pLocalDC->pbRecord ;
  253. return bRet ;
  254. }
  255. pLocalDC->flags |= ERR_XORCLIPPATH;
  256. return FALSE;
  257. }
  258. else if(pLocalDC->iXORPass == DRAWXORPASS )
  259. {
  260. // Save this record number. When we pass again the last one will be the one that send the
  261. // Postscript clip path.
  262. pLocalDC->pbLastSelectClip = pLocalDC->pbRecord ;
  263. return TRUE;
  264. }
  265. else if( pLocalDC->iXORPass == ERASEXORPASS )
  266. {
  267. if (!ConvertPathToPSClipPath(pLocalDC, FALSE) ||
  268. !bEmitWin16EmitSrcCopyComment(pLocalDC, msocommentBeginSrcCopy))
  269. {
  270. return FALSE;
  271. }
  272. return TRUE;
  273. }
  274. else
  275. {
  276. ASSERT(FALSE);
  277. }
  278. }
  279. // Convert the clippath to a PS clippath
  280. if (ConvertPathToPSClipPath(pLocalDC, TRUE))
  281. {
  282. bIgnorePS = TRUE;
  283. pLocalDC->iSavePSClipPath++;
  284. // Emit the Postscript escape to ignore the pen change
  285. wEscape = STARTPSIGNORE ;
  286. if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL))
  287. return FALSE ;
  288. }
  289. // If there is no initial clip region and we are going to operate
  290. // on the initial clip region, we have to
  291. // create one. Otherwise, GDI will create some random default
  292. // clipping region for us!
  293. if ((iMode == RGN_DIFF || iMode == RGN_XOR || iMode == RGN_OR)
  294. && bNoClipping)
  295. {
  296. HRGN hrgnDefault;
  297. if (!(hrgnDefault = CreateRectRgn((int) (SHORT) MINSHORT,
  298. (int) (SHORT) MINSHORT,
  299. (int) (SHORT) MAXSHORT,
  300. (int) (SHORT) MAXSHORT)))
  301. {
  302. ASSERTGDI(FALSE, "MF3216: CreateRectRgn failed");
  303. return(FALSE);
  304. }
  305. bRet = (ExtSelectClipRgn(pLocalDC->hdcHelper, hrgnDefault, RGN_COPY)
  306. != ERROR);
  307. ASSERTGDI(bRet, "MF3216: ExtSelectClipRgn failed");
  308. if (!DeleteObject(hrgnDefault))
  309. ASSERTGDI(FALSE, "MF3216: DeleteObject failed");
  310. if (!bRet)
  311. return(FALSE);
  312. }
  313. // Do it to the helper DC.
  314. // When we do this. It clears the path so it has to be
  315. // done when we are not using the path
  316. if(!SelectClipPath(pLocalDC->hdcHelper, iMode))
  317. return(FALSE);
  318. // Dump the clip region data.
  319. bRet = bDumpDCClipping(pLocalDC);
  320. if (bIgnorePS)
  321. {
  322. // Emit the Postscript escape to ignore the pen change
  323. wEscape = ENDPSIGNORE ;
  324. if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL))
  325. return FALSE ;
  326. }
  327. return(bRet);
  328. }
  329. /***************************************************************************
  330. * FlattenPath - Win32 to Win16 Metafile Converter Entry Point
  331. **************************************************************************/
  332. BOOL WINAPI DoFlattenPath
  333. (
  334. PLOCALDC pLocalDC
  335. )
  336. {
  337. BOOL b;
  338. b = FlattenPath(pLocalDC->hdcHelper) ;
  339. ASSERTGDI((b == TRUE), "MF3216: DoFlattenPath, FlattenPath failed\n") ;
  340. return (b) ;
  341. }
  342. /***************************************************************************
  343. * AbortPath - Win32 to Win16 Metafile Converter Entry Point
  344. **************************************************************************/
  345. BOOL WINAPI DoAbortPath
  346. (
  347. PLOCALDC pLocalDC
  348. )
  349. {
  350. BOOL b ;
  351. // Reset the global flag, turning off the path accumulation.
  352. pLocalDC->flags &= ~RECORDING_PATH ;
  353. b = AbortPath(pLocalDC->hdcHelper) ;
  354. // We cannot abort a path if we have a XORPass so return FALSE
  355. if (pLocalDC->flags & INCLUDE_W32MF_XORPATH)
  356. return FALSE ;
  357. ASSERTGDI((b == TRUE), "MF3216: DoAbortPath, AbortPath failed\n") ;
  358. return (b) ;
  359. }
  360. /***************************************************************************
  361. * CloseFigure - Win32 to Win16 Metafile Converter Entry Point
  362. **************************************************************************/
  363. BOOL WINAPI DoCloseFigure
  364. (
  365. PLOCALDC pLocalDC
  366. )
  367. {
  368. BOOL b ;
  369. b = CloseFigure(pLocalDC->hdcHelper) ;
  370. ASSERTGDI((b == TRUE), "MF3216: DoCloseFigure, CloseFigure failed\n") ;
  371. return (b) ;
  372. }
  373. /***************************************************************************
  374. * DoRenderPath - Common code for StrokePath, FillPath and StrokeAndFillPath.
  375. **************************************************************************/
  376. // Macro for copy a point in the path data.
  377. #define MOVE_A_POINT(iDst, pjTypeDst, pptDst, iSrc, pjTypeSrc, pptSrc) \
  378. { \
  379. pjTypeDst[iDst] = pjTypeSrc[iSrc]; \
  380. pptDst[iDst] = pptSrc[iSrc]; \
  381. }
  382. BOOL WINAPI DoRenderPath(PLOCALDC pLocalDC, INT mrType, BOOL psOnly)
  383. {
  384. BOOL b;
  385. PBYTE pb = (PBYTE) NULL;
  386. PBYTE pbNew = (PBYTE) NULL;
  387. LPPOINT ppt, pptNew;
  388. LPBYTE pjType, pjTypeNew;
  389. PDWORD pPolyCount;
  390. INT cpt, cptNew, cPolyCount;
  391. INT i, j, jStart;
  392. LONG lhpn32;
  393. LPVOID pGdipFlatten = NULL;
  394. INT count = 0;
  395. BOOL transform = TRUE;
  396. WORD wEscape;
  397. b = FALSE; // assume failure
  398. ppt = NULL;
  399. pjType = NULL;
  400. // Flatten the path, to convert all the beziers into polylines.
  401. // Try to use GDIPlus and transform the points before hand, if we fail then
  402. // go back and try to do it with GDI
  403. if (GdipFlattenGdiPath(pLocalDC, &pGdipFlatten, &count))
  404. {
  405. ASSERT(pGdipFlatten != NULL);
  406. ppt = (LPPOINT)pGdipFlatten;
  407. pjType = (PBYTE) (ppt + count);
  408. cpt = count;
  409. transform = FALSE;
  410. }
  411. else
  412. {
  413. if (!DoFlattenPath(pLocalDC))
  414. {
  415. RIPS("MF3216: DoRenderPath, FlattenPath failed\n");
  416. goto exit_DoRenderPath;
  417. }
  418. // Get the path data.
  419. // First get a count of the number of points.
  420. cpt = GetPath(pLocalDC->hdcHelper, (LPPOINT) NULL, (LPBYTE) NULL, 0);
  421. if (cpt == -1)
  422. {
  423. RIPS("MF3216: DoRenderPath, GetPath failed\n");
  424. goto exit_DoRenderPath;
  425. }
  426. // Check for empty path.
  427. if (cpt == 0)
  428. {
  429. b = TRUE;
  430. goto exit_DoRenderPath;
  431. }
  432. // Allocate memory for the path data.
  433. if (!(pb = (PBYTE) LocalAlloc
  434. (
  435. LMEM_FIXED,
  436. cpt * (sizeof(POINT) + sizeof(BYTE))
  437. )
  438. )
  439. )
  440. {
  441. RIPS("MF3216: DoRenderPath, LocalAlloc failed\n");
  442. goto exit_DoRenderPath;
  443. }
  444. // Order of assignment is important for dword alignment.
  445. ppt = (LPPOINT) pb;
  446. pjType = (LPBYTE) (ppt + cpt);
  447. // Finally, get the path data.
  448. if (GetPath(pLocalDC->hdcHelper, ppt, pjType, cpt) != cpt)
  449. {
  450. RIPS("MF3216: DoRenderPath, GetPath failed\n");
  451. goto exit_DoRenderPath;
  452. }
  453. }
  454. // The path data is in record-time world coordinates. They are the
  455. // coordinates we will use in the PolyPoly rendering functions below.
  456. //
  457. // Since we have flattened the path, the path data should only contain
  458. // the following types:
  459. //
  460. // PT_MOVETO
  461. // PT_LINETO
  462. // (PT_LINETO | PT_CLOSEFIGURE)
  463. //
  464. // To simplify, we will close the figure explicitly by inserting points
  465. // and removing the (PT_LINETO | PT_CLOSEFIGURE) type from the path data.
  466. // At the same time, we will create the PolyPoly structure to prepare for
  467. // the PolyPolygon or PolyPolyline call.
  468. //
  469. // Note that there cannot be more than one half (PT_LINETO | PT_CLOSEFIGURE)
  470. // points since they are followed by the PT_MOVETO points (except for the
  471. // last point). In addition, the first point must be a PT_MOVETO.
  472. //
  473. // We will also remove the empty figure, i.e. consecutive PT_MOVETO, from
  474. // the new path data in the process.
  475. // First, allocate memory for the new path data.
  476. cptNew = cpt + cpt / 2;
  477. if (!(pbNew = (PBYTE) LocalAlloc
  478. (
  479. LMEM_FIXED,
  480. cptNew * (sizeof(POINT) + sizeof(DWORD) + sizeof(BYTE))
  481. )
  482. )
  483. )
  484. {
  485. RIPS("MF3216: DoRenderPath, LocalAlloc failed\n");
  486. goto exit_DoRenderPath;
  487. }
  488. // Order of assignment is important for dword alignment.
  489. pptNew = (LPPOINT) pbNew;
  490. pPolyCount = (PDWORD) (pptNew + cptNew);
  491. pjTypeNew = (LPBYTE) (pPolyCount + cptNew);
  492. // Close the path explicitly.
  493. i = 0;
  494. j = 0;
  495. cPolyCount = 0; // number of entries in PolyCount array
  496. while (i < cpt)
  497. {
  498. ASSERTGDI(pjType[i] == PT_MOVETO, "MF3216: DoRenderPath, bad pjType[]");
  499. // Copy everything upto the next closefigure or moveto.
  500. jStart = j;
  501. // copy the moveto
  502. MOVE_A_POINT(j, pjTypeNew, pptNew, i, pjType, ppt);
  503. i++; j++;
  504. if (i >= cpt) // stop if the last point is a moveto
  505. {
  506. j--; // don't include the last moveto
  507. break;
  508. }
  509. while (i < cpt)
  510. {
  511. MOVE_A_POINT(j, pjTypeNew, pptNew, i, pjType, ppt);
  512. i++; j++;
  513. // look for closefigure and moveto
  514. if (pjTypeNew[j - 1] != PT_LINETO)
  515. break;
  516. }
  517. if (pjTypeNew[j - 1] == PT_MOVETO)
  518. {
  519. i--; j--; // restart the next figure from moveto
  520. if (j - jStart == 1) // don't include consecutive moveto's
  521. j = jStart; // ignore the first moveto
  522. else
  523. pPolyCount[cPolyCount++] = j - jStart; // add one poly
  524. }
  525. else if (pjTypeNew[j - 1] == PT_LINETO)
  526. { // we have reached the end of path data
  527. pPolyCount[cPolyCount++] = j - jStart; // add one poly
  528. break;
  529. }
  530. else if (pjTypeNew[j - 1] == (PT_LINETO | PT_CLOSEFIGURE))
  531. {
  532. pjTypeNew[j - 1] = PT_LINETO;
  533. // Insert a PT_LINETO to close the figure.
  534. pjTypeNew[j] = PT_LINETO;
  535. pptNew[j] = pptNew[jStart];
  536. j++;
  537. pPolyCount[cPolyCount++] = j - jStart; // add one poly
  538. }
  539. else
  540. {
  541. ASSERTGDI(FALSE, "MF3216: DoRenderPath, unknown pjType[]");
  542. }
  543. } // while
  544. ASSERTGDI(j <= cptNew && cPolyCount <= cptNew,
  545. "MF3216: DoRenderPath, path data overrun");
  546. cptNew = j;
  547. // Check for empty path.
  548. if (cptNew == 0)
  549. {
  550. b = TRUE;
  551. goto exit_DoRenderPath;
  552. }
  553. // Now we have a path data that consists of only PT_MOVETO and PT_LINETO.
  554. // Furthermore, there is no "empty" figure, i.e. consecutive PT_MOVETO, in
  555. // the path. We can finally render the picture with PolyPolyline or
  556. // PolyPolygon.
  557. if (mrType == EMR_STROKEPATH && !psOnly)
  558. {
  559. // Do StrokePath.
  560. b = DoPolyPolyline(pLocalDC, (PPOINTL) pptNew, (PDWORD) pPolyCount,
  561. (DWORD) cPolyCount, transform);
  562. }
  563. else // FILLPATH or PSOnly
  564. {
  565. // Setup our PS clippath
  566. if (pLocalDC->iXORPass == ERASEXORPASS || psOnly)
  567. {
  568. LONG lhpn32 = pLocalDC->lhpn32;
  569. LONG lhbr32 = pLocalDC->lhbr32;
  570. // Do it to the helper DC.
  571. DWORD oldRop = SetROP2(pLocalDC->hdcHelper, R2_NOP);
  572. // Emit the Win16 metafile drawing order.
  573. if (!bEmitWin16SetROP2(pLocalDC, LOWORD(R2_NOP)))
  574. goto exit_DoRenderPath;
  575. b = ConvertPolyPolygonToPolygons(pLocalDC, (PPOINTL) pptNew,
  576. (PDWORD) pPolyCount, (DWORD) cptNew, (DWORD) cPolyCount, transform);
  577. if (!b)
  578. {
  579. ASSERTGDI(FALSE, "GPMF3216: DoRenderPath, PolyPolygon conversion failed");
  580. goto exit_DoRenderPath;
  581. }
  582. // Do it to the helper DC.
  583. SetROP2(pLocalDC->hdcHelper, oldRop);
  584. // Emit the Win16 metafile drawing order.
  585. if (!bEmitWin16SetROP2(pLocalDC, LOWORD(oldRop)))
  586. goto exit_DoRenderPath;
  587. wEscape = STARTPSIGNORE ;
  588. if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL))
  589. goto exit_DoRenderPath;
  590. }
  591. if (!psOnly)
  592. {
  593. // Do FillPath and StrokeAndFillPath.
  594. // If we are doing fill only, we need to select in a NULL pen.
  595. if (mrType == EMR_FILLPATH)
  596. {
  597. lhpn32 = pLocalDC->lhpn32; // remember the previous pen
  598. if (!DoSelectObject(pLocalDC, ENHMETA_STOCK_OBJECT | NULL_PEN))
  599. {
  600. ASSERTGDI(FALSE, "MF3216: DoRenderPath, DoSelectObject failed");
  601. goto exit_DoRenderPath;
  602. }
  603. }
  604. // Do the PolyPolygon.
  605. b = DoPolyPolygon(pLocalDC, (PPOINTL) pptNew, (PDWORD) pPolyCount,
  606. (DWORD) cptNew, (DWORD) cPolyCount, transform);
  607. // Restore the previous pen.
  608. if (mrType == EMR_FILLPATH)
  609. if (!DoSelectObject(pLocalDC, lhpn32))
  610. ASSERTGDI(FALSE, "MF3216: DoRenderPath, DoSelectObject failed");
  611. }
  612. if (pLocalDC->iXORPass == ERASEXORPASS || psOnly)
  613. {
  614. // End the PS ignore sequence
  615. wEscape = ENDPSIGNORE ;
  616. if(!bEmitWin16Escape(pLocalDC, POSTSCRIPT_IGNORE, sizeof(wEscape), (LPSTR)&wEscape, NULL))
  617. goto exit_DoRenderPath;
  618. }
  619. }
  620. exit_DoRenderPath:
  621. // If we are doing a PSOnly path, then don't abort because we are gonna
  622. // use the path as a clipping region later
  623. if (!psOnly)
  624. {
  625. // Clear the path by calling AbortPath
  626. AbortPath(pLocalDC->hdcHelper);
  627. }
  628. if (pbNew)
  629. if (LocalFree((HANDLE) pbNew))
  630. RIPS("MF3216: DoRenderPath, LocalFree failed\n");
  631. if (pb)
  632. if (LocalFree((HANDLE) pb))
  633. RIPS("MF3216: DoRenderPath, LocalFree failed\n");
  634. if (pGdipFlatten)
  635. {
  636. if (LocalFree((HANDLE) pGdipFlatten))
  637. RIPS("MF3216: DoRenderPath, LocalFree failed\n");
  638. }
  639. return(b);
  640. }