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.

835 lines
23 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: pathflat.cxx
  3. *
  4. * Code to flatten paths
  5. *
  6. * Created: 3-Dec-1990 10:15:00
  7. * Author: Paul Butzi [paulb]
  8. *
  9. * Copyright (c) 1990-1999 Microsoft Corporation
  10. \**************************************************************************/
  11. #include "precomp.hxx"
  12. #include "pathwide.hxx"
  13. #define INLINE inline
  14. INLINE BOOL bIntersect(RECTFX* prcfx1, RECTFX* prcfx2)
  15. {
  16. BOOL bRet = (prcfx1->yTop <= prcfx2->yBottom &&
  17. prcfx1->yBottom >= prcfx2->yTop &&
  18. prcfx1->xLeft <= prcfx2->xRight &&
  19. prcfx1->xRight >= prcfx2->xLeft);
  20. return(bRet);
  21. }
  22. INLINE VOID vBoundBox(POINTFIX* aptfx, RECTFX* prcfx)
  23. {
  24. if (aptfx[0].x >= aptfx[1].x)
  25. if (aptfx[2].x >= aptfx[3].x)
  26. {
  27. prcfx->xLeft = MIN(aptfx[1].x, aptfx[3].x);
  28. prcfx->xRight = MAX(aptfx[0].x, aptfx[2].x);
  29. }
  30. else
  31. {
  32. prcfx->xLeft = MIN(aptfx[1].x, aptfx[2].x);
  33. prcfx->xRight = MAX(aptfx[0].x, aptfx[3].x);
  34. }
  35. else
  36. if (aptfx[2].x <= aptfx[3].x)
  37. {
  38. prcfx->xLeft = MIN(aptfx[0].x, aptfx[2].x);
  39. prcfx->xRight = MAX(aptfx[1].x, aptfx[3].x);
  40. }
  41. else
  42. {
  43. prcfx->xLeft = MIN(aptfx[0].x, aptfx[3].x);
  44. prcfx->xRight = MAX(aptfx[1].x, aptfx[2].x);
  45. }
  46. if (aptfx[0].y >= aptfx[1].y)
  47. if (aptfx[2].y >= aptfx[3].y)
  48. {
  49. prcfx->yTop = MIN(aptfx[1].y, aptfx[3].y);
  50. prcfx->yBottom = MAX(aptfx[0].y, aptfx[2].y);
  51. }
  52. else
  53. {
  54. prcfx->yTop = MIN(aptfx[1].y, aptfx[2].y);
  55. prcfx->yBottom = MAX(aptfx[0].y, aptfx[3].y);
  56. }
  57. else
  58. if (aptfx[2].y <= aptfx[3].y)
  59. {
  60. prcfx->yTop = MIN(aptfx[0].y, aptfx[2].y);
  61. prcfx->yBottom = MAX(aptfx[1].y, aptfx[3].y);
  62. }
  63. else
  64. {
  65. prcfx->yTop = MIN(aptfx[0].y, aptfx[3].y);
  66. prcfx->yBottom = MAX(aptfx[1].y, aptfx[2].y);
  67. }
  68. }
  69. INLINE VOID HFDBASIS32::vInit(FIX p1, FIX p2, FIX p3, FIX p4)
  70. {
  71. // ASSERTGDI(((p1 | p2 | p3 | p4) & 0xffffc000) == 0, "Range too big");
  72. #if (LTOFX(1) != 0x10)
  73. #error "FIX format changed, update flattener routine"
  74. #endif
  75. // Change basis and convert from 28.4 to 18.14 format:
  76. e0 = (p1 ) << 10;
  77. e1 = (p4 - p1 ) << 10;
  78. e2 = (3 * (p2 - p3 - p3 + p4)) << 11;
  79. e3 = (3 * (p1 - p2 - p2 + p3)) << 11;
  80. }
  81. INLINE VOID HFDBASIS32::vLazyHalveStepSize(LONG cShift)
  82. {
  83. e2 = (e2 + e3) >> 1;
  84. e1 = (e1 - (e2 >> cShift)) >> 1;
  85. }
  86. INLINE VOID HFDBASIS32::vSteadyState(LONG cShift)
  87. {
  88. // We now convert from 18.14 fixed format to 15.17:
  89. e0 <<= 3;
  90. e1 <<= 3;
  91. register LONG lShift = cShift - 3;
  92. if (lShift < 0)
  93. {
  94. lShift = -lShift;
  95. e2 <<= lShift;
  96. e3 <<= lShift;
  97. }
  98. else
  99. {
  100. e2 >>= lShift;
  101. e3 >>= lShift;
  102. }
  103. }
  104. INLINE VOID HFDBASIS32::vHalveStepSize()
  105. {
  106. e2 = (e2 + e3) >> 3;
  107. e1 = (e1 - e2) >> 1;
  108. e3 >>= 2;
  109. }
  110. INLINE VOID HFDBASIS32::vDoubleStepSize()
  111. {
  112. e1 += e1 + e2;
  113. e3 <<= 2;
  114. e2 = (e2 << 3) - e3;
  115. }
  116. INLINE VOID HFDBASIS32::vTakeStep()
  117. {
  118. e0 += e1;
  119. register LONG lTemp = e2;
  120. e1 += lTemp;
  121. e2 += lTemp - e3;
  122. e3 = lTemp;
  123. }
  124. typedef struct _BEZIERCONTROLS {
  125. POINTFIX ptfx[4];
  126. } BEZIERCONTROLS;
  127. BOOL BEZIER32::bInit(
  128. POINTFIX* aptfxBez, // Pointer to 4 control points
  129. RECTFX* prcfxClip) // Bound box of visible region (optional)
  130. {
  131. POINTFIX aptfx[4];
  132. LONG cShift = 0; // Keeps track of 'lazy' shifts
  133. cSteps = 1; // Number of steps to do before reach end of curve
  134. vBoundBox(aptfxBez, &rcfxBound);
  135. *((BEZIERCONTROLS*) aptfx) = *((BEZIERCONTROLS*) aptfxBez);
  136. {
  137. register FIX fxOr;
  138. register FIX fxOffset;
  139. fxOffset = rcfxBound.xLeft;
  140. fxOr = (aptfx[0].x -= fxOffset);
  141. fxOr |= (aptfx[1].x -= fxOffset);
  142. fxOr |= (aptfx[2].x -= fxOffset);
  143. fxOr |= (aptfx[3].x -= fxOffset);
  144. fxOffset = rcfxBound.yTop;
  145. fxOr |= (aptfx[0].y -= fxOffset);
  146. fxOr |= (aptfx[1].y -= fxOffset);
  147. fxOr |= (aptfx[2].y -= fxOffset);
  148. fxOr |= (aptfx[3].y -= fxOffset);
  149. // This 32 bit cracker can only handle points in a 10 bit space:
  150. if ((fxOr & 0xffffc000) != 0)
  151. return(FALSE);
  152. }
  153. x.vInit(aptfx[0].x, aptfx[1].x, aptfx[2].x, aptfx[3].x);
  154. y.vInit(aptfx[0].y, aptfx[1].y, aptfx[2].y, aptfx[3].y);
  155. if (prcfxClip == (RECTFX*) NULL || bIntersect(&rcfxBound, prcfxClip))
  156. {
  157. while (TRUE)
  158. {
  159. register LONG lTestMagnitude = TEST_MAGNITUDE_INITIAL << cShift;
  160. if (x.lError() <= lTestMagnitude && y.lError() <= lTestMagnitude)
  161. break;
  162. cShift += 2;
  163. x.vLazyHalveStepSize(cShift);
  164. y.vLazyHalveStepSize(cShift);
  165. cSteps <<= 1;
  166. }
  167. }
  168. x.vSteadyState(cShift);
  169. y.vSteadyState(cShift);
  170. // Note that this handles the case where the initial error for
  171. // the Bezier is already less than TEST_MAGNITUDE_NORMAL:
  172. x.vTakeStep();
  173. y.vTakeStep();
  174. cSteps--;
  175. return(TRUE);
  176. }
  177. BOOL BEZIER32::bNext(POINTFIX* pptfx)
  178. {
  179. // Return current point:
  180. pptfx->x = x.fxValue() + rcfxBound.xLeft;
  181. pptfx->y = y.fxValue() + rcfxBound.yTop;
  182. // If cSteps == 0, that was the end point in the curve!
  183. if (cSteps == 0)
  184. return(FALSE);
  185. // Okay, we have to step:
  186. if (MAX(x.lError(), y.lError()) > TEST_MAGNITUDE_NORMAL)
  187. {
  188. x.vHalveStepSize();
  189. y.vHalveStepSize();
  190. cSteps <<= 1;
  191. }
  192. ASSERTGDI(MAX(x.lError(), y.lError()) <= TEST_MAGNITUDE_NORMAL,
  193. "Please tell AndrewGo he was wrong");
  194. while (!(cSteps & 1) &&
  195. x.lParentErrorDividedBy4() <= (TEST_MAGNITUDE_NORMAL >> 2) &&
  196. y.lParentErrorDividedBy4() <= (TEST_MAGNITUDE_NORMAL >> 2))
  197. {
  198. x.vDoubleStepSize();
  199. y.vDoubleStepSize();
  200. cSteps >>= 1;
  201. }
  202. cSteps--;
  203. x.vTakeStep();
  204. y.vTakeStep();
  205. return(TRUE);
  206. }
  207. ///////////////////////////////////////////////////////////////////////////
  208. // BEZIER64
  209. //
  210. // All math is done using 64 bit fixed numbers in a 36.28 format.
  211. //
  212. // All drawing is done in a 31 bit space, then a 31 bit window offset
  213. // is applied. In the initial transform where we change to the HFD
  214. // basis, e2 and e3 require the most bits precision: e2 = 6(p2 - 2p3 + p4).
  215. // This requires an additional 4 bits precision -- hence we require 36 bits
  216. // for the integer part, and the remaining 28 bits is given to the fraction.
  217. //
  218. // In rendering a Bezier, every 'subdivide' requires an extra 3 bits of
  219. // fractional precision. In order to be reversible, we can allow no
  220. // error to creep in. Since a FIX coordinate is 32 bits, and we
  221. // require an additional 4 bits as mentioned above, that leaves us
  222. // 28 bits fractional precision -- meaning we can do a maximum of
  223. // 9 subdivides. Now, the maximum absolute error of a Bezier curve in 27
  224. // bit integer space is 2^29 - 1. But 9 subdivides reduces the error by a
  225. // guaranteed factor of 2^18, meaning we can crack down only to an error
  226. // of 2^11 before we overflow, when in fact we want to crack error to less
  227. // than 1.
  228. //
  229. // So what we do is HFD until we hit an error less than 2^11, reverse our
  230. // basis transform to get the four control points of this smaller curve
  231. // (rounding in the process to 32 bits), then invoke another copy of HFD
  232. // on the reduced Bezier curve. We again have enough precision, but since
  233. // its starting error is less than 2^11, we can reduce error to 2^-7 before
  234. // overflowing! We'll start a low HFD after every step of the high HFD.
  235. ////////////////////////////////////////////////////////////////////////////
  236. // The following is our 2^11 target error encoded as a 36.28 number
  237. // (don't forget the additional 4 bits of fractional precision!) and
  238. // the 6 times error multiplier:
  239. LONGLONG geqErrorHigh = (LONGLONG)(6 * (1L << 15) >> (32 - FRACTION64)) << 32;
  240. // The following is the default 2/3 error encoded as a 36.28 number,
  241. // multiplied by 6, and leaving 4 bits for fraction:
  242. LONGLONG geqErrorLow = (LONGLONG)4 << 32;
  243. LONGLONG* gpeqErrorHigh = &geqErrorHigh;
  244. LONGLONG* gpeqErrorLow = &geqErrorLow;
  245. INLINE FIX HFDBASIS64::fxValue()
  246. {
  247. // Convert from 36.28 and round:
  248. LONGLONG eq = e0;
  249. eq += (1L << (FRACTION64 - 1));
  250. eq >>= FRACTION64;
  251. return((FIX) (LONG) eq);
  252. }
  253. INLINE VOID HFDBASIS64::vParentError(LONGLONG* peq)
  254. {
  255. *peq = MAX(ABS(e3 << 2), ABS((e2 << 3) - (e3 << 2)));
  256. }
  257. INLINE VOID HFDBASIS64::vError(LONGLONG* peq)
  258. {
  259. *peq = MAX(ABS(e2), ABS(e3));
  260. }
  261. VOID HFDBASIS64::vInit(FIX p1, FIX p2, FIX p3, FIX p4)
  262. {
  263. LONGLONG eqTmp;
  264. LONGLONG eqP2 = (LONGLONG) p2;
  265. LONGLONG eqP3 = (LONGLONG) p3;
  266. // e0 = p1
  267. // e1 = p4 - p1
  268. // e2 = 6(p2 - 2p3 + p4)
  269. // e3 = 6(p1 - 2p2 + p3)
  270. // Change basis:
  271. e0 = p1; // e0 = p1
  272. e1 = p4;
  273. e2 = eqP2; e2 -= eqP3; e2 -= eqP3; e2 += e1; // e2 = p2 - 2*p3 + p4
  274. e3 = e0; e3 -= eqP2; e3 -= eqP2; e3 += eqP3; // e3 = p1 - 2*p2 + p3
  275. e1 -= e0; // e1 = p4 - p1
  276. // Convert to 36.28 format and multiply e2 and e3 by six:
  277. e0 <<= FRACTION64;
  278. e1 <<= FRACTION64;
  279. eqTmp = e2; e2 += eqTmp; e2 += eqTmp; e2 <<= (FRACTION64 + 1);
  280. eqTmp = e3; e3 += eqTmp; e3 += eqTmp; e3 <<= (FRACTION64 + 1);
  281. }
  282. VOID HFDBASIS64::vUntransform(FIX* afx)
  283. {
  284. // Declare some temps to hold our operations, since we can't modify e0..e3.
  285. LONGLONG eqP0;
  286. LONGLONG eqP1;
  287. LONGLONG eqP2;
  288. LONGLONG eqP3;
  289. // p0 = e0
  290. // p1 = e0 + (6e1 - e2 - 2e3)/18
  291. // p2 = e0 + (12e1 - 2e2 - e3)/18
  292. // p3 = e0 + e1
  293. eqP0 = e0;
  294. // NOTE PERF: Convert this to a multiply by 6: [andrewgo]
  295. eqP2 = e1;
  296. eqP2 += e1;
  297. eqP2 += e1;
  298. eqP1 = eqP2;
  299. eqP1 += eqP2; // 6e1
  300. eqP1 -= e2; // 6e1 - e2
  301. eqP2 = eqP1;
  302. eqP2 += eqP1; // 12e1 - 2e2
  303. eqP2 -= e3; // 12e1 - 2e2 - e3
  304. eqP1 -= e3;
  305. eqP1 -= e3; // 6e1 - e2 - 2e3
  306. // NOTE PERF: May just want to approximate these divides! [andrewgo]
  307. // Or can do a 64 bit divide by 32 bit to get 32 bits right here.
  308. VDIV(eqP1, 18, 0);
  309. VDIV(eqP2, 18, 0);
  310. eqP1 += e0;
  311. eqP2 += e0;
  312. eqP3 = e0;
  313. eqP3 += e1;
  314. // Convert from 36.28 format with rounding:
  315. eqP0 += (1L << (FRACTION64 - 1)); eqP0 >>= FRACTION64; afx[0] = (LONG) eqP0;
  316. eqP1 += (1L << (FRACTION64 - 1)); eqP1 >>= FRACTION64; afx[2] = (LONG) eqP1;
  317. eqP2 += (1L << (FRACTION64 - 1)); eqP2 >>= FRACTION64; afx[4] = (LONG) eqP2;
  318. eqP3 += (1L << (FRACTION64 - 1)); eqP3 >>= FRACTION64; afx[6] = (LONG) eqP3;
  319. }
  320. VOID HFDBASIS64::vHalveStepSize()
  321. {
  322. // e2 = (e2 + e3) >> 3
  323. // e1 = (e1 - e2) >> 1
  324. // e3 >>= 2
  325. e2 += e3; e2 >>= 3;
  326. e1 -= e2; e1 >>= 1;
  327. e3 >>= 2;
  328. }
  329. VOID HFDBASIS64::vDoubleStepSize()
  330. {
  331. // e1 = 2e1 + e2
  332. // e3 = 4e3;
  333. // e2 = 8e2 - e3
  334. e1 <<= 1; e1 += e2;
  335. e3 <<= 2;
  336. e2 <<= 3; e2 -= e3;
  337. }
  338. VOID HFDBASIS64::vTakeStep()
  339. {
  340. e0 += e1;
  341. LONGLONG eqTmp = e2;
  342. e1 += e2;
  343. e2 += eqTmp; e2 -= e3;
  344. e3 = eqTmp;
  345. }
  346. VOID BEZIER64::vInit(
  347. POINTFIX* aptfx, // Pointer to 4 control points
  348. RECTFX* prcfxVis, // Pointer to bound box of visible area (may be NULL)
  349. LONGLONG* peqError) // Fractional maximum error (32.32 format)
  350. {
  351. LONGLONG eqTmp;
  352. cStepsHigh = 1;
  353. cStepsLow = 0;
  354. xHigh.vInit(aptfx[0].x, aptfx[1].x, aptfx[2].x, aptfx[3].x);
  355. yHigh.vInit(aptfx[0].y, aptfx[1].y, aptfx[2].y, aptfx[3].y);
  356. // Initialize error:
  357. eqErrorLow = *peqError;
  358. if (prcfxVis == (RECTFX*) NULL)
  359. prcfxClip = (RECTFX*) NULL;
  360. else
  361. {
  362. rcfxClip = *prcfxVis;
  363. prcfxClip = &rcfxClip;
  364. }
  365. while (((xHigh.vError(&eqTmp), eqTmp) > *gpeqErrorHigh) ||
  366. ((yHigh.vError(&eqTmp), eqTmp) > *gpeqErrorHigh))
  367. {
  368. cStepsHigh <<= 1;
  369. xHigh.vHalveStepSize();
  370. yHigh.vHalveStepSize();
  371. }
  372. }
  373. // Returns TRUE if there is another point after this one:
  374. BOOL BEZIER64::bNext(POINTFIX* pptfx)
  375. {
  376. POINTFIX aptfx[4];
  377. RECTFX rcfxBound;
  378. LONGLONG eqTmp;
  379. if (cStepsLow == 0)
  380. {
  381. // Optimization that if the bound box of the control points doesn't
  382. // intersect with the bound box of the visible area, render entire
  383. // curve as a single line:
  384. xHigh.vUntransform(&aptfx[0].x);
  385. yHigh.vUntransform(&aptfx[0].y);
  386. xLow.vInit(aptfx[0].x, aptfx[1].x, aptfx[2].x, aptfx[3].x);
  387. yLow.vInit(aptfx[0].y, aptfx[1].y, aptfx[2].y, aptfx[3].y);
  388. cStepsLow = 1;
  389. if (prcfxClip != (RECTFX*) NULL)
  390. vBoundBox(aptfx, &rcfxBound);
  391. if (prcfxClip == (RECTFX*) NULL || bIntersect(&rcfxBound, prcfxClip))
  392. {
  393. while (((xLow.vError(&eqTmp), eqTmp) > eqErrorLow) ||
  394. ((yLow.vError(&eqTmp), eqTmp) > eqErrorLow))
  395. {
  396. cStepsLow <<= 1;
  397. xLow.vHalveStepSize();
  398. yLow.vHalveStepSize();
  399. }
  400. }
  401. // This 'if' handles the case where the initial error for the Bezier
  402. // is already less than the target error:
  403. if (--cStepsHigh != 0)
  404. {
  405. xHigh.vTakeStep();
  406. yHigh.vTakeStep();
  407. if (((xHigh.vError(&eqTmp), eqTmp) > *gpeqErrorHigh) ||
  408. ((yHigh.vError(&eqTmp), eqTmp) > *gpeqErrorHigh))
  409. {
  410. cStepsHigh <<= 1;
  411. xHigh.vHalveStepSize();
  412. yHigh.vHalveStepSize();
  413. }
  414. while (!(cStepsHigh & 1) &&
  415. ((xHigh.vParentError(&eqTmp), eqTmp) <= *gpeqErrorHigh) &&
  416. ((yHigh.vParentError(&eqTmp), eqTmp) <= *gpeqErrorHigh))
  417. {
  418. xHigh.vDoubleStepSize();
  419. yHigh.vDoubleStepSize();
  420. cStepsHigh >>= 1;
  421. }
  422. }
  423. }
  424. xLow.vTakeStep();
  425. yLow.vTakeStep();
  426. pptfx->x = xLow.fxValue();
  427. pptfx->y = yLow.fxValue();
  428. cStepsLow--;
  429. if (cStepsLow == 0 && cStepsHigh == 0)
  430. return(FALSE);
  431. if (((xLow.vError(&eqTmp), eqTmp) > eqErrorLow) ||
  432. ((yLow.vError(&eqTmp), eqTmp) > eqErrorLow))
  433. {
  434. cStepsLow <<= 1;
  435. xLow.vHalveStepSize();
  436. yLow.vHalveStepSize();
  437. }
  438. while (!(cStepsLow & 1) &&
  439. ((xLow.vParentError(&eqTmp), eqTmp) <= eqErrorLow) &&
  440. ((yLow.vParentError(&eqTmp), eqTmp) <= eqErrorLow))
  441. {
  442. xLow.vDoubleStepSize();
  443. yLow.vDoubleStepSize();
  444. cStepsLow >>= 1;
  445. }
  446. return(TRUE);
  447. }
  448. /******************************Public*Routine******************************\
  449. * newpathrec (pppr,pcMax,cNeeded) *
  450. * *
  451. * Create a new pathrecord. *
  452. * *
  453. * History: *
  454. * Fri 19-Jun-1992 19:24:56 -by- Charles Whitmer [chuckwh] *
  455. * Added the quick out if we get enough points. *
  456. * *
  457. * 5-Dec-1990 -by- Paul Butzi [paulb] *
  458. * Wrote it. *
  459. \**************************************************************************/
  460. BOOL EPATHOBJ::newpathrec(PATHRECORD **pppr,COUNT *pcMax,COUNT cNeeded)
  461. {
  462. PATHALLOC *ppa = ppath->ppachain;
  463. *pcMax = 0;
  464. if ( ppa != (PPATHALLOC) NULL )
  465. {
  466. // we have a current pathalloc, see how much will fit
  467. // computation done into temps to avoid compiler assertion!
  468. POINTFIX *start = &(ppa->pprfreestart->aptfx[0]);
  469. POINTFIX *end = (POINTFIX *)((char *)ppa + ppa->siztPathAlloc);
  470. if ( end > start )
  471. {
  472. //Sundown safe truncation
  473. ASSERT4GB((ULONGLONG)(end - start));
  474. *pcMax = (ULONG)(end - start);
  475. }
  476. }
  477. // Now we can decide if we need a new pathalloc
  478. if ((*pcMax < cNeeded) && (*pcMax < PATHALLOCTHRESHOLD))
  479. {
  480. // allocate a new pathalloc, link it into path
  481. if ( (ppa = newpathalloc()) == (PPATHALLOC) NULL)
  482. return FALSE;
  483. ppa->ppanext = ppath->ppachain;
  484. ppath->ppachain = ppa;
  485. // adjust maxadd
  486. // Sundown safe truncation
  487. ASSERT4GB((ULONGLONG)(((char *)ppa + ppa->siztPathAlloc) -
  488. (char *)ppa->pprfreestart));
  489. ULONG numbytes = (ULONG)(((char *)ppa + ppa->siztPathAlloc) -
  490. (char *)ppa->pprfreestart);
  491. *pcMax = (numbytes - offsetof(PATHRECORD, aptfx))/sizeof(POINTFIX);
  492. }
  493. // create new pathrec header
  494. *pppr = ppa->pprfreestart;
  495. return(TRUE);
  496. }
  497. /******************************Public*Routine******************************\
  498. * EPATHOBJ::bFlatten()
  499. *
  500. * Cruise over a path, translating all of the beziers into sequences of lines.
  501. *
  502. * History:
  503. * 5-Dec-1990 -by- Paul Butzi [paulb]
  504. * Wrote it.
  505. \**************************************************************************/
  506. BOOL EPATHOBJ::bFlatten()
  507. {
  508. // stress failure in RFONTOBJ::bInsertMetricsPlusPath caused by invalid
  509. // ppath. After Beta2, we will pick up the fix from Adobe.
  510. if (!bValid())
  511. {
  512. return (FALSE);
  513. }
  514. // Run down the path, looking for records that contain beziers.
  515. // Skip over the records containing lines.
  516. for ( PATHRECORD *ppr = ppath->pprfirst;
  517. ppr != (PPATHREC) NULL;
  518. ppr = ppr->pprnext)
  519. {
  520. if (ppr->flags & PD_BEZIERS)
  521. {
  522. ppr = pprFlattenRec(ppr);
  523. if (ppr == (PPATHREC) NULL)
  524. return(FALSE);
  525. }
  526. }
  527. fl &= ~PO_BEZIERS;
  528. return(TRUE);
  529. }
  530. /******************************Public*Routine******************************\
  531. * EPATHOBJ::pprFlattenRec(ppr)
  532. *
  533. * Cruise over a path, translating all of the beziers into sequences of lines.
  534. *
  535. * History:
  536. * 5-Dec-1990 -by- Paul Butzi [paulb]
  537. * Wrote it.
  538. \**************************************************************************/
  539. PPATHREC EPATHOBJ::pprFlattenRec(PATHRECORD *ppr)
  540. {
  541. // Create a new record
  542. PATHRECORD *pprNew;
  543. COUNT maxadd;
  544. if ( newpathrec(&pprNew,&maxadd,MAXLONG) != TRUE )
  545. return (PPATHREC) NULL;
  546. // Take record of Beziers out of path list, and put a new record
  547. // in its place. Update 'pprNew->pprnext' when we exit.
  548. pprNew->pprprev = ppr->pprprev;
  549. pprNew->count = 0;
  550. pprNew->flags = (ppr->flags & ~PD_BEZIERS);
  551. if (pprNew->pprprev == (PPATHREC) NULL)
  552. ppath->pprfirst = pprNew;
  553. else
  554. pprNew->pprprev->pprnext = pprNew;
  555. POINTFIX aptfxControl[4]; // If needed, temp buf for control points
  556. PPOINTFIX pptfxControl; // Points to Bezier's 4 control points
  557. PPOINTFIX pptfxNext; // Points to 2nd point of next Bezier
  558. // Now, run down the beziers, flattening them into the record
  559. // First, set up for the first bezier in record
  560. if ((ppr->flags & PD_BEGINSUBPATH) == 0)
  561. {
  562. // Because we are not starting a new subpath we don't need to
  563. // enter the first control point into the record of lines. Since
  564. // all 4 control points for the first Bezier aren't contiguous in
  565. // memory, copy the points to aptfxControl[].
  566. aptfxControl[0] = ppr->pprprev->aptfx[ppr->pprprev->count - 1];
  567. pptfxNext = ppr->aptfx;
  568. for (LONG ii = 1; ii < 4; ii++)
  569. {
  570. // If the Bezier's control points are spread across two
  571. // pathrecords, then handle it.
  572. if (pptfxNext >= &ppr->aptfx[ppr->count])
  573. {
  574. ASSERTGDI(ppr->pprnext != NULL, "Lost the other control points");
  575. ppr = ppr->pprnext;
  576. ASSERTGDI((ppr->flags & (PD_BEZIERS | PD_BEGINSUBPATH)) != 0,
  577. "Mucked up continuation");
  578. pptfxNext = ppr->aptfx;
  579. }
  580. aptfxControl[ii] = *pptfxNext++;
  581. }
  582. pptfxControl = aptfxControl;
  583. ASSERTGDI(PATHALLOCTHRESHOLD > 3, "Threshold too small.");
  584. ASSERTGDI(pptfxNext <= &ppr->aptfx[ppr->count], "Threshold too small");
  585. }
  586. else
  587. {
  588. pptfxNext = ppr->aptfx + 4;
  589. pptfxControl = ppr->aptfx;
  590. pprNew->aptfx[pprNew->count++] = ppr->aptfx[0];
  591. }
  592. // Now run down the list of Beziers, flattening them out.
  593. while (TRUE)
  594. {
  595. // We've removing a curve, so adjust the curve count appropriately:
  596. cCurves--;
  597. // Crack Bezier described by points pointed to by pptfxControl:
  598. BEZIER bez;
  599. bez.vInit(pptfxControl);
  600. do
  601. {
  602. if ( pprNew->count >= maxadd )
  603. {
  604. // Since we're continuing this path record onto another,
  605. // we have to adjust this record's flags to note that:
  606. pprNew->flags &= ~(PD_ENDSUBPATH | PD_CLOSEFIGURE);
  607. // Filled the record, get a new one. Insert it after one we
  608. // just filled and adjust the pathalloc record.
  609. ppath->ppachain->pprfreestart = NEXTPATHREC(pprNew);
  610. PATHRECORD *pprNewNew;
  611. if (newpathrec(&pprNewNew,&maxadd,MAXLONG) != TRUE)
  612. return((PPATHREC) NULL);
  613. pprNewNew->pprprev = pprNew;
  614. pprNew->pprnext = pprNewNew;
  615. pprNew = pprNewNew;
  616. pprNew->count = 0;
  617. pprNew->flags = (ppr->flags &
  618. ~(PD_BEZIERS | PD_BEGINSUBPATH | PD_RESETSTYLE));
  619. }
  620. // Now that we've generated the next point, stash it into the
  621. // new path record:
  622. cCurves++;
  623. } while (bez.bNext(&pprNew->aptfx[pprNew->count++]));
  624. // Move on to the next bezier:
  625. // Sundown safe truncation
  626. COUNT cptfxRemaining = (COUNT)(&ppr->aptfx[ppr->count] - pptfxNext);
  627. if (cptfxRemaining <= 0)
  628. break;
  629. if (cptfxRemaining >= 3)
  630. {
  631. pptfxControl = pptfxNext - 1;
  632. pptfxNext += 3;
  633. }
  634. else
  635. {
  636. // Handle case where the Bezier's control points are spread
  637. // across two pathrecord's. Copy all the points to
  638. // aptfxControl[].
  639. pptfxNext--;
  640. for (INT ii = 0; ii < 4; ii++)
  641. {
  642. if (pptfxNext >= &ppr->aptfx[ppr->count])
  643. {
  644. ASSERTGDI(ppr != NULL, "Lost the other control points.");
  645. ppr = ppr->pprnext;
  646. ASSERTGDI((ppr->flags &
  647. (PD_BEZIERS | PD_BEGINSUBPATH)) != 0,
  648. "Mucked up continuation.");
  649. pptfxNext = ppr->aptfx;
  650. }
  651. aptfxControl[ii] = *pptfxNext++;
  652. }
  653. pptfxControl = aptfxControl;
  654. }
  655. }
  656. ASSERTGDI(pptfxNext == &ppr->aptfx[ppr->count], "Lost some points");
  657. // Adjust the pathalloc record:
  658. ppath->ppachain->pprfreestart = NEXTPATHREC(pprNew);
  659. pprNew->pprnext = ppr->pprnext;
  660. if (pprNew->pprnext == (PPATHREC) NULL)
  661. ppath->pprlast = pprNew;
  662. else
  663. pprNew->pprnext->pprprev = pprNew;
  664. return(pprNew);
  665. }