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.

2330 lines
74 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: drawgdi.cxx
  3. *
  4. * Contains all the draw APIs for GDI.
  5. *
  6. * Created: 29-Oct-1990
  7. * Author: J. Andrew Goossen [andrewgo]
  8. *
  9. * Copyright (c) 1990-1999 Microsoft Corporation
  10. *
  11. \**************************************************************************/
  12. #include "precomp.hxx"
  13. extern PPEN gpPenNull;
  14. extern PBRUSH gpbrNull;
  15. #include "flhack.hxx"
  16. /******************************Public*Routine******************************\
  17. * LONG lGetQuadrant(eptef)
  18. *
  19. * Returns the quadrant number (0 to 3) of the point.
  20. *
  21. * 22-Aug-1991 -by- J. Andrew Goossen [andrewgo]
  22. * Wrote it.
  23. \**************************************************************************/
  24. LONG lGetQuadrant(EPOINTFL& eptef)
  25. {
  26. LONG lQuadrant = 0;
  27. if (eptef.y.bIsNegative())
  28. {
  29. if (eptef.x.bIsNegative())
  30. {
  31. lQuadrant = 2;
  32. } else {
  33. lQuadrant = 3;
  34. }
  35. } else {
  36. if ((eptef.x.bIsNegative()) || (eptef.x.bIsZero()))
  37. {
  38. lQuadrant = 1;
  39. //
  40. // check for case of exactly on -x axis
  41. //
  42. if (eptef.y.bIsZero()) {
  43. lQuadrant = 2;
  44. }
  45. }
  46. }
  47. return(lQuadrant);
  48. }
  49. /******************************Public*Routine******************************\
  50. * BOOL GreAngleArc (hdc,x,y,ulRadius,eStartAngle,eSweepAngle)
  51. *
  52. * Draws an arc. Angles are in degrees and are specified in IEEE floating
  53. * point, and not necessarily our own internal representation.
  54. *
  55. * History:
  56. * Sat 22-Jun-1991 00:34:22 -by- Charles Whitmer [chuckwh]
  57. * Added ATTRCACHE support.
  58. *
  59. * 20-Nov-1990 -by- J. Andrew Goossen [andrewgo]
  60. * Wrote it.
  61. \**************************************************************************/
  62. BOOL APIENTRY GreAngleArc
  63. (
  64. HDC hdc,
  65. int x,
  66. int y,
  67. ULONG ulRadius,
  68. FLOATL eStartAngle,
  69. FLOATL eSweepAngle
  70. )
  71. {
  72. LONG lStartQuad;
  73. LONG lEndQuad;
  74. LONG lSweptQuadrants;
  75. EFLOAT efEndAngle;
  76. // Lock the DC.
  77. DCOBJ dco(hdc);
  78. if (!dco.bValid() || dco.bStockBitmap())
  79. {
  80. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  81. return(FALSE);
  82. }
  83. // sync user-mode attributes
  84. SYNC_DRAWING_ATTRS(dco.pdc);
  85. LONG lRadius = (LONG) ulRadius;
  86. ERECTL ercl(x - lRadius, y - lRadius, x + lRadius, y + lRadius);
  87. // Check for overflow of either ulRadius to lRadius conversion or that
  88. // the circle defining the arc extends outside of world space:
  89. if (lRadius < 0 || ercl.left > x || ercl.right < x
  90. || ercl.top > y || ercl.bottom < y)
  91. {
  92. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  93. return(FALSE);
  94. }
  95. EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
  96. // Get a path, and notify that we will update the current point:
  97. PATHSTACKOBJ pso(dco, TRUE);
  98. if (!pso.bValid())
  99. {
  100. return(FALSE);
  101. }
  102. // Make the rectangle well ordered in logical space:
  103. ercl.vOrder();
  104. // Convert IEEE floats to our internal representation:
  105. EFLOAT efStartAngle;
  106. EFLOAT efSweepAngle;
  107. efStartAngle = eStartAngle;
  108. efSweepAngle = eSweepAngle;
  109. // efEndAngle must be more than efStartAngle for 'bPartialArc':
  110. if (efSweepAngle.bIsNegative())
  111. {
  112. register LONG ll;
  113. SWAPL(ercl.top, ercl.bottom, ll);
  114. efSweepAngle.vNegate();
  115. efStartAngle.vNegate();
  116. }
  117. // Assert: Now efSweepAngle >= 0
  118. EBOX ebox(exo, ercl);
  119. // A line is always drawn to the first point of the arc:
  120. PARTIALARC paType = PARTIALARCTYPE_LINETO;
  121. // The arc is swept multiple times if the sweep angle is more than
  122. // 360 degrees. Because we approximate circles with Beziers,
  123. // arcs of less than 90 degrees are more circular than arcs of 90
  124. // degrees. Since the resulting curves are different, we can't do
  125. // multiple sweeps by:
  126. //
  127. // bPartialArc(StartAngle, 360)
  128. // bEllipse()
  129. // bPartialArc(0, EndAngle)
  130. //
  131. // Since multiple sweeps will be rare, we don't bother making it
  132. // too efficient.
  133. EFLOAT efQuadrantsSwept = efSweepAngle;
  134. efQuadrantsSwept *= FP_1DIV90;
  135. efQuadrantsSwept.bEfToLTruncate(lSweptQuadrants);
  136. // We arbitrarily limit this to sweeping eight circles (otherwise, if
  137. // someone gave a really big sweep angle we would lock the system for
  138. // a really long time):
  139. LONG lCirclesSwept = lSweptQuadrants >> 2;
  140. if (lCirclesSwept > 8)
  141. lCirclesSwept = 8;
  142. EPOINTFL eptefStart;
  143. EPOINTFL eptefEnd;
  144. EFLOAT efAngleSwept;
  145. BOOL bAngleSweptIsZero;
  146. efEndAngle = efStartAngle;
  147. efEndAngle += efSweepAngle;
  148. // ASSERT: efEndAngle >= efStartAngle, since efSweepAngle >= 0.
  149. // If the difference between efEndAngle and efStartAngle is less than about 3 degrees,
  150. // then the error in computation of eptefStart and eptefEnd using vCosSin will be enough
  151. // so that the computation of the Bezier points in bPartialArc (which calls bPartialQuadrantArc)
  152. // will be noticeably wrong.
  153. // determine whether (efEndAngle - efStartAngle - 3.0 < 0.0)
  154. efAngleSwept = efEndAngle;
  155. efAngleSwept -= efStartAngle;
  156. bAngleSweptIsZero = efAngleSwept.bIsZero();
  157. efAngleSwept -= FP_3_0;
  158. if (efAngleSwept.bIsNegative() && !bAngleSweptIsZero)
  159. {
  160. vCosSinPrecise(efStartAngle, &eptefStart.x, &eptefStart.y);
  161. vCosSinPrecise(efEndAngle, &eptefEnd.x, &eptefEnd.y);
  162. }
  163. else
  164. {
  165. vCosSin(efStartAngle, &eptefStart.x, &eptefStart.y);
  166. vCosSin(efEndAngle, &eptefEnd.x, &eptefEnd.y);
  167. }
  168. lStartQuad = lGetQuadrant(eptefStart);
  169. if (efStartAngle > FP_3600_0 || efStartAngle < FP_M3600_0)
  170. {
  171. vArctan(eptefStart.x, eptefStart.y, efStartAngle, lStartQuad);
  172. }
  173. lEndQuad = lGetQuadrant(eptefEnd);
  174. if (efEndAngle > FP_3600_0 || efEndAngle < FP_M3600_0)
  175. {
  176. vArctan(eptefEnd.x, eptefEnd.y, efEndAngle, lEndQuad);
  177. // We have to re-count the number of swept quadrants:
  178. lSweptQuadrants = (lEndQuad - lStartQuad) & 3;
  179. if ((lSweptQuadrants == 0) && (efStartAngle > efEndAngle))
  180. lSweptQuadrants = 3;
  181. }
  182. // Quadrants range from 0 to 3:
  183. lEndQuad &= 3;
  184. lStartQuad &= 3;
  185. lSweptQuadrants &= 3;
  186. for (LONG ll = 0; ll < lCirclesSwept; ll++)
  187. {
  188. if (!bPartialArc(paType, pso, ebox,
  189. eptefStart, lStartQuad, efStartAngle,
  190. eptefEnd, lEndQuad, efEndAngle,
  191. lSweptQuadrants) ||
  192. !bPartialArc(PARTIALARCTYPE_CONTINUE, pso, ebox,
  193. eptefEnd, lEndQuad, efEndAngle,
  194. eptefStart, lStartQuad, efStartAngle,
  195. 3 - lSweptQuadrants))
  196. return(FALSE);
  197. paType = PARTIALARCTYPE_CONTINUE;
  198. }
  199. if (!bPartialArc(paType, pso, ebox,
  200. eptefStart, lStartQuad, efStartAngle,
  201. eptefEnd, lEndQuad, efEndAngle,
  202. lSweptQuadrants))
  203. return(FALSE);
  204. // Set the DC's current position in device space. It would be too much
  205. // work to calculate the world space current position, so simply mark it
  206. // as invalid:
  207. dco.pdc->vInvalidatePtlCurrent();
  208. dco.pdc->vValidatePtfxCurrent();
  209. dco.ptfxCurrent() = pso.ptfxGetCurrent();
  210. // If we're not in an active path bracket, stroke the temporary path
  211. // we created:
  212. return(dco.pdc->bActive() ||
  213. pso.bStroke(dco, dco.plaRealize(exo), &exo));
  214. }
  215. /******************************Public*Routine******************************\
  216. * BOOL NtGdiEllipse()
  217. *
  218. * Draws an ellipse in a counter-clockwise direction.
  219. *
  220. * History:
  221. * 20-Nov-1990 -by- J. Andrew Goossen [andrewgo]
  222. * Wrote it.
  223. \**************************************************************************/
  224. BOOL
  225. APIENTRY
  226. NtGdiEllipse(
  227. HDC hdc,
  228. int xLeft,
  229. int yTop,
  230. int xRight,
  231. int yBottom
  232. )
  233. {
  234. DCOBJ dco(hdc);
  235. if (!dco.bValid() || dco.bStockBitmap())
  236. {
  237. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  238. return(FALSE);
  239. }
  240. ERECTL ercl(xLeft, yTop, xRight, yBottom);
  241. // Handle the PS_INSIDEFRAME pen attribute and lower-right exclusion
  242. // by adjusting the box now. At the same time, get the transform
  243. // type and order the rectangle:
  244. EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
  245. LINEATTRS *pla = dco.plaRealize(exo);
  246. // sync the client side cached brush
  247. SYNC_DRAWING_ATTRS(dco.pdc);
  248. // TRUE flag indicates that this is an ellipse, so adjust the bound box
  249. // to make the fill nice:
  250. EBOX ebox(dco, ercl, pla, TRUE);
  251. if (ebox.bEmpty())
  252. return(TRUE);
  253. // Get a path and notify that we won't update the current position:
  254. PATHSTACKOBJ pso(dco);
  255. if (!pso.bValid())
  256. {
  257. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  258. return(FALSE);
  259. }
  260. if (!bEllipse(pso, ebox))
  261. {
  262. return(FALSE);
  263. }
  264. // If the transform is simple and the path consists entirely of the
  265. // ellipse we just added, we can set the flag indicating that the path
  266. // consists of a single ellipse inscribed in the path's bounding
  267. // rectangle. (This flag will get reset if anything is added to the
  268. // path later.)
  269. if (exo.bScale() && pso.cCurves == 5)
  270. pso.fl |= PO_ELLIPSE;
  271. if (dco.pdc->bActive())
  272. return(TRUE);
  273. BOOL bRet;
  274. if (!ebox.bFillInsideFrame())
  275. bRet = pso.bStrokeAndFill(dco, pla, &exo);
  276. else
  277. {
  278. // Handle PS_INSIDEFRAME pen attribute for case when the pen is
  279. // bigger than the bound box. We fill the result with the pen
  280. // brush:
  281. PBRUSH pbrOldFill = dco.pdc->pbrushFill();
  282. dco.pdc->pbrushFill(dco.pdc->pbrushLine());
  283. dco.pdc->flbrushAdd(DIRTY_FILL);
  284. bRet = pso.bFill(dco);
  285. dco.pdc->pbrushFill(pbrOldFill);
  286. dco.pdc->flbrushAdd(DIRTY_FILL);
  287. }
  288. return(bRet);
  289. }
  290. /******************************Public*Routine******************************\
  291. * BOOL NtGdiLineTo (hdc,x,y)
  292. *
  293. * Draws a line from the current position to the specified point.
  294. *
  295. * Current position is used.
  296. *
  297. * History:
  298. * 29-Oct-1990 -by- J. Andrew Goossen [andrewgo]
  299. * Wrote it.
  300. \**************************************************************************/
  301. BOOL APIENTRY NtGdiLineTo
  302. (
  303. HDC hdc,
  304. int x,
  305. int y
  306. )
  307. {
  308. FIX x1;
  309. FIX y1;
  310. FIX x2;
  311. FIX y2;
  312. ERECTL rclBounds;
  313. MIX mix;
  314. BOOL bReturn = TRUE; // Assume we'll succeed
  315. XDCOBJ dco(hdc);
  316. if (dco.bValid())
  317. {
  318. if (!dco.bStockBitmap())
  319. {
  320. EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
  321. LINEATTRS* pla = dco.plaRealize(exo);
  322. // Make sure that the line is solid and cosmetic, that no path is
  323. // being accumulated in the DC, and that this is not an Info DC
  324. // or something that has no surface:
  325. SYNC_DRAWING_ATTRS(dco.pdc);
  326. // Since we can send down only integer end-points to the driver
  327. // with DrvLineTo, we go through this special case only if we're
  328. // not in 'advanced mode' (non-advanced mode supports only integer
  329. // transforms, for compatibility), or if the current transform
  330. // does translation only:
  331. if (!(pla->fl & (LA_STYLED | LA_GEOMETRIC | LA_ALTERNATE)) &&
  332. !(dco.pdc->bActive()) &&
  333. (exo.bTranslationsOnly() || (dco.pdc->iGraphicsMode() != GM_ADVANCED)))
  334. {
  335. // If it's a device managed surface, call DrvLineTo if it's
  336. // hooked by the driver, otherwise call DrvStrokePath; if it's
  337. // an engine managed surface, call DrvLineTo if it's hooked by
  338. // the driver, otherwise call EngLineTo:
  339. PDEVOBJ po(dco.hdev());
  340. // Grab the devlock now so that we can safely get the window
  341. // origin and look at the surface:
  342. DEVLOCKOBJ dlo(dco);
  343. if (dlo.bValid())
  344. {
  345. if (dco.bHasSurface())
  346. {
  347. // Don't call EngLineTo if the driver doesn't hook DrvLineTo
  348. // but does hook DrvStrokePath.
  349. SURFACE* pSurfDst = dco.pSurface();
  350. PFN_DrvLineTo pfnDrvLineTo = NULL;
  351. if (pSurfDst->flags() & HOOK_LINETO)
  352. {
  353. pfnDrvLineTo = PPFNDRV(po, LineTo);
  354. }
  355. else if ((pSurfDst->iType() == STYPE_BITMAP) &&
  356. !(pSurfDst->flags() & HOOK_STROKEPATH))
  357. {
  358. pfnDrvLineTo = EngLineTo;
  359. }
  360. if (pfnDrvLineTo != NULL)
  361. {
  362. // We've satisfied all the conditions for DrvLineTo!
  363. if (exo.bTranslationsOnly())
  364. {
  365. LONG xOffset = exo.fxDx() >> 4;
  366. LONG yOffset = exo.fxDy() >> 4;
  367. x2 = x + xOffset;
  368. y2 = y + yOffset;
  369. if (dco.pdc->bValidPtlCurrent())
  370. {
  371. x1 = dco.ptlCurrent().x + xOffset;
  372. y1 = dco.ptlCurrent().y + yOffset;
  373. }
  374. else
  375. {
  376. x1 = dco.ptfxCurrent().x >> 4;
  377. y1 = dco.ptfxCurrent().y >> 4;
  378. }
  379. }
  380. else
  381. {
  382. ASSERTGDI(dco.pdc->iGraphicsMode() != GM_ADVANCED,
  383. "Someone changed an 'if'");
  384. POINTL aptl[2];
  385. aptl[0].x = x;
  386. aptl[0].y = y;
  387. if (!dco.pdc->bValidPtfxCurrent())
  388. {
  389. aptl[1].x = dco.ptlCurrent().x;
  390. aptl[1].y = dco.ptlCurrent().y;
  391. exo.bXform(aptl, 2);
  392. x1 = aptl[1].x;
  393. y1 = aptl[1].y;
  394. }
  395. else
  396. {
  397. exo.bXform(aptl, 1);
  398. x1 = dco.ptfxCurrent().x >> 4;
  399. y1 = dco.ptfxCurrent().y >> 4;
  400. }
  401. x2 = aptl[0].x;
  402. y2 = aptl[0].y;
  403. }
  404. // Validation to avoid FIX overflow errors.
  405. // Input after transformation must be restricted to 27bits.
  406. // This is apparently a spec issue.
  407. if (!BLTOFXOK(x2)||
  408. !BLTOFXOK(y2))
  409. {
  410. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  411. // The XDCOBJ dco is locked and the destructor does not
  412. // automagically clean up the lock so we do it here.
  413. dco.vUnlockFast();
  414. return FALSE;
  415. }
  416. // Remember the new current position, in both logical
  417. // space and device space, before applying the window offset:
  418. dco.pdc->vCurrentPosition(x, y, x2 << 4, y2 << 4);
  419. LONG xOrigin = dco.eptlOrigin().x;
  420. LONG yOrigin = dco.eptlOrigin().y;
  421. x1 += xOrigin;
  422. x2 += xOrigin;
  423. y1 += yOrigin;
  424. y2 += yOrigin;
  425. // parameter validation to avoid sticky overflow errors.
  426. // Using BLTOFXOK here is really an overkill - we're trying to
  427. // avoid the +1 below from wrapping and generating a non well-ordered
  428. // bounds rectangle.
  429. // Note: the above code adding xOrigin and yOrigin cannot generate
  430. // non well-ordered rectangles because of the comparisons below during
  431. // the computation of the bound box. This is true even if one of the
  432. // corners wraps and an incorrect bound box is computed (The rect will
  433. // be wrong and the line will be wrong too - but they'll match and the
  434. // code won't crash with an access violation because a valid clip rect
  435. // will be generated.)
  436. if (!BLTOFXOK(x1)||
  437. !BLTOFXOK(y1)||
  438. !BLTOFXOK(x2)||
  439. !BLTOFXOK(y2))
  440. {
  441. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  442. // We're exiting - undo the current position.
  443. // This code should match the undo code just after the call to
  444. // the driver below.
  445. dco.pdc->vPtfxCurrentPosition(
  446. (x1 - xOrigin) << 4, (y1 - yOrigin) << 4);
  447. // The XDCOBJ dco is locked and the destructor does not
  448. // automagically clean up the lock so we do it here.
  449. dco.vUnlockFast();
  450. return FALSE;
  451. }
  452. // Compute the bound box, remembering that it must be lower-right
  453. // exclusive:
  454. if (x1 <= x2)
  455. {
  456. rclBounds.left = x1;
  457. rclBounds.right = x2 + 1;
  458. }
  459. else
  460. {
  461. rclBounds.left = x2;
  462. rclBounds.right = x1 + 1;
  463. }
  464. if (y1 <= y2)
  465. {
  466. rclBounds.top = y1;
  467. rclBounds.bottom = y2 + 1;
  468. }
  469. else
  470. {
  471. rclBounds.top = y2;
  472. rclBounds.bottom = y1 + 1;
  473. }
  474. if (dco.fjAccum())
  475. {
  476. // Bounds are accumulated relative to the window origin.
  477. // Fortunately, we don't often take this path:
  478. ERECTL rclWindow;
  479. rclWindow.left = rclBounds.left - xOrigin;
  480. rclWindow.right = rclBounds.right - xOrigin;
  481. rclWindow.top = rclBounds.top - yOrigin;
  482. rclWindow.bottom = rclBounds.bottom - yOrigin;
  483. dco.vAccumulate(rclWindow);
  484. }
  485. if (dco.pdc->pbrushLine() != gpPenNull)
  486. {
  487. ECLIPOBJ *pco = NULL;
  488. // This is a pretty gnarly expression to save a return in here.
  489. // Basically pco can be NULL if the rect is completely in the
  490. // cached rect in the DC or if we set up a clip object that
  491. // isn't empty.
  492. if (((rclBounds.left >= dco.prclClip()->left) &&
  493. (rclBounds.right <= dco.prclClip()->right) &&
  494. (rclBounds.top >= dco.prclClip()->top) &&
  495. (rclBounds.bottom <= dco.prclClip()->bottom)) ||
  496. (pco = dco.pco(),
  497. pco->vSetup(dco.prgnEffRao(),rclBounds,CLIP_NOFORCE),
  498. (!pco->erclExclude().bEmpty())))
  499. {
  500. EBRUSHOBJ* pebo = dco.peboLine();
  501. // We have to make sure that we have a solid pen
  502. // for cosmetic lines. If the pen is dirty, we
  503. // may be looking at an uninitialized field, but
  504. // that's okay because we'd only be making the pen
  505. // dirty again:
  506. if (pebo->iSolidColor == (ULONG) -1)
  507. {
  508. dco.ulDirtyAdd(DIRTY_LINE);
  509. }
  510. if (dco.bDirtyBrush(DIRTY_LINE))
  511. {
  512. dco.vCleanBrush(DIRTY_LINE);
  513. XEPALOBJ palDst(pSurfDst->ppal());
  514. XEPALOBJ palDstDC(dco.ppal());
  515. pebo->vInitBrush(dco.pdc,
  516. dco.pdc->pbrushLine(),
  517. palDstDC,
  518. palDst,
  519. pSurfDst,
  520. FALSE);
  521. }
  522. // Exclude the pointer:
  523. DEVEXCLUDEOBJ dxo(
  524. dco,
  525. (pco == NULL) ? &rclBounds : &pco->erclExclude(),
  526. pco
  527. );
  528. // Update the target surface uniqueness:
  529. INC_SURF_UNIQ(pSurfDst);
  530. // No validation has been done on jROP2, so we must
  531. // do it here:
  532. mix = (((MIX) dco.pdc->jROP2() - 1) & 0xf) + 1;
  533. mix |= (mix << 8);
  534. if (!pfnDrvLineTo(pSurfDst->pSurfobj(),
  535. pco,
  536. pebo,
  537. x1,
  538. y1,
  539. x2,
  540. y2,
  541. &rclBounds,
  542. mix))
  543. {
  544. // The driver decided to punt. Make sure
  545. // we undo the current position:
  546. dco.pdc->vPtfxCurrentPosition(
  547. (x1 - xOrigin) << 4, (y1 - yOrigin) << 4);
  548. goto SlowWay;
  549. }
  550. }
  551. else
  552. {
  553. // Completely clipped away, so return success.
  554. }
  555. }
  556. else
  557. {
  558. // Null pens always succeed.
  559. }
  560. }
  561. else
  562. {
  563. // LineTo isn't hooked:
  564. goto SlowWay;
  565. }
  566. }
  567. else
  568. {
  569. // It's an info DC, so we have no alternative...
  570. goto SlowWay;
  571. }
  572. }
  573. else
  574. {
  575. // If we can't grab the devlock, we may be full-screen:
  576. bReturn = dco.bFullScreen();
  577. }
  578. dco.vUnlockFast();
  579. return(bReturn);
  580. }
  581. SlowWay:
  582. // We have to do it the slow way, by making a path:
  583. EPOINTL eptl(x, y);
  584. // Get a path, and notify that we will update the current point:
  585. {
  586. PATHSTACKOBJ pso(dco, TRUE);
  587. if (!pso.bValid())
  588. {
  589. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  590. }
  591. else
  592. {
  593. if (pso.bPolyLineTo(&exo, &eptl, 1))
  594. {
  595. dco.pdc->vCurrentPosition(eptl, pso.ptfxGetCurrent());
  596. bReturn = (dco.pdc->bActive() ||
  597. pso.bStroke(dco, pla, &exo));
  598. }
  599. }
  600. }
  601. }
  602. else
  603. {
  604. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  605. bReturn = FALSE;
  606. }
  607. dco.vUnlockFast();
  608. }
  609. else
  610. {
  611. // We couldn't lock the DC.
  612. bReturn = FALSE;
  613. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  614. }
  615. return(bReturn);
  616. }
  617. /******************************Public*Routine******************************\
  618. * BOOL GreMoveTo(hdc, x, y, pptl)
  619. *
  620. * Changes the current position. Optionally returns old current position.
  621. *
  622. * History:
  623. * 29-Oct-1990 -by- J. Andrew Goossen [andrewgo]
  624. * Wrote it.
  625. \**************************************************************************/
  626. BOOL APIENTRY GreMoveTo
  627. (
  628. HDC hdc,
  629. int x,
  630. int y,
  631. LPPOINT pptl
  632. )
  633. {
  634. XDCOBJ dco(hdc);
  635. if (dco.bValid())
  636. {
  637. if (!dco.bStockBitmap())
  638. {
  639. if (pptl != (LPPOINT) NULL)
  640. {
  641. if (!dco.pdc->bValidPtlCurrent())
  642. {
  643. ASSERTGDI(dco.pdc->bValidPtfxCurrent(), "Both CPs invalid?");
  644. EXFORMOBJ exoDtoW(dco, DEVICE_TO_WORLD);
  645. if (!exoDtoW.bValid())
  646. {
  647. dco.vUnlockFast();
  648. return(FALSE);
  649. }
  650. exoDtoW.bXform(&dco.ptfxCurrent(), &dco.ptlCurrent(), 1);
  651. }
  652. *((POINTL*) pptl) = dco.ptlCurrent();
  653. }
  654. // Don't bother computing the device-space current position; simply mark
  655. // it invalid:
  656. dco.ptlCurrent().x = x;
  657. dco.ptlCurrent().y = y;
  658. dco.pdc->vInvalidatePtfxCurrent();
  659. dco.pdc->vValidatePtlCurrent();
  660. if (!dco.pdc->bActive())
  661. {
  662. // If we're not in a path, we have to reset our style state:
  663. LINEATTRS* pla = dco.plaRealized();
  664. if (pla->fl & LA_GEOMETRIC)
  665. pla->elStyleState.e = IEEE_0_0F;
  666. else
  667. pla->elStyleState.l = 0L;
  668. }
  669. dco.vUnlockFast();
  670. return(TRUE);
  671. }
  672. else
  673. {
  674. dco.vUnlockFast();
  675. }
  676. }
  677. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  678. return(FALSE);
  679. }
  680. /******************************Public*Routine******************************\
  681. * BOOL GrePolyBezier (hdc,pptl,cptl)
  682. *
  683. * Draw multiple Beziers. Current position is not used.
  684. *
  685. * History:
  686. * 29-Oct-1990 -by- J. Andrew Goossen [andrewgo]
  687. * Wrote it.
  688. \**************************************************************************/
  689. BOOL APIENTRY GrePolyBezier
  690. (
  691. HDC hdc,
  692. LPPOINT pptl,
  693. ULONG cptl
  694. )
  695. {
  696. DCOBJ dco(hdc);
  697. if (!dco.bValid() || dco.bStockBitmap())
  698. {
  699. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  700. return(FALSE);
  701. }
  702. // Number of points must be 1 more than 3 times the number of curves:
  703. if (cptl < 4 || cptl % 3 != 1)
  704. {
  705. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  706. return(FALSE);
  707. }
  708. // sync the client side cached brush
  709. SYNC_DRAWING_ATTRS(dco.pdc);
  710. EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
  711. // Get a path and notify that we won't update the current position:
  712. PATHSTACKOBJ pso(dco);
  713. if (!pso.bValid())
  714. {
  715. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  716. return(FALSE);
  717. }
  718. if (!pso.bMoveTo(&exo, (PPOINTL) pptl) ||
  719. !pso.bPolyBezierTo(&exo, ((PPOINTL) pptl) + 1, cptl - 1))
  720. {
  721. return(FALSE);
  722. }
  723. return(dco.pdc->bActive() ||
  724. pso.bStroke(dco, dco.plaRealize(exo), &exo));
  725. }
  726. /******************************Public*Routine******************************\
  727. * BOOL GrePolyBezierTo (hdc,pptl,cptl)
  728. *
  729. * Draws multiple Beziers. Current position is used and updated.
  730. *
  731. * History:
  732. * 29-Oct-1990 -by- J. Andrew Goossen [andrewgo]
  733. * Wrote it.
  734. \**************************************************************************/
  735. BOOL APIENTRY GrePolyBezierTo
  736. (
  737. HDC hdc,
  738. LPPOINT pptl,
  739. ULONG cptl
  740. )
  741. {
  742. DCOBJ dco(hdc);
  743. if (!dco.bValid() || dco.bStockBitmap())
  744. {
  745. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  746. return(FALSE);
  747. }
  748. // Number of points must be 3 times the number of curves:
  749. if (cptl < 3 || cptl % 3 != 0)
  750. {
  751. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  752. return(FALSE);
  753. }
  754. // sync the client side cached brush
  755. SYNC_DRAWING_ATTRS(dco.pdc);
  756. EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
  757. // Get a path, and notify that we will update the current point:
  758. PATHSTACKOBJ pso(dco, TRUE);
  759. if (!pso.bValid())
  760. {
  761. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  762. return(FALSE);
  763. }
  764. if (!pso.bPolyBezierTo(&exo, (PPOINTL) pptl, cptl))
  765. return(FALSE);
  766. dco.pdc->vCurrentPosition(((POINTL*) pptl)[cptl - 1],
  767. pso.ptfxGetCurrent());
  768. return(dco.pdc->bActive() ||
  769. pso.bStroke(dco, dco.plaRealize(exo), &exo));
  770. }
  771. /******************************Public*Routine******************************\
  772. * BOOL GrePolyDraw(hdc,pptl,pfj,cptl)
  773. *
  774. * Draw a collection of lines and Bezier curves in a single call.
  775. *
  776. * History:
  777. * 31-Jul-1991 -by- J. Andrew Goossen [andrewgo]
  778. * Wrote it.
  779. \**************************************************************************/
  780. BOOL APIENTRY GrePolyDraw
  781. (
  782. HDC hdc,
  783. LPPOINT pptl,
  784. LPBYTE pfj,
  785. ULONG cptl
  786. )
  787. {
  788. // No point in validating pfj[] now because with shared memory
  789. // window, client could trounce on pfj[] between now and when we
  790. // get around to processing it.
  791. DCOBJ dco(hdc);
  792. if (!dco.bValid() || dco.bStockBitmap())
  793. {
  794. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  795. return(FALSE);
  796. }
  797. SYNC_DRAWING_ATTRS(dco.pdc);
  798. // Handle easy case:
  799. if (cptl == 0)
  800. return(TRUE);
  801. EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
  802. // Get a path, and notify that we will update the current point:
  803. PATHSTACKOBJ pso(dco, TRUE);
  804. if (!pso.bValid())
  805. {
  806. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  807. return(FALSE);
  808. }
  809. // Accumulate the path.
  810. PBYTE pfjEnd = pfj + cptl;
  811. PBYTE pfjStart;
  812. SIZE_T cc;
  813. BOOL bReturn = FALSE; // Fail by default
  814. while (pfj < pfjEnd)
  815. {
  816. pfjStart = pfj;
  817. switch(*pfj++)
  818. {
  819. case (PT_LINETO):
  820. // Collect all the consecutive LineTo's
  821. while (pfj < pfjEnd && *pfj == PT_LINETO)
  822. pfj++;
  823. if (pfj < pfjEnd && (*pfj & ~PT_CLOSEFIGURE) == PT_LINETO)
  824. pfj++;
  825. // Now fall through...
  826. case (PT_LINETO | PT_CLOSEFIGURE):
  827. cc = (SIZE_T)(pfj - pfjStart);
  828. // Sundown, pfj will never exceed pfjEnd = pj + cptl where cptl is a
  829. // ULONG, so it's safe to truncate here.
  830. if (!pso.bPolyLineTo(&exo, (PPOINTL) pptl, (ULONG)cc))
  831. return(bReturn);
  832. pptl += cc;
  833. if (*(pfj - 1) & PT_CLOSEFIGURE)
  834. pso.bCloseFigure();
  835. break;
  836. case (PT_BEZIERTO):
  837. // Collect all the consecutive BezierTo's (the first PT_BEZIERTO in
  838. // a series should never have the PT_CLOSEFIGURE flag set)
  839. while (pfj < pfjEnd && *pfj == PT_BEZIERTO)
  840. pfj++;
  841. if (pfj < pfjEnd && (*pfj & ~PT_CLOSEFIGURE) == PT_BEZIERTO)
  842. pfj++;
  843. // The number of BezierTo points must be a multiple of 3
  844. cc = (SIZE_T)(pfj - pfjStart);
  845. if (cc % 3 != 0)
  846. {
  847. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  848. return(FALSE);
  849. }
  850. //Sundown, safe to truncate here
  851. if (!pso.bPolyBezierTo(&exo, (PPOINTL) pptl, (ULONG)cc))
  852. return(bReturn);
  853. pptl += cc;
  854. if (*(pfj - 1) & PT_CLOSEFIGURE)
  855. pso.bCloseFigure();
  856. break;
  857. case (PT_MOVETO):
  858. if (!pso.bMoveTo(&exo, (PPOINTL) pptl))
  859. return(bReturn);
  860. pptl++;
  861. break;
  862. default:
  863. // Abort without drawing anything:
  864. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  865. return(FALSE);
  866. }
  867. }
  868. dco.pdc->vCurrentPosition(*((POINTL*) pptl - 1),
  869. pso.ptfxGetCurrent());
  870. return(dco.pdc->bActive() ||
  871. pso.bStroke(dco, dco.plaRealize(exo), &exo));
  872. }
  873. /******************************Public*Routine******************************\
  874. * BOOL GrePolylineTo (hdc,pptl,cptl)
  875. *
  876. * Draw a polyline figure. Current position is used and updated.
  877. *
  878. * History:
  879. * 29-Oct-1990 -by- J. Andrew Goossen [andrewgo]
  880. * Wrote it.
  881. \**************************************************************************/
  882. BOOL APIENTRY GrePolylineTo
  883. (
  884. HDC hdc,
  885. LPPOINT pptl,
  886. ULONG cptl
  887. )
  888. {
  889. // Lock the DC.
  890. DCOBJ dco(hdc);
  891. if (!dco.bValid() || dco.bStockBitmap())
  892. {
  893. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  894. return(FALSE);
  895. }
  896. SYNC_DRAWING_ATTRS(dco.pdc);
  897. // Return a trivial call.
  898. if (cptl == 0)
  899. return(TRUE);
  900. // Locate the current transform.
  901. EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
  902. // Get a path, and notify that we will update the current point:
  903. PATHSTACKOBJ pso(dco, TRUE);
  904. // Accumulate the lines.
  905. if (!pso.bValid())
  906. {
  907. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  908. return(FALSE);
  909. }
  910. if (!pso.bPolyLineTo(&exo,(PPOINTL) pptl, cptl))
  911. return(FALSE);
  912. dco.pdc->vCurrentPosition(((POINTL*) pptl)[cptl - 1],
  913. pso.ptfxGetCurrent());
  914. // Return now if we're in a path bracket, otherwise stroke the line:
  915. return(dco.pdc->bActive() ||
  916. pso.bStroke(dco, dco.plaRealize(exo), &exo));
  917. }
  918. /******************************Public*Routine******************************\
  919. * BOOL GrePolyPolygonInternal(hdc,pptl,pcptl,ccptl,cMaxPoints)
  920. *
  921. * Creates multiple polygons. Current position is not used.
  922. *
  923. * History:
  924. * 29-Oct-1990 -by- J. Andrew Goossen [andrewgo]
  925. * Wrote it.
  926. \**************************************************************************/
  927. BOOL APIENTRY GrePolyPolygonInternal(
  928. HDC hdc,
  929. LPPOINT pptl,
  930. LPINT pcptl,
  931. int ccptl,
  932. UINT cMaxPoints
  933. )
  934. {
  935. BOOL bStatus = TRUE;
  936. DCOBJ dco(hdc);
  937. if (dco.bValid() && !dco.bStockBitmap())
  938. {
  939. //
  940. // sync the client side cached brush
  941. //
  942. SYNC_DRAWING_ATTRS(dco.pdc);
  943. //
  944. // quick out on the trivial case
  945. //
  946. if (ccptl != 0)
  947. {
  948. EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
  949. //
  950. // Get a path and notify that we won't update the current position:
  951. //
  952. PATHSTACKOBJ pso(dco);
  953. if (pso.bValid())
  954. {
  955. bStatus = bPolyPolygon(pso,
  956. exo,
  957. (PPOINTL) pptl,
  958. (PLONG) pcptl,
  959. (LONG) ccptl,
  960. cMaxPoints);
  961. if (bStatus)
  962. {
  963. bStatus = (dco.pdc->bActive() ||
  964. pso.bStrokeAndFill(dco, dco.plaRealize(exo), &exo));
  965. }
  966. }
  967. else
  968. {
  969. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  970. bStatus = FALSE;
  971. }
  972. }
  973. }
  974. else
  975. {
  976. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  977. bStatus = FALSE;
  978. }
  979. return(bStatus);
  980. }
  981. /******************************Public*Routine******************************\
  982. * BOOL bMakePathRecords
  983. *
  984. * Constructs an array of pathrecords from a given set of pre-transformed
  985. * polypolyline points.
  986. *
  987. * NOTE: 'pcptl' and 'pptlSrc' are allowed to be user-mode pointers, so this
  988. * routine may access violate -- in this case, the caller must provide
  989. * 'try/excepts'!
  990. *
  991. * History:
  992. * 24-Sep-1996 -by- J. Andrew Goossen [andrewgo]
  993. * Wrote it.
  994. \**************************************************************************/
  995. BOOL bMakePathRecords
  996. (
  997. PATHRECORD* pprThis, // Destination buffer for pathrecords
  998. ULONG* pcptl, // Pointer to count of polylines
  999. // Note: Might be user-mode address!
  1000. LONG cptlRem, // Maximum number of points allowable
  1001. POINTL* pptlSrc, // Pointer to polypolyline points
  1002. // Note: Might be user-mode address!
  1003. ULONG cpr, // Count of resulting pathrecords
  1004. LONG xOffset, // x-offset in pre-transformed coordinates
  1005. LONG yOffset, // y-offset in pre-transformed coordinates
  1006. RECTFX* prcfxBoundBox, // Returns bounds of lines
  1007. PATHRECORD**pprLast // Returns pointer to last pathrecord
  1008. )
  1009. {
  1010. ULONG cptl;
  1011. LONG xBoundLeft;
  1012. LONG yBoundsTop;
  1013. LONG xBoundRight;
  1014. LONG yBoundsBottom;
  1015. BOOL bRet;
  1016. PATHRECORD* pprPrev;
  1017. bRet = TRUE; // Assume success
  1018. xBoundLeft = LONG_MAX;
  1019. yBoundsTop = LONG_MAX;
  1020. xBoundRight = LONG_MIN;
  1021. yBoundsBottom = LONG_MIN;
  1022. pprThis->pprprev = NULL;
  1023. while (TRUE)
  1024. {
  1025. // We have to check 'cptlRem' to be sure that the malevolent
  1026. // application hasn't modified the pcptl array -- we must make
  1027. // sure we don't add any more points than what we allocated
  1028. // (less is okay, though):
  1029. cptl = *pcptl++;
  1030. cptlRem -= cptl;
  1031. if ((cptlRem < 0) || (((LONG) cptl) < 2))
  1032. {
  1033. // We either ran out of buffer space, do not have enough
  1034. // points in the array, or a negative number of points were
  1035. // specified (keep in mind that cptlRem is a LONG, so cptl
  1036. // also needs to be treated as a LONG for the check).
  1037. bRet = FALSE;
  1038. break;
  1039. }
  1040. pprThis->count = cptl;
  1041. pprThis->flags = (PD_BEGINSUBPATH | PD_ENDSUBPATH);
  1042. pprPrev = pprThis;
  1043. // Copy all the points for this pathrecord, and at the same time
  1044. // add in the window offset and collect the bounds:
  1045. do {
  1046. LONG x;
  1047. LONG y;
  1048. x = pptlSrc->x;
  1049. if (x < xBoundLeft)
  1050. xBoundLeft = x;
  1051. if (x > xBoundRight)
  1052. xBoundRight = x;
  1053. pprThis->aptfx[0].x = x + xOffset;
  1054. y = pptlSrc->y;
  1055. if (y < yBoundsTop)
  1056. yBoundsTop = y;
  1057. if (y > yBoundsBottom)
  1058. yBoundsBottom = y;
  1059. pprThis->aptfx[0].y = y + yOffset;
  1060. // For efficiency, we advance 'pprThis' by the size of a point,
  1061. // rather than incuring more cycles to get a pointer directly
  1062. // to the points:
  1063. pprThis = (PATHRECORD*) ((BYTE*) pprThis + sizeof(POINTFIX));
  1064. pptlSrc++;
  1065. } while (--cptl != 0);
  1066. if (--cpr == 0)
  1067. break;
  1068. pprThis = (PATHRECORD*) (pprThis->aptfx);
  1069. pprThis->pprprev = pprPrev;
  1070. pprPrev->pprnext = pprThis;
  1071. }
  1072. if (bRet)
  1073. {
  1074. pprPrev->pprnext = NULL;
  1075. *pprLast = pprPrev;
  1076. // Watch for overflow when we added in 'xOffset' and 'yOffset':
  1077. prcfxBoundBox->xLeft = xOffset + xBoundLeft;
  1078. prcfxBoundBox->xRight = xOffset + xBoundRight;
  1079. if (xBoundLeft > xBoundRight)
  1080. bRet = FALSE;
  1081. prcfxBoundBox->yTop = yOffset + yBoundsTop;
  1082. prcfxBoundBox->yBottom = yOffset + yBoundsBottom;
  1083. if (yBoundsTop > yBoundsBottom)
  1084. bRet = FALSE;
  1085. // If 'cptlRem' isn't zero, someone modified the 'pcptl' array while we
  1086. // were looking at it!
  1087. if (cptlRem != 0)
  1088. bRet = FALSE;
  1089. }
  1090. return(bRet);
  1091. }
  1092. /******************************Public*Routine******************************\
  1093. * BOOL NtGdiFastPolyPolyline(hdc, pptl, pcptl, ccpl)
  1094. *
  1095. * Fast path for drawing solid, nominal width polylines. Will return FALSE
  1096. * if the fast-path can't be used.
  1097. *
  1098. * History:
  1099. * 29-Oct-1990 -by- J. Andrew Goossen [andrewgo]
  1100. * Wrote it.
  1101. \**************************************************************************/
  1102. extern "C" {
  1103. BOOL NtGdiFastPolyPolyline(HDC, CONST POINT*, ULONG*, ULONG);
  1104. };
  1105. #define POLYBUFFERSIZE 100
  1106. BOOL NtGdiFastPolyPolyline
  1107. (
  1108. HDC hdc,
  1109. CONST POINT *pptl, // Pointer to user-mode data
  1110. ULONG *pcptl, // Pointer to user-mode data
  1111. ULONG ccptl
  1112. )
  1113. {
  1114. ULONG cMaxPoints = 0;
  1115. BOOL bReturn = FALSE; // Assume we'll fail
  1116. DCOBJ dco(hdc);
  1117. if (dco.bValid() && !dco.bStockBitmap())
  1118. {
  1119. EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
  1120. LINEATTRS* pla = dco.plaRealize(exo);
  1121. SYNC_DRAWING_ATTRS(dco.pdc);
  1122. if (ccptl != 0)
  1123. {
  1124. __try
  1125. {
  1126. ULONG i;
  1127. ULONG* pul;
  1128. ULONG c;
  1129. if (ccptl <= (MAXULONG/sizeof(ULONG)))
  1130. {
  1131. ProbeForRead(pcptl, ccptl * sizeof(ULONG), sizeof(BYTE));
  1132. c = 0;
  1133. i = ccptl;
  1134. pul = pcptl;
  1135. do {
  1136. // Don't add directly to 'cMaxPoints' here because we're in
  1137. // a try/except and the compiler can't register 'cMaxPoints'
  1138. // but can enregister 'c.
  1139. //
  1140. // Also note that we do not care if a bad app puts bogus
  1141. // data in here to cause cMaxPoints to overflow since
  1142. // code not only uses cMaxPoints to allocate memory, but
  1143. // also passes it to bXform and bMakePathRecords to
  1144. // ensure we do not access past the amount allocated.
  1145. // Furthermore, bMakePathRecords also checks for the
  1146. // overflow case as it processes each Polyline and
  1147. // will return failure if it detects the overflow.
  1148. c += *pul++;
  1149. } while (--i != 0);
  1150. if (c <= (MAXULONG/sizeof(POINT)))
  1151. {
  1152. ProbeForRead(pptl, c * sizeof(POINT), sizeof(BYTE));
  1153. // Only set cMaxPoints if no overflows or exceptions
  1154. // occur. Otherwise cMaxPoints is zero and test
  1155. // for cMaxPoints > 0 below will fail.
  1156. cMaxPoints = c;
  1157. }
  1158. }
  1159. }
  1160. __except(EXCEPTION_EXECUTE_HANDLER)
  1161. {
  1162. WARNINGX(5);
  1163. }
  1164. // Watch out for overflow:
  1165. if ((cMaxPoints > 0) &&
  1166. (ccptl < 0x08000000) &&
  1167. (cMaxPoints < 0x08000000))
  1168. {
  1169. // We handle only solid cosmetic lines in this special case.
  1170. // We don't do styled lines so that we don't have to worry about
  1171. // updating the style state in the DC after the call is done, and
  1172. // we don't have to check for opaque styles (for which we would
  1173. // have to call the driver twice).
  1174. if (!dco.pdc->bActive() &&
  1175. ((pla->fl & (LA_GEOMETRIC | LA_ALTERNATE)) == 0) &&
  1176. (pla->pstyle == NULL))
  1177. {
  1178. LONG xOffset;
  1179. LONG yOffset;
  1180. BOOL bIntegers;
  1181. MIX mix;
  1182. ULONG cjAlloc;
  1183. EPATHOBJ epo;
  1184. PATH path;
  1185. PATHRECORD* pprFirst;
  1186. POINTL* pptlTransform;
  1187. union {
  1188. PATHRECORD prStackBuffer;
  1189. BYTE ajStackBuffer[POLYBUFFERSIZE];
  1190. };
  1191. cjAlloc = ccptl * offsetof(PATHRECORD, aptfx)
  1192. + cMaxPoints * sizeof(POINTFIX);
  1193. if (cjAlloc > POLYBUFFERSIZE)
  1194. {
  1195. pprFirst = (PATHRECORD*) PVALLOCTEMPBUFFER(cjAlloc);
  1196. if (pprFirst == NULL)
  1197. {
  1198. // bReturn is already FALSE
  1199. return(bReturn);
  1200. }
  1201. }
  1202. else
  1203. {
  1204. pprFirst = &prStackBuffer;
  1205. }
  1206. DEVLOCKOBJ dlo(dco);
  1207. if (dlo.bValid())
  1208. {
  1209. // Now that we have the devlock, we can safely add in
  1210. // the window offset:
  1211. xOffset = dco.eptlOrigin().x;
  1212. yOffset = dco.eptlOrigin().y;
  1213. bReturn = TRUE;
  1214. bIntegers = TRUE;
  1215. pptlTransform = (POINTL*) pptl;
  1216. // We don't have to call transform routines if we only
  1217. // have a translation. If we are not in compatible mode
  1218. // we also require integer translations.
  1219. if ((!exo.bTranslationsOnly()) ||
  1220. (dco.pdc->iGraphicsMode() != GM_COMPATIBLE &&
  1221. ((exo.fxDx() | exo.fxDy()) & (FIX_ONE - 1)) != 0))
  1222. {
  1223. // The transform isn't trivial, so call out to transform
  1224. // all the points. Rather than allocate yet another
  1225. // buffer, we stick the transformed points at the end
  1226. // of our pathrecords buffer.
  1227. pptlTransform = (POINTL*) ((BYTE*) pprFirst
  1228. + cjAlloc
  1229. - sizeof(POINTFIX) * cMaxPoints);
  1230. // Because we're dealing with user-mode buffers for
  1231. // 'pptl' and 'pcptl', we copy the points under the
  1232. // protection of a 'try / except'. 'bXform' is
  1233. // guaranteed to be recoverable:
  1234. __try
  1235. {
  1236. if (dco.pdc->iGraphicsMode() == GM_ADVANCED)
  1237. {
  1238. // In advanced mode, the transform can cause
  1239. // fractional coordinates, so we can't set the
  1240. // PO_ALL_INTEGERS flag:
  1241. bIntegers = FALSE;
  1242. // Since we will add DC offsets to the
  1243. // path records in bMakePathRecords,
  1244. // just convert to fixed and apply
  1245. // non-translation transformation
  1246. // elements here.
  1247. bReturn = exo.bXform(
  1248. (VECTORL*) pptl,
  1249. (VECTORFX*) pptlTransform,
  1250. cMaxPoints);
  1251. // Convert offsets to fixed point and add
  1252. // translation values
  1253. xOffset = LTOFX(xOffset) + exo.fxDx();
  1254. yOffset = LTOFX(yOffset) + exo.fxDy();
  1255. }
  1256. else
  1257. {
  1258. // In compatibility mode, the transform never
  1259. // causes fractional coordinates, so we can
  1260. // transform directly to integers and set the
  1261. // PO_ALL_INTEGERS flag:
  1262. bIntegers = TRUE;
  1263. bReturn = exo.bXform(
  1264. (POINTL*) pptl,
  1265. (POINTL*) pptlTransform,
  1266. cMaxPoints);
  1267. }
  1268. }
  1269. __except(EXCEPTION_EXECUTE_HANDLER)
  1270. {
  1271. bReturn = FALSE;
  1272. }
  1273. }
  1274. else
  1275. {
  1276. // Add translation values to offsets applied in
  1277. // bMakePathRecords
  1278. xOffset += FXTOL(exo.fxDx());
  1279. yOffset += FXTOL(exo.fxDy());
  1280. }
  1281. // We special case integer polylines and actually
  1282. // record integer coordinates in the path instead
  1283. // of integers. At bEnum() time we will transform
  1284. // them to fixed coordinates if the driver doesn't
  1285. // expect to receive integers.
  1286. epo.fl = bIntegers ? PO_ALL_INTEGERS : 0;
  1287. // Because we're dealing with user-mode buffers for
  1288. // 'pptl' and 'pcptl', we copy the points under the
  1289. // protection of a 'try / except'. bMakePathRecord
  1290. // is guaranteed to be recoverable:
  1291. __try
  1292. {
  1293. bReturn &= bMakePathRecords(
  1294. pprFirst,
  1295. pcptl,
  1296. cMaxPoints,
  1297. pptlTransform,
  1298. ccptl,
  1299. xOffset,
  1300. yOffset,
  1301. &path.rcfxBoundBox,
  1302. &path.pprlast);
  1303. }
  1304. __except(EXCEPTION_EXECUTE_HANDLER)
  1305. {
  1306. bReturn = FALSE;
  1307. }
  1308. // The bound-box was collected in integer coordinates
  1309. // but has to be fixed:
  1310. if (bIntegers)
  1311. {
  1312. path.rcfxBoundBox.xLeft <<= 4;
  1313. path.rcfxBoundBox.xRight <<= 4;
  1314. path.rcfxBoundBox.yTop <<= 4;
  1315. path.rcfxBoundBox.yBottom <<= 4;
  1316. }
  1317. if (!bReturn)
  1318. {
  1319. if (pprFirst != &prStackBuffer)
  1320. {
  1321. FREEALLOCTEMPBUFFER(pprFirst);
  1322. }
  1323. return(bReturn);
  1324. }
  1325. // Initialize all the remaining path fields:
  1326. path.pprfirst = pprFirst;
  1327. path.flags = 0;
  1328. path.pprEnum = NULL;
  1329. epo.cCurves = cMaxPoints - ccptl;
  1330. epo.ppath = &path;
  1331. ERECTL erclBoundBox(path.rcfxBoundBox);
  1332. // Make sure the bounds are lower-right exclusive:
  1333. erclBoundBox.bottom++;
  1334. erclBoundBox.right++;
  1335. if (dco.fjAccum())
  1336. {
  1337. ERECTL ercl;
  1338. // Bounds are accumulated relative to the window
  1339. // origin:
  1340. ercl.left = erclBoundBox.left - dco.eptlOrigin().x;
  1341. ercl.right = erclBoundBox.right - dco.eptlOrigin().x;
  1342. ercl.top = erclBoundBox.top - dco.eptlOrigin().y;
  1343. ercl.bottom = erclBoundBox.bottom - dco.eptlOrigin().y;
  1344. dco.vAccumulate(ercl);
  1345. }
  1346. if (dco.pdc->pbrushLine() != gpPenNull)
  1347. {
  1348. SURFACE* pSurfDst = dco.pSurface();
  1349. if (pSurfDst != NULL)
  1350. {
  1351. XEPALOBJ palDst(pSurfDst->ppal());
  1352. XEPALOBJ palDstDC(dco.ppal());
  1353. EBRUSHOBJ* pebo = dco.peboLine();
  1354. // We have to make sure that we have a solid pen
  1355. // for cosmetic lines. If the pen is dirty, we
  1356. // may be looking at an uninitialized field, but
  1357. // that's okay because we'd only be making the pen
  1358. // dirty again:
  1359. if (pebo->iSolidColor == (ULONG) -1)
  1360. {
  1361. dco.ulDirtyAdd(DIRTY_LINE);
  1362. }
  1363. if (dco.bDirtyBrush(DIRTY_LINE))
  1364. {
  1365. dco.vCleanBrush(DIRTY_LINE);
  1366. pebo->vInitBrush(dco.pdc,
  1367. dco.pdc->pbrushLine(),
  1368. palDstDC, palDst,
  1369. pSurfDst,
  1370. FALSE);
  1371. }
  1372. // No validation has been done on jROP2, so we must
  1373. // do it here:
  1374. mix = (((MIX) dco.pdc->jROP2() - 1) & 0xf) + 1;
  1375. mix |= (mix << 8);
  1376. ECLIPOBJ eco(dco.prgnEffRao(), erclBoundBox);
  1377. if (!eco.erclExclude().bEmpty())
  1378. {
  1379. PDEVOBJ pdo(pSurfDst->hdev());
  1380. // Exclude the pointer:
  1381. DEVEXCLUDEOBJ dxo(dco, &eco.erclExclude(), &eco);
  1382. // Update the target surface uniqueness:
  1383. INC_SURF_UNIQ(pSurfDst);
  1384. bReturn = (*PPFNGET(pdo, StrokePath, pSurfDst->flags()))
  1385. (
  1386. pSurfDst->pSurfobj(),
  1387. &epo,
  1388. &eco,
  1389. NULL,
  1390. pebo,
  1391. NULL,
  1392. pla,
  1393. mix
  1394. );
  1395. }
  1396. else
  1397. {
  1398. // Completely clipped away:
  1399. bReturn = TRUE;
  1400. }
  1401. }
  1402. else
  1403. {
  1404. // When there's no surface pointer, we're drawing to an
  1405. // INFO DC, or something:
  1406. bReturn = TRUE;
  1407. }
  1408. }
  1409. else
  1410. {
  1411. // Null pens will always succeed:
  1412. bReturn = TRUE;
  1413. }
  1414. }
  1415. else
  1416. {
  1417. // If we can't grab the devlock, it may be because we're
  1418. // in full-screen:
  1419. bReturn = dco.bFullScreen();
  1420. }
  1421. if (pprFirst != &prStackBuffer)
  1422. {
  1423. FREEALLOCTEMPBUFFER(pprFirst);
  1424. }
  1425. }
  1426. }
  1427. }
  1428. else
  1429. {
  1430. // Trivial case always succeeds:
  1431. bReturn = TRUE;
  1432. }
  1433. }
  1434. return(bReturn);
  1435. }
  1436. /******************************Public*Routine******************************\
  1437. * BOOL GrePolyPolylineInternal(hdc,pptl,pcptl,cptl,cMaxPoints)
  1438. *
  1439. * Slow way to draw multiple polylines. Current position is not used.
  1440. *
  1441. * History:
  1442. * 29-Oct-1990 -by- J. Andrew Goossen [andrewgo]
  1443. * Wrote it.
  1444. \**************************************************************************/
  1445. #define POLYBUFFERSIZE 100
  1446. BOOL APIENTRY GrePolyPolylineInternal
  1447. (
  1448. HDC hdc,
  1449. CONST POINT *pptl,
  1450. ULONG *pcptl,
  1451. ULONG ccptl,
  1452. UINT cMaxPoints
  1453. )
  1454. {
  1455. BOOL bReturn = FALSE; // Assume we'll fail
  1456. DCOBJ dco(hdc);
  1457. if (dco.bValid() && !dco.bStockBitmap())
  1458. {
  1459. EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
  1460. LINEATTRS* pla = dco.plaRealize(exo);
  1461. SYNC_DRAWING_ATTRS(dco.pdc);
  1462. if (ccptl != 0)
  1463. {
  1464. // We'll do it the slow way. First, get a path and notify that
  1465. // we won't update the current position:
  1466. // Note: This instance of PATHSTACKOBJ takes up a bunch of stack
  1467. // space that we could share with prStackBuffer is stack
  1468. // space ever becomes tight.
  1469. PATHSTACKOBJ pso(dco);
  1470. if (!pso.bValid())
  1471. {
  1472. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  1473. return(FALSE);
  1474. }
  1475. LONG cPts;
  1476. ULONG* pcptlEnd = pcptl + ccptl;
  1477. do {
  1478. // We have to be careful to make a local copy of this
  1479. // polyline's point count (by copying it to cPts) to get
  1480. // the value out of the shared client/server memory window,
  1481. // where the app could trash the value at any time:
  1482. cPts = *pcptl;
  1483. cMaxPoints = (UINT) ((LONG) cMaxPoints - cPts);
  1484. // Fail if any polyline is less than 2 points or if we've
  1485. // passed our maximum number of points:
  1486. if ((LONG) cMaxPoints < 0 || cPts < 2)
  1487. {
  1488. SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
  1489. return(FALSE);
  1490. }
  1491. if (!pso.bMoveTo(&exo, (PPOINTL) pptl) ||
  1492. !pso.bPolyLineTo(&exo, ((PPOINTL) pptl) + 1, cPts - 1))
  1493. return(FALSE);
  1494. pptl += cPts;
  1495. pcptl++;
  1496. } while (pcptl < pcptlEnd);
  1497. bReturn = (dco.pdc->bActive() ||
  1498. pso.bStroke(dco, dco.plaRealize(exo), &exo));
  1499. }
  1500. else
  1501. {
  1502. // Trivial case always succeeds:
  1503. bReturn = TRUE;
  1504. }
  1505. }
  1506. else
  1507. {
  1508. // We couldn't lock the DC. bReturn is already FALSE.
  1509. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  1510. }
  1511. return(bReturn);
  1512. }
  1513. /******************************Public*Routine******************************\
  1514. * BOOL NtGdiRectangle()
  1515. *
  1516. * Draws a rectangle. Current position is not used. The rectangle is
  1517. * drawn in a counter-clockwise direction.
  1518. *
  1519. * History:
  1520. * 29-Oct-1990 -by- J. Andrew Goossen [andrewgo]
  1521. * Wrote it.
  1522. \**************************************************************************/
  1523. BOOL
  1524. APIENTRY
  1525. NtGdiRectangle(
  1526. HDC hdc,
  1527. int xLeft,
  1528. int yTop,
  1529. int xRight,
  1530. int yBottom
  1531. )
  1532. {
  1533. BOOL bRet;
  1534. LINEATTRS* pla;
  1535. DCOBJ dco(hdc);
  1536. if (!dco.bValid() || dco.bStockBitmap())
  1537. {
  1538. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  1539. return(FALSE);
  1540. }
  1541. if (MIRRORED_DC(dco.pdc))
  1542. {
  1543. // If it a mirrored DC then shift the rect one pixel to the right
  1544. // This will give the effect of including the right edge of the rect and exclude the left edge.
  1545. --xLeft;
  1546. --xRight;
  1547. }
  1548. ERECTL ercl(xLeft, yTop, xRight, yBottom);
  1549. // Sync the client side cached brush
  1550. SYNC_DRAWING_ATTRS(dco.pdc);
  1551. EXFORMOBJ exoWorld(dco, WORLD_TO_DEVICE);
  1552. if (exoWorld.bScale() && !dco.pdc->bActive())
  1553. {
  1554. // We try to optimize the simple cases as much as possible. The first
  1555. // criteria is that there is no funky transform in effect, and the
  1556. // second is that we're not accumulating a path.
  1557. if (dco.pdc->pbrushLine() == gpPenNull)
  1558. {
  1559. // Unfortunately, we have to check here if we have a NULL brush
  1560. // as well:
  1561. if (dco.pdc->pbrushFill() == gpbrNull)
  1562. {
  1563. return(TRUE);
  1564. }
  1565. // When we don't have a pen, we do a simple PatBlt:
  1566. if (dco.pdc->iGraphicsMode() != GM_ADVANCED)
  1567. {
  1568. // Round to the nearest integer if not in advanced mode.
  1569. if (exoWorld.bTranslationsOnly())
  1570. {
  1571. LONG lOffset;
  1572. lOffset = FXTOLROUND(exoWorld.fxDx());
  1573. ercl.left += lOffset;
  1574. ercl.right += lOffset;
  1575. lOffset = FXTOLROUND(exoWorld.fxDy());
  1576. ercl.top += lOffset;
  1577. ercl.bottom += lOffset;
  1578. }
  1579. else
  1580. {
  1581. ASSERTGDI(exoWorld.bScale(), "Fast path can't do weird xforms");
  1582. ercl.left = FXTOLROUND(exoWorld.fxFastX(ercl.left));
  1583. ercl.right = FXTOLROUND(exoWorld.fxFastX(ercl.right));
  1584. ercl.top = FXTOLROUND(exoWorld.fxFastY(ercl.top));
  1585. ercl.bottom = FXTOLROUND(exoWorld.fxFastY(ercl.bottom));
  1586. }
  1587. ercl.vOrder();
  1588. // If we're not in advanced mode, figures are lower-right
  1589. // exclusive, so we have to adjust the rectangle:
  1590. ercl.right--;
  1591. ercl.bottom--;
  1592. }
  1593. else
  1594. {
  1595. if (exoWorld.bTranslationsOnly())
  1596. {
  1597. LONG lOffset;
  1598. lOffset = FXTOLCEILING(exoWorld.fxDx());
  1599. ercl.left += lOffset;
  1600. ercl.right += lOffset;
  1601. lOffset = FXTOLCEILING(exoWorld.fxDy());
  1602. ercl.top += lOffset;
  1603. ercl.bottom += lOffset;
  1604. }
  1605. else
  1606. {
  1607. ASSERTGDI(exoWorld.bScale(), "Fast path can't do weird xforms");
  1608. ercl.left = FXTOLCEILING(exoWorld.fxFastX(ercl.left));
  1609. ercl.right = FXTOLCEILING(exoWorld.fxFastX(ercl.right));
  1610. ercl.top = FXTOLCEILING(exoWorld.fxFastY(ercl.top));
  1611. ercl.bottom = FXTOLCEILING(exoWorld.fxFastY(ercl.bottom));
  1612. }
  1613. ercl.vOrder();
  1614. }
  1615. if (ercl.bWrapped())
  1616. return(TRUE);
  1617. return(GreRectBlt(dco, &ercl));
  1618. }
  1619. pla = dco.plaRealize(exoWorld);
  1620. if (!(pla->fl & LA_GEOMETRIC))
  1621. {
  1622. // We handle here the case where we draw the outline with a pen.
  1623. BYTE rpo[sizeof(RECTANGLEPATHOBJ)];
  1624. // NOTE: For compatibility with Win3.1, we round the points to
  1625. // integer coordinates. If we didn't do this, the rectangle outline
  1626. // would be rendered according to GIQ, and could have pixels
  1627. // 'missing' in the corners if the corners didn't end on integers.
  1628. if (dco.pdc->iGraphicsMode() != GM_ADVANCED)
  1629. {
  1630. if (exoWorld.bTranslationsOnly())
  1631. {
  1632. LONG lOffset;
  1633. lOffset = FXTOLROUND(exoWorld.fxDx());
  1634. ercl.left += lOffset;
  1635. ercl.right += lOffset;
  1636. lOffset = FXTOLROUND(exoWorld.fxDy());
  1637. ercl.top += lOffset;
  1638. ercl.bottom += lOffset;
  1639. }
  1640. else
  1641. {
  1642. ASSERTGDI(exoWorld.bScale(), "Fast path can't do weird xforms");
  1643. ercl.left = FXTOLROUND(exoWorld.fxFastX(ercl.left));
  1644. ercl.right = FXTOLROUND(exoWorld.fxFastX(ercl.right));
  1645. ercl.top = FXTOLROUND(exoWorld.fxFastY(ercl.top));
  1646. ercl.bottom = FXTOLROUND(exoWorld.fxFastY(ercl.bottom));
  1647. }
  1648. ercl.vOrder();
  1649. // If we're not in advanced mode, figures are lower-right
  1650. // exclusive, so we have to adjust the rectangle.
  1651. ercl.right--;
  1652. ercl.bottom--;
  1653. if ((ercl.left > ercl.right) || (ercl.top > ercl.bottom))
  1654. return(TRUE);
  1655. }
  1656. else
  1657. {
  1658. if (exoWorld.bTranslationsOnly())
  1659. {
  1660. LONG lOffset;
  1661. lOffset = FXTOLCEILING(exoWorld.fxDx());
  1662. ercl.left += lOffset;
  1663. ercl.right += lOffset;
  1664. lOffset = FXTOLCEILING(exoWorld.fxDy());
  1665. ercl.top += lOffset;
  1666. ercl.bottom += lOffset;
  1667. }
  1668. else
  1669. {
  1670. ASSERTGDI(exoWorld.bScale(), "Fast path can't do weird xforms");
  1671. ercl.left = FXTOLCEILING(exoWorld.fxFastX(ercl.left));
  1672. ercl.right = FXTOLCEILING(exoWorld.fxFastX(ercl.right));
  1673. ercl.top = FXTOLCEILING(exoWorld.fxFastY(ercl.top));
  1674. ercl.bottom = FXTOLCEILING(exoWorld.fxFastY(ercl.bottom));
  1675. }
  1676. ercl.vOrder();
  1677. }
  1678. ((RECTANGLEPATHOBJ*) &rpo)->vInit(&ercl, dco.pdc->bClockwise());
  1679. // An important feature is to not draw the interior when we've
  1680. // got a NULL brush:
  1681. if (dco.pdc->pbrushFill() != gpbrNull)
  1682. {
  1683. // For compatibility, we also have to shrink the fill rectangle
  1684. // on the top and left sides when we don't have a NULL pen
  1685. // (this matters for some ROPs and styled pens):
  1686. ercl.left++;
  1687. ercl.top++;
  1688. if (!ercl.bWrapped() && !GreRectBlt(dco, &ercl))
  1689. return(FALSE);
  1690. }
  1691. return(((RECTANGLEPATHOBJ*) &rpo)->bStroke(dco, pla, NULL));
  1692. }
  1693. }
  1694. // Now cover the cases we haven't handled.
  1695. // We may have not realize the LINEATTRS yet, so make sure we do now (it
  1696. // will early-out if we have already realized it):
  1697. pla = dco.plaRealize(exoWorld);
  1698. EBOX ebox(dco, ercl, pla);
  1699. if (ebox.bEmpty())
  1700. return(TRUE);
  1701. // Get a path and add to it:
  1702. PATHSTACKOBJ pso(dco);
  1703. if (!pso.bValid())
  1704. {
  1705. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  1706. return(FALSE);
  1707. }
  1708. if (!pso.bMoveTo((EXFORMOBJ*) NULL, &ebox.aeptl[0]) ||
  1709. !pso.bPolyLineTo((EXFORMOBJ*) NULL, &ebox.aeptl[1], 3) ||
  1710. !pso.bCloseFigure())
  1711. {
  1712. return(FALSE);
  1713. }
  1714. if (dco.pdc->bActive())
  1715. return(TRUE);
  1716. if (!ebox.bFillInsideFrame())
  1717. {
  1718. // Rectangles created with old-style pens always have miter joins:
  1719. ULONG iSaveJoin = pla->iJoin;
  1720. if (((PPEN)dco.pdc->pbrushLine())->bIsOldStylePen())
  1721. {
  1722. pla->iJoin = JOIN_MITER;
  1723. }
  1724. bRet = pso.bStrokeAndFill(dco, pla, &exoWorld);
  1725. pla->iJoin = iSaveJoin;
  1726. }
  1727. else
  1728. {
  1729. // Handle PS_INSIDEFRAME pen attribute for case when the pen is
  1730. // bigger than the bound box. We fill the result with the pen
  1731. // brush:
  1732. PBRUSH pbrOldFill = dco.pdc->pbrushFill();
  1733. dco.pdc->pbrushFill(dco.pdc->pbrushLine());
  1734. dco.pdc->flbrushAdd(DIRTY_FILL);
  1735. bRet = pso.bFill(dco);
  1736. dco.pdc->pbrushFill(pbrOldFill);
  1737. dco.pdc->flbrushAdd(DIRTY_FILL);
  1738. }
  1739. return(bRet);
  1740. }
  1741. /******************************Public*Routine******************************\
  1742. * BOOL NtGdiRoundRect (hdc,x1,y1,x2,y2,x3,y3)
  1743. *
  1744. * Draws a rounded rectangle in a counter-clockwise direction.
  1745. *
  1746. * History:
  1747. * 20-Nov-1990 -by- J. Andrew Goossen [andrewgo]
  1748. * Wrote it.
  1749. \**************************************************************************/
  1750. BOOL
  1751. APIENTRY
  1752. NtGdiRoundRect(
  1753. HDC hdc,
  1754. int x1,
  1755. int y1,
  1756. int x2,
  1757. int y2,
  1758. int x3,
  1759. int y3
  1760. )
  1761. {
  1762. // If either axis of the ellipse is zero, then we'll be outputing
  1763. // a rectangle. We do this check here and not in 'bRoundRect'
  1764. // because Rectangle needs the DC (for checking for the fast rectangle
  1765. // condition).
  1766. // Note that for compatibility with Win3, this must be here! Zero-size
  1767. // ellipse roundrects created with old-style pens must have miter joins,
  1768. // and Rectangle will take care of that:
  1769. if (x3 == 0 || y3 == 0)
  1770. return(NtGdiRectangle(hdc,x1,y1,x2,y2));
  1771. DCOBJ dco(hdc);
  1772. if (!dco.bValid() || dco.bStockBitmap())
  1773. {
  1774. SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
  1775. return(FALSE);
  1776. }
  1777. // Sync the client side cached brush
  1778. SYNC_DRAWING_ATTRS(dco.pdc);
  1779. ERECTL ercl(x1, y1, x2, y2);
  1780. EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
  1781. EBOX ebox(dco, ercl, dco.plaRealize(exo), TRUE);
  1782. if (ebox.bEmpty())
  1783. return(TRUE);
  1784. // Get a path and notify that we won't update the current position:
  1785. PATHSTACKOBJ pso(dco);
  1786. if (!pso.bValid())
  1787. {
  1788. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  1789. return(FALSE);
  1790. }
  1791. if (!bRoundRect(pso, ebox, x3, y3))
  1792. return(FALSE);
  1793. if (dco.pdc->bActive())
  1794. return(TRUE);
  1795. BOOL bRet;
  1796. if (!ebox.bFillInsideFrame())
  1797. bRet = pso.bStrokeAndFill(dco, dco.plaRealize(exo), &exo);
  1798. else
  1799. {
  1800. // Handle PS_INSIDEFRAME pen attribute for case when the pen is
  1801. // bigger than the bound box. We fill the result with the pen
  1802. // brush:
  1803. PBRUSH pbrOldFill = dco.pdc->pbrushFill();
  1804. dco.pdc->pbrushFill(dco.pdc->pbrushLine());
  1805. dco.pdc->flbrushAdd(DIRTY_FILL);
  1806. bRet = pso.bFill(dco);
  1807. dco.pdc->pbrushFill(pbrOldFill);
  1808. dco.pdc->flbrushAdd(DIRTY_FILL);
  1809. }
  1810. return(bRet);
  1811. }
  1812. /******************************Public*Routine******************************\
  1813. * bSyncBrushObj()
  1814. *
  1815. * This routine just makes sure that the kernel brush matches the user mode
  1816. * brush.
  1817. *
  1818. * History:
  1819. * 19-Jul-1995 -by- Eric Kutter [erick]
  1820. * Wrote it.
  1821. \**************************************************************************/
  1822. BOOL bSyncBrushObj(
  1823. PBRUSH pbrush)
  1824. {
  1825. BOOL bRet = TRUE;
  1826. if (pbrush)
  1827. {
  1828. PBRUSHATTR pBrushattr = pbrush->pBrushattr();
  1829. //
  1830. // if the brush handle is a cached solid brush,
  1831. // call GreSetSolidBrushInternal to change the color
  1832. //
  1833. if (pBrushattr->AttrFlags & ATTR_NEW_COLOR)
  1834. {
  1835. //
  1836. // set the new color for the cached brush
  1837. //
  1838. if (!GreSetSolidBrushLight(pbrush,pBrushattr->lbColor,pbrush->bIsPen()))
  1839. {
  1840. WARNING1("GreSyncbrush failed to setsolidbrushiternal\n");
  1841. bRet = FALSE;
  1842. }
  1843. else
  1844. {
  1845. pBrushattr->AttrFlags &= ~ATTR_NEW_COLOR;
  1846. }
  1847. }
  1848. }
  1849. return(bRet);
  1850. }