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.

645 lines
20 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: pathwide.hxx
  3. *
  4. * Path widening defines.
  5. *
  6. * CLASS HIERARCHY
  7. *
  8. * In constructing the wide-line, we keep track of 4 paths:
  9. *
  10. * 1) The original path.
  11. * 2) The path holding the vertices of the polygonized pen.
  12. * 3) The 'left' side of the wide-line outline.
  13. * 4) The 'right' side of the wide-line outline.
  14. *
  15. * To keep track of the latter 3 paths, we use:
  16. *
  17. * PATHMEMOBJ // Regular path
  18. * |
  19. * v
  20. * WIDEPATHOBJ // Path object to keep track of one side of the
  21. * | // wide-line. Adds methods for easily adding
  22. * | // one point at a time.
  23. * v
  24. * WIDEPENOBJ // Path object to keep the pen shape. A pen is
  25. * // composed of an arbitrary number of points,
  26. * // like a path, so we make it a path. Plus we
  27. * // add some pen functionality.
  28. *
  29. * It was useful to compartmentalize the task of the widener into separate
  30. * base classes:
  31. *
  32. * READER // Reads the original path a point at a time
  33. * |
  34. * v
  35. * LINER // Reads the path a line at a time (flattening
  36. * | // Beziers and generating close-figure lines as
  37. * | // it goes).
  38. * v
  39. * STYLER // Handles styling by hacking the lines into
  40. * | // itty bitty pieces.
  41. * v
  42. * WIDENER // Widens the path by generating the points at
  43. * // every line-join and end-cap.
  44. *
  45. * Created: 9-Oct-1991
  46. * Author: J. Andrew Goossen [andrewgo]
  47. *
  48. * Copyright (c) 1991-1999 Microsoft Corporation
  49. \**************************************************************************/
  50. #if DBG
  51. // #define DEBUG_WIDE
  52. #endif
  53. class WIDENER;
  54. #define SQUARE(x) ((x) * (x))
  55. #define LPLUSHALFTOFX(x) (LTOFX(x) + (LTOFX(1) >> 1))
  56. /***********************************Struct*********************************\
  57. * struct HOBBY
  58. *
  59. * Structure used for containing half a Hobby pen.
  60. *
  61. * History:
  62. * 9-Oct-1991 -by- J. Andrew Goossen [andrewgo]
  63. * Wrote it.
  64. \**************************************************************************/
  65. typedef struct _HOBBY
  66. {
  67. PPOINTFIX pptfx;
  68. COUNT cptfx;
  69. } HOBBY, *PHOBBY; /* hob, phob */
  70. /*********************************class************************************\
  71. * class EVECTORFLEXT
  72. *
  73. * Can use VECTORFX's.
  74. *
  75. * History:
  76. * 22-Oct-1991 -by- J. Andrew Goossen [andrewgo]
  77. * Wrote it.
  78. \**************************************************************************/
  79. class EVECTORFLEXT : public EVECTORFL /* evecfl */
  80. {
  81. public:
  82. EVECTORFLEXT(VECTORFX& vec)
  83. {
  84. x.vFxToEf(vec.x);
  85. y.vFxToEf(vec.y);
  86. }
  87. BOOL bToVECTORFX(VECTORFX& vec)
  88. {
  89. return(x.bEfToFx(vec.x) && y.bEfToFx(vec.y));
  90. }
  91. };
  92. /*********************************class************************************\
  93. * class LINEDATA
  94. *
  95. * Keeps track of useful stuff about the current line in the original
  96. * path that we're processing.
  97. *
  98. * History:
  99. * 22-Oct-1991 -by- J. Andrew Goossen [andrewgo]
  100. * Wrote it.
  101. \**************************************************************************/
  102. // LINEDATA flags:
  103. #define LDF_INVERT 0x0001L
  104. #define LDF_VECSQUARECOMPUTED 0x0002L
  105. #define LDF_VECPERPCOMPUTED 0x0004L
  106. #define LDF_VECDRAWCOMPUTED 0x0008L
  107. #define LDF_NORMALIZEDCOMPUTED 0x0010L
  108. class LINEDATA /* ld */
  109. {
  110. public:
  111. FLONG fl; // LINEDATA flags, as above
  112. PPATHREC ppr; // Pathrecord containing point
  113. PPOINTFIX pptfx; // *pptfx == -ptfx if bInvert is TRUE
  114. LONGLONG fxCrossStart;
  115. LONGLONG fxCrossEnd;
  116. EVECTORFX vecLine; // Actual line vector
  117. EVECTORFX vecTangent; // True tangent to current point. Direction
  118. // only -- to be used for calculating perps
  119. // Cached values:
  120. EVECTORFX vecSquare; // Vector to offset to square cap start
  121. EVECTORFX vecPerp; // Perpendicular vector to line
  122. EVECTORFX vecDraw; // Drawing vector for line
  123. POINTFL ptflNormalized; // Normalized version of line vector
  124. BOOL bInvert() { return(fl & LDF_INVERT); }
  125. VOID vSetInvert() { fl |= LDF_INVERT; }
  126. VOID vClearInvert() { fl &= ~LDF_INVERT; }
  127. VOID vSetVecSquareComputed() { fl |= LDF_VECSQUARECOMPUTED; }
  128. VOID vSetVecPerpComputed() { fl |= LDF_VECPERPCOMPUTED; }
  129. VOID vSetVecDrawComputed() { fl |= LDF_VECDRAWCOMPUTED; }
  130. VOID vSetNormalizedComputed() { fl |= LDF_NORMALIZEDCOMPUTED; }
  131. BOOL bVecSquareComputed() { return(fl & LDF_VECSQUARECOMPUTED); }
  132. BOOL bVecPerpComputed() { return(fl & LDF_VECPERPCOMPUTED); }
  133. BOOL bVecDrawComputed() { return(fl & LDF_VECDRAWCOMPUTED); }
  134. BOOL bNormalizedComputed() { return(fl & LDF_NORMALIZEDCOMPUTED); }
  135. VOID vInit() { fl = 0; }
  136. VOID vInit(POINTFIX& ptfxEnd, POINTFIX& ptfxStart)
  137. { fl = 0;
  138. vecLine = ptfxEnd;
  139. vecLine -= ptfxStart;
  140. vecTangent = vecLine; }
  141. // bToLeftSide() returns true if the perpendicular for the line
  142. // falls to the left of the draw vector:
  143. BOOL bToLeftSide() { return(fxCrossStart > fxCrossEnd); }
  144. // bSamePenSection() returns true if the two lines have perpendicular
  145. // vectors in the same area:
  146. BOOL bSamePenSection(LINEDATA& ld)
  147. {
  148. return((pptfx == ld.pptfx) && (bToLeftSide() == ld.bToLeftSide()));
  149. }
  150. };
  151. typedef LINEDATA *PLINEDATA;
  152. /*********************************Class************************************\
  153. * class WIDEPATHOBJ
  154. *
  155. * History:
  156. * 12-Sep-1991 -by- J. Andrew Goossen [andrewgo]
  157. * Wrote it.
  158. \**************************************************************************/
  159. class WIDEPATHOBJ : public PATHMEMOBJ /* wpath */
  160. {
  161. private:
  162. #ifdef DEBUG_WIDE
  163. BOOL bOpenPath;
  164. #endif
  165. protected:
  166. BOOL bOutOfMemory;
  167. PPOINTFIX pptfxPathRecCurrent;
  168. PPOINTFIX pptfxPathRecEnd;
  169. PPATHREC pprFigureStart;
  170. BOOL bGrowPath();
  171. VOID vGrowPathAndAddPoint(
  172. PPOINTFIX, PEVECTORFX = (PEVECTORFX) NULL, BOOL = FALSE);
  173. public:
  174. WIDEPATHOBJ()
  175. {
  176. bOutOfMemory = FALSE;
  177. #ifdef DEBUG_WIDE
  178. bOpenPath = FALSE;
  179. #endif
  180. }
  181. ~WIDEPATHOBJ() {}
  182. VOID vAddPoint(PPOINTFIX pptfx, BOOL bAddRecordIfNeeded = TRUE)
  183. {
  184. #ifdef DEBUG_WIDE
  185. ASSERTGDI(bOpenPath, "vAddPoint path not open!");
  186. #endif
  187. if (pptfxPathRecCurrent >= pptfxPathRecEnd)
  188. {
  189. #ifdef DEBUG_WIDE
  190. ASSERTGDI(pptfxPathRecCurrent == pptfxPathRecEnd,
  191. "vAddPoint out of bounds!");
  192. #endif
  193. if (bAddRecordIfNeeded)
  194. vGrowPathAndAddPoint(pptfx);
  195. }
  196. else
  197. {
  198. #ifdef DEBUG_WIDE
  199. ASSERTGDI((PBYTE) pptfxPathRecCurrent - (PBYTE) ppath->ppachain
  200. < (LONG) ppath->ppachain->siztPathAlloc, "vAddPoint out of bounds.");
  201. #endif
  202. *pptfxPathRecCurrent++ = *pptfx;
  203. }
  204. }
  205. VOID vAddPoint(PPOINTFIX pptfx, PEVECTORFX pvec, BOOL bInvert)
  206. {
  207. #ifdef DEBUG_WIDE
  208. ASSERTGDI(bOpenPath, "vAddPoint2 path not open!");
  209. #endif
  210. if (pptfxPathRecCurrent >= pptfxPathRecEnd)
  211. {
  212. #ifdef DEBUG_WIDE
  213. ASSERTGDI(pptfxPathRecCurrent == pptfxPathRecEnd,
  214. "vAddPoint2 out of bounds!");
  215. #endif
  216. vGrowPathAndAddPoint(pptfx, pvec, bInvert);
  217. }
  218. else
  219. {
  220. #ifdef DEBUG_WIDE
  221. ASSERTGDI((PBYTE) pptfxPathRecCurrent - (PBYTE) ppath->ppachain
  222. < (LONG) ppath->ppachain->siztPathAlloc, "vAddPoint2 out of bounds.");
  223. #endif
  224. // 'bInvert' will usually be constant, and so one of these code
  225. // paths will optimize away:
  226. if (bInvert)
  227. {
  228. pptfxPathRecCurrent->x = pptfx->x - pvec->x;
  229. pptfxPathRecCurrent->y = pptfx->y - pvec->y;
  230. }
  231. else
  232. {
  233. pptfxPathRecCurrent->x = pptfx->x + pvec->x;
  234. pptfxPathRecCurrent->y = pptfx->y + pvec->y;
  235. }
  236. pptfxPathRecCurrent++;
  237. }
  238. }
  239. VOID vReverseConcatenate(WIDEPATHOBJ&);
  240. VOID vPrependBeforeFigure();
  241. VOID vPrependBeforeSubpath();
  242. VOID vMarkFigureStart() { pprFigureStart = ppath->pprlast; }
  243. BOOL bBeginFigure();
  244. VOID vEndFigure();
  245. VOID vCloseFigure() { ppath->pprlast->flags |= PD_CLOSEFIGURE; }
  246. BOOL bValid() { return(PATHMEMOBJ::bValid() && !bOutOfMemory); }
  247. VOID vSetError() { bOutOfMemory = TRUE; }
  248. };
  249. /******************************Public*Routine******************************\
  250. * WIDEPATHOBJ::vAddPoint(pptfx, pvec, bInvert)
  251. *
  252. * Adds a single point to the path. The added point is the given point
  253. * plus the specified vector (minus the vector if bInvert is TRUE).
  254. *
  255. * History:
  256. * 1-Oct-1991 -by- J. Andrew Goossen [andrewgo]
  257. * Wrote it.
  258. \**************************************************************************/
  259. /*********************************Class************************************\
  260. * class WIDEPENOBJ
  261. *
  262. * History:
  263. * 12-Sep-1991 -by- J. Andrew Goossen [andrewgo]
  264. * Wrote it.
  265. \**************************************************************************/
  266. class WIDEPENOBJ : public WIDEPATHOBJ /* wpen */
  267. {
  268. private:
  269. // Pre-computed look-up tables containing points of circular Hobby pens
  270. // for widths 1 through 6:
  271. #define HOBBY_TABLE_SIZE 6L
  272. static POINTFIX aptfxHobby1[4];
  273. static POINTFIX aptfxHobby2[5];
  274. static POINTFIX aptfxHobby3[6];
  275. static POINTFIX aptfxHobby4[8];
  276. static POINTFIX aptfxHobby5[10];
  277. static POINTFIX aptfxHobby6[10];
  278. static HOBBY ahob[HOBBY_TABLE_SIZE];
  279. BOOL bHobby; // TRUE if this is a Hobby pen
  280. BOOL bThicken(PPOINTFIX pptfx); // Thickens pen if need-be
  281. BOOL bHobbyize(EVECTORFX avec[]);// Makes a Hobby pen if need-be
  282. BOOL bPenFlatten(PPOINTFIX); // Converts Beziers to lines
  283. VOID vAddPenPoint(PPOINTFIX); // Adds a point to the end of our path
  284. public:
  285. WIDEPENOBJ() { bHobby = FALSE; }
  286. BOOL bIsHobby() { return(bHobby); }
  287. BOOL bIsHobby(BOOL b) { return(bHobby = b); }
  288. BOOL bPolygonizePen(EXFORMOBJ&, LONG);
  289. VOID vDetermineDrawVertex(EVECTORFX&, LINEDATA&);
  290. COUNT cptAddRound(WIDENER&, LINEDATA&, LINEDATA&,
  291. BOOL, BOOL, BOOL);
  292. VOID vAddRoundEndCap(WIDENER&, LINEDATA&, BOOL, BOOL);
  293. };
  294. /*********************************class************************************\
  295. * class READER
  296. *
  297. * Reads the path.
  298. *
  299. * History:
  300. * 22-Oct-1991 -by- J. Andrew Goossen [andrewgo]
  301. * Wrote it.
  302. \**************************************************************************/
  303. // Path widening flags:
  304. #define FW_MORETOENUM 0x00000001L
  305. #define FW_DOINGSTYLES 0x00000002L
  306. #define FW_STYLENEXT 0x00000004L
  307. #define FW_FIGURESTYLED 0x00000008L
  308. #define FW_ALLROUND 0x00000010L
  309. class READER
  310. {
  311. private:
  312. EPATHOBJ* pepoSpine;
  313. PATHDATA pd;
  314. VOID vMoreToEnum(BOOL b) { vSetFlag(b, FW_MORETOENUM); }
  315. BOOL bMoreToEnum() { return(fl & FW_MORETOENUM); }
  316. PPOINTFIX pptfxRead;
  317. PPOINTFIX pptfxEnd;
  318. protected:
  319. FLONG fl; // For widening flags, as above
  320. VOID vSetFlag(BOOL b, FLONG flBit)
  321. {
  322. if (b)
  323. fl |= flBit;
  324. else
  325. fl &= ~flBit;
  326. }
  327. READER(EPATHOBJ& epo) { pepoSpine = &epo;
  328. pepoSpine->vEnumStart();
  329. vMoreToEnum(TRUE); }
  330. BOOL bIsBezier() { return(pd.flags & PD_BEZIERS); }
  331. BOOL bNextFigure();
  332. BOOL bNextPoint(POINTFIX& ptfx);
  333. // Only valid when !bNextPoint():
  334. BOOL bIsClosedFigure() { return(pd.flags & PD_CLOSEFIGURE); }
  335. };
  336. /*********************************class************************************\
  337. * class LINER
  338. *
  339. * Cracks Beziers and handles CloseFigures.
  340. *
  341. * History:
  342. * 22-Oct-1991 -by- J. Andrew Goossen [andrewgo]
  343. * Wrote it.
  344. \**************************************************************************/
  345. enum WIDENEVENT { WE_STARTFIGURE, // Figure starts at 'ptfxThis'
  346. WE_ENDFIGURE, // Figure ends at 'ptfxThis'
  347. WE_CLOSEFIGURE, // Do a close figure join at 'ptfxThis'
  348. WE_JOIN, // Do a join at 'ptfxThis'
  349. WE_BEZIERJOIN, // Do a Bezier join at 'ptfxThis'
  350. WE_STOPDASH, // Stop a styling dash at 'ptfxThis'
  351. WE_STARTDASH, // Start a styling dash at 'ptfxThis'
  352. WE_ZEROFIGURE, // Figure has zero length at 'ptfxThis'
  353. WE_FINISHFIGURE, // Do start-cap of figure at 'ptfxThis'
  354. WE_DONEPATH };
  355. enum LINESTATE { LS_READPATH, // Next point in figure comes from path
  356. LS_STARTFIGURE, // Next point in path is the start of
  357. // a figure
  358. LS_FINISHFIGURE, // Go back to first point in figure
  359. LS_READBEZIER, // Next point comes from current Bezier
  360. LS_DONEPATH };
  361. class LINER : public READER
  362. {
  363. private:
  364. BEZIER bez;
  365. BOOL bReadLine(LINEDATA& ld);
  366. POINTFIX ptfxNext; // Next point in path after 'ptfxThis' (see below)
  367. POINTFIX ptfxStartFigure; // Keep around for later
  368. LINEDATA ldStartFigure; // Start point for current figure
  369. LINEDATA ldBuf[2]; // Line vector data buffer for current lines
  370. LINESTATE ls; // Reading path state
  371. VOID vNextPoint();
  372. VOID vZeroFigure(); // Sets up for a zero-length figure
  373. protected:
  374. LINEDATA ldEndTangent; // Line vector data for last line in figure
  375. LINEDATA ldStartTangent; // Line vector data for first line in figure
  376. public:
  377. LINER(EPATHOBJ& epo) : READER(epo)
  378. {
  379. if (!bNextFigure())
  380. ls = LS_DONEPATH;
  381. else
  382. {
  383. bNextPoint(ptfxNext);
  384. ptfxStartFigure = ptfxNext;
  385. ls = LS_STARTFIGURE;
  386. }
  387. }
  388. VOID vNextEvent();
  389. // Keeps track of all the info needed to add a join, start-cap or end-cap:
  390. WIDENEVENT we; // Flag to indicate start-cap, end-cap, etc.
  391. POINTFIX ptfxThis; // Point at which to add cap or join
  392. PLINEDATA pldIn; // Vector of line entering 'ptfxThis' (used for
  393. // end-caps and joins)
  394. PLINEDATA pldOut; // Vector of line exiting 'ptfxThis' (used for
  395. // start-caps and joins)
  396. };
  397. /*********************************class************************************\
  398. * class STYLER
  399. *
  400. * Hacks up the path into itty bitty pieces to feed to the widener.
  401. *
  402. * History:
  403. * 22-Oct-1991 -by- J. Andrew Goossen [andrewgo]
  404. * Wrote it.
  405. \**************************************************************************/
  406. class STYLER : public LINER
  407. {
  408. private:
  409. VOID vStyleNext(BOOL b) { vSetFlag(b, FW_STYLENEXT); }
  410. VOID vDoingStyles(BOOL b) { vSetFlag(b, FW_DOINGSTYLES); }
  411. BOOL bStyleNext() { return(fl & FW_STYLENEXT); }
  412. BOOL bDoingStyles() { return(fl & FW_DOINGSTYLES); }
  413. PFLOAT_LONG pstyleStart;
  414. PFLOAT_LONG pstyleCurrent;
  415. PFLOAT_LONG pstyleEnd;
  416. EFLOAT efRemainingLength;// Length remaining in current line
  417. EFLOAT efStyleLength; // Length of current dash or gap
  418. EFLOAT efDoneLength; // Length of current line done
  419. EFLOAT efLineLength; // efLineLength = efDoneLength + efRemainingLength
  420. POINTFIX ptfxLineStart; // Start point of line
  421. protected:
  422. EFLOAT efWorldLength(EVECTORFX);
  423. EFLOAT efNextStyleLength();
  424. VOID vResetStyles() { pstyleCurrent = pstyleStart; }
  425. // These two actually get initialized by the derived class because it's
  426. // a bit of work, and it will know if we'll need them:
  427. MATRIX mxDeviceToWorld;
  428. EXFORMOBJ exoDeviceToWorld;
  429. public:
  430. STYLER(EPATHOBJ&, PLINEATTRS);
  431. VOID vNextStyleEvent();
  432. };
  433. // Prototype used in WIDENER:
  434. VOID vAddNice(WIDEPATHOBJ&, PPOINTFIX, PEVECTORFX, BOOL);
  435. /*********************************class************************************\
  436. * class WIDENER
  437. *
  438. * Widens the path.
  439. *
  440. * History:
  441. * 22-Oct-1991 -by- J. Andrew Goossen [andrewgo]
  442. * Wrote it.
  443. \**************************************************************************/
  444. class WIDENER : public STYLER
  445. {
  446. friend VOID WIDEPENOBJ::vAddRoundEndCap(WIDENER&, LINEDATA&, BOOL, BOOL);
  447. friend COUNT WIDEPENOBJ::cptAddRound(WIDENER&, LINEDATA&, LINEDATA&,
  448. BOOL, BOOL, BOOL);
  449. private:
  450. WIDEPENOBJ wpen;
  451. WIDEPATHOBJ wpathLeft;
  452. WIDEPATHOBJ wpathRight;
  453. ULONG iJoin;
  454. ULONG iEndCap;
  455. VOID vFigureStyled(BOOL b) { vSetFlag(b, FW_FIGURESTYLED); }
  456. VOID vAllRound(BOOL b) { vSetFlag(b, FW_ALLROUND); }
  457. BOOL bFigureStyled() { return(fl & FW_FIGURESTYLED); }
  458. BOOL bAllRound() { return(fl & FW_ALLROUND); }
  459. EFLOAT efHalfWidthMiterLimitSquared;
  460. EFLOAT efHalfWidth;
  461. VOID vVecPerpCompute(LINEDATA&);
  462. VOID vVecSquareCompute(LINEDATA&);
  463. VOID vVecDrawCompute(LINEDATA&);
  464. protected:
  465. BOOL bMiterInLimit(EVECTORFX);
  466. EVECTORFX vecInDraw() { if (!pldIn->bVecDrawComputed())
  467. vVecDrawCompute(*pldIn);
  468. return(pldIn->vecDraw); }
  469. EVECTORFX vecInPerp() { if (!pldIn->bVecPerpComputed())
  470. vVecPerpCompute(*pldIn);
  471. return(pldIn->vecPerp); }
  472. EVECTORFX vecInSquare() { if (!pldIn->bVecSquareComputed())
  473. vVecSquareCompute(*pldIn);
  474. return(pldIn->vecSquare); }
  475. EVECTORFX vecOutDraw() { if (!pldOut->bVecDrawComputed())
  476. vVecDrawCompute(*pldOut);
  477. return(pldOut->vecDraw); }
  478. EVECTORFX vecOutPerp() { if (!pldOut->bVecPerpComputed())
  479. vVecPerpCompute(*pldOut);
  480. return(pldOut->vecPerp); }
  481. EVECTORFX vecOutSquare() { if (!pldOut->bVecSquareComputed())
  482. vVecSquareCompute(*pldOut);
  483. return(pldOut->vecSquare); }
  484. VOID vAddLeft(EVECTORFX& vec, BOOL bInvert = FALSE)
  485. { wpathLeft.vAddPoint(&ptfxThis, &vec, !bInvert); }
  486. VOID vAddLeft(PEVECTORFX pvec, BOOL bInvert)
  487. { wpathLeft.vAddPoint(&ptfxThis, pvec, !bInvert); }
  488. VOID vAddLeft() { wpathLeft.vAddPoint(&ptfxThis); }
  489. VOID vAddLeftNice(PEVECTORFX pvec, BOOL bInvert)
  490. { vAddNice(wpathLeft, &ptfxThis, pvec, !bInvert); }
  491. VOID vAddRight(EVECTORFX& vec, BOOL bInvert = FALSE)
  492. { wpathRight.vAddPoint(&ptfxThis, &vec, bInvert); }
  493. VOID vAddRight(PEVECTORFX pvec, BOOL bInvert)
  494. { wpathRight.vAddPoint(&ptfxThis, pvec, bInvert); }
  495. VOID vAddRight() { wpathRight.vAddPoint(&ptfxThis); }
  496. VOID vAddRightNice(PEVECTORFX pvec, BOOL bInvert)
  497. { vAddNice(wpathRight, &ptfxThis, pvec, bInvert); }
  498. VOID vAddJoin(BOOL);
  499. VOID vAddRoundJoin(BOOL);
  500. VOID vAddEndCap();
  501. VOID vAddStartCap();
  502. BOOL bWiden();
  503. VOID vSetError() { wpathRight.vSetError(); }
  504. public:
  505. WIDENER(EPATHOBJ&, EXFORMOBJ&, PLINEATTRS);
  506. BOOL bValid() { return(wpathRight.bValid() &&
  507. wpathLeft.bValid() &&
  508. wpen.bValid()); }
  509. VOID vMakeItWide(EPATHOBJ&);
  510. };