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.

2971 lines
90 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: pathobj.cxx
  3. *
  4. * Non inline PATHOBJ methods
  5. *
  6. * Created: 28-Sep-1990 12:36:30
  7. * Author: Paul Butzi [paulb]
  8. *
  9. * Copyright (c) 1990-1999 Microsoft Corporation
  10. \**************************************************************************/
  11. #include "precomp.hxx"
  12. extern PBRUSH gpbrBackground;
  13. extern PPEN gpPenNull;
  14. extern PBRUSH gpbrNull;
  15. extern LINEATTRS glaNominalGeometric;
  16. // Default LINEATTRS for bSimpleStroke:
  17. LA glaSimpleStroke =
  18. {
  19. 0, // fl
  20. 0, // iJoin
  21. 0, // iEndCap
  22. {1L}, // elWidth
  23. IEEE_0_0F, // eMiterLimit
  24. 0, // cstyle
  25. (LONG_FLOAT*) NULL, // pstyle
  26. {0L} // elStyleState
  27. };
  28. #define XFORMNULL ((EXFORMOBJ *) NULL)
  29. // The following declarations are required by the native c8 compiler.
  30. HSEMAPHORE PATHALLOC::hsemFreelist; // Semaphore for freelist
  31. PATHALLOC *PATHALLOC::freelist; // Free-list of pathallocs
  32. COUNT PATHALLOC::cFree; // Count of free pathallocs
  33. COUNT PATHALLOC::cAllocated; // Count of pathallocs allocated
  34. /******************************Public*Routine******************************\
  35. * XEPATHOBJ::XEPATHOBJ(hpath)
  36. *
  37. * Path user object constructor
  38. *
  39. * History:
  40. * 28-Sep-1990 -by- Paul Butzi [paulb]
  41. * Wrote it.
  42. \**************************************************************************/
  43. XEPATHOBJ::XEPATHOBJ(HPATH hPath)
  44. {
  45. ppath = (PPATH)HmgShareLock((HOBJ) hPath, PATH_TYPE);
  46. if (ppath != (PATH*) NULL)
  47. {
  48. // Load up accelerator values:
  49. cCurves = ppath->cCurves;
  50. fl = ppath->fl;
  51. }
  52. return;
  53. }
  54. /******************************Public*Routine******************************\
  55. * XEPATHOBJ::XEPATHOBJ(dco)
  56. *
  57. * Path user object constructor to get at the DC's path.
  58. *
  59. * History:
  60. * 22-Mar-1992 -by- J. Andrew Goossen [andrewgo]
  61. * Wrote it.
  62. \**************************************************************************/
  63. XEPATHOBJ::XEPATHOBJ(XDCOBJ& dco)
  64. {
  65. ASSERTGDI(dco.hpath() != HPATH_INVALID, "Invalid path");
  66. // If a SaveDC was done, we may have to copy the path before mucking
  67. // with it:
  68. if (dco.pdc->bLazySave())
  69. {
  70. dco.pdc->vClearLazySave();
  71. XEPATHOBJ epath(dco.hpath());
  72. ASSERTGDI (epath.bValid(),"hpath invalid when bLazySave is set");
  73. PATHMEMOBJ pmo;
  74. if (pmo.bValid() && epath.bValid() && pmo.bClone(epath))
  75. {
  76. pmo.vKeepIt();
  77. dco.pdc->hpath(pmo.hpath());
  78. }
  79. else
  80. {
  81. // Error case simply deletes the path if we managed to allocate
  82. // one, and marks the DC path as invalid:
  83. pmo.vDelete();
  84. dco.pdc->hpath(HPATH_INVALID);
  85. }
  86. }
  87. ppath = (PPATH)HmgShareLock((HOBJ) dco.hpath(), PATH_TYPE);
  88. if (ppath != (PATH*) NULL)
  89. {
  90. // Load up accelerator values:
  91. cCurves = ppath->cCurves;
  92. fl = ppath->fl;
  93. }
  94. return;
  95. }
  96. /******************************Public*Routine******************************\
  97. * EPATHFONTOBJ::vInit(ULONG)
  98. *
  99. * Initialize a chunk of memory to be a font pathobj
  100. *
  101. * History:
  102. * 22-Mar-1992 -by- J. Andrew Goossen [andrewgo]
  103. * Wrote it.
  104. \**************************************************************************/
  105. VOID EPATHFONTOBJ::vInit(ULONGSIZE_T size)
  106. {
  107. ppath = &path;
  108. path.ppachain = &pa;
  109. path.ptfxSubPathStart.x = 0;
  110. path.ptfxSubPathStart.y = 0;
  111. path.flags = PD_BEGINSUBPATH;
  112. path.pprfirst = (PATHRECORD*) NULL;
  113. path.pprlast = (PATHRECORD*) NULL;
  114. path.rcfxBoundBox.xLeft = 0;
  115. path.rcfxBoundBox.xRight = 0;
  116. path.rcfxBoundBox.yTop = 0;
  117. path.rcfxBoundBox.yBottom = 0;
  118. path.flType = PATHTYPE_STACK;
  119. pa.ppanext = (PATHALLOC*) NULL;
  120. pa.pprfreestart = pa.apr;
  121. pa.siztPathAlloc = size - offsetof(EPATHFONTOBJ,pa);
  122. fl = 0;
  123. cCurves = 0;
  124. }
  125. /******************************Public*Routine******************************\
  126. * XEPATHOBJ::~XEPATHOBJ()
  127. *
  128. * Path user object destructor
  129. *
  130. * History:
  131. * 1-Oct-1990 -by- Paul Butzi [paulb]
  132. * Wrote it.
  133. \**************************************************************************/
  134. XEPATHOBJ::~XEPATHOBJ()
  135. {
  136. if (ppath != (PPATH) NULL)
  137. {
  138. // Since we're keeping the object, save the accelerator values
  139. // away and unlock the object:
  140. ppath->cCurves = cCurves;
  141. ppath->fl = fl;
  142. DEC_SHARE_REF_CNT(ppath);
  143. }
  144. return;
  145. }
  146. /******************************Public*Routine******************************\
  147. * PATHMEMOBJ::PATHMEMOBJ()
  148. *
  149. * Create a new path object.
  150. *
  151. * Note: Using this constructor, the path will not inherit the current
  152. * point from the DC!
  153. *
  154. * History:
  155. * 1-Oct-1990 -by- Paul Butzi [paulb]
  156. * Wrote it.
  157. \**************************************************************************/
  158. PATHMEMOBJ::PATHMEMOBJ()
  159. {
  160. PPATH ppathTemp;
  161. ppath = ppathTemp = (PPATH)HmgAlloc(sizeof(PATH) ,PATH_TYPE, HMGR_ALLOC_ALT_LOCK);
  162. if (ppathTemp != (PATH*) NULL)
  163. {
  164. // Private debug code to catch invalid hpath handle in DC
  165. // 6/24/98 - davidx
  166. ASSERTGDI(HmgObjtype(ppath->hGet()) == PATH_TYPE,
  167. "Private debug breakpoint. Please contact ntgdi.");
  168. //
  169. // Since we 0 init in the Alloc we don't need to do most of this.
  170. //
  171. // pPathTemp->ppachain = (PATHALLOC*) NULL;
  172. // pPathTemp->pprfirst = (PATHRECORD*) NULL;
  173. // pPathTemp->pprlast = (PATHRECORD*) NULL;
  174. // pPathTemp->rcfxBoundBox.xLeft = 0;
  175. // pPathTemp->rcfxBoundBox.xRight = 0;
  176. // pPathTemp->rcfxBoundBox.yTop = 0;
  177. // pPathTemp->rcfxBoundBox.yBottom = 0;
  178. // pPathTemp->ptfxSubPathStart.x = 0;
  179. // pPathTemp->ptfxSubPathStart.y = 0;
  180. // pPathTemp->flType = 0;
  181. // pPathTemp->fl = 0;
  182. // pPathTemp->cCurves = 0;
  183. ppathTemp->flags = PD_BEGINSUBPATH | PD_ENDSUBPATH;
  184. fl = 0;
  185. cCurves = 0;
  186. }
  187. return;
  188. }
  189. /******************************Public*Routine******************************\
  190. * PATHMEMOBJ::~PATHMEMOBJ()
  191. *
  192. * Release a path object unless made permanent.
  193. *
  194. * History:
  195. * 1-Oct-1990 -by- Paul Butzi [paulb]
  196. * Wrote it.
  197. \**************************************************************************/
  198. PATHMEMOBJ::~PATHMEMOBJ()
  199. {
  200. // ppath may have been made NULL by vDelete(), or by a failed PATH
  201. // allocation in the constructor:
  202. if (ppath != (PATH*) NULL)
  203. {
  204. if (!(ppath->flType & PATHTYPE_KEEPMEM))
  205. {
  206. // Free all the blocks in the path:
  207. vFreeBlocks();
  208. // Free the handle too:
  209. HmgFree((HOBJ) ppath->hGet());
  210. }
  211. else
  212. {
  213. // Since we're keeping the object, save the accelerator values away
  214. // and unlock the object:
  215. ppath->cCurves = cCurves;
  216. ppath->fl = fl;
  217. DEC_SHARE_REF_CNT(ppath);
  218. }
  219. }
  220. }
  221. /******************************Public*Routine******************************\
  222. * PATHSTACKOBJ::PATHSTACKOBJ()
  223. *
  224. * Create a new path object on the stack. The path can hold only a small
  225. * number of points on the stack, and will overflow onto the heap if
  226. * necessary.
  227. *
  228. * History:
  229. * 22-Mar-1992 -by- J. Andrew Goossen [andrewgo]
  230. * Wrote it.
  231. \**************************************************************************/
  232. PATHSTACKOBJ::PATHSTACKOBJ()
  233. {
  234. ppath = &path;
  235. path.ppachain = &paBuf.pa;
  236. path.ptfxSubPathStart.x = 0;
  237. path.ptfxSubPathStart.y = 0;
  238. path.flags = PD_BEGINSUBPATH;
  239. path.pprfirst = (PATHRECORD*) NULL;
  240. path.pprlast = (PATHRECORD*) NULL;
  241. path.rcfxBoundBox.xLeft = 0;
  242. path.rcfxBoundBox.xRight = 0;
  243. path.rcfxBoundBox.yTop = 0;
  244. path.rcfxBoundBox.yBottom = 0;
  245. path.flType = PATHTYPE_STACK;
  246. paBuf.pa.ppanext = (PATHALLOC*) NULL;
  247. paBuf.pa.pprfreestart = paBuf.pa.apr;
  248. paBuf.pa.siztPathAlloc = PATHSTACKALLOCSIZE;
  249. cCurves = 0;
  250. fl = 0;
  251. }
  252. /******************************Public*Routine******************************\
  253. * PATHSTACKOBJ::PATHSTACKOBJ(dco, bUseCP)
  254. *
  255. * Create a new path object on the stack or locate an old one. If the DC
  256. * is currently in a path bracket, we use the active path (which will NOT
  257. * be on the path). Otherwise, we create a new path on the stack (it will
  258. * overflow onto the heap if necessary). If we create a new path, we use
  259. * some of the state from the DC to initialize the path, most notably the
  260. * current position (ptfxSubPathStart).
  261. *
  262. * If bUseCP is set, the current position in the DC will be used to set the
  263. * current position in the path. Calls that don't use the current position
  264. * (i.e., immediately do a bMoveTo) shouldn't set bUseCP because it may
  265. * require a transform call to set it (we need the value in device space).
  266. *
  267. * SaveDC's do lazy saves of paths. If a lazy save is pending, we have
  268. * to copy the path and update the DC's path handle before we can modify
  269. * it.
  270. *
  271. * History:
  272. * 22-Mar-1992 -by- J. Andrew Goossen [andrewgo]
  273. * Wrote it.
  274. \**************************************************************************/
  275. PATHSTACKOBJ::PATHSTACKOBJ(XDCOBJ& dco, BOOL bUseCP)
  276. {
  277. if (!dco.pdc->bActive())
  278. {
  279. cCurves = 0;
  280. fl = 0;
  281. // There's no active path in the DC, so we create a temporary
  282. // path on the stack to hold our points:
  283. ppath = &path;
  284. path.ppachain = &paBuf.pa;
  285. path.flags = PD_BEGINSUBPATH;
  286. path.pprfirst = (PATHRECORD*) NULL;
  287. path.pprlast = (PATHRECORD*) NULL;
  288. path.rcfxBoundBox.xLeft = 0;
  289. path.rcfxBoundBox.xRight = 0;
  290. path.rcfxBoundBox.yTop = 0;
  291. path.rcfxBoundBox.yBottom = 0;
  292. path.flType = PATHTYPE_STACK;
  293. paBuf.pa.ppanext = (PATHALLOC*) NULL;
  294. paBuf.pa.pprfreestart = paBuf.pa.apr;
  295. paBuf.pa.siztPathAlloc = PATHSTACKALLOCSIZE;
  296. if (bUseCP)
  297. {
  298. if (!dco.pdc->bValidPtfxCurrent())
  299. {
  300. ASSERTGDI(dco.pdc->bValidPtlCurrent(), "Both CPs invalid?");
  301. EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
  302. exo.bXformRound(&dco.ptlCurrent(), &dco.ptfxCurrent(), 1);
  303. dco.pdc->vValidatePtfxCurrent();
  304. }
  305. path.ptfxSubPathStart = dco.ptfxCurrent();
  306. // If we're not in a path, and a previous call to MoveToEx means
  307. // that the style state should be reset, we do it now:
  308. if (dco.ulDirty() & DIRTY_STYLESTATE)
  309. {
  310. dco.ulDirtySub(DIRTY_STYLESTATE);
  311. LINEATTRS* pla = dco.plaRealized();
  312. if (pla->fl & LA_GEOMETRIC)
  313. pla->elStyleState.e = IEEE_0_0F;
  314. else
  315. pla->elStyleState.l = 0L;
  316. }
  317. }
  318. }
  319. else
  320. {
  321. // If a SaveDC was done, we may have to copy the path before we can
  322. // muck with it:
  323. if (dco.pdc->bLazySave())
  324. {
  325. dco.pdc->vClearLazySave();
  326. XEPATHOBJ epath(dco.hpath());
  327. ASSERTGDI (epath.bValid(),"hpath invalid when bLazySave is set");
  328. PATHMEMOBJ pmo;
  329. if (pmo.bValid() && epath.bValid() && pmo.bClone(epath))
  330. {
  331. pmo.vKeepIt();
  332. dco.pdc->hpath(pmo.hpath());
  333. }
  334. else
  335. {
  336. pmo.vDelete();
  337. dco.pdc->hpath(HPATH_INVALID);
  338. }
  339. }
  340. // There is an active path bracket, so just add to it:
  341. ppath = (PPATH)HmgShareLock((HOBJ) dco.hpath(), PATH_TYPE);
  342. if (ppath == (PATH*) NULL)
  343. return;
  344. ASSERTGDI(ppath->flType & PATHTYPE_KEEPMEM, "Path not kept?");
  345. // Load up accelerator values:
  346. cCurves = ppath->cCurves;
  347. fl = ppath->fl;
  348. if (bUseCP)
  349. {
  350. if (!dco.pdc->bValidPtfxCurrent())
  351. {
  352. // If the device space current position has been invalidated
  353. // (meaning that it's moved), always do a bMoveTo to the new
  354. // device space point:
  355. ASSERTGDI(dco.pdc->bValidPtlCurrent(), "Both CPs invalid?");
  356. EXFORMOBJ exo(dco, WORLD_TO_DEVICE);
  357. exo.bXformRound(&dco.ptlCurrent(), &dco.ptfxCurrent(), 1);
  358. dco.pdc->vValidatePtfxCurrent();
  359. bMoveTo(&dco.ptfxCurrent());
  360. }
  361. else
  362. {
  363. // See if what we think is the current position matches the DC's
  364. // value (this code will be used when there is a path bracket
  365. // and the path is being added to for the first time):
  366. POINTFIX ptfx = ptfxGetCurrent();
  367. if (dco.ptfxCurrent().x != ptfx.x ||
  368. dco.ptfxCurrent().y != ptfx.y)
  369. bMoveTo(&dco.ptfxCurrent());
  370. }
  371. }
  372. }
  373. }
  374. /******************************Public*Routine******************************\
  375. * PATHSTACKOBJ::~PATHSTACKOBJ()
  376. *
  377. * Deletes the path if it isn't the DC path.
  378. *
  379. * History:
  380. * 22-Mar-1992 -by- J. Andrew Goossen [andrewgo]
  381. * Wrote it.
  382. \**************************************************************************/
  383. PATHSTACKOBJ::~PATHSTACKOBJ()
  384. {
  385. // If we ran out of memory allocating blocks, we would have deleted the path,
  386. // in which case ppath may be NULL:
  387. if (ppath != (PATH*) NULL)
  388. {
  389. ASSERTGDI(ppath->flType == PATHTYPE_KEEPMEM ||
  390. ppath->flType == PATHTYPE_STACK, "Unexpected path type");
  391. if (ppath->flType & PATHTYPE_STACK)
  392. {
  393. // Path was only temporary; free any additional blocks if there
  394. // are any:
  395. if (ppath->ppachain != (PATHALLOC*) NULL)
  396. vFreeBlocks();
  397. }
  398. else
  399. {
  400. // Path is a permanent path, so unlock object and save some
  401. // accelerator values:
  402. ppath->cCurves = cCurves;
  403. ppath->fl = fl;
  404. DEC_SHARE_REF_CNT(ppath);
  405. }
  406. }
  407. }
  408. /******************************Public*Routine******************************\
  409. * RECTANGLEPATHOBJ::vInit(prcfx, bClockwise)
  410. *
  411. * Initializes the path with a single rectangle. Should probably only ever
  412. * be called from Rectangle.
  413. *
  414. * History:
  415. * 13-Dec-1992 -by- J. Andrew Goossen [andrewgo]
  416. * Wrote it.
  417. \**************************************************************************/
  418. VOID RECTANGLEPATHOBJ::vInit(
  419. RECTL* prcl, // Must be well-ordered
  420. BOOL bClockwise) // Direction rectangle is to be drawn
  421. {
  422. prRect.pr.pprnext = (PATHRECORD*) NULL;
  423. prRect.pr.pprprev = (PATHRECORD*) NULL;
  424. prRect.pr.flags = (PD_BEGINSUBPATH | PD_ENDSUBPATH |
  425. PD_RESETSTYLE | PD_CLOSEFIGURE);
  426. prRect.pr.count = 4;
  427. path.pprfirst = &prRect.pr;
  428. path.pprlast = &prRect.pr;
  429. path.flags = 0;
  430. ppath = &path;
  431. cCurves = 4;
  432. fl = 0;
  433. // Initialize PATHRECORD variables. When drawing in the counter-
  434. // clockwise direction, we draw the vertices in the following order
  435. // (this must match the EBOX constructor):
  436. //
  437. // 1 ___ 0
  438. // | |
  439. // |___|
  440. // 2 3
  441. path.rcfxBoundBox.xLeft = LTOFX(prcl->left);
  442. prRect.pr.aptfx[1].x = path.rcfxBoundBox.xLeft;
  443. prRect.pr.aptfx[2].x = path.rcfxBoundBox.xLeft;
  444. path.rcfxBoundBox.xRight = LTOFX(prcl->right);
  445. prRect.pr.aptfx[0].x = path.rcfxBoundBox.xRight;
  446. prRect.pr.aptfx[3].x = path.rcfxBoundBox.xRight;
  447. path.rcfxBoundBox.yTop = LTOFX(prcl->top);
  448. path.rcfxBoundBox.yBottom = LTOFX(prcl->bottom);
  449. if (!bClockwise)
  450. {
  451. prRect.pr.aptfx[0].y = path.rcfxBoundBox.yTop;
  452. prRect.pr.aptfx[1].y = path.rcfxBoundBox.yTop;
  453. prRect.pr.aptfx[2].y = path.rcfxBoundBox.yBottom;
  454. prRect.pr.aptfx[3].y = path.rcfxBoundBox.yBottom;
  455. }
  456. else
  457. {
  458. prRect.pr.aptfx[2].y = path.rcfxBoundBox.yTop;
  459. prRect.pr.aptfx[3].y = path.rcfxBoundBox.yTop;
  460. prRect.pr.aptfx[0].y = path.rcfxBoundBox.yBottom;
  461. prRect.pr.aptfx[1].y = path.rcfxBoundBox.yBottom;
  462. }
  463. }
  464. /******************************Public*Routine******************************\
  465. * EngCreatePath()
  466. *
  467. * DDI entry point to create a temporary path.
  468. *
  469. * History:
  470. * 17-Feb-1992 -by- J. Andrew Goossen
  471. * Wrote it.
  472. \**************************************************************************/
  473. PATHOBJ* EngCreatePath()
  474. {
  475. PATHMEMOBJ pmo;
  476. if (!pmo.bValid())
  477. return((PATHOBJ*) NULL);
  478. EPATHOBJ* pepo = (EPATHOBJ*) PALLOCMEM(sizeof(EPATHOBJ), 'tapG');
  479. if (pepo == (EPATHOBJ*) NULL)
  480. return((PATHOBJ*) NULL);
  481. pmo.vKeepIt();
  482. pepo->vLock(pmo.hpath());
  483. return(pepo);
  484. }
  485. /******************************Public*Routine******************************\
  486. * EngDeletePath()
  487. *
  488. * DDI entry point to delete a path allocated by EngCreatePath().
  489. *
  490. * History:
  491. * 17-Feb-1992 -by- J. Andrew Goossen
  492. * Wrote it.
  493. \**************************************************************************/
  494. VOID EngDeletePath(PATHOBJ* ppo)
  495. {
  496. if (ppo != (PATHOBJ*) NULL)
  497. {
  498. ((EPATHOBJ*) ppo)->vDelete();
  499. VFREEMEM((PVOID) ppo);
  500. }
  501. else
  502. WARNING("ERROR: EngDeletePath given NULL pointer");
  503. }
  504. /******************************Public*Routine******************************\
  505. * EPATHOBJ::vFreeBlocks()
  506. *
  507. * Frees all the heap blocks in a path.
  508. *
  509. * History:
  510. * 13-Sep-1991 -by- J. Andrew Goossen [andrewgo]
  511. * Wrote it.
  512. \**************************************************************************/
  513. VOID EPATHOBJ::vFreeBlocks()
  514. {
  515. ASSERTGDI(ppath != (PATH*) NULL, "Trying to free freed path!");
  516. // Free all the blocks in the path:
  517. PATHALLOC* ppa = ppath->ppachain;
  518. while (ppa != (PATHALLOC*) NULL)
  519. {
  520. PATHALLOC* ppasave = ppa->ppanext;
  521. // Don't free blocks that aren't PATHALLOCSIZE in size because
  522. // those were created on the stack:
  523. if (ppa->siztPathAlloc == PATHALLOCSIZE)
  524. {
  525. ASSERTGDI(ppa->siztPathAlloc != PATHSTACKALLOCSIZE,
  526. "PATHALLOCSIZE and PATHSTACKALLOCSIZE can't be the same!");
  527. freepathalloc(ppa);
  528. }
  529. ppa = ppasave;
  530. }
  531. }
  532. /******************************Public*Routine******************************\
  533. * EPATHOBJ::vDelete()
  534. *
  535. * Delete the path and free the handle if there is one. It's polymorphic
  536. * and can handle path type EPATHOBJ or PATHMEMOBJ.
  537. *
  538. * It can't handle PATHSTACKOBJ's or journal paths.
  539. *
  540. * History:
  541. * 13-Sep-1991 -by- J. Andrew Goossen [andrewgo]
  542. * Wrote it.
  543. \**************************************************************************/
  544. VOID EPATHOBJ::vDelete()
  545. {
  546. if (ppath != (PATH*) NULL)
  547. {
  548. ASSERTGDI(!(ppath->flags & PATH_JOURNAL), "Can't delete journal path");
  549. // Free all the blocks in the path:
  550. vFreeBlocks();
  551. if (ppath->flType != PATHTYPE_STACK)
  552. {
  553. // Free the handle too (stack paths don't have handles):
  554. HmgFree((HOBJ) ppath->hGet());
  555. ppath = (PATH*) NULL; // Prevent destructors from doing anything
  556. }
  557. }
  558. }
  559. /******************************Public*Routine******************************\
  560. * EPATHOBJ::bClone(epo)
  561. *
  562. * Copy the specified path.
  563. *
  564. * History:
  565. * 22-Mar-1992 -by- J. Andrew Goossen [andrewgo]
  566. * Wrote it.
  567. \**************************************************************************/
  568. BOOL EPATHOBJ::bClone(EPATHOBJ& epo)
  569. {
  570. // First, copy path information:
  571. fl = epo.fl;
  572. cCurves = epo.cCurves;
  573. ppath->pprfirst = (PATHRECORD*) NULL;
  574. ppath->pprlast = (PATHRECORD*) NULL;
  575. ppath->rcfxBoundBox = epo.ppath->rcfxBoundBox;
  576. ppath->ptfxSubPathStart = epo.ppath->ptfxSubPathStart;
  577. ppath->flags = epo.ppath->flags;
  578. // Copy rest of path on a PATHRECORD by PATHRECORD basis:
  579. PATHRECORD* ppr = epo.ppath->pprfirst;
  580. PATHRECORD* pprPrev = (PATHRECORD*) NULL;
  581. PATHRECORD* pprNew;
  582. while (ppr != (PATHRECORD*) NULL)
  583. {
  584. FLONG fl = ppr->flags;
  585. POINTFIX* pptfx = ppr->aptfx;
  586. COUNT cpt = ppr->count;
  587. COUNT cptMax;
  588. while (cpt > 0)
  589. {
  590. if (!newpathrec(&pprNew,&cptMax,cpt))
  591. return(FALSE);
  592. pprNew->flags = fl;
  593. pprNew->pprprev = pprPrev;
  594. pprNew->pprnext = (PATHRECORD*) NULL;
  595. if (cpt <= cptMax)
  596. pprNew->count = cpt;
  597. else
  598. {
  599. // Have to copy this PATHRECORD into two separate PATHRECORDs,
  600. // so adjust the count and clean up the flags:
  601. // Adjust cptMax for Beziers.
  602. if (fl & PD_BEZIERS)
  603. {
  604. if (fl & PD_BEGINSUBPATH)
  605. cptMax -= (cptMax-1) % 3;
  606. else
  607. cptMax -= cptMax % 3;
  608. }
  609. pprNew->count = cptMax;
  610. pprNew->flags &= ~(PD_ENDSUBPATH | PD_CLOSEFIGURE);
  611. fl &= ~(PD_BEGINSUBPATH | PD_RESETSTYLE);
  612. }
  613. ppath->pprlast = pprNew;
  614. if (pprPrev == (PATHRECORD*) NULL)
  615. ppath->pprfirst = pprNew;
  616. else
  617. pprPrev->pprnext = pprNew;
  618. RtlCopyMemory(pprNew->aptfx,
  619. pptfx,
  620. (SIZE_T) pprNew->count * sizeof(POINTFIX));
  621. pptfx += pprNew->count;
  622. cpt -= pprNew->count;
  623. // Adjust the PATHALLOC record:
  624. ppath->ppachain->pprfreestart = NEXTPATHREC(pprNew);
  625. pprPrev = pprNew;
  626. }
  627. ppr = ppr->pprnext;
  628. }
  629. return(TRUE);
  630. }
  631. /******************************Public*Routine******************************\
  632. * EPATHOBJ::cjSize(epo)
  633. *
  634. * Compute the size needed if a single PATHALLOC was to hold the entire
  635. * path.
  636. *
  637. * History:
  638. * 20-May-1992 -by- Paul Butzi
  639. * Wrote it.
  640. \**************************************************************************/
  641. ULONGSIZE_T EPATHOBJ::cjSize()
  642. {
  643. ULONGSIZE_T cjRV = 0;
  644. // Run down the path, adding up the sizes of the pathrecords.
  645. PATHRECORD* ppr = ppath->pprfirst;
  646. while (ppr != (PATHRECORD*) NULL)
  647. {
  648. cjRV += offsetof(PATHRECORD, aptfx)
  649. + (ULONGSIZE_T)ppr->count * sizeof(POINTFIX);
  650. ppr = ppr->pprnext;
  651. }
  652. return(cjRV);
  653. }
  654. /******************************Member*Function*****************************\
  655. * ULONG EPATHOBJ::cTotalCurves()
  656. *
  657. * Figure out the number of curves in the path for the path's cCurves
  658. * field.
  659. *
  660. * History:
  661. * 6-Apr-1992 -by- J. Andrew Goossen [andrewgo]
  662. * Wrote it.
  663. \**************************************************************************/
  664. ULONG EPATHOBJ::cTotalCurves()
  665. {
  666. ULONG count = 0;
  667. for (PATHRECORD *ppr = ppath->pprfirst;
  668. ppr != (PPATHREC) NULL;
  669. ppr = ppr->pprnext)
  670. {
  671. if (ppr->flags & PD_CLOSEFIGURE)
  672. count++;
  673. if (ppr->flags & PD_BEZIERS)
  674. count += ppr->count / 3;
  675. else
  676. {
  677. count += ppr->count;
  678. if (ppr->flags & PD_BEGINSUBPATH)
  679. count--;
  680. }
  681. }
  682. return(count);
  683. }
  684. /******************************Member*Function*****************************\
  685. * ULONG EPATHOBJ::cTotalPts()
  686. *
  687. * Figure out the number of control points in a path.
  688. *
  689. * History:
  690. * 20-Feb-1991 -by- Wendy Wu [wendywu]
  691. * Wrote it.
  692. \**************************************************************************/
  693. ULONG EPATHOBJ::cTotalPts()
  694. {
  695. ULONG count = 0;
  696. for (PATHRECORD *ppr = ppath->pprfirst;
  697. ppr != (PPATHREC) NULL;
  698. ppr = ppr->pprnext)
  699. {
  700. count += ppr->count;
  701. }
  702. return(count);
  703. }
  704. /******************************Public*Routine******************************\
  705. * EPATHOBJ::bAppend (ppoNew,pptfxDelta) *
  706. * *
  707. * Appends an offset version of the given path (ppoNew) to the target path. *
  708. * *
  709. * Wed 17-Jun-1992 00:21:57 -by- Charles Whitmer [chuckwh] *
  710. * Wrote it. *
  711. \**************************************************************************/
  712. BOOL EPATHOBJ::bAppend(EPATHOBJ *ppoNew,POINTFIX *pptfxDelta)
  713. {
  714. PATHDATAL pd; // Needed to call growlastrec and createrec.
  715. PATHRECORD *ppr; // For enumeration.
  716. POINTFIX ptfx;
  717. for
  718. (
  719. ppr = ppoNew->ppath->pprfirst;
  720. ppr != (PPATHREC) NULL;
  721. ppr = ppr->pprnext
  722. )
  723. {
  724. pd.count = ppr->count;
  725. pd.flags = ppr->flags & PD_BEZIERS;
  726. pd.pptl = (POINTL *) &(ppr->aptfx[0]);
  727. // Call bMoveTo if we are starting a new subpath.
  728. if (ppr->flags & PD_BEGINSUBPATH)
  729. {
  730. ptfx.x = ppr->aptfx[0].x + pptfxDelta->x;
  731. ptfx.y = ppr->aptfx[0].y + pptfxDelta->y;
  732. bMoveTo(XFORMNULL,(POINTL *) &ptfx);
  733. pd.count--;
  734. pd.pptl++;
  735. }
  736. // Copy all the control points.
  737. while (pd.count > 0)
  738. {
  739. if (!createrec(XFORMNULL,&pd,pptfxDelta))
  740. return(FALSE);
  741. }
  742. // Set the CloseFigure flag to close it.
  743. if (ppr->flags & PD_CLOSEFIGURE)
  744. {
  745. ppath->pprlast->flags |= PD_CLOSEFIGURE;
  746. // Indicate that we are starting a new subpath:
  747. ppath->flags |= PD_BEGINSUBPATH;
  748. }
  749. }
  750. // Always reset the PO_ELLIPSE flag (the Ellipse call will set it
  751. // appropriately) and turn on the PO_BEZIERS flag if we added Beziers:
  752. fl &= ~PO_ELLIPSE;
  753. if (ppoNew->fl & PO_BEZIERS)
  754. fl |= PO_BEZIERS;
  755. // Add in the count of curves.
  756. cCurves += ppoNew->cCurves;
  757. return(TRUE);
  758. }
  759. /******************************Public*Routine******************************\
  760. * vOffsetPoints (pptfxDest,pptfxSrc,c,dx,dy) *
  761. * *
  762. * A simple routine that moves points while offsetting them. This is much *
  763. * faster than calling the transform code! *
  764. * *
  765. * Wed 17-Jun-1992 00:54:32 -by- Charles Whitmer [chuckwh] *
  766. * Wrote it. *
  767. \**************************************************************************/
  768. VOID vOffsetPoints
  769. (
  770. POINTFIX *pptfxDest,
  771. POINTFIX *pptfxSrc,
  772. UINT c,
  773. LONG dx,
  774. LONG dy
  775. )
  776. {
  777. while (c--)
  778. {
  779. pptfxDest->x = pptfxSrc->x + dx;
  780. pptfxDest->y = pptfxSrc->y + dy;
  781. pptfxDest++;
  782. pptfxSrc++;
  783. }
  784. }
  785. /******************************Public*Routine******************************\
  786. * EPATHOBJ::addpts()
  787. *
  788. * We add the specified points to the path. If possible, we tack the
  789. * points onto the last record ('grow the last record') otherwise we
  790. * create one or more records and stash the points in them.
  791. *
  792. * History:
  793. * 1-Oct-1990 -by- Paul Butzi [paulb]
  794. * Wrote it.
  795. \**************************************************************************/
  796. BOOL EPATHOBJ::addpoints(EXFORMOBJ *pxfo, PATHDATAL *ppd)
  797. {
  798. // No points always succeeds!
  799. if (ppd->count == 0)
  800. return(TRUE);
  801. // Try to add to end of last record. Can't do it if:
  802. //
  803. // - beginsubpath flag set in ppath (must be new record)
  804. //
  805. // growlastrec may do nothing, in which case we just
  806. // fall thru and add records.
  807. if ((ppath->flags & PD_BEGINSUBPATH) == 0)
  808. growlastrec(pxfo,ppd,(POINTFIX *) NULL);
  809. // Now add new records until we're done. Note that if BEGINSUBPATH is
  810. // set in the path, it means that we must add in the current position
  811. // before the points in the ppd; this is handled by createrec.
  812. while (ppd->count > 0)
  813. {
  814. if (!createrec(pxfo,ppd,(POINTFIX *) NULL)) // Adds a new pathalloc
  815. return(FALSE); // when needed.
  816. }
  817. // Always reset the PO_ELLIPSE flag (the Ellipse call will set it
  818. // appropriately) and turn on the PO_BEZIERS flag if we added Beziers:
  819. fl &= ~PO_ELLIPSE;
  820. if (ppd->flags & PD_BEZIERS)
  821. fl |= PO_BEZIERS;
  822. return(TRUE);
  823. }
  824. /******************************Public*Routine******************************\
  825. * EPATHOBJ::growlastrec() *
  826. * *
  827. * growlastrec - add data to the already existing last record in path. *
  828. * *
  829. * Note: *
  830. * If the PD_BEGINSUBPATH flag is set in the path header, then *
  831. * it means that the current position has *not* been put in the path, *
  832. * and it must be added to the path before we begin adding more *
  833. * control points. Note that this cannot happen in this routine, *
  834. * since we cannot both start a new path and extend an existing *
  835. * record at the same time. *
  836. * *
  837. * History: *
  838. * Wed 17-Jun-1992 00:15:06 -by- Charles Whitmer [chuckwh] *
  839. * Added the pptfxDelta parameter. *
  840. * *
  841. * 1-Oct-1990 -by- Paul Butzi [paulb] *
  842. * Wrote it. *
  843. \**************************************************************************/
  844. void EPATHOBJ::growlastrec(EXFORMOBJ *pxfo,PATHDATAL *ppd,POINTFIX *pptfxDelta)
  845. {
  846. PATHALLOC *ppa = ppath->ppachain;
  847. PATHRECORD *ppr = ppath->pprlast;
  848. // Check conditions for adding to last record
  849. //
  850. // 1. there must be a last record
  851. // 2. there must be an existing pathalloc
  852. // 3. the path data to be added must not start a new
  853. // sub-path
  854. // 4. the other flags must match (bezier, etc.)
  855. if ( ppr == (PPATHREC) NULL )
  856. return;
  857. if ( ppa == (PATHALLOC*) NULL )
  858. return;
  859. if (ppd->flags !=
  860. (ppr->flags & ~(PD_BEGINSUBPATH | PD_ENDSUBPATH)))
  861. {
  862. return;
  863. }
  864. // Figure out how much we can expand the current last record.
  865. //
  866. // NOTE: pointer casts are below are safe, since both the
  867. // start and end of a pathalloc block are aligned on
  868. // the most restrictive boundary. These alignment points
  869. // are the *only* safe points to cast between types, since
  870. // only there are we guaranteed to be safely aligned.
  871. POINTFIX *oldend = &(ppr->aptfx[ppr->count]);
  872. POINTFIX *newend = (POINTFIX *)((char *)ppa + ppa->siztPathAlloc);
  873. ULONGSIZE_T maxadd = 0;
  874. if ( newend > oldend )
  875. {
  876. //Sundown truncation
  877. ASSERT4GB((ULONGLONG)(newend - oldend));
  878. maxadd = (ULONG)(newend - oldend);
  879. }
  880. // Don't add more than we need!
  881. if ( maxadd > ppd->count )
  882. maxadd = (ULONGSIZE_T)ppd->count;
  883. // We must add a multiple of 3 points for Beziers.
  884. if (ppd->flags & PD_BEZIERS)
  885. maxadd -= maxadd % 3;
  886. if (maxadd == 0)
  887. return;
  888. // Copy the points:
  889. if (pptfxDelta != (POINTFIX *) NULL)
  890. {
  891. vOffsetPoints(
  892. &(ppr->aptfx[ppr->count]),
  893. (POINTFIX *) ppd->pptl,
  894. maxadd,
  895. pptfxDelta->x,
  896. pptfxDelta->y
  897. );
  898. }
  899. else if (pxfo == XFORMNULL)
  900. RtlCopyMemory(&(ppr->aptfx[ppr->count]),
  901. ppd->pptl,
  902. (SIZE_T) maxadd * sizeof(POINTFIX));
  903. else
  904. pxfo->bXformRound(ppd->pptl, &(ppr->aptfx[ppr->count]), maxadd);
  905. ASSERTGDI((CHAR*) &ppr->aptfx[ppr->count + maxadd] <=
  906. (CHAR*) ppa + ppa->siztPathAlloc,
  907. "Overwrote bounds!");
  908. ASSERTGDI((CHAR*) &(ppr->aptfx[ppr->count]) > (CHAR*) ppa, "Bad bound");
  909. // Adjust the bounding box:
  910. register POINTFIX *pptfx = &ppr->aptfx[ppr->count];
  911. for ( register ULONG i = 0; i < maxadd; i += 1, pptfx += 1 )
  912. {
  913. ((ERECTFX*) &ppath->rcfxBoundBox)->vInclude(*pptfx);
  914. }
  915. // adjust the path record
  916. ppr->count += maxadd;
  917. // adjust the pathalloc record
  918. ppa->pprfreestart = NEXTPATHREC(ppr);
  919. ASSERTGDI((CHAR*) ppa->pprfreestart <= (CHAR*) ppa + ppa->siztPathAlloc,
  920. "Weird freestart");
  921. // adjust the pathdata record
  922. ppd->count -= maxadd;
  923. ppd->pptl += maxadd;
  924. }
  925. /******************************Public*Routine******************************\
  926. * EPATHOBJ::reinit() *
  927. * Reinitialize an existing path so that it becomes an empty path. *
  928. * This is useful in error cases when the path cannot be restored, *
  929. * but also cannot be deleted (because the handle is in a DC). See *
  930. * bug 177612 for details. *
  931. * *
  932. * History: *
  933. * *
  934. * 11-Aug-1998 -by- Ori Gershony [orig] *
  935. * Wrote it. *
  936. \**************************************************************************/
  937. VOID EPATHOBJ::reinit()
  938. {
  939. if (ppath != (PATH *) NULL)
  940. {
  941. ASSERTGDI(!(ppath->flags & PATH_JOURNAL), "Can't delete journal path");
  942. // Free all the blocks in the path:
  943. vFreeBlocks();
  944. // And reinitialize the path data
  945. ppath->ppachain = (PATHALLOC*) NULL;
  946. ppath->pprfirst = (PATHRECORD*) NULL;
  947. ppath->pprlast = (PATHRECORD*) NULL;
  948. ppath->rcfxBoundBox.xLeft = 0;
  949. ppath->rcfxBoundBox.xRight = 0;
  950. ppath->rcfxBoundBox.yTop = 0;
  951. ppath->rcfxBoundBox.yBottom = 0;
  952. ppath->ptfxSubPathStart.x = 0;
  953. ppath->ptfxSubPathStart.y = 0;
  954. ppath->flags = PD_BEGINSUBPATH | PD_ENDSUBPATH;
  955. ppath->pprEnum = (PATHRECORD *) NULL;
  956. // Don't clear flType - it's used by the destructor to determine
  957. // how we allocated the memory and hence how to dispose of it correctly.
  958. //ppath->flType = 0;
  959. ppath->fl = 0;
  960. ppath->cCurves = 0;
  961. // don't need to initialize ppath->cle, because it will be initialized by vEnumPathStart
  962. fl = 0;
  963. cCurves = 0;
  964. }
  965. }
  966. /******************************Public*Routine******************************\
  967. * EPATHOBJ::createrec() *
  968. * *
  969. * Add a new path record to the path, taking control points and flags *
  970. * from the pathdata struct passed. We try to fit things in the *
  971. * last pathdata block if we can sensibly do it, but otherwise we *
  972. * allocate a new pathdata and tack it on the end. Note that a pathdata *
  973. * may not be filled completely if it isn't convenient. *
  974. * *
  975. * History: *
  976. * Wed 17-Jun-1992 00:15:06 -by- Charles Whitmer [chuckwh] *
  977. * Added the pptfxDelta parameter. *
  978. * *
  979. * 1-Oct-1990 -by- Paul Butzi [paulb] *
  980. * Wrote it. *
  981. \**************************************************************************/
  982. BOOL EPATHOBJ::createrec(EXFORMOBJ *pxfo,PATHDATAL *ppd,POINTFIX *pptfxDelta)
  983. {
  984. PATHALLOC *ppa = ppath->ppachain;
  985. ULONGSIZE_T maxadd = 0; // # of pts we can fit into zero space
  986. if ( ppa != (PATHALLOC*) NULL )
  987. {
  988. // We have a current pathalloc, see how much will fit.
  989. // Computation done into temps to avoid compiler assertion!
  990. POINTFIX *start = &(ppa->pprfreestart->aptfx[0]);
  991. POINTFIX *end = (POINTFIX *)((char *)ppa + ppa->siztPathAlloc);
  992. if (end > start)
  993. //Sundown safe truncation
  994. maxadd =(ULONG)(end - start);
  995. }
  996. // Decide if we need to enter the current position before adding
  997. // the points in the pathdata. cPoints gets the count of how many
  998. // we add; either zero or one.
  999. COUNT cPoints = (ppath->flags & PD_BEGINSUBPATH) ? 1 : 0;
  1000. // We must add a multiple of 3 points for Beziers.
  1001. if ((ppd->flags & PD_BEZIERS) && (maxadd > 0))
  1002. maxadd -= (maxadd - (ULONGSIZE_T)cPoints) % 3;
  1003. // At this point, 'maxadd' indicates how many points we could get
  1004. // into a record if we added it in the current pathalloc.
  1005. // Now we can decide if we need a new pathalloc
  1006. if ( (maxadd < (cPoints + ppd->count)) && (maxadd < PATHALLOCTHRESHOLD) )
  1007. {
  1008. // allocate a new pathalloc, link it into path
  1009. ppa = newpathalloc();
  1010. if (ppa == (PATHALLOC*) NULL)
  1011. {
  1012. // We're out of memory.
  1013. //
  1014. // At this point, our PATHALLOC chain is intact (so we can safely
  1015. // traverse the chain to free the blocks), but the rest of the path
  1016. // data can be corrupt (it's not worth trying to recover in this
  1017. // case), so we can't allow the path to be used anymore.
  1018. //
  1019. // But paths are persistent between API calls when there is an
  1020. // active path; we have to mark that the path is invalid, and not
  1021. // let any subsequent APIs try to do any operation on it other than
  1022. // to delete it.
  1023. SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
  1024. // We free all blocks and re-initialize the path. We don't want to delete
  1025. // it here because the handle might be stored in a DC (see bug 177612)
  1026. reinit();
  1027. return(FALSE);
  1028. }
  1029. ppa->ppanext = ppath->ppachain;
  1030. ppath->ppachain = ppa;
  1031. // adjust maxadd
  1032. ASSERTGDI((CHAR*) ppa + ppa->siztPathAlloc > (CHAR*) ppa->pprfreestart,
  1033. "Invalid pprfreeestart");
  1034. //Sundown truncation
  1035. ASSERT4GB((ULONGLONG)(((char *)ppa + ppa->siztPathAlloc) -
  1036. (char *)ppa->pprfreestart));
  1037. ULONGSIZE_T numbytes = (ULONG)(((char *)ppa + ppa->siztPathAlloc) -
  1038. (char *)ppa->pprfreestart);
  1039. maxadd = (ULONGSIZE_T)(numbytes - offsetof(PATHRECORD, aptfx)) /
  1040. sizeof(POINTFIX);
  1041. // We must add a multiple of 3 points for Beziers.
  1042. if (ppd->flags & PD_BEZIERS)
  1043. maxadd -= (maxadd - (ULONGSIZE_T)cPoints) % 3;
  1044. }
  1045. // Don't add more points than we need:
  1046. if ( maxadd > (ppd->count + cPoints) )
  1047. maxadd = (ULONGSIZE_T)(ppd->count + cPoints);
  1048. // Create new pathrec header:
  1049. PATHRECORD *ppr = ppa->pprfreestart;
  1050. ppr->flags = ppd->flags | PD_ENDSUBPATH;
  1051. ppr->count = maxadd;
  1052. ppr->pprnext = (PPATHREC)NULL;
  1053. ppr->pprprev = ppath->pprlast;
  1054. if ( cPoints == 0 )
  1055. {
  1056. // This new record is a continuation of the old one, so clear
  1057. // the previous record's end-subpath flag
  1058. if (ppath->pprlast != (PPATHREC) NULL)
  1059. ppath->pprlast->flags &= ~PD_ENDSUBPATH;
  1060. }
  1061. else
  1062. {
  1063. // This is a new sub-path, so add in the current point
  1064. *(ppr->aptfx) = ppath->ptfxSubPathStart;
  1065. maxadd -= 1;
  1066. ppr->flags |= (ppath->flags & (PD_BEGINSUBPATH | PD_RESETSTYLE));
  1067. ppath->flags &= ~(PD_BEGINSUBPATH | PD_RESETSTYLE);;
  1068. }
  1069. // Copy in the points:
  1070. if (pptfxDelta != (POINTFIX *) NULL)
  1071. {
  1072. vOffsetPoints(
  1073. &(ppr->aptfx[cPoints]),
  1074. (POINTFIX *) ppd->pptl,
  1075. maxadd,
  1076. pptfxDelta->x,
  1077. pptfxDelta->y
  1078. );
  1079. }
  1080. else if (pxfo == XFORMNULL)
  1081. RtlCopyMemory(&(ppr->aptfx[cPoints]),
  1082. ppd->pptl,
  1083. maxadd * sizeof(POINTFIX));
  1084. else
  1085. pxfo->bXformRound(ppd->pptl, &(ppr->aptfx[cPoints]), maxadd);
  1086. ASSERTGDI((CHAR*) &ppr->aptfx[cPoints + maxadd] <=
  1087. (CHAR*) ppa + ppa->siztPathAlloc,
  1088. "Overwrote bounds!");
  1089. // Adjust the bounding box:
  1090. register POINTFIX *pptfx = ppr->aptfx;
  1091. if ( ppath->pprlast == (PPATHREC) NULL )
  1092. {
  1093. // if path was empty, set the bound box to a single pt.
  1094. ppath->rcfxBoundBox.xLeft = ppath->rcfxBoundBox.xRight = pptfx->x;
  1095. ppath->rcfxBoundBox.yTop = ppath->rcfxBoundBox.yBottom = pptfx->y;
  1096. }
  1097. for ( register ULONG i = 0; i < maxadd + cPoints; i += 1, pptfx += 1 )
  1098. {
  1099. ((ERECTFX*) &ppath->rcfxBoundBox)->vInclude(*pptfx);
  1100. }
  1101. // Now that we know we have succeeded, add the pathrec to the path chain
  1102. // Prior to doing this, we can back out it's as if we hadn't changed anything.
  1103. if (ppath->pprlast == (PPATHREC) NULL )
  1104. {
  1105. // first pathrec in path!
  1106. ppath->pprfirst = ppath->pprlast = ppr;
  1107. }
  1108. else
  1109. {
  1110. // add to pathrec chain
  1111. ppath->pprlast->pprnext = ppr;
  1112. ppath->pprlast = ppr;
  1113. }
  1114. // Adjust the pathalloc record:
  1115. ppa->pprfreestart = NEXTPATHREC(ppr);
  1116. ASSERTGDI((CHAR*) ppa->pprfreestart <= (CHAR*) ppa + ppa->siztPathAlloc,
  1117. "Weird freestart");
  1118. // Adjust a bunch of state:
  1119. ppd->count -= maxadd;
  1120. ppd->pptl += maxadd;
  1121. ppd->flags &= ~(PD_BEGINSUBPATH | PD_RESETSTYLE);
  1122. return(TRUE);
  1123. }
  1124. /******************************Public*Routine******************************\
  1125. * PATHOBJ_vGetBounds(ppo, prcfx)
  1126. *
  1127. * Gets the path bounds.
  1128. *
  1129. * History:
  1130. * 19-Aug-1991 -by- J. Andrew Goossen [andrewgo]
  1131. * Wrote it.
  1132. \**************************************************************************/
  1133. VOID PATHOBJ_vGetBounds(PATHOBJ* ppo, PRECTFX prcfx)
  1134. {
  1135. *prcfx = ((EPATHOBJ *) ppo)->rcfxBoundBox();
  1136. // Make the box lower-right exclusive if not empty (i.e., not {0,0,0,0}):
  1137. if (prcfx->yTop || prcfx->xLeft || prcfx->yBottom || prcfx->xRight)
  1138. {
  1139. prcfx->yBottom += 1;
  1140. prcfx->xRight += 1;
  1141. }
  1142. }
  1143. VOID PATHOBJ_vEnumStart(PATHOBJ* ppo)
  1144. {
  1145. ((EPATHOBJ*) ppo)->vEnumStart();
  1146. }
  1147. /******************************Public*Routine******************************\
  1148. * EPATHOBJ::bEnum()
  1149. *
  1150. * Enumerate the path
  1151. *
  1152. * History:
  1153. * 19-Oct-1990 -by- Paul Butzi [paulb]
  1154. * Wrote it.
  1155. \**************************************************************************/
  1156. BOOL EPATHOBJ::bEnum(PATHDATA *ppd)
  1157. {
  1158. return(PATHOBJ_bEnum(this, ppd));
  1159. }
  1160. BOOL PATHOBJ_bEnum(PATHOBJ* ppo, PATHDATA* ppd)
  1161. {
  1162. PATH* ppath;
  1163. LONG i;
  1164. PATHRECORD* ppr;
  1165. POINTFIX* pptfx;
  1166. ppath = ((EPATHOBJ*) ppo)->ppath;
  1167. // Detect case where he didn't call bStartEnum()
  1168. if (ppath->pprEnum == NULL)
  1169. {
  1170. if (ppath->pprfirst == NULL)
  1171. {
  1172. // It's an empty path:
  1173. ppd->count = 0;
  1174. ppd->flags = 0;
  1175. ppd->pptfx = (PPOINTFIX) NULL;
  1176. return(FALSE);
  1177. }
  1178. else
  1179. {
  1180. // Start again at first record:
  1181. ppath->pprEnum = ppath->pprfirst;
  1182. }
  1183. }
  1184. ppr = ppath->pprEnum;
  1185. ppd->count = ppr->count;
  1186. ppd->flags = ppr->flags;
  1187. ppd->pptfx = ppr->aptfx;
  1188. ppath->pprEnum = ppr->pprnext;
  1189. // By setting PO_ENUM_AS_INTEGERS in the PATHOBJ before calling bEnum,
  1190. // the driver signals that it saw the PO_ALL_INTEGERS flag and wants
  1191. // the coordinates as integers instead of fixed point. That's great
  1192. // because if PO_ALL_INTEGERS was set, that means we recorded the path
  1193. // in integer coordinates.
  1194. if ((ppo->fl & (PO_ALL_INTEGERS | PO_ENUM_AS_INTEGERS)) == PO_ALL_INTEGERS)
  1195. {
  1196. // Uh oh, the driver didn't ask for integer coordinates. So we'll
  1197. // simply convert the path to fixed coordinates and remove the
  1198. // PO_ALL_INTEGERS flag:
  1199. ppo->fl &= ~PO_ALL_INTEGERS;
  1200. for (ppr = ppath->pprfirst; ppr != NULL; ppr = ppr->pprnext)
  1201. {
  1202. for (pptfx = ppr->aptfx, i = ppr->count; i != 0; pptfx++, i--)
  1203. {
  1204. pptfx->x <<= 4;
  1205. pptfx->y <<= 4;
  1206. }
  1207. }
  1208. }
  1209. if ((ppo->fl & (PO_ALL_INTEGERS | PO_ENUM_AS_INTEGERS)) == PO_ENUM_AS_INTEGERS)
  1210. {
  1211. // The driver set PO_ENUM_AS_INTEGERS when PO_ALL_INTEGERS wasn't
  1212. // set. Tsk, tsk.
  1213. RIP("Driver mustn't set PO_ENUM_AS_INTEGERS unless PO_ALL_INTEGERS was set by GDI");
  1214. }
  1215. return(ppath->pprEnum != (PPATHREC) NULL);
  1216. }
  1217. /******************************Public*Routine******************************\
  1218. * EPATHOBJ::vOffset()
  1219. *
  1220. * Enumerate the path
  1221. *
  1222. * History:
  1223. * 29-Oct-1990 -by- Paul Butzi [paulb]
  1224. * Wrote it.
  1225. \**************************************************************************/
  1226. VOID EPATHOBJ::vOffset(EPOINTL &eptl)
  1227. {
  1228. LONG xOffset = LTOFX(eptl.x);
  1229. LONG yOffset = LTOFX(eptl.y);
  1230. RECTFX *prcfxBoundBox = &ppath->rcfxBoundBox;
  1231. prcfxBoundBox->xLeft += xOffset;
  1232. prcfxBoundBox->xRight += xOffset;
  1233. prcfxBoundBox->yTop += yOffset;
  1234. prcfxBoundBox->yBottom += yOffset;
  1235. if (fl & PO_ALL_INTEGERS)
  1236. {
  1237. // If 'PO_ALL_INTEGERS' is set, the path has been recorded as integers
  1238. // instead of 28.4 fixed point. So convert the offsets back to integers
  1239. // again:
  1240. xOffset = FXTOL(xOffset);
  1241. yOffset = FXTOL(yOffset);
  1242. }
  1243. register PATHRECORD* ppr;
  1244. for (ppr = ppath->pprfirst; ppr != (PPATHREC) NULL; ppr = ppr->pprnext)
  1245. {
  1246. for (register EPOINTFIX *peptfx = (EPOINTFIX *)ppr->aptfx;
  1247. peptfx < (EPOINTFIX *)&ppr->aptfx[ppr->count];
  1248. peptfx += 1)
  1249. {
  1250. peptfx->x += xOffset;
  1251. peptfx->y += yOffset;
  1252. }
  1253. }
  1254. }
  1255. /******************************Public*Routine******************************\
  1256. * EPATHOBJ::bMoveTo()
  1257. *
  1258. * Set the current position in the path. Note that the following effects
  1259. * also occur:
  1260. * - last existing record in path is marked as ending the subpath
  1261. * - flag is set indicating that next path record will start a new
  1262. * subpath.
  1263. *
  1264. * History:
  1265. * 1-Oct-1990 -by- Paul Butzi [paulb]
  1266. * Wrote it.
  1267. \**************************************************************************/
  1268. BOOL EPATHOBJ::bMoveTo(EXFORMOBJ *pxfo, PPOINTL pptl)
  1269. {
  1270. // we can fail if the driver got a previous out of memory error
  1271. if (!bValid())
  1272. return(FALSE);
  1273. if (pxfo == XFORMNULL)
  1274. ppath->ptfxSubPathStart = *((PPOINTFIX) pptl);
  1275. else
  1276. {
  1277. pxfo->bXformRound(pptl, &ppath->ptfxSubPathStart, 1);
  1278. }
  1279. ppath->flags |= (PD_BEGINSUBPATH | PD_RESETSTYLE);
  1280. return(TRUE);
  1281. }
  1282. BOOL PATHOBJ_bMoveTo(PATHOBJ* ppo, POINTFIX ptfx)
  1283. {
  1284. return(((EPATHOBJ*) ppo)->bMoveTo(XFORMNULL, (PPOINTL) &ptfx));
  1285. }
  1286. /******************************Public*Routine******************************\
  1287. * EPATHOBJ::bCloseFigure()
  1288. *
  1289. * close the current subpath in the path.
  1290. *
  1291. * History:
  1292. * 8-Nov-1990 -by- Paul Butzi [paulb]
  1293. * Wrote it.
  1294. \**************************************************************************/
  1295. BOOL EPATHOBJ::bCloseFigure()
  1296. {
  1297. // we can fail if the driver got a previous out of memory error
  1298. if (!bValid())
  1299. return(FALSE);
  1300. if (ppath->pprlast != (PATHRECORD*) NULL)
  1301. {
  1302. if (!(ppath->pprlast->flags & PD_CLOSEFIGURE))
  1303. {
  1304. ppath->pprlast->flags |= PD_CLOSEFIGURE;
  1305. cCurves++;
  1306. }
  1307. }
  1308. // Indicate that we are starting a new subpath:
  1309. ppath->flags |= PD_BEGINSUBPATH;
  1310. // We don't have to update ptfxSubPathStart because the current position
  1311. // after a CloseFigure is set to the sub-path start point.
  1312. return(TRUE);
  1313. }
  1314. BOOL PATHOBJ_bCloseFigure(PATHOBJ* ppo)
  1315. {
  1316. return(((EPATHOBJ*) ppo)->bCloseFigure());
  1317. }
  1318. /******************************Public*Routine******************************\
  1319. * EPATHOBJ::vCloseAllFigures()
  1320. *
  1321. * Closes any open figures in the path. Used for FillPath and
  1322. * StrokeAndFillPath.
  1323. *
  1324. * History:
  1325. * 17-Sep-1991 -by- J. Andrew Goossen [andrewgo]
  1326. * Wrote it.
  1327. \**************************************************************************/
  1328. VOID EPATHOBJ::vCloseAllFigures()
  1329. {
  1330. PPATHREC ppr = ppath->pprfirst;
  1331. while (ppr != (PPATHREC) NULL)
  1332. {
  1333. if (ppr->flags & PD_ENDSUBPATH)
  1334. {
  1335. if (!(ppr->flags & PD_CLOSEFIGURE))
  1336. {
  1337. ppr->flags |= PD_CLOSEFIGURE;
  1338. cCurves++;
  1339. }
  1340. }
  1341. ppr = ppr->pprnext;
  1342. }
  1343. }
  1344. /******************************Public*Routine******************************\
  1345. * EPATHOBJ::bPolyLineTo()
  1346. *
  1347. * Draw lines from the current position in the path thru the specified
  1348. * points. Sets the current position to the last specified point.
  1349. *
  1350. * History:
  1351. * 1-Oct-1990 -by- Paul Butzi [paulb]
  1352. * Wrote it.
  1353. \**************************************************************************/
  1354. BOOL EPATHOBJ::bPolyLineTo(EXFORMOBJ *pxfo, PPOINTL pptl, ULONG cPts)
  1355. {
  1356. // we can fail if the driver got a previous out of memory error
  1357. if (!bValid())
  1358. return(FALSE);
  1359. PATHDATAL pd;
  1360. BOOL bRet;
  1361. pd.flags = 0;
  1362. pd.pptl = pptl;
  1363. pd.count = cPts;
  1364. bRet = addpoints(pxfo, &pd);
  1365. if (bRet)
  1366. cCurves += cPts;
  1367. return(bRet);
  1368. }
  1369. BOOL PATHOBJ_bPolyLineTo(PATHOBJ* ppo, PPOINTFIX pptfx, ULONG cptfx)
  1370. {
  1371. // NULL transform indicates that the points are already in device space:
  1372. return(((EPATHOBJ*) ppo)->bPolyLineTo(XFORMNULL,
  1373. (PPOINTL) pptfx,
  1374. cptfx));
  1375. }
  1376. /******************************Public*Routine******************************\
  1377. * EPATHOBJ::bPolyBezierTo()
  1378. *
  1379. * Draw curves from the current position in the path thru the specified
  1380. * points. Sets the current position to the last specified point.
  1381. *
  1382. * History:
  1383. * 1-Oct-1990 -by- Paul Butzi [paulb]
  1384. * Wrote it.
  1385. \**************************************************************************/
  1386. BOOL EPATHOBJ::bPolyBezierTo(EXFORMOBJ *pxfo, PPOINTL pptl, ULONG cPts)
  1387. {
  1388. // we can fail if the driver got a previous out of memory error
  1389. if (!bValid())
  1390. return(FALSE);
  1391. PATHDATAL pd;
  1392. BOOL bRet;
  1393. ASSERTGDI(cPts % 3 == 0, "Weird number of Bezier points");
  1394. pd.flags = PD_BEZIERS;
  1395. pd.pptl = pptl;
  1396. pd.count = cPts;
  1397. bRet = addpoints(pxfo, &pd);
  1398. if (bRet)
  1399. cCurves += cPts / 3;
  1400. return(bRet);
  1401. }
  1402. BOOL PATHOBJ_bPolyBezierTo(PATHOBJ* ppo, PPOINTFIX pptfx, ULONG cptfx)
  1403. {
  1404. // NULL transform indicates that the points are already in device space:
  1405. return(((EPATHOBJ*) ppo)->bPolyBezierTo(XFORMNULL,
  1406. (PPOINTL) pptfx,
  1407. cptfx));
  1408. }
  1409. BOOL EPATHOBJ::bTextOutSimpleFill(
  1410. XDCOBJ& dco,
  1411. RFONTOBJ& rfo,
  1412. PDEVOBJ* pdo,
  1413. SURFACE* pSurf,
  1414. CLIPOBJ* pco,
  1415. BRUSHOBJ* pbo,
  1416. POINTL* pptlBrushOrg,
  1417. MIX mix,
  1418. FLONG flOptions)
  1419. {
  1420. BOOL bSem = FALSE, bRet;
  1421. ULONG fl = 0, numLinks = 0;
  1422. BOOL aFaceLink[UMPD_MAX_FONTFACELINK], *pFaceLink = aFaceLink;
  1423. //
  1424. // Release rfont semaphores, otherwise holding rfont semaphores can
  1425. // disable APC queue while calling to the user mode.
  1426. //
  1427. //
  1428. // WINBUG #214225 tessiew 10-27-2000 Blackcomb: re-visit the RFONT.hsemCace acquiring/releasing issue
  1429. // Need to revisit the font semaphore problem in Blackcomb
  1430. // It seems that a thread doesn't need to hold the font caching semaphore
  1431. // during the whole GreExtTextOutWLocked call.
  1432. //
  1433. if (dco.bPrinter() && dco.bUMPD() && rfo.bValid())
  1434. {
  1435. bSem = UMPDReleaseRFONTSem(rfo, NULL, &fl, &numLinks, &pFaceLink);
  1436. }
  1437. bRet = bSimpleFill(dco.flGraphicsCaps(),
  1438. pdo,
  1439. pSurf,
  1440. pco,
  1441. pbo,
  1442. pptlBrushOrg,
  1443. mix,
  1444. flOptions);
  1445. if (bSem)
  1446. {
  1447. UMPDAcquireRFONTSem(rfo, NULL, fl, numLinks, pFaceLink);
  1448. if (pFaceLink && pFaceLink != aFaceLink)
  1449. {
  1450. VFREEMEM(pFaceLink);
  1451. }
  1452. }
  1453. return bRet;
  1454. }
  1455. BOOL EPATHOBJ::bTextOutSimpleStroke1(
  1456. XDCOBJ& dco,
  1457. RFONTOBJ& rfo,
  1458. PDEVOBJ* plo,
  1459. SURFACE* pSurface,
  1460. CLIPOBJ* pco,
  1461. BRUSHOBJ* pbo,
  1462. POINTL* pptlBrushOrg,
  1463. MIX mix)
  1464. {
  1465. BOOL bSem = FALSE, bRet;
  1466. ULONG fl = 0, numLinks = 0;
  1467. BOOL aFaceLink[UMPD_MAX_FONTFACELINK], *pFaceLink = aFaceLink;
  1468. //
  1469. // Release rfont semaphores, otherwise holding rfont semaphores can
  1470. // disable APC queue while calling to the user mode.
  1471. //
  1472. //
  1473. // WINBUG #214225 tessiew 10-27-2000 Blackcomb: re-visit the RFONT.hsemCace acquiring/releasing issue
  1474. // Need to revisit the font semaphore problem in Blackcomb
  1475. // It seems that a thread doesn't need to hold the font caching semaphore
  1476. // during the whole GreExtTextOutWLocked call.
  1477. //
  1478. if (dco.bPrinter() && dco.bUMPD() && rfo.bValid())
  1479. {
  1480. bSem = UMPDReleaseRFONTSem(rfo, NULL, &fl, &numLinks, &pFaceLink);
  1481. }
  1482. LINEATTRS laTmp = glaSimpleStroke.la;
  1483. bRet = bSimpleStroke(dco.flGraphicsCaps(),
  1484. plo,
  1485. pSurface,
  1486. pco,
  1487. (XFORMOBJ*) NULL,
  1488. pbo,
  1489. pptlBrushOrg,
  1490. &laTmp,
  1491. mix);
  1492. if (bSem)
  1493. {
  1494. UMPDAcquireRFONTSem(rfo, NULL, fl, numLinks, pFaceLink);
  1495. if (pFaceLink && pFaceLink != aFaceLink)
  1496. {
  1497. VFREEMEM(pFaceLink);
  1498. }
  1499. }
  1500. return bRet;
  1501. }
  1502. /******************************Member*Function*****************************\
  1503. * EPATHOBJ::bSimpleFill(flCaps, plo, pSurf, pco, pbo, pptlBrushOrg,
  1504. * mix, flOptions)
  1505. *
  1506. * Fill the path, accounting for smart devices.
  1507. *
  1508. * History:
  1509. * 7-Apr-1992 -by- J. Andrew Goossen [andrewgo]
  1510. * Wrote it.
  1511. \**************************************************************************/
  1512. BOOL EPATHOBJ::bSimpleFill(
  1513. FLONG flCaps, // For device graphics caps
  1514. PDEVOBJ* pdo,
  1515. SURFACE* pSurf,
  1516. CLIPOBJ* pco,
  1517. BRUSHOBJ* pbo,
  1518. POINTL* pptlBrushOrg,
  1519. MIX mix,
  1520. FLONG flOptions)
  1521. {
  1522. BOOL bRet;
  1523. #if DBG
  1524. ASSERTGDI(bAllClosed(), "A sub-path in the filled path wasn't closed.");
  1525. #endif
  1526. ASSERTGDI(cTotalCurves() == cCurves, "Messed up curve count somewhere.");
  1527. ASSERTGDI(mix & 0xff00, "Background mix uninitialized");
  1528. // The DDI restricts all paths to a 2^27 by 2^27 pixel space to allow
  1529. // device drivers to compute deltas using 32-bit integers without
  1530. // overflowing.
  1531. if (((rcfxBoundBox().xRight - rcfxBoundBox().xLeft) < 0) ||
  1532. ((rcfxBoundBox().yBottom - rcfxBoundBox().yTop) < 0))
  1533. {
  1534. return(FALSE);
  1535. }
  1536. if (cCurves == 0)
  1537. {
  1538. return(TRUE);
  1539. }
  1540. if (pSurf->flags() & HOOK_FillPath)
  1541. {
  1542. if (((flOptions & WINDING) && (flCaps & GCAPS_WINDINGFILL)) ||
  1543. (!(flOptions & WINDING) && (flCaps & GCAPS_ALTERNATEFILL)))
  1544. {
  1545. if (bBeziers())
  1546. {
  1547. if (flCaps & GCAPS_BEZIERS)
  1548. {
  1549. // The driver says it can handle Beziers, so try giving it
  1550. // the path, Beziers and all:
  1551. ASSERTGDI(PPFNVALID(*pdo,FillPath),
  1552. "Driver hooked FillPath but didn't supply routine");
  1553. INC_SURF_UNIQ(pSurf);
  1554. bRet = (*PPFNDRV(*pdo,FillPath)) (
  1555. pSurf->pSurfobj(),
  1556. (PATHOBJ*) this,
  1557. pco,
  1558. pbo,
  1559. pptlBrushOrg,
  1560. mix,
  1561. flOptions);
  1562. if (bRet == TRUE)
  1563. return(TRUE);
  1564. else if (bRet == DDI_ERROR)
  1565. return(FALSE);
  1566. }
  1567. // If there's complex clipping, the driver might not want to
  1568. // render Beziers itself, so we'll flatten it and try again
  1569. // (or maybe the driver doesn't handle Beziers at all):
  1570. if (!bFlatten())
  1571. return(FALSE);
  1572. }
  1573. ASSERTGDI(PPFNVALID(*pdo,FillPath),
  1574. "Driver hooked FillPath but didn't supply routine");
  1575. INC_SURF_UNIQ(pSurf);
  1576. bRet = (*PPFNDRV(*pdo,FillPath)) (
  1577. pSurf->pSurfobj(),
  1578. (PATHOBJ*) this,
  1579. pco,
  1580. pbo,
  1581. pptlBrushOrg,
  1582. mix,
  1583. flOptions);
  1584. if (bRet == TRUE)
  1585. return(TRUE);
  1586. else if (bRet == DDI_ERROR)
  1587. return(FALSE);
  1588. }
  1589. }
  1590. INC_SURF_UNIQ(pSurf);
  1591. return(EngFillPath(pSurf->pSurfobj(),
  1592. (PATHOBJ*) this,
  1593. pco,
  1594. pbo,
  1595. pptlBrushOrg,
  1596. mix,
  1597. flOptions));
  1598. }
  1599. /******************************Member*Function*****************************\
  1600. * EPATHOBJ::bSimpleStroke(flCaps, pdo, pSurf, pco, pxo, pbo, pptlBrushOrg,
  1601. * pla, mix)
  1602. *
  1603. * Stroke the path, accounting for smart devices.
  1604. *
  1605. * History:
  1606. * 7-Apr-1992 -by- J. Andrew Goossen [andrewgo]
  1607. * Wrote it.
  1608. \**************************************************************************/
  1609. BOOL EPATHOBJ::bSimpleStroke(
  1610. FLONG flCaps, // For device graphics caps
  1611. PDEVOBJ* pdo,
  1612. SURFACE* pSurf,
  1613. CLIPOBJ* pco,
  1614. XFORMOBJ* pxo,
  1615. BRUSHOBJ* pbo,
  1616. POINTL* pptlBrushOrg,
  1617. LINEATTRS* pla,
  1618. MIX mix)
  1619. {
  1620. BOOL bRet;
  1621. // The DDI restricts all paths to a 2^27 by 2^27 pixel space to allow
  1622. // device drivers to compute deltas using 32-bit integers without
  1623. // overflowing.
  1624. if (((rcfxBoundBox().xRight - rcfxBoundBox().xLeft) < 0) ||
  1625. ((rcfxBoundBox().yBottom - rcfxBoundBox().yTop) < 0))
  1626. {
  1627. return(FALSE);
  1628. }
  1629. if (cCurves == 0)
  1630. {
  1631. return(TRUE);
  1632. }
  1633. // the real thing
  1634. ASSERTGDI(cTotalCurves() == cCurves, "Messed up curve count somewhere.");
  1635. ASSERTGDI(mix & 0xff00, "Background mix uninitialized");
  1636. INC_SURF_UNIQ(pSurf);
  1637. if (pSurf->flags() & HOOK_StrokePath)
  1638. {
  1639. // Pass the path to the driver if it's not a wide line, or if the driver
  1640. // says it can take wide lines:
  1641. if (!(pla->fl & LA_GEOMETRIC) || (flCaps & GCAPS_GEOMETRICWIDE))
  1642. {
  1643. if (bBeziers())
  1644. {
  1645. if (flCaps & GCAPS_BEZIERS)
  1646. {
  1647. // The driver says it can handle Beziers, so try giving it
  1648. // the path, Beziers and all:
  1649. ASSERTGDI(PPFNVALID(*pdo,StrokePath),
  1650. "Driver hooked StrokePath but didn't supply routine");
  1651. bRet = (*PPFNDRV(*pdo,StrokePath)) (
  1652. pSurf->pSurfobj(),
  1653. (PATHOBJ*) this,
  1654. pco,
  1655. pxo,
  1656. pbo,
  1657. pptlBrushOrg,
  1658. pla,
  1659. mix);
  1660. if (bRet == TRUE)
  1661. return(TRUE);
  1662. else if (bRet == DDI_ERROR)
  1663. return(FALSE);
  1664. }
  1665. // If there's complex clipping, the driver might not want to
  1666. // render Beziers itself, so we'll flatten it and try again
  1667. // (or maybe the driver doesn't handle Beziers at all):
  1668. if (!bFlatten())
  1669. return(FALSE);
  1670. }
  1671. ASSERTGDI(PPFNVALID(*pdo,StrokePath),
  1672. "Driver hooked StrokePath but didn't supply routine");
  1673. bRet = (*PPFNDRV(*pdo,StrokePath)) (
  1674. pSurf->pSurfobj(),
  1675. (PATHOBJ*) this,
  1676. pco,
  1677. pxo,
  1678. pbo,
  1679. pptlBrushOrg,
  1680. pla,
  1681. mix);
  1682. if (bRet == TRUE)
  1683. return(TRUE);
  1684. else if (bRet == DDI_ERROR)
  1685. return(FALSE);
  1686. }
  1687. }
  1688. if (pla->fl & LA_GEOMETRIC)
  1689. {
  1690. //
  1691. // Handle wide lines, remembering that the widened bounds have
  1692. // already been computed:
  1693. //
  1694. if (!bWiden(pxo, pla))
  1695. return(FALSE);
  1696. return(bSimpleFill(flCaps,
  1697. pdo,
  1698. pSurf,
  1699. pco,
  1700. pbo,
  1701. pptlBrushOrg,
  1702. mix,
  1703. WINDING));
  1704. }
  1705. //
  1706. // Pass it off to the engine:
  1707. //
  1708. return(EngStrokePath(pSurf->pSurfobj(),
  1709. (PATHOBJ*) this,
  1710. pco,
  1711. pxo,
  1712. pbo,
  1713. pptlBrushOrg,
  1714. pla,
  1715. mix));
  1716. }
  1717. /******************************Member*Function*****************************\
  1718. * EPATHOBJ::bSimpleStrokeAndFill(flCaps, pdo, pSurf, pco, pxo, pboStroke,
  1719. * pla, pboFill, pptlBrushOrg, mix, flOptions)
  1720. *
  1721. * Stroke and fill the path, accounting for smart devices.
  1722. *
  1723. * History:
  1724. * 7-Apr-1992 -by- J. Andrew Goossen [andrewgo]
  1725. * Wrote it.
  1726. \**************************************************************************/
  1727. BOOL EPATHOBJ::bSimpleStrokeAndFill(
  1728. FLONG flCaps, // For device graphics caps
  1729. PDEVOBJ* pdo,
  1730. SURFACE* pSurf,
  1731. CLIPOBJ* pco,
  1732. XFORMOBJ* pxo,
  1733. BRUSHOBJ* pboStroke,
  1734. LINEATTRS* pla,
  1735. BRUSHOBJ* pboFill,
  1736. POINTL* pptlBrushOrg,
  1737. MIX mix,
  1738. FLONG flOptions)
  1739. {
  1740. BOOL bRet;
  1741. #if DBG
  1742. ASSERTGDI(bAllClosed(), "A sub-path in the filled path wasn't closed.");
  1743. #endif
  1744. ASSERTGDI(cTotalCurves() == cCurves, "Messed up curve count somewhere.");
  1745. ASSERTGDI(mix & 0xff00, "Background mix uninitialized");
  1746. // The DDI restricts all paths to a 2^27 by 2^27 pixel space to allow
  1747. // device drivers to compute deltas using 32-bit integers without
  1748. // overflowing.
  1749. if (((rcfxBoundBox().xRight - rcfxBoundBox().xLeft) < 0) ||
  1750. ((rcfxBoundBox().yBottom - rcfxBoundBox().yTop) < 0))
  1751. {
  1752. return(FALSE);
  1753. }
  1754. if (cCurves == 0)
  1755. {
  1756. return(TRUE);
  1757. }
  1758. INC_SURF_UNIQ(pSurf);
  1759. if (pSurf->flags() & HOOK_StrokeAndFillPath)
  1760. {
  1761. // Pass the path to the driver if either it's not a wide line, or
  1762. // if the driver says it can take wide lines:
  1763. if (!(pla->fl & LA_GEOMETRIC) || (flCaps & GCAPS_GEOMETRICWIDE))
  1764. {
  1765. if (bBeziers())
  1766. {
  1767. if (flCaps & GCAPS_BEZIERS)
  1768. {
  1769. // The driver says it can handle Beziers, so try giving it
  1770. // the path, Beziers and all:
  1771. ASSERTGDI(PPFNVALID(*pdo,StrokeAndFillPath),
  1772. "Driver hooked StrokeAndFillPath but didn't supply routine");
  1773. bRet = (*PPFNDRV(*pdo,StrokeAndFillPath)) (
  1774. pSurf->pSurfobj(),
  1775. (PATHOBJ*) this,
  1776. pco,
  1777. pxo,
  1778. pboStroke,
  1779. pla,
  1780. pboFill,
  1781. pptlBrushOrg,
  1782. mix,
  1783. flOptions);
  1784. if (bRet == TRUE)
  1785. return(TRUE);
  1786. else if (bRet == DDI_ERROR)
  1787. return(FALSE);
  1788. }
  1789. // If there's complex clipping, the driver might not want to
  1790. // render Beziers itself, so we'll flatten it and try again
  1791. // (or maybe the driver doesn't handle Beziers at all):
  1792. if (!bFlatten())
  1793. return(FALSE);
  1794. }
  1795. ASSERTGDI(PPFNVALID(*pdo,StrokeAndFillPath),
  1796. "Driver hooked StrokeAndFillPath but didn't supply routine");
  1797. bRet = (*PPFNDRV(*pdo,StrokeAndFillPath)) (
  1798. pSurf->pSurfobj(),
  1799. (PATHOBJ*) this,
  1800. pco,
  1801. pxo,
  1802. pboStroke,
  1803. pla,
  1804. pboFill,
  1805. pptlBrushOrg,
  1806. mix,
  1807. flOptions);
  1808. if (bRet == TRUE)
  1809. return(TRUE);
  1810. else if (bRet == DDI_ERROR)
  1811. return(FALSE);
  1812. }
  1813. }
  1814. BOOL bDemote = FALSE;
  1815. // Can demote into separate Fill and Stroke calls if we're not doing a
  1816. // wide-line, or if we're doing a SRCCOPY and the display is raster, we
  1817. // can also demote (because in that case, we don't mind if we re-light
  1818. // pixels):
  1819. if (!(pla->fl & LA_GEOMETRIC))
  1820. bDemote = TRUE;
  1821. else if ((mix & 0xFF) == R2_COPYPEN)
  1822. {
  1823. PDEVOBJ po(pSurf->hdev());
  1824. if (po.ulTechnology() == DT_RASDISPLAY ||
  1825. po.ulTechnology() == DT_RASPRINTER)
  1826. bDemote = TRUE;
  1827. }
  1828. if (bDemote)
  1829. {
  1830. MIX mixFill, mixStroke;
  1831. mixFill = mixStroke = mix;
  1832. if (!((EBRUSHOBJ *)pboFill)->bIsMasking())
  1833. {
  1834. mixFill = (mix & 0xff) | ((mix & 0xff) << 8);
  1835. }
  1836. if (!((EBRUSHOBJ *)pboStroke)->bIsMasking())
  1837. {
  1838. mixStroke = (mix & 0xff) | ((mix & 0xff) << 8);
  1839. }
  1840. return(bSimpleFill(flCaps,
  1841. pdo,
  1842. pSurf,
  1843. pco,
  1844. pboFill,
  1845. pptlBrushOrg,
  1846. mixFill,
  1847. flOptions) &&
  1848. bSimpleStroke(flCaps,
  1849. pdo,
  1850. pSurf,
  1851. pco,
  1852. pxo,
  1853. pboStroke,
  1854. pptlBrushOrg,
  1855. pla,
  1856. mixStroke));
  1857. }
  1858. // Hand off to the engine simulation, which will nicely subtract the regions
  1859. // if necessary:
  1860. return(EngStrokeAndFillPath(pSurf->pSurfobj(),
  1861. (PATHOBJ*) this,
  1862. pco,
  1863. pxo,
  1864. pboStroke,
  1865. pla,
  1866. pboFill,
  1867. pptlBrushOrg,
  1868. mix,
  1869. flOptions));
  1870. }
  1871. /******************************Member*Function*****************************\
  1872. * EPATHOBJ::bStrokeAndOrFill(dco, pla, pexo, flType)
  1873. *
  1874. * Stroke and/or fills the path, depending on flType and the current pen
  1875. * and brush.
  1876. *
  1877. * Note that unless the only output operations you're doing is with the
  1878. * path, you probably want to do your own locking, pointer exclusion, etc.
  1879. * and call bSimpleStroke, bSimpleFill or bSimpleStrokeAndFill.
  1880. *
  1881. * History:
  1882. * 7-Apr-1992 -by- J. Andrew Goossen [andrewgo]
  1883. * Wrote it.
  1884. \**************************************************************************/
  1885. BOOL EPATHOBJ::bStrokeAndOrFill(
  1886. XDCOBJ& dco,
  1887. LINEATTRS* pla,
  1888. EXFORMOBJ* pexo,
  1889. FLONG flType)
  1890. {
  1891. ASSERTGDI(bValid(), "Invalid Path");
  1892. ASSERTGDI(dco.bValid(), "Invalid DC");
  1893. BOOL bRet = FALSE;
  1894. BOOL bOpaqueStyle = FALSE;
  1895. LONG lOldStyleState;
  1896. MIX mix;
  1897. BOOL bCanDither;
  1898. FLONG flOriginal;
  1899. // If there aren't any points (as may happen with consecutive calls to
  1900. // BeginPath and EndPath), we're all done -- don't let this get down to
  1901. // the driver, which won't expect it.
  1902. if (cCurves == 0)
  1903. {
  1904. return(TRUE);
  1905. }
  1906. flOriginal = flType;
  1907. // Simplify if NULL pen or NULL brush:
  1908. if (dco.pdc->pbrushLine() == gpPenNull)
  1909. {
  1910. flType &= ~PATH_STROKE;
  1911. }
  1912. if (dco.pdc->pbrushFill() == gpbrNull)
  1913. {
  1914. flType &= ~PATH_FILL;
  1915. }
  1916. // If doing a wide line, have to adjust bounds:
  1917. if (flType & PATH_STROKE)
  1918. {
  1919. if (pla->fl & LA_GEOMETRIC)
  1920. {
  1921. if (!bComputeWidenedBounds((XFORMOBJ*) pexo, pla))
  1922. {
  1923. SAVE_ERROR_CODE(ERROR_ARITHMETIC_OVERFLOW);
  1924. return(bRet);
  1925. }
  1926. // We don't support preserving the style state accross DrvStrokePaths
  1927. // in Product One for geometric lines, so make sure we always reset
  1928. // the style state value:
  1929. if (pla->pstyle != (PFLOAT_LONG) NULL)
  1930. pla->elStyleState.e = IEEE_0_0F;
  1931. }
  1932. }
  1933. // Compute bound box and make it lower-right exclusive:
  1934. ERECTL erclBoundsDevice(ppath->rcfxBoundBox);
  1935. erclBoundsDevice.bottom++;
  1936. erclBoundsDevice.right++;
  1937. if (dco.fjAccum())
  1938. dco.vAccumulate(erclBoundsDevice);
  1939. // If we're in FULLSCREEN mode, exit with success.
  1940. if (dco.bFullScreen()) // If in FULLSCREEN mode, exit.
  1941. return(TRUE);
  1942. // Lock Rao region, VisRgn. We would really like to do all the flattening,
  1943. // widening and converting to regions before we grab this, because they
  1944. // are time intensive and the DEVLOCK prevents any other screen updating.
  1945. // This might have to change if it becomes a performance issue.
  1946. DEVLOCKOBJ dlo(dco);
  1947. if (!dlo.bValid())
  1948. {
  1949. return(dco.bFullScreen());
  1950. }
  1951. if (dco.bDisplay() && !dco.bRedirection() && !UserScreenAccessCheck())
  1952. {
  1953. SAVE_ERROR_CODE(ERROR_ACCESS_DENIED);
  1954. return(FALSE);
  1955. }
  1956. ERECTL erclBoundsScreen = erclBoundsDevice;
  1957. erclBoundsScreen += dco.eptlOrigin();
  1958. vOffset(dco.eptlOrigin());
  1959. ECLIPOBJ eco(dco.prgnEffRao(), erclBoundsScreen);
  1960. // Might be able to do a quick-out:
  1961. if ((dco.dctp() == DCTYPE_INFO) || eco.erclExclude().bEmpty())
  1962. {
  1963. if (flType & PATH_STROKE)
  1964. {
  1965. if ((pla->pstyle != (PFLOAT_LONG) NULL && !(pla->fl & LA_GEOMETRIC))
  1966. || pla->fl & LA_ALTERNATE)
  1967. {
  1968. vUpdateCosmeticStyleState(dco.pSurface(), pla);
  1969. }
  1970. }
  1971. bRet = TRUE;
  1972. return(bRet);
  1973. }
  1974. // Lock the destination surface and the ldev:
  1975. SURFACE *pSurfDest = dco.pSurface();
  1976. PDEVOBJ po(dco.hdev());
  1977. XEPALOBJ epalDest(pSurfDest->ppal());
  1978. XEPALOBJ epalDestDC(dco.ppal());
  1979. // Realize the brushes:
  1980. EBRUSHOBJ *peboPen = dco.peboLine();
  1981. EBRUSHOBJ *peboBrush = dco.peboFill();
  1982. EBRUSHOBJ *peboStroke = peboPen;
  1983. if (flType & PATH_STROKE)
  1984. {
  1985. ASSERTGDI(pla != (LINEATTRS*) NULL, "Invalid LineAttrs for stroke");
  1986. ASSERTGDI(!(pla->fl & LA_GEOMETRIC) || pexo != (EXFORMOBJ*) NULL,
  1987. "Invalid xform on geometric line");
  1988. if (pla->fl & LA_GEOMETRIC)
  1989. {
  1990. // The bCanDither flag actually means 'bCanDitherIfBrushSaysSo' --
  1991. // the brush has to be marked as ditherable AND bCanDither has to be
  1992. // set before the brush is dithered:
  1993. bCanDither = TRUE;
  1994. // Because of Win3.1 compatibility, when the PS_INSIDEFRAME pen
  1995. // is treated as a wideline, we can dither the brush. But the
  1996. // dither/can't dither decision depends on the transform,
  1997. // and the last time we used this brush we may have realized
  1998. // it as non-ditherable.
  1999. // PS_INSIDEFRAME pens are reasonably rare, and realizing a brush
  2000. // is relatively quick (particularly compared to the wide-line
  2001. // rendering time), so if the cached brush is a solid color, we
  2002. // simply mark the brush so that it will be re-realized (but only
  2003. // for PS_INSIDEFRAME pens):
  2004. // if the driver says dither (mainly for 8 color printer devices) we
  2005. // can dither even if it is not InsideFrame.
  2006. // Note: If the pen is dirty, we'll actually be looking at
  2007. // uninitialized fields! But that's okay, because we'd only be
  2008. // marking the pen dirty again:
  2009. if ((peboPen->iSolidColor != (ULONG) -1) &&
  2010. (peboPen->bIsInsideFrame() || po.bCapsForceDither()))
  2011. {
  2012. dco.ulDirty(dco.ulDirty() | DIRTY_LINE);
  2013. }
  2014. }
  2015. else
  2016. {
  2017. // Here we've got the opposite case. When the transform is such
  2018. // that a PS_INSIDEFRAME pen is treated as a cosmetic pen,
  2019. // the brush has to be solid colored:
  2020. bCanDither = FALSE;
  2021. if (peboPen->iSolidColor == (ULONG) -1)
  2022. {
  2023. dco.ulDirty(dco.ulDirty() | DIRTY_LINE);
  2024. }
  2025. }
  2026. if (dco.bDirtyBrush(DIRTY_LINE))
  2027. {
  2028. dco.vCleanBrush(DIRTY_LINE);
  2029. peboPen->vInitBrush(dco.pdc,
  2030. dco.pdc->pbrushLine(),
  2031. epalDestDC, epalDest,
  2032. pSurfDest,
  2033. bCanDither);
  2034. }
  2035. if (pla->pstyle != (PFLOAT_LONG) NULL &&
  2036. peboPen->bIsOldStylePen() &&
  2037. dco.pdc->jBkMode() == OPAQUE &&
  2038. !(pla->fl & LA_GEOMETRIC)) // Don't style wide Win3 pens
  2039. {
  2040. // If the background mode is OPAQUE, and we're styling with an
  2041. // old Win3-style pen, we have to note it. We do this styling in
  2042. // two passes. On the first pass, we use the opaque pen.
  2043. bOpaqueStyle = TRUE;
  2044. ASSERTGDI(peboPen->bIsDefaultStyle(), "Expect only default style");
  2045. // Change the sense of the first element in the style array:
  2046. pla->fl ^= LA_STARTGAP;
  2047. lOldStyleState = pla->elStyleState.l;
  2048. peboStroke = dco.peboBackground();
  2049. // Initialize the opaque pen:
  2050. // The opaquing brush must be solid colored. If the cached version
  2051. // isn't solid colored, mark the cached entry as invalid so that
  2052. // we'll re-realize. I don't expect this to ever happen (we merely
  2053. // implmement this for completeness), so it's hardly a performance
  2054. // hit.
  2055. if (!(dco.ulDirty() & DIRTY_BACKGROUND))
  2056. {
  2057. if (peboStroke->iSolidColor == (ULONG) -1)
  2058. {
  2059. dco.ulDirty(dco.ulDirty() | DIRTY_BACKGROUND);
  2060. }
  2061. }
  2062. if (dco.bDirtyBrush(DIRTY_BACKGROUND))
  2063. {
  2064. if((dco.flGraphicsCaps() & GCAPS_ARBRUSHOPAQUE) == 0)
  2065. {
  2066. // BUGFIX #27335 2-18-2000 bhouse
  2067. // We can clear the DIRTY_BACKGROUND bit only if
  2068. // we would have otherwise realized it without
  2069. // dithering enabled.
  2070. dco.vCleanBrush(DIRTY_BACKGROUND);
  2071. }
  2072. peboStroke->vInitBrush(
  2073. dco.pdc,
  2074. (PBRUSH)gpbrBackground,
  2075. epalDestDC, epalDest,
  2076. pSurfDest,
  2077. FALSE); // False means can't dither
  2078. }
  2079. }
  2080. mix = peboPen->mixBest(dco.pdc->jROP2(), dco.pdc->jBkMode());
  2081. }
  2082. if (flType & PATH_FILL)
  2083. {
  2084. if (dco.bDirtyBrush(DIRTY_FILL))
  2085. {
  2086. dco.vCleanBrush(DIRTY_FILL);
  2087. peboBrush->vInitBrush(dco.pdc,
  2088. dco.pdc->pbrushFill(),
  2089. epalDestDC, epalDest,
  2090. pSurfDest);
  2091. }
  2092. // For StrokeAndFill, we can pass down only a single 'mix' that applies
  2093. // to both brushes (normally, we don't want to pass down a transparent
  2094. // mix when the brush is not a hatch because the mix is what the display/
  2095. // printer driver cues off of to know if it has to do a transparent fill,
  2096. // which it typically does very slowly).
  2097. //
  2098. // If either brush is a hatched brush, and the BkMode is TRANSPARENT,
  2099. // then 'mix' must indicate a transparent mix. The way it works here
  2100. // is that if a transparent mix was already initialized for the pen, we
  2101. // don't recompute the mix:
  2102. if (!(flType & PATH_STROKE) ||
  2103. ((mix >> 8) == (mix & 0xff)))
  2104. {
  2105. mix = peboBrush->mixBest(dco.pdc->jROP2(), dco.pdc->jBkMode());
  2106. }
  2107. }
  2108. // Reset the path for enumeration:
  2109. ppath->pprEnum = (PATHRECORD*) NULL;
  2110. // Exclude the pointer:
  2111. DEVEXCLUDEOBJ dxo(dco,&eco.erclExclude(),&eco);
  2112. if ((flType == 0) && (po.ulTechnology() != DT_RASDISPLAY))
  2113. {
  2114. // Microsoft Publisher and Adobe Persuasion draw colored pattern
  2115. // and gradient fills on Postscript by doing the following sequence:
  2116. //
  2117. // 1. Send BEGIN_PATH printer escape;
  2118. // 2. Draw a path using a hollow brush and a NULL pen;
  2119. // 3. Send END_PATH escape;
  2120. // 4. Send CLIP_TO_PATH.
  2121. //
  2122. // The problem is that we used to detect these path cases and
  2123. // optimize out the calls to the driver, so the clipping path
  2124. // would never get down to Postscript.
  2125. //
  2126. // To fix this, we now detect this case and subsitute R2_NOP for
  2127. // the mix instead, and in this manner the path will still get down
  2128. // to the driver. If the driver is not currently accumulating a
  2129. // path, the right thing will still be printed: that is, nothing.
  2130. flType = flOriginal;
  2131. mix = ((R2_NOP << 8) | R2_NOP);
  2132. pla = &glaSimpleStroke.la; // Give them something to look at
  2133. }
  2134. // Finally, make the necessary calls:
  2135. switch(flType)
  2136. {
  2137. case 0:
  2138. bRet = TRUE;
  2139. break;
  2140. case PATH_FILL:
  2141. bRet = bSimpleFill(dco.flGraphicsCaps(),
  2142. &po,
  2143. pSurfDest,
  2144. &eco,
  2145. peboBrush,
  2146. &dco.pdc->ptlFillOrigin(),
  2147. mix,
  2148. dco.pdc->jFillMode());
  2149. break;
  2150. case PATH_STROKE:
  2151. bRet = bSimpleStroke(dco.flGraphicsCaps(),
  2152. &po,
  2153. pSurfDest,
  2154. &eco,
  2155. (XFORMOBJ *) pexo,
  2156. peboStroke,
  2157. &dco.pdc->ptlFillOrigin(),
  2158. pla,
  2159. mix);
  2160. break;
  2161. case PATH_STROKE | PATH_FILL:
  2162. bRet = bSimpleStrokeAndFill(dco.flGraphicsCaps(),
  2163. &po,
  2164. pSurfDest,
  2165. &eco,
  2166. (XFORMOBJ *) pexo,
  2167. peboStroke,
  2168. pla,
  2169. peboBrush,
  2170. &dco.pdc->ptlFillOrigin(),
  2171. mix,
  2172. dco.pdc->jFillMode());
  2173. break;
  2174. default:
  2175. RIP("Woah Nellie!");
  2176. }
  2177. // Do a second pass to draw the dashes for opaque styled lines:
  2178. if (bOpaqueStyle)
  2179. {
  2180. pla->fl ^= LA_STARTGAP;
  2181. pla->elStyleState.l = lOldStyleState;
  2182. ppath->pprEnum = (PATHRECORD*) NULL;
  2183. bRet &= bSimpleStroke(dco.flGraphicsCaps(),
  2184. &po,
  2185. pSurfDest,
  2186. &eco,
  2187. (XFORMOBJ *) pexo,
  2188. peboPen,
  2189. &dco.pdc->ptlFillOrigin(),
  2190. pla,
  2191. mix);
  2192. }
  2193. return(bRet);
  2194. }
  2195. //
  2196. // Pathalloc structure
  2197. //
  2198. // We allocate the space for paths in blocks that are essentially
  2199. // independent of the chain used to order the pathdata records. Typically
  2200. // we will have several ( or many ) pathdata records packed into each
  2201. // pathalloc block. The pathalloc blocks for a path are all chained together
  2202. // using the ppanext pointers; the end of the chain is marked with a NULL
  2203. // pointer.
  2204. //
  2205. // Each pathalloc structure has two fields which describe the space available
  2206. // in the block; the 'start' field is the pointer to the start of the
  2207. // available space, and the 'end' field is the pointer to the address
  2208. // *following* the last valid address in the pathalloc. Thus, the space
  2209. // remaining in the pathalloc can be computed as end - start.
  2210. //
  2211. // Routines to allocate and free pathalloc structures
  2212. /******************************Public*Routine******************************\
  2213. * friend BOOL bInitPathAlloc()
  2214. *
  2215. * Initialize the freelist for pathallocs. Get a semaphore, set the
  2216. * freelist to empty.
  2217. *
  2218. * History:
  2219. * 1-Oct-1990 -by- Paul Butzi [paulb]
  2220. * Wrote it.
  2221. \**************************************************************************/
  2222. BOOL bInitPathAlloc()
  2223. {
  2224. if ((PATHALLOC::hsemFreelist = GreCreateSemaphore()) == NULL)
  2225. {
  2226. return(FALSE);
  2227. }
  2228. PATHALLOC::freelist = (PATHALLOC*) NULL;
  2229. PATHALLOC::cFree = 0;
  2230. PATHALLOC::cAllocated = 0;
  2231. return(TRUE);
  2232. }
  2233. /******************************Public*Routine******************************\
  2234. * friend void freepathalloc()
  2235. *
  2236. * Deallocate a pathalloc.
  2237. *
  2238. * History:
  2239. * 1-Oct-1990 -by- Paul Butzi [paulb]
  2240. * Wrote it.
  2241. \**************************************************************************/
  2242. VOID freepathalloc(PATHALLOC *ppa)
  2243. {
  2244. ASSERTGDI(ppa->siztPathAlloc == PATHALLOCSIZE, "Not a heap PATHALLOC");
  2245. SEMOBJ so(PATHALLOC::hsemFreelist);
  2246. if (PATHALLOC::cFree >= FREELIST_MAX)
  2247. {
  2248. // Free the memory if we've already got enough blocks on the freelist.
  2249. VFREEMEM(ppa);
  2250. PATHALLOC::cAllocated--;
  2251. }
  2252. else
  2253. {
  2254. // Keep around a couple of blocks on the freelist for fast access.
  2255. ppa->ppanext = PATHALLOC::freelist;
  2256. PATHALLOC::freelist = ppa;
  2257. PATHALLOC::cFree++;
  2258. }
  2259. }
  2260. /******************************Public*Routine******************************\
  2261. * friend PATHALLOC *newpathalloc()
  2262. *
  2263. * Allocate a new pathalloc, taking it off the freelist unless the
  2264. * freelist is empty. In that case, just allocate a new one
  2265. *
  2266. * 1-Oct-1990 -by- Paul Butzi [paulb]
  2267. * Wrote it.
  2268. \**************************************************************************/
  2269. PPATHALLOC newpathalloc()
  2270. {
  2271. SEMOBJ so(PATHALLOC::hsemFreelist);
  2272. register PPATHALLOC ppaNew = PATHALLOC::freelist;
  2273. if ( ppaNew != (PPATHALLOC) NULL )
  2274. {
  2275. PATHALLOC::freelist = ppaNew->ppanext;
  2276. PATHALLOC::cFree--;
  2277. }
  2278. else
  2279. {
  2280. ppaNew = (PPATHALLOC) PALLOCMEM(PATHALLOCSIZE, 'tapG');
  2281. if (ppaNew == (PPATHALLOC) NULL)
  2282. return((PPATHALLOC) NULL);
  2283. PATHALLOC::cAllocated++;
  2284. }
  2285. // Initialize the pathalloc structure:
  2286. ppaNew->pprfreestart = &(ppaNew->apr[0]);
  2287. ppaNew->ppanext = (PATHALLOC*) NULL;
  2288. ppaNew->siztPathAlloc = PATHALLOCSIZE;
  2289. return(ppaNew);
  2290. }
  2291. /******************************Public*Routine******************************\
  2292. * BOOL bSavePath(dco, lSave)
  2293. *
  2294. * Lazily save the DC's active or inactive path. We only actually copy
  2295. * the path when the user starts mucking around with it.
  2296. *
  2297. * History:
  2298. * 21-Mar-1992 -by- J. Andrew Goossen [andrewgo]
  2299. * Wrote it.
  2300. \**************************************************************************/
  2301. BOOL bSavePath(XDCOBJ& dco, LONG lSave)
  2302. {
  2303. DONTUSE(lSave);
  2304. // If there's a path in the DC (either active or inactive), make a note
  2305. // to save it when it's about to be modified:
  2306. if (dco.hpath() != HPATH_INVALID)
  2307. dco.pdc->vSetLazySave();
  2308. return(TRUE);
  2309. }
  2310. /******************************Public*Routine******************************\
  2311. * VOID vRestorePath(dco, lSave)
  2312. *
  2313. * Restore the active path.
  2314. *
  2315. * History:
  2316. * 21-Mar-1992 -by- J. Andrew Goossen [andrewgo]
  2317. * Wrote it.
  2318. \**************************************************************************/
  2319. VOID vRestorePath(XDCOBJ& dco, LONG lSave)
  2320. {
  2321. DONTUSE(lSave);
  2322. // If there's a path in the DC, and the bLazySave flag isn't set, it means
  2323. // that it's a new path created at this level, so we have to nuke it:
  2324. if (dco.hpath() != HPATH_INVALID && !dco.pdc->bLazySave())
  2325. {
  2326. XEPATHOBJ epath(dco.hpath());
  2327. ASSERTGDI(epath.bValid(), "Invalid DC path");
  2328. epath.vDelete();
  2329. dco.pdc->vDestroy();
  2330. }
  2331. }
  2332. /******************************Member*Function*****************************\
  2333. * BOOL EPATHOBJ::bAllClosed()
  2334. *
  2335. * If a fill is to be done on the path, every subpath must be have been
  2336. * explicitly marked as closed. This routine returns TRUE if all subpaths
  2337. * have be closed.
  2338. *
  2339. * Note: This is needed in checked builds only!
  2340. *
  2341. * History:
  2342. * 77-Nov-1993 -by- J. Andrew Goossen [andrewgo]
  2343. * Wrote it.
  2344. \**************************************************************************/
  2345. BOOL EPATHOBJ::bAllClosed()
  2346. {
  2347. ULONG count = 0;
  2348. for (PATHRECORD *ppr = ppath->pprfirst;
  2349. ppr != (PPATHREC) NULL;
  2350. ppr = ppr->pprnext)
  2351. {
  2352. if (ppr->flags & PD_ENDSUBPATH)
  2353. {
  2354. if (!(ppr->flags & PD_CLOSEFIGURE))
  2355. return(FALSE);
  2356. }
  2357. else
  2358. {
  2359. ASSERTGDI(!(ppr->flags & PD_CLOSEFIGURE),
  2360. "Shouldn't be a close figure when not end of subpath");
  2361. }
  2362. }
  2363. return(TRUE);
  2364. }
  2365. /******************************Public*Routine******************************\
  2366. * VOID EPATHOBJ::vPrint()
  2367. *
  2368. * Prints the path points, for debugging purposes.
  2369. *
  2370. * History:
  2371. * 21-Mar-1992 -by- J. Andrew Goossen [andrewgo]
  2372. * Wrote it.
  2373. \**************************************************************************/
  2374. VOID EPATHOBJ::vPrint()
  2375. {
  2376. DbgPrint("cCurves: %li fl: %lx\n", cCurves, fl);
  2377. PPATHREC ppr;
  2378. for (ppr = ppath->pprfirst; ppr != NULL; ppr = ppr->pprnext)
  2379. {
  2380. DbgPrint("\n%li: ", ppr->flags);
  2381. COUNT ii;
  2382. for (ii = 0; ii < ppr->count; ii++)
  2383. DbgPrint("(%li, %li) ", ppr->aptfx[ii].x, ppr->aptfx[ii].y);
  2384. }
  2385. DbgPrint("\n");
  2386. }
  2387. /******************************Public*Routine******************************\
  2388. * VOID EPATHOBJ::vPrint()
  2389. *
  2390. * Prints the path structure, for debugging purposes.
  2391. *
  2392. * History:
  2393. * 21-Mar-1992 -by- J. Andrew Goossen [andrewgo]
  2394. * Wrote it.
  2395. \**************************************************************************/
  2396. VOID EPATHOBJ::vDiag()
  2397. {
  2398. DbgPrint("flType: %lx\n", ppath->flType);
  2399. DbgPrint("Chain: %p PprFirst: %p PprLast: %p\n",
  2400. ppath->ppachain, ppath->pprfirst, ppath->pprlast);
  2401. for (PPATHALLOC ppa = ppath->ppachain; ppa != NULL; ppa = ppa->ppanext)
  2402. DbgPrint(" ppa: %p ppaNext: %p pprFreeStart: %p sizt: %li\n",
  2403. ppa, ppa->ppanext, ppa->pprfreestart, ppa->siztPathAlloc);
  2404. for (PPATHREC ppr = ppath->pprfirst; ppr != NULL; ppr = ppr->pprnext)
  2405. DbgPrint(" ppr: %p pprNext: %p pprPrev: %p count: %li flags: %li\n",
  2406. ppr, ppr->pprnext, ppr->pprprev, ppr->count, ppr->flags);
  2407. }
  2408. /******************************Public*Routine******************************\
  2409. * VOID vPathDebug()
  2410. *
  2411. * Prints the number of currently allocated PATHALLOCs, and the number of
  2412. * PATHALLOCs available on the free list, for debugging purposes.
  2413. *
  2414. * History:
  2415. * 21-Mar-1992 -by- J. Andrew Goossen [andrewgo]
  2416. * Wrote it.
  2417. \**************************************************************************/
  2418. VOID vPathDebug()
  2419. {
  2420. SEMOBJ so(PATHALLOC::hsemFreelist);
  2421. DbgPrint("F: %li A: %li\n", PATHALLOC::cFree, PATHALLOC::cAllocated);
  2422. }