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.

2480 lines
68 KiB

  1. /*++
  2. Copyright (c) 1990-2003 Microsoft Corporation
  3. Module Name:
  4. polygon.c
  5. Abstract:
  6. This module contains path forming code utilized by the rest of the
  7. driver. Path primitive functions (such as DrvStrokePath, DrvTextOut)
  8. use this code to generate and fill and stroke paths.
  9. Since this code is aware of all the combinations of complex paths and
  10. complex clipping regions and how to deal with them.
  11. Development History:
  12. 15:30 on Wed 09 Mar 1993
  13. Created it
  14. 15-Nov-1993 Mon 19:42:05 updated
  15. clean up / fixed / add debugging information
  16. 27-Jan-1994 Thu 23:40:57 updated
  17. Add user defined pattern caching
  18. 16-Mar-1994 Wed 11:21:02 updated
  19. Add SetBrushOrigin() so we can align brush origins for filling
  20. correctly
  21. Environment:
  22. GDI Device Driver - Plotter.
  23. --*/
  24. #include "precomp.h"
  25. #pragma hdrstop
  26. //
  27. // General debug flags for module, see dbgread.txt for overview.
  28. //
  29. #define DBG_PLOTFILENAME DbgPolygon
  30. #define DBG_GENPOLYGON 0x00000001
  31. #define DBG_GENPOLYPATH 0x00000002
  32. #define DBG_BEZIER 0x00000004
  33. #define DBG_DORECT 0x00000008
  34. #define DBG_FILL_CLIP 0x00000010
  35. #define DBG_CHECK_FOR_WHITE 0x00000020
  36. #define DBG_USERPAT 0x00000040
  37. #define DBG_FILL_LOGIC 0x00000080
  38. #define DBG_HANDLELINEATTR 0x00000100
  39. DEFINE_DBGVAR(0);
  40. //
  41. // Derive new rect by offsetting the source rect
  42. //
  43. #define POLY_GEN_RECTFIX(dest, src, offset) { dest.x = src->x + offset.x; \
  44. dest.y = src->y + offset.y; }
  45. //
  46. // Build table with HPGL2 commands for cursor movement, and path construction.
  47. //
  48. static BYTE __ER[] = { 'E', 'R' };
  49. static BYTE __RR[] = { 'R', 'R' };
  50. static BYTE __EP[] = { 'E', 'P' };
  51. static BYTE __FP[] = { 'F', 'P' };
  52. static BYTE __PM0[] = { 'P', 'M', '0' };
  53. static BYTE __PM1[] = { 'P', 'M', '1' };
  54. static BYTE __PM2[] = { 'P', 'M', '2' };
  55. static BYTE __TR0[] = { 'T', 'R', '0' };
  56. static BYTE __TR1[] = { 'T', 'R', '1' };
  57. static BYTE __SEMI[] = { ';' };
  58. static BYTE __1SEMI[] = { '1', ';' };
  59. static BYTE __BR[] = { 'B', 'R' };
  60. static BYTE __BZ[] = { 'B', 'Z' };
  61. static BYTE __PE[] = { 'P', 'E' };
  62. static BYTE __PD[] = { 'P', 'D' };
  63. static BYTE __COMMA[] = { ',' };
  64. //
  65. // Make MACROS for sending out command streams to device
  66. //
  67. #define SEND_ER(pPDev) OutputBytes(pPDev, __ER , sizeof(__ER ) );
  68. #define SEND_RR(pPDev) OutputBytes(pPDev, __RR , sizeof(__RR ) );
  69. #define SEND_EP(pPDev) OutputBytes(pPDev, __EP , sizeof(__EP ) );
  70. #define SEND_FP(pPDev) OutputBytes(pPDev, __FP , sizeof(__FP ) );
  71. #define SEND_PM0(pPDev) OutputBytes(pPDev, __PM0 , sizeof(__PM0 ) );
  72. #define SEND_PM1(pPDev) OutputBytes(pPDev, __PM1 , sizeof(__PM1 ) );
  73. #define SEND_PM2(pPDev) OutputBytes(pPDev, __PM2 , sizeof(__PM2 ) );
  74. #define SEND_TR0(pPDev) OutputBytes(pPDev, __TR0 , sizeof(__TR0 ) );
  75. #define SEND_TR1(pPDev) OutputBytes(pPDev, __TR1 , sizeof(__TR1 ) );
  76. #define SEND_SEMI(pPDev) OutputBytes(pPDev, __SEMI , sizeof(__SEMI ) );
  77. #define SEND_1SEMI(pPDev) OutputBytes(pPDev, __1SEMI , sizeof(__1SEMI) );
  78. #define SEND_BR(pPDev) OutputBytes(pPDev, __BR , sizeof(__BR ) );
  79. #define SEND_BZ(pPDev) OutputBytes(pPDev, __BZ , sizeof(__BZ ) );
  80. #define SEND_PE(pPDev) OutputBytes(pPDev, __PE , sizeof(__PE ) );
  81. #define SEND_PD(pPDev) OutputBytes(pPDev, __PD , sizeof(__PD ) );
  82. #define SEND_COMMA(pPDev) OutputBytes(pPDev, __COMMA , sizeof(__COMMA) );
  83. #define TERM_PE_MODE(pPDev, Mode) \
  84. { \
  85. if (Mode == 'PE') { \
  86. \
  87. SEND_SEMI(pPDev); \
  88. Mode = 0; \
  89. } \
  90. }
  91. #define SWITCH_TO_PE(pPDev, Mode, PenIsDown) \
  92. { \
  93. if (Mode != 'PE') { \
  94. \
  95. SEND_PE(pPDev); \
  96. Mode = 'PE'; \
  97. PenIsDown = TRUE; \
  98. } \
  99. }
  100. #define SWITCH_TO_BR(pPDev, Mode, PenIsDown) \
  101. { \
  102. TERM_PE_MODE(pPDev, Mode) \
  103. \
  104. if (Mode != 'BR') { \
  105. \
  106. if (!PenIsDown) { \
  107. \
  108. SEND_PD(pPDev); \
  109. PenIsDown = TRUE; \
  110. } \
  111. \
  112. SEND_BR(pPDev); \
  113. Mode = 'BR'; \
  114. \
  115. } else { \
  116. \
  117. SEND_COMMA(pPDev); \
  118. } \
  119. }
  120. #define PLOT_IS_WHITE(pdev, ulCol) (ulCol == WHITE_INDEX)
  121. #define TOGGLE_DASH(x) ((x) ? FALSE : TRUE)
  122. #define ROP4_USE_DEST(Rop4) ((Rop4 & 0x5555) != ((Rop4 & 0xAAAA) >> 1))
  123. #define SET_PP_WITH_ROP4(pPDev, Rop4) \
  124. SetPixelPlacement(pPDev, (ROP4_USE_DEST(Rop4)) ? SPP_MODE_EDGE : \
  125. SPP_MODE_CENTER)
  126. VOID
  127. SetBrushOrigin(
  128. PPDEV pPDev,
  129. PPOINTL pptlBrushOrg
  130. )
  131. /*++
  132. Routine Description:
  133. This function sets the brush origin onto the device for the next brush
  134. fill. Brush origins are used in order for paths being filled to line up
  135. correctly. In this way, if many different paths are filled, the patterns
  136. will line up based on the pattern being repeated starting at the correct
  137. origin.
  138. Arguments:
  139. pPDev - Pointer to our PDEV
  140. pptlBrushOrg - Pointer to the brush origin to be set
  141. Return Value:
  142. VOID
  143. Developmet History:
  144. 16-Mar-1994 Wed 10:56:46 created
  145. --*/
  146. {
  147. POINTL ptlAC;
  148. if (pptlBrushOrg) {
  149. ptlAC = *pptlBrushOrg;
  150. } else {
  151. ptlAC.x =
  152. ptlAC.y = 0;
  153. }
  154. //
  155. // Check to see if the origin is different, and if it is output the
  156. // new origin to the device.
  157. //
  158. if ((ptlAC.x != pPDev->ptlAnchorCorner.x) ||
  159. (ptlAC.y != pPDev->ptlAnchorCorner.y)) {
  160. OutputString(pPDev, "AC");
  161. if ((ptlAC.x) || (ptlAC.y)) {
  162. OutputLONGParams(pPDev, (PLONG)&ptlAC, 2, 'd');
  163. }
  164. //
  165. // Save the current setting
  166. //
  167. pPDev->ptlAnchorCorner = ptlAC;
  168. }
  169. }
  170. BOOL
  171. DoRect(
  172. PPDEV pPDev,
  173. RECTL *pRectl,
  174. BRUSHOBJ *pBrushFill,
  175. BRUSHOBJ *pBrushStroke,
  176. POINTL *pptlBrush,
  177. ROP4 rop4,
  178. LINEATTRS *plineattrs,
  179. ULONG ulFlags
  180. )
  181. /*++
  182. Routine Description:
  183. This function will draw and optionally fill a rectangle. It uses seperate
  184. BRUSHOBJ's for the outline and interior of the rectangle. Since the stroke
  185. operation may include data for a styled line (dashes etc.) the LINEATTRS
  186. structure is included as well.
  187. Arguments:
  188. pPDev - Pointer to our PDEV
  189. pRectl - rectangle area to fill
  190. pBrushFill - Brush used to fill the rectangle
  191. pBrushStroke - Brush used to stroke the rectangle
  192. pptlBrush - brush origin
  193. rop4 - rop to be used
  194. plineattrs - Pointer to the line attributes for a styled line
  195. ulFlags - FPOLY_xxxx flags
  196. Return Value:
  197. TRUE if sucessful and false if not
  198. Development History:
  199. 15-Feb-1994 Tue 11:59:52 updated
  200. We will do RR or RA now
  201. 24-Mar-1994 Thu 19:37:05 updated
  202. Do local MovePen and make sure we at least output ONE RASTER PEL
  203. --*/
  204. {
  205. POINTL ptlPlot;
  206. SIZEL szlRect;
  207. if (PLOT_CANCEL_JOB(pPDev)) {
  208. return(FALSE);
  209. }
  210. //
  211. // Check to see if we can short cut some of our work if its a pen plotter
  212. //
  213. if (PlotCheckForWhiteIfPenPlotter(pPDev,
  214. pBrushFill,
  215. pBrushStroke,
  216. rop4,
  217. &ulFlags)) {
  218. return(TRUE);
  219. }
  220. PLOTDBG(DBG_DORECT,
  221. ("DoRect: Passed In RECTL=(%ld, %ld)-(%ld, %ld)=%ld x %ld",
  222. pRectl->left, pRectl->top,
  223. pRectl->right, pRectl->bottom,
  224. pRectl->right - pRectl->left,
  225. pRectl->bottom - pRectl->top));
  226. ptlPlot.x = LTODEVL(pPDev, pRectl->left);
  227. ptlPlot.y = LTODEVL(pPDev, pRectl->top);
  228. szlRect.cx = LTODEVL(pPDev, pRectl->right) - ptlPlot.x;
  229. szlRect.cy = LTODEVL(pPDev, pRectl->bottom) - ptlPlot.y;
  230. //
  231. // No need to fill an empty rectangle.
  232. //
  233. if ((szlRect.cx) && (szlRect.cy)) {
  234. SET_PP_WITH_ROP4(pPDev, rop4);
  235. //
  236. // If the rectangle is not of sufficient size to actually cause any
  237. // bits to appear on the target device, we grow the rectangle
  238. // to the correct amount. This is done because the target device
  239. // may after converting to physical units, decide there is no work to
  240. // do. In this case nothing would show up on the page at all. So we
  241. // opt to have at least a one pixel object show up.
  242. //
  243. if (szlRect.cx < (LONG)pPDev->MinLToDevL) {
  244. PLOTWARN(("DoRect: cxRect=%ld < MIN=%ld, Make it as MIN",
  245. szlRect.cx, (LONG)pPDev->MinLToDevL));
  246. szlRect.cx = (LONG)pPDev->MinLToDevL;
  247. }
  248. if (szlRect.cy < (LONG)pPDev->MinLToDevL) {
  249. PLOTWARN(("DoRect: cyRect=%ld < MIN=%ld, Make it as MIN",
  250. szlRect.cy, (LONG)pPDev->MinLToDevL));
  251. szlRect.cy = (LONG)pPDev->MinLToDevL;
  252. }
  253. //
  254. // Do the MOVE PEN.
  255. //
  256. OutputFormatStr(pPDev, "PE<=#D#D;", ptlPlot.x, ptlPlot.y);
  257. PLOTDBG(DBG_DORECT,
  258. ("DoRect: PLOTUNIT=%ld, MovePen=(%ld, %ld), RR=%ld x %ld",
  259. pPDev->pPlotGPC->PlotXDPI,
  260. ptlPlot.x, ptlPlot.y, szlRect.cx, szlRect.cy));
  261. //
  262. // Since all the parameters are set up correctly, call the core routine
  263. // for filling a rectangle.
  264. //
  265. DoFillLogic(pPDev,
  266. pptlBrush,
  267. pBrushFill,
  268. pBrushStroke,
  269. rop4,
  270. plineattrs,
  271. &szlRect,
  272. ulFlags);
  273. } else {
  274. PLOTDBG(DBG_DORECT, ("DoRect: Pass a NULL Rectl, Do NOTHING"));
  275. }
  276. return(!PLOT_CANCEL_JOB(pPDev));
  277. }
  278. BOOL
  279. DoFillByEnumingClipRects(
  280. PPDEV pPDev,
  281. POINTL *ppointlOffset,
  282. CLIPOBJ *pco,
  283. POINTL *pPointlBrushOrg,
  284. BRUSHOBJ *pBrushFill,
  285. ROP4 Rop4,
  286. LINEATTRS *plineattrs,
  287. ULONG ulFlags
  288. )
  289. /*++
  290. Routine Description:
  291. This function, fills a CLIPOBJ by enurating the CLIPOBJ as seperate
  292. rectangles and filling each of them in turn. This is typically done when
  293. the CLIPOBJ is comprised of so many path objects, that the path cannot
  294. be described in HPGL2 (overfilling the path buffer in the target device).
  295. Arguments:
  296. pPDev - Pointer to our PDEV
  297. ppointlOffset - Extra offset to the output polygon
  298. pClipObj - clip object
  299. pPointlBrushOrg - brush origin for the fill brush.
  300. pBrushFill - Brush used to fill the rectangle
  301. Rop4 - rop to be used
  302. plineattrs - Pointer to the line attributes for a styled line
  303. ulFlags - FPOLY_xxxx flags
  304. Return Value:
  305. BOOL TRUE - Function succeded
  306. FALSE - Function failed.
  307. Development History:
  308. 28-Nov-1993 created
  309. 18-Dec-1993 Sat 10:35:24 updated
  310. use PRECTL rather RECTL *, and use INT rater than int, removed compiler
  311. warning which has unreferenced local variable
  312. 16-Feb-1994 Wed 16:12:53 updated
  313. Re-structure and make it Polyline encoded
  314. 09-Apr-1994 Sat 16:38:16 updated
  315. Fixed the ptlCur++ twice typo which make us Do the RECT crazy.
  316. --*/
  317. {
  318. PRECTL prclCur;
  319. POINTFIX ptsFix[4];
  320. HTENUMRCL EnumRects;
  321. POINTL ptlCur;
  322. DWORD MaxRects;
  323. DWORD cRects;
  324. BOOL bMore;
  325. BOOL NeedSendPM0;
  326. PLOTDBG(DBG_FILL_CLIP,
  327. ("DoFillByEnumingRects: Maximum polygon points = %d",
  328. pPDev->pPlotGPC->MaxPolygonPts));
  329. PLOTASSERT(1, "DoFillByEnumingRects: Minimum must be 5 points [%ld]",
  330. pPDev->pPlotGPC->MaxPolygonPts >= 5,
  331. pPDev->pPlotGPC->MaxPolygonPts);
  332. //
  333. // In this mode we will enter polygon mode and try to batch based on the
  334. // number of points the device can handle in its polygon buffer.
  335. //
  336. bMore = FALSE;
  337. EnumRects.c = 1;
  338. if ((!pco) || (pco->iDComplexity == DC_TRIVIAL)) {
  339. PLOTASSERT(1, "DoFillByEnumingClipRects: Invalid pco TRIVIAL passed (%08lx)",
  340. (pco) && (pco->iDComplexity != DC_TRIVIAL), pco);
  341. return(FALSE);
  342. } else if (pco->iDComplexity == DC_RECT) {
  343. //
  344. // The visible area is one rectangle intersect with the destinaiton
  345. //
  346. PLOTDBG(DBG_FILL_CLIP, ("DoFillByEnumingClipRects: pco=DC_RECT"));
  347. EnumRects.rcl[0] = pco->rclBounds;
  348. } else {
  349. //
  350. // We have complex clipping region to be computed, call engine to start
  351. // enumerate the rectangles and set More = TRUE so we can get the first
  352. // batch of rectangles.
  353. //
  354. PLOTDBG(DBG_FILL_CLIP, ("DoFillByEnumingClipRects: pco=DC_COMPLEX, EnumRects now"));
  355. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  356. bMore = TRUE;
  357. }
  358. //
  359. // Calculate how many rects we can do at a time, based on how large of
  360. // a polygon buffer the target device can hold. Make sure that value
  361. // is at least 1.
  362. //
  363. if (!(MaxRects = (DWORD)pPDev->pPlotGPC->MaxPolygonPts / 7)) {
  364. MaxRects = 1;
  365. }
  366. cRects = MaxRects;
  367. NeedSendPM0 = TRUE;
  368. do {
  369. //
  370. // If the job was cancelled, break out now. This is typically done
  371. // anytime the code enters some looping that may take a while.
  372. //
  373. if (PLOT_CANCEL_JOB(pPDev)) {
  374. return(FALSE);
  375. }
  376. //
  377. // If More is true then we need to get next batch of rectangles
  378. //
  379. if (bMore == TRUE) {
  380. bMore = CLIPOBJ_bEnum(pco, sizeof(EnumRects), (ULONG *)&EnumRects);
  381. if (bMore == DDI_ERROR || !EnumRects.c) {
  382. PLOTWARN(("DoFillByEnumingClipRects: MORE CLIPOBJ_bEnum BUT Count=0"));
  383. }
  384. }
  385. PLOTDBG( DBG_FILL_CLIP,
  386. ("DoFillByEnumingClipRects: Doing batch of %ld clip rects",
  387. EnumRects.c));
  388. //
  389. // prclCur will point to the first enumerated rectangle
  390. //
  391. prclCur = (PRECTL)&EnumRects.rcl[0];
  392. while (bMore != DDI_ERROR && EnumRects.c--) {
  393. ptsFix[3].x = LTOFX(prclCur->left);
  394. ptsFix[3].y = LTOFX(prclCur->top);
  395. MovePen(pPDev, &ptsFix[3], &ptlCur);
  396. if (NeedSendPM0) {
  397. SEND_PM0(pPDev);
  398. NeedSendPM0 = FALSE;
  399. }
  400. ptsFix[0].x = LTOFX(prclCur->right);
  401. ptsFix[0].y = ptsFix[3].y;
  402. ptsFix[1].x = ptsFix[0].x;
  403. ptsFix[1].y = LTOFX(prclCur->bottom);;
  404. ptsFix[2].x = ptsFix[3].x;
  405. ptsFix[2].y = ptsFix[1].y;
  406. SEND_PE(pPDev);
  407. OutputXYParams(pPDev,
  408. (PPOINTL)ptsFix,
  409. (PPOINTL)NULL,
  410. (PPOINTL)&ptlCur,
  411. (UINT)4,
  412. (UINT)1,
  413. 'F');
  414. PLOTDBG(DBG_FILL_CLIP,
  415. ("DoFillByEnumingRects: Rect = (%ld, %ld) - (%ld, %ld)",
  416. FXTOL(ptsFix[3].x), FXTOL( ptsFix[3].y),
  417. FXTOL(ptsFix[1].x), FXTOL( ptsFix[1].y) ));
  418. #if DBG
  419. if ((FXTODEVL(pPdev, ptsFix[1].x - ptsFix[3].x) >= (1016 * 34)) ||
  420. (FXTODEVL(pPdev, ptsFix[1].y - ptsFix[3].y) >= (1016 * 34))) {
  421. PLOTWARN(("DoFillByEnumingClipRect: *** BIG RECT (%ld x %ld) *****",
  422. FXTODEVL( pPDev, ptsFix[1].x - ptsFix[3].x),
  423. FXTODEVL( pPDev, ptsFix[1].y - ptsFix[3].y)));
  424. }
  425. #endif
  426. SEND_SEMI(pPDev);
  427. SEND_PM1(pPDev);
  428. SEND_SEMI(pPDev);
  429. //
  430. // 5 points per RECT polygon, so if we hit the limit then batch
  431. // it out first. we also calling the DoFillLogic when we are at
  432. // the very last enumeration of clipping rectangle.
  433. //
  434. --cRects;
  435. ++prclCur;
  436. if ((!cRects) ||
  437. ((!EnumRects.c) && (!bMore))) {
  438. PLOTDBG(DBG_FILL_CLIP,
  439. ("DoFillByEnumingRects: Hit MaxPolyPts limit"));
  440. //
  441. // We have hit the limit so close the polygon and do the fill
  442. // logic then continue till were done
  443. //
  444. SEND_PM2(pPDev);
  445. SETLINETYPESOLID(pPDev);
  446. DoFillLogic(pPDev,
  447. pPointlBrushOrg,
  448. pBrushFill,
  449. NULL,
  450. Rop4,
  451. plineattrs,
  452. NULL,
  453. ulFlags);
  454. //
  455. // Reset the count of points generated thus far, and set the
  456. // flag to init polygon mode
  457. //
  458. cRects = MaxRects;
  459. NeedSendPM0 = TRUE;
  460. }
  461. }
  462. } while (bMore);
  463. if (cRects != MaxRects) {
  464. PLOTWARN(("DoFillByEnumingRects: Why are we here?? Send Last Batch of =%ld",
  465. MaxRects - cRects));
  466. SEND_PM2(pPDev);
  467. SETLINETYPESOLID(pPDev);
  468. DoFillLogic(pPDev,
  469. pPointlBrushOrg,
  470. pBrushFill,
  471. NULL,
  472. Rop4,
  473. plineattrs,
  474. NULL,
  475. ulFlags);
  476. }
  477. return(!PLOT_CANCEL_JOB(pPDev));
  478. }
  479. BOOL
  480. PlotCheckForWhiteIfPenPlotter(
  481. PPDEV pPDev,
  482. BRUSHOBJ *pBrushFill,
  483. BRUSHOBJ *pBrushStroke,
  484. ROP4 rop4,
  485. PULONG pulFlags
  486. )
  487. /*++
  488. Routine Description:
  489. This function checks to see if we can safely ignore a drawing command
  490. if it will cause only white to get rendered. Although this is legal on
  491. a raster device (white fill over some other previously rendered object),
  492. it doesn't make sense on a pen plotter.
  493. Arguments:
  494. pPDev - Pointer to our PDEV
  495. pBrushFill - Brush used to fill the rectangle
  496. pBrushStroke - Brush used to stroke the rectangle
  497. rop4 - rop to be used
  498. pulFlags - FPOLY_xxxx flags, may be reset.
  499. Return Value:
  500. BOOL TRUE - Bypass future operations
  501. FALSE - Operation needs to be completed
  502. Developmet History:
  503. 28-Nov-1993 created
  504. 15-Jan-1994 Sat 04:57:55 updated
  505. Change GetColor() and make it tab 5
  506. --*/
  507. {
  508. ULONG StrokeColor;
  509. ULONG FillColor;
  510. //
  511. // Initially we do a quick check if were a PEN plotter to get rid of
  512. // either filling or stroking white. If we are a raster device, we
  513. // support filling white, so we cannot ignore the call.
  514. //
  515. if (!IS_RASTER(pPDev)) {
  516. //
  517. // Check to see if filling is enabled and if it is undo the fill flag
  518. // if the fill color is white.
  519. //
  520. if (*pulFlags & FPOLY_FILL ) {
  521. //
  522. // Get the fill color so we can look at it and decide if its a NOOP
  523. // on pen plotters. If it is, undo the FILL flag.
  524. //
  525. GetColor(pPDev, pBrushFill, &FillColor, NULL, rop4);
  526. if (PLOT_IS_WHITE( pPDev, FillColor)) {
  527. *pulFlags &= ~FPOLY_FILL;
  528. }
  529. }
  530. if (*pulFlags & FPOLY_STROKE) {
  531. //
  532. // Get the Stroke color so we can look at it and decide it its a
  533. // NOOP on pen plotters. If it is, undo the STROKE flag.
  534. //
  535. GetColor(pPDev, pBrushStroke, &StrokeColor, NULL, rop4);
  536. if (PLOT_IS_WHITE(pPDev, StrokeColor)) {
  537. *pulFlags &= ~FPOLY_STROKE;
  538. }
  539. }
  540. if (!(*pulFlags & (FPOLY_STROKE | FPOLY_FILL))) {
  541. //
  542. // Nothing left to do so simply return success
  543. //
  544. PLOTDBG(DBG_CHECK_FOR_WHITE,
  545. ("PlotCheckForWhiteIfPen: ALL WHITE detected"));
  546. return(TRUE);
  547. }
  548. PLOTDBG(DBG_CHECK_FOR_WHITE,
  549. ("PlotCheckForWhiteIfPen: Painting required!"));
  550. }
  551. return(FALSE);
  552. }
  553. BOOL
  554. DoPolygon(
  555. PPDEV pPDev,
  556. POINTL *ppointlOffset,
  557. CLIPOBJ *pClipObj,
  558. PATHOBJ *pPathObj,
  559. POINTL *pPointlBrushOrg,
  560. BRUSHOBJ *pBrushFill,
  561. BRUSHOBJ *pBrushStroke,
  562. ROP4 rop4,
  563. LINEATTRS *plineattrs,
  564. ULONG ulFlags
  565. )
  566. /*++
  567. Routine Description:
  568. This function is the core path handling function for the entire driver.
  569. The passed PATHOBJ and CLIPOBJ are looked at, and various logic is
  570. enabled to determine the correct sequence of events to get the target
  571. path filled. Since HPGL2 cannot handle complex clipping, this function
  572. must deal with the issue of having both a COMPLEX CLIPOBJ, and a
  573. COMPLEX PATHOBJ. When this function decides the work it needs to do
  574. is too complex, it fails this call, the NT graphics engine in turn will
  575. break down the work, most likely calling DrvPaint multiple times in
  576. order to get the object drawn.
  577. Arguments:
  578. pPDev - Pointer to our PDEV
  579. ppointlOffset - Extra offset to the output polygon
  580. pClipObj - clip object
  581. pPathObj - The path object to be used
  582. pPointlBrushOrg - brush origin in the brush to be fill or stroke
  583. pBrushFill - brush object to be used in the FILL
  584. pBrushStroke - brush object to be used in the STROKE
  585. rop4 - Rop4 used in the fill
  586. plineattrs - LINEATTRS for style lines stroke
  587. ulFlags - polygon flags for stroke or fill
  588. Return Value:
  589. BOOL TRUE - Function succeded
  590. FALSE - Function failed
  591. Development History:
  592. 28-Nov-1993 created
  593. 28-Jan-1994 Fri 00:58:25 updated
  594. Style, commented, re-structure the loop and reduce code size.
  595. 04-Aug-1994 Thu 20:00:23 updated
  596. bug# 22348 which actually is a raster plotter firmware bug
  597. --*/
  598. {
  599. PRECTL prclClip = NULL;
  600. POINTFIX *pptfx;
  601. POINTFIX ptOffsetFix;
  602. POINTFIX ptStart;
  603. POINTL ptlCur;
  604. PATHDATA pd;
  605. DWORD cptfx;
  606. DWORD cptExtra;
  607. UINT cCurPosSkips;
  608. WORD PolyMode;
  609. BOOL bPathCameFromClip = FALSE;
  610. BOOL bStrokeOnTheFly = FALSE;
  611. BOOL bFirstSubPath;
  612. BOOL bMore;
  613. BOOL bRet;
  614. BOOL PenIsDown;
  615. BYTE NumType;
  616. //
  617. // Check to see if we can short cut some of our work if its a pen plotter
  618. //
  619. if (PlotCheckForWhiteIfPenPlotter(pPDev,
  620. pBrushFill,
  621. pBrushStroke,
  622. rop4,
  623. &ulFlags)) {
  624. return(TRUE);
  625. }
  626. //
  627. // There are a few different scenarios to deal with here when the
  628. // item in question is too complex and we need to fail. They are
  629. // catagorized as follows
  630. //
  631. // 1) The fill mode is unsupported, in which case we fail the call
  632. // and it should come back in in a simpler format (DrvPaint)
  633. //
  634. // 2) We have a CLIPOBJ thats more complicated than a RECT and, a
  635. // PATHOBJ, if we only have a clipobj we can enum it as a path
  636. //
  637. if ((ulFlags & FPOLY_WINDING) &&
  638. (!IS_WINDINGFILL(pPDev))) {
  639. //
  640. // The plotter cannot support WINDING Mode fills, all we can do
  641. // is fail the call and have it come back in a mode we can support
  642. //
  643. PLOTDBG(DBG_GENPOLYGON, ("DoPolygon: Can't do WINDING, return(FALSE)"));
  644. return(FALSE);
  645. }
  646. if (pClipObj != NULL) {
  647. //
  648. // We have a clipobj so decide what to do
  649. //
  650. if (pClipObj->iDComplexity == DC_COMPLEX) {
  651. //
  652. // Since the clipobj is complex we have two choices, either there is
  653. // no PATHOBJ, in which case we will enum the clipobj as a path, or
  654. // if there is a pathobj we must fail the call. HPGL2 doesn't
  655. // support COMPLEX clipping objects.
  656. //
  657. if (pPathObj != NULL) {
  658. //
  659. // We have a complex clip and a path? we cannot handle this so
  660. // fail the call, the NT graphics engine will simplify the
  661. // object by calling into other primitives (like DrvPaint).
  662. //
  663. PLOTDBG(DBG_GENPOLYGON,
  664. ("DoPolygon: pco=COMPLEX, pPath != NULL, can handle, FALSE"));
  665. return(FALSE);
  666. }
  667. //
  668. // We have come this far, so we must have a CLIPOBJ that is complex
  669. // and we will go ahead and enum it as a path.
  670. //
  671. if ((pPathObj = CLIPOBJ_ppoGetPath(pClipObj)) == NULL) {
  672. PLOTERR(("Engine path from clipobj returns NULL"));
  673. return(FALSE);
  674. }
  675. //
  676. // Record the fact that the PATHOBJ is really coming froma CLIPOBJ
  677. //
  678. bPathCameFromClip = TRUE;
  679. } else if (pClipObj->iDComplexity == DC_RECT) {
  680. //
  681. // We have a RECT CLIPOBJ, if we have no PATHOBJ we simply fill
  682. // the clipping rectangle. If we do have a PATHOBJ we need to set
  683. // the HPGL2 clip window before enumerating and filling the PATHOBJ.
  684. //
  685. if (pPathObj != NULL) {
  686. //
  687. // Some plotters have a firmware bug with clipping windows
  688. // when using styled lines that keep the styled lines from
  689. // being rendered, even though they fit inside the CLIPOBJ.
  690. //
  691. // We get around this limitation by failing this call. This in
  692. // turn will cause DoStrokePathByEnumingClipLines() to be used
  693. // instead.
  694. //
  695. if ((IS_RASTER(pPDev)) &&
  696. (ulFlags & FPOLY_STROKE) &&
  697. (plineattrs) &&
  698. ((plineattrs->fl & LA_ALTERNATE) ||
  699. ((plineattrs->cstyle) &&
  700. (plineattrs->pstyle)))) {
  701. PLOTWARN(("DoPolygon: RASTER/Stroke/DC_RECT/PathObj/StyleLine: (Firmware BUG) FAILED and using EnumClipLine()"));
  702. return(FALSE);
  703. }
  704. prclClip = &pClipObj->rclBounds;
  705. } else {
  706. //
  707. // Simply call the fill rect code and return, no more work
  708. // to do in this function.
  709. //
  710. return(DoRect(pPDev,
  711. &pClipObj->rclBounds,
  712. pBrushFill,
  713. pBrushStroke,
  714. pPointlBrushOrg,
  715. rop4,
  716. plineattrs,
  717. ulFlags));
  718. }
  719. } else {
  720. //
  721. // CLIPOBJ is trivial so we simply ignore it and fill using the
  722. // passed PATHOBJ.
  723. //
  724. NULL;
  725. }
  726. } else {
  727. //
  728. // No CLIPOBJ so use the PATHOBJ passed in.
  729. //
  730. NULL;
  731. }
  732. //
  733. // Setup the offset coordinate data, in case were coming from
  734. // DrvTextOut. In this case there is an offset passed in that
  735. // must be applied to each point. This is used when the glyphs we
  736. // are painting, are actually interpreted as paths. In this case,
  737. // the paths are fixed based on the origin of the glyph. We must
  738. // add the current X/Y position in order to render the glyph in the
  739. // correct place on the page.
  740. //
  741. if (ppointlOffset) {
  742. ptOffsetFix.x = LTOFX(ppointlOffset->x);
  743. ptOffsetFix.y = LTOFX(ppointlOffset->y);
  744. } else {
  745. ptOffsetFix.x =
  746. ptOffsetFix.y = 0;
  747. }
  748. //
  749. // First we need to verify that we dont have more points than will fit
  750. // in our polygon buffer for this device. If this is the case we have two
  751. // choices. If the path did not come from a clip obj we fail this call,
  752. // if it did we handle this based on enuming the clipobj as rects and
  753. // filling. If we were also asked to stroke the PATHOBJ, we need to
  754. // enumerate the path yet another time.
  755. //
  756. cptfx = 0;
  757. cptExtra = 1;
  758. PATHOBJ_vEnumStart(pPathObj);
  759. do {
  760. bRet = PATHOBJ_bEnum(pPathObj, &pd);
  761. cptfx += pd.count;
  762. if ( pd.flags & PD_ENDSUBPATH ) {
  763. //
  764. // Count both the ENDSUBPATH and the PM1 as taking space...
  765. //
  766. cptExtra++;
  767. if (!(pd.flags & PD_CLOSEFIGURE)) {
  768. //
  769. // Since we were not asked to close the figure, we will generate
  770. // a move back to our starting point with the pen up, in order
  771. // eliminate problems with HPGL/2 closing the polygon for
  772. // us when we send the PM2
  773. cptExtra++;
  774. }
  775. }
  776. } while ((bRet) && (!PLOT_CANCEL_JOB(pPDev)));
  777. PLOTDBG(DBG_GENPOLYGON,
  778. ("DoPolygon: Total points = %d, Extra %d",
  779. cptfx, cptExtra ));
  780. //
  781. // We will only do this if we have any points to do, first set bRet to
  782. // true in case we were not asked to do anything.
  783. //
  784. bRet = TRUE;
  785. if (cptfx) {
  786. SET_PP_WITH_ROP4(pPDev, rop4);
  787. //
  788. // Now add in the extra points that account for the PM0 and PM1
  789. // since we have some REAL points in the path.
  790. //
  791. cptfx += cptExtra;
  792. if (cptfx > pPDev->pPlotGPC->MaxPolygonPts) {
  793. PLOTWARN(("DoPolygon: Too many polygon points = %ld > PCD=%ld",
  794. cptfx, pPDev->pPlotGPC->MaxPolygonPts));
  795. if (bPathCameFromClip) {
  796. PLOTWARN(("DoPolygon: Using DoFillByEnumingClipRects()"));
  797. //
  798. // The path the engine created for us to enum must be freed.
  799. //
  800. EngDeletePath(pPathObj);
  801. //
  802. // Since the path is to complex to fill with native HPLG2
  803. // path code, we must do it the slower way.
  804. //
  805. return(DoFillByEnumingClipRects(pPDev,
  806. ppointlOffset,
  807. pClipObj,
  808. pPointlBrushOrg,
  809. pBrushFill,
  810. rop4,
  811. plineattrs,
  812. ulFlags));
  813. } else {
  814. //
  815. // If were dealing with a REAL PATHOBJ and there are too many
  816. // points in the polygon, and were being asked to FILL, all
  817. // we can do is fail the call and have the NT graphics engine
  818. // simplify the object.
  819. //
  820. if (ulFlags & FPOLY_FILL) {
  821. PLOTERR(("DoPolygon: Too many POINTS, return FALSE"));
  822. return(FALSE);
  823. } else if (ulFlags & FPOLY_STROKE) {
  824. //
  825. // Since were stroking we can go ahead and do it on the
  826. // fly. Rather than building up a POLYGON object in the
  827. // target device and asking the device to stroke it, we
  828. // simply set up the correct stroke attributes, and request
  829. // each path component to be stroked individually.
  830. //
  831. PLOTDBG(DBG_GENPOLYGON, ("DoPolygon: Is stroking manually"));
  832. //
  833. // At this point were ONLY being asked to stroke so we simply
  834. // setup up the stroke color and set a flag to keep us from
  835. // going into polygon mode.
  836. //
  837. DoSetupOfStrokeAttributes( pPDev,
  838. pPointlBrushOrg,
  839. pBrushStroke,
  840. rop4,
  841. plineattrs );
  842. bStrokeOnTheFly = TRUE;
  843. }
  844. }
  845. }
  846. //
  847. // At this point were sure to actually do some real RENDERING so set
  848. // the clip window in the target device.
  849. //
  850. if (prclClip) {
  851. PLOTDBG(DBG_GENPOLYGON,
  852. ("DoPolygon: Setting Clip Window to: (%ld, %ld)-(%ld, %ld)=%ld x %ld",
  853. prclClip->left, prclClip->top,
  854. prclClip->right, prclClip->bottom,
  855. prclClip->right - prclClip->left,
  856. prclClip->bottom - prclClip->top));
  857. SetClipWindow( pPDev, prclClip);
  858. }
  859. //
  860. // Now setup to enumerate the PATHOBJ and output the points.
  861. //
  862. PATHOBJ_vEnumStart(pPathObj);
  863. PenIsDown = FALSE;
  864. PolyMode = 0;
  865. bFirstSubPath = TRUE;
  866. do {
  867. //
  868. // Check to see if the print job has been cancelled.
  869. //
  870. if (PLOT_CANCEL_JOB(pPDev)) {
  871. bRet = FALSE;
  872. break;
  873. }
  874. bMore = PATHOBJ_bEnum(pPathObj, &pd);
  875. cptfx = pd.count;
  876. pptfx = pd.pptfx;
  877. //
  878. // Check the BEGINSUBPATH or if this is our first time here.
  879. //
  880. if ((pd.flags & PD_BEGINSUBPATH) || (bFirstSubPath)) {
  881. PLOTDBG(DBG_GENPOLYGON, ("DoPolygon: Getting PD_BEGINSUBPATH"));
  882. TERM_PE_MODE(pPDev, PolyMode);
  883. ptStart.x = pptfx->x + ptOffsetFix.x;
  884. ptStart.y = pptfx->y + ptOffsetFix.y;
  885. MovePen(pPDev, &ptStart, &ptlCur);
  886. PenIsDown = FALSE;
  887. pptfx++;
  888. cptfx--;
  889. if ((!bStrokeOnTheFly) && (bFirstSubPath)) {
  890. SEND_PM0(pPDev);
  891. }
  892. bFirstSubPath = FALSE;
  893. }
  894. //
  895. // Now check if we are sending out Beziers.
  896. //
  897. if (pd.flags & PD_BEZIERS) {
  898. PLOTASSERT(1, "DoPolygon: PD_BEZIERS (count % 3) != 0 (%ld)",
  899. (cptfx % 3) == 0, cptfx);
  900. SWITCH_TO_BR(pPDev, PolyMode, PenIsDown);
  901. NumType = 'f';
  902. cCurPosSkips = 3;
  903. } else {
  904. SWITCH_TO_PE(pPDev, PolyMode, PenIsDown);
  905. NumType = 'F';
  906. cCurPosSkips = 1;
  907. }
  908. PLOTDBG(DBG_GENPOLYGON, ("DoPolygon: OutputXYParam(%ld pts=%hs)",
  909. cptfx, (pd.flags & PD_BEZIERS) ? "BEZIER" : "POLYGON"));
  910. OutputXYParams(pPDev,
  911. (PPOINTL)pptfx,
  912. (PPOINTL)&ptOffsetFix,
  913. (PPOINTL)&ptlCur,
  914. (UINT)cptfx,
  915. (UINT)cCurPosSkips,
  916. NumType);
  917. //
  918. // Check to see if we are ending the sub path.
  919. //
  920. if (pd.flags & PD_ENDSUBPATH) {
  921. PLOTDBG(DBG_GENPOLYGON,
  922. ("DoPolygon: Getting PD_ENDSUBPATH %hs",
  923. (pd.flags & PD_CLOSEFIGURE) ? "PD_CLOSEFIGURE" : ""));
  924. //
  925. // If we are not closing the figure then move the pen to the
  926. // starting position so we do not have the plotter automatically
  927. // close the sub-path.
  928. //
  929. if (pd.flags & PD_CLOSEFIGURE) {
  930. PLOTDBG(DBG_GENPOLYGON,
  931. ("DoPolygon: OutputXYParam(1) to ptStart=(%ld, %ld)",
  932. ptStart.x, ptStart.y));
  933. //
  934. // We must not pass the ptOffsetFix, because we already
  935. // added it into the ptStart at BEGSUBPATH.
  936. //
  937. SWITCH_TO_PE(pPDev, PolyMode, PenIsDown);
  938. OutputXYParams(pPDev,
  939. (PPOINTL)&ptStart,
  940. (PPOINTL)NULL,
  941. (PPOINTL)&ptlCur,
  942. (UINT)1,
  943. (UINT)1,
  944. 'F');
  945. }
  946. TERM_PE_MODE(pPDev, PolyMode);
  947. if (!(pd.flags & PD_CLOSEFIGURE)) {
  948. MovePen(pPDev, &ptStart, &ptlCur);
  949. PenIsDown = FALSE;
  950. }
  951. //
  952. // If we are not stroking on the fly, close the subpath.
  953. //
  954. if (!bStrokeOnTheFly) {
  955. SEND_PM1(pPDev);
  956. }
  957. }
  958. } while (bMore);
  959. TERM_PE_MODE(pPDev, PolyMode);
  960. //
  961. // Now end polygon mode.
  962. //
  963. if ((bRet) &&
  964. (!bStrokeOnTheFly) &&
  965. (!PLOT_CANCEL_JOB(pPDev))) {
  966. SEND_PM2(pPDev);
  967. SETLINETYPESOLID(pPDev);
  968. //
  969. // Now fill and/or stroke the current polygon.
  970. //
  971. DoFillLogic(pPDev,
  972. pPointlBrushOrg,
  973. pBrushFill,
  974. pBrushStroke,
  975. rop4,
  976. plineattrs,
  977. NULL,
  978. ulFlags);
  979. }
  980. //
  981. // If we set a clip window, clear it.
  982. //
  983. if (prclClip) {
  984. ClearClipWindow(pPDev);
  985. }
  986. } else {
  987. PLOTDBG(DBG_GENPOLYGON, ("DoPolygon: PATHOBJ_bEnum=NO POINT"));
  988. }
  989. //
  990. // If the path was constructed from a complex clip object we need to
  991. // delete that path now.
  992. //
  993. if (bPathCameFromClip) {
  994. EngDeletePath(pPathObj);
  995. }
  996. return(bRet);
  997. }
  998. VOID
  999. HandleLineAttributes(
  1000. PPDEV pPDev,
  1001. LINEATTRS *plineattrs,
  1002. PLONG pStyleToUse,
  1003. LONG lExtraStyle
  1004. )
  1005. /*++
  1006. Routine Description:
  1007. This function does any setup necessary to correctly handle stroking of
  1008. a path. It does this by looking at the LINEATTRS structure passed in
  1009. and setting up the HPGL2 plotter with the appropriate style info using
  1010. HPGL2 styled line commands.
  1011. Arguments:
  1012. pPDev - Pointer to our PDEV
  1013. plineattrs - LINEATTRS for style lines stroke
  1014. pStyleToUse - The starting style offset to use, if this is NULL then
  1015. we use the starting member in plineatts.
  1016. lExtraStyle - Any extra style to use based on the current run
  1017. Return Value:
  1018. VOID
  1019. Development History:
  1020. 01-Feb-1994 created
  1021. --*/
  1022. {
  1023. LONG lTotLen = 0L;
  1024. INT i;
  1025. LONG lScaleVal;
  1026. INT iCount;
  1027. PFLOAT_LONG pStartStyle;
  1028. FLOAT_LONG aAlternate[2];
  1029. BOOL bSolid = TRUE;
  1030. LONG lStyleState;
  1031. PLONG pArrayToUse;
  1032. PLOTDBG( DBG_HANDLELINEATTR,
  1033. ("HandleLineAttr: plineattrs = %hs",
  1034. (plineattrs) ? "Exists" : "NULL" ));
  1035. if (plineattrs) {
  1036. PLOTASSERT(1,
  1037. "HandleLineAttrs: Getting a LA_GEOMETRIC and cannot handle %u",
  1038. (!(plineattrs->fl & LA_GEOMETRIC)),
  1039. plineattrs->fl);
  1040. //
  1041. // Set up the correct lStyleState to use, the passed one has precedence
  1042. // over the one imbedded in the lineattributes structure.
  1043. //
  1044. if (pStyleToUse) {
  1045. lStyleState = *pStyleToUse;
  1046. } else {
  1047. lStyleState = plineattrs->elStyleState.l;
  1048. }
  1049. if (plineattrs->fl & LA_ALTERNATE) {
  1050. PLOTDBG( DBG_HANDLELINEATTR,
  1051. ("HandleLineAttr: plineattrs has LA_ALTERNATE bit set!"));
  1052. //
  1053. // This is a special case where every other pixel is on...
  1054. //
  1055. pStartStyle = &aAlternate[0];
  1056. iCount = sizeof(aAlternate) / sizeof(aAlternate[0]);
  1057. aAlternate[0].l = 1;
  1058. aAlternate[1].l = 1;
  1059. } else if ((plineattrs->cstyle != 0) &&
  1060. (plineattrs->pstyle != (PFLOAT_LONG)NULL)) {
  1061. //
  1062. // There is a user defined style passed in so set up for it
  1063. //
  1064. iCount = plineattrs->cstyle;
  1065. pStartStyle = plineattrs->pstyle;
  1066. PLOTDBG(DBG_HANDLELINEATTR, ("HandleLineAttr: Count = %ld",
  1067. plineattrs->cstyle));
  1068. } else {
  1069. //
  1070. // This is a SOLID line, so simply set the number of points to 0
  1071. //
  1072. iCount = 0;
  1073. }
  1074. if (iCount) {
  1075. PFLOAT_LONG pCurStyle;
  1076. INT idx;
  1077. LONG lTempValue;
  1078. LONG lValueToEnd;
  1079. BOOL bInDash;
  1080. LONG convArray[MAX_USER_POINTS];
  1081. PLONG pConverted;
  1082. LONG newArray[MAX_USER_POINTS+2];
  1083. PLONG pNewArray;
  1084. LONG lCountOfNewArray = CCHOF(newArray);
  1085. PLOTASSERT(0,
  1086. "HandleLineAttributes: Getting more than 18 points (%ld)",
  1087. (iCount <= MAX_STYLE_ENTRIES) ,
  1088. iCount);
  1089. //
  1090. // Record our current DASH state, the line either starts with
  1091. // a gap or a dash.
  1092. //
  1093. if (plineattrs->fl & LA_STARTGAP) {
  1094. bInDash = FALSE;
  1095. } else {
  1096. bInDash = TRUE;
  1097. }
  1098. //
  1099. // Since we know we can't handle more than 20 points sent to HPGL2
  1100. // we limit it now to 18 in order to compensate for the up-to 2
  1101. // additional points we may add later.
  1102. //
  1103. iCount = min(MAX_STYLE_ENTRIES, iCount);
  1104. //
  1105. // Get our scaling value, so we can convert style units to
  1106. // our units.
  1107. //
  1108. lScaleVal = PLOT_STYLE_STEP(pPDev);
  1109. //
  1110. // Now convert to the new units, and store the result in the
  1111. // new array. Also keep track of the total length of the style
  1112. //
  1113. for (i = 0, pConverted = &convArray[0], lTotLen = 0,
  1114. pCurStyle = pStartStyle;
  1115. i < iCount ;
  1116. i++, pCurStyle++, pConverted++) {
  1117. *pConverted = pCurStyle->l * lScaleVal;
  1118. PLOTDBG( DBG_HANDLELINEATTR,
  1119. ("HandleLineAttr: Orig Array [%ld]= %ld becomes %ld",
  1120. i, pCurStyle->l, *pConverted ));
  1121. lTotLen += *pConverted;
  1122. }
  1123. //
  1124. // Now convert the passed style state and extra info into the
  1125. // real final style state to use, we do this by taking the value of
  1126. // interest which is packed into the HIWORD and LOWORD of
  1127. // lstylestate based on the DDK definition, then we must add on
  1128. // any additional distance (which may have come from enuming
  1129. // a CLIPLINE structure).
  1130. //
  1131. lStyleState = (HIWORD(lStyleState) * PLOT_STYLE_STEP(pPDev) +
  1132. LOWORD(lStyleState) + lExtraStyle) % lTotLen ;
  1133. PLOTDBG(DBG_HANDLELINEATTR,
  1134. ("HandleLineAttributes: Computed Style state = %ld, extra = %ld",
  1135. lStyleState, lExtraStyle));
  1136. //
  1137. // Set up our final pointer to the new array, since we may be done
  1138. // based on the final computed stylestate being 0.
  1139. //
  1140. pNewArray = &newArray[0];
  1141. if (lStyleState != 0) {
  1142. lTempValue = 0;
  1143. //
  1144. // Since lStyleState has a value other than zero we must
  1145. // construct a new style array to pass to HPGL2 that has been
  1146. // rotated in order to take into account the style state.
  1147. // the code below constructs the new array.
  1148. //
  1149. for (i=0, pConverted = &convArray[0];
  1150. i < iCount ;
  1151. i++, pConverted++) {
  1152. //
  1153. // At this point were looking for the entry which partially
  1154. // encompasses the style state derived. Based on this
  1155. // we can create a new array that is a transformation of the
  1156. // original array rotated the correct amount.
  1157. //
  1158. if (lStyleState < lTempValue + *pConverted) {
  1159. //
  1160. // Here is the transition point.
  1161. //
  1162. if (lCountOfNewArray > 0)
  1163. {
  1164. lCountOfNewArray --;
  1165. *pNewArray++ = *pConverted - (lStyleState - lTempValue);
  1166. }
  1167. //
  1168. // Record the value that needs to be appended to the end
  1169. // of the array
  1170. //
  1171. lValueToEnd = lStyleState - lTempValue;
  1172. idx = i;
  1173. idx++;
  1174. pConverted++;
  1175. //
  1176. // Fill up the end
  1177. //
  1178. while (idx++ < iCount && lCountOfNewArray -- > 0) {
  1179. *pNewArray++ = *pConverted++;
  1180. }
  1181. //
  1182. // Now fill up the beginning...
  1183. //
  1184. idx = 0;
  1185. pConverted = &convArray[0];
  1186. //
  1187. // If there was an odd number we can add together
  1188. // the starting and ending one since they have the
  1189. // same state
  1190. //
  1191. if ((iCount % 2) == 1 ) {
  1192. pNewArray--;
  1193. *pNewArray += *pConverted++;
  1194. idx++;
  1195. pNewArray++;
  1196. }
  1197. while (idx++ < i && lCountOfNewArray-- > 0) {
  1198. *pNewArray++ = *pConverted++;
  1199. }
  1200. if (lCountOfNewArray-- > 0)
  1201. {
  1202. *pNewArray++ = lValueToEnd;
  1203. }
  1204. break;
  1205. }
  1206. lTempValue += *pConverted;
  1207. bInDash = TOGGLE_DASH(bInDash);
  1208. }
  1209. pArrayToUse = &newArray[0];
  1210. iCount = (INT)(pNewArray - &newArray[0]);
  1211. } else {
  1212. pArrayToUse = &convArray[0];
  1213. }
  1214. PLOTASSERT(0,
  1215. "HandleLineAttributes: Getting more than 20 points (%ld)",
  1216. (iCount <= MAX_USER_POINTS) ,
  1217. iCount);
  1218. //
  1219. // There is a style pattern so set up for it.
  1220. //
  1221. bSolid = FALSE;
  1222. //
  1223. // Begin the HPGL2 line command to define a custom style type
  1224. //
  1225. OutputString(pPDev, "UL1");
  1226. //
  1227. // If this flag is set, the first segment is a gap NOT a dash so
  1228. // we trick HPGL2 into doing the right thing by having a zero
  1229. // length dash in the begining.
  1230. //
  1231. if (!bInDash) {
  1232. OutputString(pPDev, ",0");
  1233. }
  1234. //
  1235. // Since we output the 0 len dash at the begining if the line
  1236. // starts with a gap, the most additional points we send out
  1237. // is decremented by 1.
  1238. //
  1239. iCount = min((bInDash ? MAX_USER_POINTS : MAX_USER_POINTS - 1) ,
  1240. iCount);
  1241. //
  1242. // Enum through the points in the style array, converting to our
  1243. // Graphics units and send them to the plotter.
  1244. //
  1245. for (i = 0; i < iCount; i++, pArrayToUse++) {
  1246. PLOTDBG(DBG_HANDLELINEATTR,
  1247. ("HandleLineAttr: New Array [%ld]= %ld",
  1248. i, *pArrayToUse));
  1249. OutputFormatStr(pPDev, ",#l", *pArrayToUse);
  1250. }
  1251. //
  1252. // Now output the linetype and specify the total lenght of the
  1253. // pattern.
  1254. //
  1255. OutputFormatStr(pPDev, "LT1,#d,1",
  1256. ((lTotLen * 254) / pPDev->lCurResolution ) / 10 );
  1257. //
  1258. // Update our linetype in the pdev since we ALWAYS send out this
  1259. // line type
  1260. //
  1261. pPDev->LastLineType = PLOT_LT_USERDEFINED;
  1262. }
  1263. }
  1264. //
  1265. // If it was SOLID just send out the SOLID (default command)
  1266. //
  1267. if (bSolid) {
  1268. PLOTDBG(DBG_HANDLELINEATTR, ("HandleLineAttr: Line type is SOLID"));
  1269. //
  1270. // Send out the correct commands to the plotter
  1271. //
  1272. SETLINETYPESOLID(pPDev);
  1273. }
  1274. }
  1275. VOID
  1276. DoFillLogic(
  1277. PPDEV pPDev,
  1278. POINTL *pPointlBrushOrg,
  1279. BRUSHOBJ *pBrushFill,
  1280. BRUSHOBJ *pBrushStroke,
  1281. ROP4 Rop4,
  1282. LINEATTRS *plineattrs,
  1283. SIZEL *pszlRect,
  1284. ULONG ulFlags
  1285. )
  1286. /*++
  1287. Routine Description:
  1288. This routine has the core logic for filling and already established
  1289. polygon, or a passed in segment.
  1290. Arguments:
  1291. pPDev - Pointer to our PDEV
  1292. pptlBrushOrg - Pointer to the brush origin to be set
  1293. pBrushFill - Brush used to fill the rectangle
  1294. pBrushStroke - Brush used to stroke the rectangle
  1295. Rop4 - rop to be used
  1296. plineattrs - Pointer to the line attributes for a styled line
  1297. pszlRect - Pointer to a segment to stroke.
  1298. ulFlags - FPOLY_XXX, stroking and or filling flags.
  1299. Return Value:
  1300. VOID
  1301. Development History:
  1302. 30-Nov-1993 created
  1303. 15-Jan-1994 Sat 05:02:42 updated
  1304. Change GetColor() and tabify
  1305. 18-Jan-1994 Sat 05:02:42 updated
  1306. 16-Feb-1994 Wed 09:34:06 updated
  1307. Update for the rectangle polygon case to use RR/ER commands
  1308. --*/
  1309. {
  1310. INTDECIW PenWidth;
  1311. if (PLOT_CANCEL_JOB(pPDev)) {
  1312. return;
  1313. }
  1314. //
  1315. // Since a polygon must already be defined this code simply
  1316. // looks at the passed data and sends out the appropriate codes to
  1317. // fill/stroke this polygon correctly.
  1318. //
  1319. PenWidth.Integer =
  1320. PenWidth.Decimal = 0;
  1321. if (ulFlags & FPOLY_FILL) {
  1322. DEVBRUSH *pDevFill;
  1323. DWORD FillForeColor;
  1324. LONG HSType;
  1325. LONG HSParam;
  1326. BOOL bSetTransparent = FALSE;
  1327. //
  1328. // If we are filling, get the current color taking the ROP into
  1329. // acount.
  1330. //
  1331. if (!GetColor(pPDev, pBrushFill, &FillForeColor, &pDevFill, Rop4)) {
  1332. PLOTERR(("DoFillLogic: GetColor()=FALSE"));
  1333. return;
  1334. }
  1335. HSType = -1;
  1336. HSParam = (LONG)((pDevFill) ? pDevFill->LineSpacing : 0);
  1337. //
  1338. // If the plotter cannot support tranparent mode there is no need
  1339. // to wory about backgrounds. we will only ever care about foreground.
  1340. //
  1341. if (((IS_TRANSPARENT(pPDev)) || (!IS_RASTER(pPDev))) &&
  1342. (pDevFill)) {
  1343. //
  1344. // Determine if we are using a Pre-defined pattern to fill with.
  1345. //
  1346. switch(pDevFill->PatIndex) {
  1347. case HS_HORIZONTAL:
  1348. case HS_VERTICAL:
  1349. case HS_BDIAGONAL:
  1350. case HS_FDIAGONAL:
  1351. case HS_CROSS:
  1352. case HS_DIAGCROSS:
  1353. PenWidth.Integer = PW_HATCH_INT;
  1354. PenWidth.Decimal = PW_HATCH_DECI;
  1355. bSetTransparent = (BOOL)IS_TRANSPARENT(pPDev);
  1356. if ((Rop4 & 0xFF00) != 0xAA00) {
  1357. if (IS_RASTER(pPDev)) {
  1358. //
  1359. // Send out the Background Rop.
  1360. //
  1361. SetRopMode(pPDev, ROP4_BG_ROP(Rop4));
  1362. PLOTDBG(DBG_FILL_LOGIC,
  1363. ("DoFillLogic: BCK = MC=%02lx", ROP4_BG_ROP(Rop4)));
  1364. }
  1365. //
  1366. // We need to select the background color fill then
  1367. // select the foreground color back... ONLY if it is
  1368. // non white.
  1369. //
  1370. if ((IS_RASTER(pPDev)) ||
  1371. (!PLOT_IS_WHITE(pPDev, pDevFill->ColorBG))) {
  1372. HSType = HS_DDI_MAX;
  1373. }
  1374. }
  1375. break;
  1376. default:
  1377. //
  1378. // If we are a pen plotter and have a user defined pattern.
  1379. // Do a horizontal hatch for background color and a vertical
  1380. // hatch for the foreground color.
  1381. //
  1382. if ((!IS_RASTER(pPDev)) &&
  1383. (pDevFill->PatIndex >= HS_DDI_MAX)) {
  1384. PLOTWARN(("DoFillLogic: PEN+USER PAT, Do HS_FDIAGONAL for BG [%ld]",
  1385. pDevFill->ColorBG));
  1386. HSParam <<= 1;
  1387. if (!PLOT_IS_WHITE(pPDev, pDevFill->ColorBG)) {
  1388. HSType = HS_FDIAGONAL;
  1389. } else {
  1390. PLOTWARN(("DoFillLogic: PEN+USER PAT, Skip WHITE COLOR"));
  1391. }
  1392. }
  1393. break;
  1394. }
  1395. }
  1396. //
  1397. // Check for a valid pre-defined hatch type and send out the commands.
  1398. //
  1399. if (HSType != -1) {
  1400. PLOTDBG(DBG_FILL_LOGIC, ("DoFillLogic: Fill BGColor = %08lx", pDevFill->ColorBG));
  1401. SelectColor(pPDev, pDevFill->ColorBG, PenWidth);
  1402. SetHSFillType(pPDev, (DWORD)HSType, HSParam);
  1403. SetBrushOrigin(pPDev, pPointlBrushOrg);
  1404. if (pszlRect) {
  1405. SEND_RR(pPDev);
  1406. OutputLONGParams(pPDev, (PLONG)pszlRect, 2, 'd');
  1407. pszlRect = NULL;
  1408. } else {
  1409. SEND_FP(pPDev);
  1410. //
  1411. // Fill with the correct winding mode.
  1412. //
  1413. if (ulFlags & FPOLY_WINDING) {
  1414. SEND_1SEMI(pPDev);
  1415. }
  1416. }
  1417. }
  1418. //
  1419. // Send out the foreground ROP.
  1420. //
  1421. if (IS_RASTER(pPDev)) {
  1422. SetRopMode(pPDev, ROP4_FG_ROP(Rop4));
  1423. }
  1424. //
  1425. // Now select the foreground color.
  1426. //
  1427. SelectColor(pPDev, FillForeColor, PenWidth);
  1428. if (bSetTransparent) {
  1429. PLOTDBG(DBG_FILL_LOGIC, ("DoFillLogic: TRANSPARENT MODE"));
  1430. //
  1431. // Set up for transparent.
  1432. //
  1433. SEND_TR1(pPDev);
  1434. }
  1435. if (pDevFill) {
  1436. //
  1437. // If the pattern to fill with is user defined, the convert it
  1438. // to a user defined pattern in HPGL2. A user defined pattern
  1439. // is where the client code passed a bitmap in to GDI that
  1440. // it expects to fill with (with tileing). If its a pen plotter,
  1441. // this won't work, so simulate it with a diagonal fill.
  1442. //
  1443. if (pDevFill->PatIndex >= HS_DDI_MAX) {
  1444. if (IS_RASTER(pPDev)) {
  1445. DownloadUserDefinedPattern(pPDev, pDevFill);
  1446. } else {
  1447. PLOTWARN(("DoFillLogic: PEN+USER PAT, Do HS_BDIAGONAL for FG [%ld]",
  1448. FillForeColor));
  1449. SetHSFillType(pPDev, HS_BDIAGONAL, HSParam);
  1450. }
  1451. } else {
  1452. //
  1453. // The pattern is a predefined one, so convert it to an HPGL2
  1454. // pattern type.
  1455. //
  1456. SetHSFillType(pPDev, pDevFill->PatIndex, pDevFill->LineSpacing);
  1457. }
  1458. //
  1459. // Set the brush origin.
  1460. //
  1461. SetBrushOrigin(pPDev, pPointlBrushOrg);
  1462. } else {
  1463. SetHSFillType(pPDev, HS_DDI_MAX, 0);
  1464. }
  1465. //
  1466. // If we were passed a segment, paint it now.
  1467. //
  1468. if (pszlRect) {
  1469. SEND_RR(pPDev);
  1470. OutputLONGParams(pPDev, (PLONG)pszlRect, 2, 'd');
  1471. pszlRect = NULL;
  1472. } else {
  1473. //
  1474. // Execute the command to paint the existing path using the current
  1475. // parameters.
  1476. //
  1477. SEND_FP(pPDev);
  1478. if (ulFlags & FPOLY_WINDING) {
  1479. SEND_1SEMI(pPDev);
  1480. }
  1481. }
  1482. //
  1483. // If we used tranparent mode put it back
  1484. //
  1485. if (bSetTransparent) {
  1486. SEND_TR0(pPDev);
  1487. }
  1488. }
  1489. if (ulFlags & FPOLY_STROKE) {
  1490. DoSetupOfStrokeAttributes(pPDev,
  1491. pPointlBrushOrg,
  1492. pBrushStroke,
  1493. Rop4,
  1494. plineattrs);
  1495. //
  1496. // give the plotter the command to stroke the polygon outline!
  1497. //
  1498. if (pszlRect) {
  1499. SEND_ER(pPDev);
  1500. OutputLONGParams(pPDev, (PLONG)pszlRect, 2, 'd');
  1501. } else {
  1502. SEND_EP(pPDev);
  1503. }
  1504. }
  1505. }
  1506. VOID
  1507. DoSetupOfStrokeAttributes(
  1508. PPDEV pPDev,
  1509. POINTL *pPointlBrushOrg,
  1510. BRUSHOBJ *pBrushStroke,
  1511. ROP4 Rop4,
  1512. LINEATTRS *plineattrs
  1513. )
  1514. /*++
  1515. Routine Description:
  1516. This routine sets up the plotter in order to correctly handle stroking,
  1517. based on the passed brush and lineattributes structures.
  1518. Arguments:
  1519. pPDev Pointer to our current PDEV with state info about
  1520. driver
  1521. pPointlBrushOrg Brush origin
  1522. pBrushStroke BRUSHOBJ to stroke with (should only be solid color)
  1523. Rop4 The rop to use when stroking
  1524. plineattrs LINEATTRS structure with the specified line styles
  1525. Return Value:
  1526. VOID
  1527. Development History:
  1528. 01-Feb-1994 Tue 05:02:42 created
  1529. --*/
  1530. {
  1531. INTDECIW PenWidth;
  1532. DWORD StrokeColor;
  1533. GetColor(pPDev, pBrushStroke, &StrokeColor, NULL, Rop4);
  1534. PenWidth.Integer =
  1535. PenWidth.Decimal = 0;
  1536. SelectColor(pPDev, StrokeColor, PenWidth);
  1537. //
  1538. // Send out the foreground Rop, if we are RASTER
  1539. //
  1540. if (IS_RASTER(pPDev)) {
  1541. SetRopMode(pPDev, ROP4_FG_ROP(Rop4));
  1542. }
  1543. //
  1544. // Handle the line attributes
  1545. //
  1546. HandleLineAttributes(pPDev, plineattrs, NULL, 0);
  1547. }
  1548. LONG
  1549. DownloadUserDefinedPattern(
  1550. PPDEV pPDev,
  1551. PDEVBRUSH pBrush
  1552. )
  1553. /*++
  1554. Routine Description:
  1555. This function defines a user pattern to the HPGL2 device. This is used
  1556. when a client application passes a bitmap to GDI to use for filling
  1557. polygons.
  1558. Arguments:
  1559. pPDev - Pointer to the PDEV
  1560. pBrush - Pointer to the cached device brush
  1561. Return Value:
  1562. INT to indicate a pattern number downloaed/defined
  1563. Development History:
  1564. 09-Feb-1994 Wed 13:11:01 updated
  1565. Remove 4bpp/1bpp, it always must have pbgr24
  1566. 08-Feb-1994 Tue 01:49:53 updated
  1567. make PalEntry.B = *pbgr++ as first color, since the order we have
  1568. is PALENTRY and first color is B in the structure.
  1569. 27-Jan-1994 Thu 21:20:30 updated
  1570. Add the RF cache codes
  1571. 14-Jan-1994 Fri 15:23:40 updated
  1572. Added assert for compatible device pattern
  1573. Added so it will take device compatible pattern (8x8,16x16,32x32,64x64)
  1574. 13-Jan-1994 Thu 19:04:04 created
  1575. Re-write
  1576. 16-Feb-1994 Wed 11:00:19 updated
  1577. Change return value to return the HSFillType, and fixed the bugs which
  1578. if we found the cached but we do not set the fill type again
  1579. 05-Aug-1994 Fri 18:35:45 updated
  1580. Bug# 22381, we do FindCachedPen() for during the pattern downloading
  1581. and this causing the problem if the pen is not in the cache then we
  1582. will send the PEN DEFINITION at middle of pattern downloading. If this
  1583. happened then downloading sequence is broken. We fixes this by
  1584. 1) Cache the pen indices if we have enough memory
  1585. 2) Run through FindCachePen() for all the RGB colors in the pattern
  1586. 3) Download cached pen indices if we have memory OR run through
  1587. FindCachedPen() again to download the pen indices
  1588. This may still have problem if we have
  1589. 1) No pen indices caching memory
  1590. 2) more color in the pattern then the max pens in the device
  1591. BUT if this happens then we have no choice but to have the wrong output.
  1592. --*/
  1593. {
  1594. LONG HSFillType;
  1595. LONG RFIndex;
  1596. //
  1597. // Firs we must find the RFIndex
  1598. //
  1599. //
  1600. HSFillType = HS_FT_USER_DEFINED;
  1601. if ((RFIndex = FindDBCache(pPDev, pBrush->Uniq)) < 0) {
  1602. LPBYTE pbgr24;
  1603. RFIndex = -RFIndex;
  1604. //
  1605. // We must download new pattern to the plotter now, make it positive
  1606. //
  1607. if (pbgr24 = pBrush->pbgr24) {
  1608. PALENTRY PalEntry;
  1609. LPWORD pwIdx;
  1610. UINT Idx;
  1611. UINT Size;
  1612. Size = (UINT)pBrush->cxbgr24 * (UINT)pBrush->cybgr24;
  1613. PLOTDBG(DBG_USERPAT,
  1614. ("PlotGenUserDefinedPattern: DOWNLOAD %ld x %ld=%ld USER PAT #%ld",
  1615. (LONG)pBrush->cxbgr24, (LONG)pBrush->cybgr24, Size, RFIndex));
  1616. if (!(pwIdx = (LPWORD)LocalAlloc(LPTR, Size * sizeof(WORD)))) {
  1617. //
  1618. // Do not have memory to do it, so forget it
  1619. //
  1620. PLOTWARN(("Download User defined pattern NO Memory so REAL TIME RUN"));
  1621. }
  1622. //
  1623. // We must first get all the pens cached so we have the indices to
  1624. // use, otherwise we will download the pen color when the pen color
  1625. // is defined.
  1626. //
  1627. PalEntry.Flags = 0;
  1628. for (Idx = 0; Idx < Size; Idx++) {
  1629. WORD PenIdx;
  1630. PalEntry.B = *pbgr24++;
  1631. PalEntry.G = *pbgr24++;
  1632. PalEntry.R = *pbgr24++;
  1633. PenIdx = (WORD)FindCachedPen(pPDev, &PalEntry);
  1634. if (pwIdx) {
  1635. pwIdx[Idx] = PenIdx;
  1636. }
  1637. }
  1638. //
  1639. // Now output the download header/size first
  1640. //
  1641. OutputFormatStr(pPDev, "RF#d,#d,#d", RFIndex,
  1642. (LONG)pBrush->cxbgr24, (LONG)pBrush->cybgr24);
  1643. //
  1644. // If we cached the indices, then use them. Otherwise, find the
  1645. // cache again.
  1646. //
  1647. if (pwIdx) {
  1648. for (Idx = 0; Idx < Size; Idx++) {
  1649. OutputFormatStr(pPDev, ",#d", pwIdx[Idx]);
  1650. }
  1651. //
  1652. // Free the indices memory if we have one.
  1653. //
  1654. LocalFree((HLOCAL)pwIdx);
  1655. } else {
  1656. //
  1657. // We do not have cached indices, so run through again.
  1658. //
  1659. pbgr24 = pBrush->pbgr24;
  1660. for (Idx = 0; Idx < Size; Idx++) {
  1661. PalEntry.B = *pbgr24++;
  1662. PalEntry.G = *pbgr24++;
  1663. PalEntry.R = *pbgr24++;
  1664. OutputFormatStr(pPDev, ",#d", FindCachedPen(pPDev, &PalEntry));
  1665. }
  1666. }
  1667. SEND_SEMI(pPDev);
  1668. } else {
  1669. PLOTERR(("PlotGenUserDefinedPattern: NO pbgr24??, set SOLID"));
  1670. HSFillType = HS_DDI_MAX;
  1671. RFIndex = 0;
  1672. }
  1673. } else {
  1674. PLOTDBG(DBG_USERPAT,
  1675. ("PlotGenUserDefinedPattern: We have CACHED RFIndex=%ld",
  1676. RFIndex));
  1677. }
  1678. SetHSFillType(pPDev, (DWORD)HSFillType, RFIndex);
  1679. return(RFIndex);
  1680. }