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.

1192 lines
29 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 2000 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * CustomLineCap.cpp
  8. *
  9. * Abstract:
  10. *
  11. * Implementation of custom line cap class
  12. *
  13. * Revision History:
  14. *
  15. * 02/21/00 ikkof
  16. * Created it
  17. *
  18. \**************************************************************************/
  19. #include "precomp.hpp"
  20. /**************************************************************************\
  21. *
  22. * Function Description:
  23. *
  24. * ComputeCapLength
  25. *
  26. * Compute the length of the cap from zero along the + y axis
  27. * Typically custom caps will return a negative length.
  28. *
  29. * Arguments:
  30. *
  31. * GpPointF *points, the points representing the cap path.
  32. * BYTE *types, the types "
  33. * INT pointCount how many points in the above arrays.
  34. *
  35. * Return Value:
  36. * REAL -- the length.
  37. *
  38. * 08/25/2000 [asecchia]
  39. * Created it
  40. *
  41. \**************************************************************************/
  42. static REAL ComputeCapLength(
  43. DpPath * path
  44. )
  45. {
  46. const GpPointF *points = path->GetPathPoints();
  47. const BYTE *types = path->GetPathTypes();
  48. INT pointCount = path->GetPointCount();
  49. REAL length = 0.0f;
  50. BOOL isClosed = (types[pointCount-1] & PathPointTypeCloseSubpath) != 0;
  51. // Eliminate degenerate paths and uninitialized paths.
  52. if( points && (pointCount>1) )
  53. {
  54. REAL curlength = 0.0f;
  55. GpArrayIterator<GpPointF> pIt(const_cast<GpPointF *>(points), pointCount);
  56. // Get the last item in the list.
  57. pIt.SeekLast();
  58. GpPointF *lastPoint = pIt.CurrentItem();
  59. // Begin at the first item.
  60. pIt.SeekFirst();
  61. GpPointF *curPoint;
  62. if(!isClosed)
  63. {
  64. // if it's not a closed path, skip the last-to-first point line.
  65. lastPoint = pIt.CurrentItem();
  66. }
  67. while(!pIt.IsDone())
  68. {
  69. curPoint = pIt.CurrentItem();
  70. if(intersect_line_yaxis(*curPoint, *lastPoint, &curlength))
  71. {
  72. length = min(length, curlength);
  73. }
  74. lastPoint = curPoint;
  75. pIt.Next();
  76. }
  77. }
  78. return length;
  79. }
  80. GpStatus GpCustomLineCap::ComputeFillCapLength()
  81. {
  82. FillLength = -ComputeCapLength(FillPath);
  83. // Fill paths cannot have a length of zero or less.
  84. if(FillLength < REAL_EPSILON)
  85. {
  86. return NotImplemented;
  87. }
  88. return Ok;
  89. }
  90. GpStatus GpCustomLineCap::ComputeStrokeCapLength()
  91. {
  92. StrokeLength = -ComputeCapLength(StrokePath);
  93. // Stroke paths can have a length of zero - we explicitly check for
  94. // this and handle it.
  95. if(StrokeLength < -REAL_EPSILON)
  96. {
  97. return NotImplemented;
  98. }
  99. return Ok;
  100. }
  101. GpCustomLineCap::GpCustomLineCap(
  102. const DpPath* fillPath,
  103. const DpPath* strokePath,
  104. GpLineCap baseCap,
  105. REAL baseInset
  106. ) : GpFillPath (NULL, 0, PointsBuffer1, TypesBuffer1, CLCAP_BUFFER_SIZE, FillModeWinding, DpPath::PossiblyNonConvex),
  107. GpStrokePath(NULL, 0, PointsBuffer2, TypesBuffer2, CLCAP_BUFFER_SIZE, FillModeWinding, DpPath::PossiblyNonConvex)
  108. {
  109. Initialize();
  110. GpStatus status = Ok;
  111. if(fillPath)
  112. {
  113. GpPath* gpFillPath = GpPath::GetPath(fillPath);
  114. status = SetFillPath(gpFillPath);
  115. }
  116. if(status == Ok && strokePath)
  117. {
  118. GpPath* gpStrokePath = GpPath::GetPath(strokePath);
  119. status = SetStrokePath(gpStrokePath);
  120. }
  121. if(status == Ok)
  122. {
  123. switch(baseCap)
  124. {
  125. case LineCapFlat:
  126. case LineCapSquare:
  127. case LineCapRound:
  128. case LineCapTriangle:
  129. BaseCap = baseCap;
  130. break;
  131. default:
  132. BaseCap = LineCapFlat;
  133. break;
  134. }
  135. BaseInset = baseInset;
  136. }
  137. else
  138. {
  139. Reset();
  140. SetValid(FALSE);
  141. m_creationStatus = status; // this defaults to Ok.
  142. }
  143. }
  144. VOID
  145. GpCustomLineCap::ResetFillPath()
  146. {
  147. GpFillPath.Reset(FillModeWinding);
  148. }
  149. VOID
  150. GpCustomLineCap::ResetStrokePath()
  151. {
  152. GpStrokePath.Reset(FillModeWinding);
  153. }
  154. VOID
  155. GpCustomLineCap::ReverseFillPath()
  156. {
  157. GpFillPath.Reverse();
  158. }
  159. VOID
  160. GpCustomLineCap::ReverseStrokePath()
  161. {
  162. GpStrokePath.Reverse();
  163. }
  164. VOID
  165. GpCustomLineCap::Reset()
  166. {
  167. // Clean up and reset to the default state.
  168. Initialize();
  169. ResetFillPath();
  170. ResetStrokePath();
  171. }
  172. GpCustomLineCap::GpCustomLineCap(
  173. const GpCustomLineCap* customCap
  174. ) : GpFillPath (NULL, 0, PointsBuffer1, TypesBuffer1, CLCAP_BUFFER_SIZE, FillModeWinding, DpPath::PossiblyNonConvex),
  175. GpStrokePath(NULL, 0, PointsBuffer2, TypesBuffer2, CLCAP_BUFFER_SIZE, FillModeWinding, DpPath::PossiblyNonConvex)
  176. {
  177. Initialize();
  178. if(customCap == NULL)
  179. return;
  180. GpStatus status = Ok;
  181. status = SetFillPath(customCap->FillPath);
  182. if(status == Ok)
  183. status = SetStrokePath(customCap->StrokePath);
  184. if(status == Ok)
  185. {
  186. GpLineCap baseCap = customCap->BaseCap;
  187. switch(baseCap)
  188. {
  189. case LineCapFlat:
  190. case LineCapSquare:
  191. case LineCapRound:
  192. case LineCapTriangle:
  193. BaseCap = baseCap;
  194. break;
  195. default:
  196. BaseCap = LineCapFlat;
  197. break;
  198. }
  199. BaseInset = customCap->BaseInset;
  200. StrokeStartCap = customCap->StrokeStartCap;
  201. StrokeEndCap = customCap->StrokeEndCap;
  202. StrokeJoin = customCap->StrokeJoin;
  203. WidthScale = customCap->WidthScale;
  204. }
  205. else
  206. {
  207. Reset();
  208. SetValid(FALSE);
  209. m_creationStatus = status; // this defaults to Ok.
  210. }
  211. }
  212. GpCustomLineCap::~GpCustomLineCap()
  213. {
  214. }
  215. GpStatus
  216. GpCustomLineCap::SetFillPath(
  217. const DpPath* path
  218. )
  219. {
  220. // If the given path is NULL, empty the fill path.
  221. if(path == NULL)
  222. {
  223. ResetFillPath();
  224. return Ok;
  225. }
  226. INT count = path->GetPointCount();
  227. return SetFillPath(path->GetPathPoints(), path->GetPathTypes(), count);
  228. }
  229. GpStatus
  230. GpCustomLineCap::SetFillPath(
  231. const GpPointF* fillPoints,
  232. const BYTE* fillTypes,
  233. INT fillCount)
  234. {
  235. if(fillCount == 0)
  236. {
  237. ResetFillPath();
  238. return Ok;
  239. }
  240. if(fillCount <= 2 || fillPoints == NULL || fillTypes == NULL)
  241. return InvalidParameter;
  242. GpPathData pathData;
  243. pathData.Points = const_cast<GpPointF *>(fillPoints);
  244. pathData.Types = const_cast<BYTE *>(fillTypes);
  245. pathData.Count = fillCount;
  246. GpStatus status = FillPath->SetPathData(&pathData);
  247. if(status == Ok)
  248. {
  249. status = ComputeFillCapLength();
  250. }
  251. return status;
  252. }
  253. GpStatus
  254. GpCustomLineCap::GetFillPath(
  255. GpPath* path
  256. ) const
  257. {
  258. if(!path)
  259. return InvalidParameter;
  260. GpPathData pathData;
  261. pathData.Points = const_cast<GpPointF *>(FillPath->GetPathPoints());
  262. pathData.Types = const_cast<BYTE *>(FillPath->GetPathTypes());
  263. pathData.Count = FillPath->GetPointCount();
  264. return path->SetPathData(&pathData);
  265. }
  266. GpStatus
  267. GpCustomLineCap::SetStrokePath(
  268. const DpPath* path
  269. )
  270. {
  271. // If the given path is NULL, empty the stroke path.
  272. if(path == NULL)
  273. {
  274. ResetStrokePath();
  275. return Ok;
  276. }
  277. INT count = path->GetPointCount();
  278. return SetStrokePath(path->GetPathPoints(), path->GetPathTypes(), count);
  279. }
  280. GpStatus
  281. GpCustomLineCap::SetStrokePath(
  282. const GpPointF* strokePoints,
  283. const BYTE* strokeTypes,
  284. INT strokeCount)
  285. {
  286. if(strokeCount == 0)
  287. {
  288. ResetStrokePath();
  289. return Ok;
  290. }
  291. if(strokeCount <= 1 || strokePoints == NULL || strokeTypes == NULL)
  292. return InvalidParameter;
  293. GpPathData pathData;
  294. pathData.Points = const_cast<GpPointF *>(strokePoints);
  295. pathData.Types = const_cast<BYTE *>(strokeTypes);
  296. pathData.Count = strokeCount;
  297. GpStatus status = StrokePath->SetPathData(&pathData);
  298. if(status == Ok)
  299. {
  300. status = ComputeStrokeCapLength();
  301. }
  302. return status;
  303. }
  304. GpStatus
  305. GpCustomLineCap::GetStrokePath(
  306. GpPath* path
  307. ) const
  308. {
  309. if(!path)
  310. return InvalidParameter;
  311. GpPathData pathData;
  312. pathData.Points = const_cast<GpPointF *>(StrokePath->GetPathPoints());
  313. pathData.Types = const_cast<BYTE *>(StrokePath->GetPathTypes());
  314. pathData.Count = StrokePath->GetPointCount();
  315. return path->SetPathData(&pathData);
  316. }
  317. BOOL
  318. GpCustomLineCap::IsEqual(
  319. const DpCustomLineCap* customLineCap
  320. ) const
  321. {
  322. if(!customLineCap)
  323. return FALSE;
  324. const GpCustomLineCap* otherCap;
  325. otherCap = static_cast<const GpCustomLineCap*>(customLineCap);
  326. return (
  327. (BaseCap == otherCap->BaseCap) &&
  328. (BaseInset == otherCap->BaseInset) &&
  329. (StrokeStartCap == otherCap->StrokeStartCap) &&
  330. (StrokeEndCap == otherCap->StrokeEndCap) &&
  331. (StrokeJoin == otherCap->StrokeJoin) &&
  332. (WidthScale == otherCap->WidthScale) &&
  333. GpFillPath.IsEqual(&(otherCap->GpFillPath)) &&
  334. GpStrokePath.IsEqual(&(otherCap->GpStrokePath))
  335. );
  336. }
  337. INT getTransformedPoints(
  338. GpPointF* points,
  339. BYTE* types,
  340. INT count,
  341. const GpPointF* srcPoints,
  342. const BYTE* srcTypes,
  343. INT srcCount,
  344. const GpPointF& origin,
  345. const GpPointF& tangent,
  346. REAL lineWidth,
  347. REAL minLineWidth,
  348. const GpPointF& hotSpot
  349. )
  350. {
  351. if(points == NULL && types == NULL)
  352. {
  353. return 0;
  354. }
  355. ASSERT(srcPoints && srcTypes);
  356. if(srcPoints == NULL || srcTypes == NULL)
  357. {
  358. return 0;
  359. }
  360. INT count1 = srcCount;
  361. if(count1 > count)
  362. {
  363. count1 = count;
  364. }
  365. if(types)
  366. {
  367. GpMemcpy(types, srcTypes, count1);
  368. }
  369. // Make sure the line width used for the cap path is
  370. // larger than the minimum line width.
  371. REAL width = lineWidth;
  372. if(lineWidth < minLineWidth)
  373. {
  374. width = minLineWidth;
  375. }
  376. if(points)
  377. {
  378. GpPointF* dstPts = points;
  379. const GpPointF* srcPts = srcPoints;
  380. REAL m11, m12, m21, m22, tx, ty;
  381. m11 = width*tangent.Y;
  382. m21 = width*tangent.X;
  383. m12 = - width*tangent.X;
  384. m22 = width*tangent.Y;
  385. // Adjust the origin according to the hot spot.
  386. tx = hotSpot.X*(1.0f - width);
  387. ty = hotSpot.Y*(1.0f - width);
  388. REAL savedTx = tx;
  389. tx = tx*tangent.Y + ty*tangent.X + origin.X;
  390. ty = - savedTx*tangent.X + ty*tangent.Y + origin.Y;
  391. // Transform the points.
  392. for(INT i = 0; i < count1; i++)
  393. {
  394. dstPts->X = m11*srcPts->X + m21*srcPts->Y + tx;
  395. dstPts->Y = m12*srcPts->X + m22*srcPts->Y + ty;
  396. dstPts++;
  397. srcPts++;
  398. }
  399. }
  400. return count1;
  401. }
  402. INT
  403. GpCustomLineCap::GetTransformedFillCap(
  404. GpPointF* points,
  405. BYTE* types,
  406. INT count,
  407. const GpPointF& origin,
  408. const GpPointF& tangent,
  409. REAL lineWidth,
  410. REAL minimumWidth
  411. ) const
  412. {
  413. INT fillCount = GetFillPointCount();
  414. if(fillCount <= 0)
  415. return 0;
  416. // Calculate the minimum line width and hot spot.
  417. // FillHotSpot is defined relative to the minimumWidth.
  418. REAL minLineWidth = minimumWidth;
  419. GpPointF hotSpot;
  420. hotSpot.X = minimumWidth*FillHotSpot.X;
  421. hotSpot.Y = minimumWidth*FillHotSpot.Y;
  422. return getTransformedPoints(
  423. points,
  424. types,
  425. count,
  426. GetFillPoints(),
  427. GetFillTypes(),
  428. fillCount,
  429. origin,
  430. tangent,
  431. lineWidth,
  432. minLineWidth,
  433. hotSpot);
  434. }
  435. INT
  436. GpCustomLineCap::GetTransformedStrokeCap(
  437. INT cCapacity, // In, initial pPoints & pTypes capacity
  438. GpPointF ** pPoints, // In/out, may be reallocated here
  439. BYTE ** pTypes, // In/out, may be reallocated here
  440. INT * pCount, // In/out, may change here if flattened
  441. const GpPointF& origin,
  442. const GpPointF& tangent,
  443. REAL lineWidth,
  444. REAL minimumWidth
  445. ) const
  446. {
  447. INT strokeCount = GetStrokePointCount();
  448. if(strokeCount <= 0 || lineWidth <= 0)
  449. return 0;
  450. if (!pPoints || !pTypes || !pCount)
  451. return 0;
  452. // Calculate the minimum line width and hot spot.
  453. // StrokeHotSpot is defined relative to the minimumWidth.
  454. GpPointF hotSpot;
  455. hotSpot.X = minimumWidth*StrokeHotSpot.X;
  456. hotSpot.Y = minimumWidth*StrokeHotSpot.Y;
  457. strokeCount = getTransformedPoints(
  458. *pPoints,
  459. *pTypes,
  460. *pCount,
  461. GetStrokePoints(),
  462. GetStrokeTypes(),
  463. strokeCount,
  464. origin,
  465. tangent,
  466. lineWidth,
  467. minimumWidth,
  468. hotSpot);
  469. // The widener expects a flattened path
  470. GpPath path(*pPoints, *pTypes, strokeCount, FillModeWinding);
  471. if (Ok == path.Flatten(NULL, FlatnessDefault))
  472. {
  473. // Flattening succeeded
  474. strokeCount = path.GetPointCount();
  475. if (strokeCount > cCapacity)
  476. {
  477. // Reallocate the points and types arrays
  478. GpPointF * ptfTemp = (GpPointF*) GpRealloc(*pPoints,
  479. strokeCount*sizeof(GpPointF));
  480. if (ptfTemp)
  481. *pPoints = ptfTemp;
  482. else
  483. strokeCount = 0;
  484. BYTE * pbTemp = (BYTE*)GpRealloc(*pTypes, strokeCount);
  485. if (pbTemp)
  486. *pTypes = pbTemp;
  487. else
  488. strokeCount = 0;
  489. }
  490. if (strokeCount)
  491. {
  492. // Replace with the flattened points
  493. GpMemcpy(*pPoints, path.GetPathPoints(), strokeCount*sizeof(GpPointF));
  494. GpMemcpy(*pTypes, path.GetPathTypes(), strokeCount);
  495. }
  496. *pCount = strokeCount;
  497. } // end if flattening succeeded
  498. return strokeCount;
  499. }
  500. REAL
  501. GpCustomLineCap::GetRadius(
  502. REAL lineWidth,
  503. REAL minimumWidth
  504. ) const
  505. {
  506. INT fillCount = GetFillPointCount();
  507. INT strokeCount = GetStrokePointCount();
  508. if((fillCount <= 0 && strokeCount <= 0) || lineWidth <= 0)
  509. return 0;
  510. INT maxCount = max(fillCount, strokeCount);
  511. const INT buffCount = 32;
  512. GpPointF pointBuff[buffCount];
  513. BYTE typeBuff[buffCount];
  514. GpPointF* points = NULL;
  515. BYTE* types = NULL;
  516. if(maxCount <= buffCount)
  517. {
  518. points = &pointBuff[0];
  519. types = &typeBuff[0];
  520. }
  521. else
  522. {
  523. points = (GpPointF*) GpMalloc(maxCount*sizeof(GpPointF));
  524. types = (BYTE*) GpMalloc(maxCount);
  525. }
  526. REAL maxR = 0;
  527. if(points && types)
  528. {
  529. GpPointF origin(0, 0);
  530. GpPointF tangent(0, 1);
  531. REAL minLineWidth;
  532. GpPointF hotSpot;
  533. REAL d;
  534. INT count;
  535. if(fillCount > 0)
  536. {
  537. // Calculate the minimum line width and hot spot.
  538. // FillHotSpot is defined relative to the minimumWidth.
  539. minLineWidth = minimumWidth;
  540. hotSpot.X = minimumWidth*FillHotSpot.X;
  541. hotSpot.Y = minimumWidth*FillHotSpot.Y;
  542. count = getTransformedPoints(
  543. points,
  544. types,
  545. fillCount,
  546. GetFillPoints(),
  547. GetFillTypes(),
  548. fillCount,
  549. origin,
  550. tangent,
  551. lineWidth,
  552. minLineWidth,
  553. hotSpot);
  554. REAL i;
  555. GpPointF* pts = points;
  556. maxR = pts->X*pts->X + pts->Y*pts->Y;
  557. for(i = 1, pts++; i < count; i++, pts++)
  558. {
  559. d = pts->X*pts->X + pts->Y*pts->Y;
  560. if(d > maxR)
  561. maxR = d;
  562. }
  563. }
  564. if(strokeCount > 0)
  565. {
  566. // Calculate the minimum line width and hot spot.
  567. // FillHotSpot is defined relative to the minimumWidth.
  568. minLineWidth = minimumWidth;
  569. hotSpot.X = minimumWidth*StrokeHotSpot.X;
  570. hotSpot.Y = minimumWidth*StrokeHotSpot.Y;
  571. count = getTransformedPoints(
  572. points,
  573. types,
  574. strokeCount,
  575. GetStrokePoints(),
  576. GetStrokeTypes(),
  577. strokeCount,
  578. origin,
  579. tangent,
  580. lineWidth,
  581. minLineWidth,
  582. hotSpot);
  583. GpPath strokePath(points, types, count, FillModeWinding);
  584. GpRectF rect;
  585. strokePath.GetBounds(&rect);
  586. REAL sharpestAngle = strokePath.GetSharpestAngle();
  587. REAL delta0 = max(lineWidth*WidthScale, minimumWidth);
  588. REAL delta = delta0/2;
  589. if(StrokeJoin == LineJoinMiter ||
  590. StrokeJoin == LineJoinMiterClipped)
  591. {
  592. REAL miterLimit = StrokeMiterLimit;
  593. delta = delta0*miterLimit;
  594. if(delta > 20)
  595. {
  596. delta = GpPen::ComputeMiterLength(
  597. sharpestAngle,
  598. miterLimit
  599. );
  600. delta *= delta0;
  601. }
  602. }
  603. REAL left, right, top, bottom;
  604. left = rect.X - delta;
  605. right = rect.X + delta;
  606. top = rect.Y - delta;
  607. bottom = rect.Y + delta;
  608. d = left*left + top*top;
  609. if(d > maxR)
  610. maxR = d;
  611. d = left*left + bottom*bottom;
  612. if(d > maxR)
  613. maxR = d;
  614. d = right*right + top*top;
  615. if(d > maxR)
  616. maxR = d;
  617. d = right*right + bottom*bottom;
  618. if(d > maxR)
  619. maxR = d;
  620. }
  621. }
  622. else
  623. {
  624. //!!! Do something when the memory is not available.
  625. }
  626. if(points != &pointBuff[0])
  627. GpFree(points);
  628. if(types != &typeBuff[0])
  629. GpFree(types);
  630. if(maxR > 0)
  631. maxR = REALSQRT(maxR);
  632. return maxR;
  633. }
  634. GpAdjustableArrowCap::GpAdjustableArrowCap(
  635. const GpAdjustableArrowCap* arrowCap
  636. ) : GpCustomLineCap(arrowCap)
  637. {
  638. if(arrowCap)
  639. {
  640. Height = arrowCap->Height;
  641. Width = arrowCap->Width;
  642. MiddleInset = arrowCap->MiddleInset;
  643. FillState = arrowCap->FillState;
  644. }
  645. else
  646. {
  647. SetDefaultValue();
  648. }
  649. Update();
  650. }
  651. GpStatus
  652. GpAdjustableArrowCap::GetPathData(
  653. GpPathData* pathData,
  654. REAL height,
  655. REAL width,
  656. REAL middleInset,
  657. BOOL isFilled
  658. )
  659. {
  660. if(pathData == NULL)
  661. return InvalidParameter;
  662. GpPointF* points = pathData->Points;
  663. BYTE* types = pathData->Types;
  664. points[0].X = width/2;
  665. points[0].Y = - height;
  666. points[1].X = 0;
  667. points[1].Y = 0;
  668. points[2].X = - width/2;
  669. points[2].Y = - height;
  670. points[3].X = 0;
  671. points[3].Y = - height + middleInset;
  672. types[0] = PathPointTypeStart;
  673. types[1] = PathPointTypeLine;
  674. types[2] = PathPointTypeLine;
  675. types[3] = PathPointTypeLine;
  676. INT lastIndex = 2;
  677. if(middleInset != 0 && isFilled)
  678. lastIndex = 3;
  679. if(isFilled)
  680. types[lastIndex] |= PathPointTypeCloseSubpath;
  681. pathData->Count = lastIndex + 1;
  682. return Ok;
  683. }
  684. GpStatus
  685. GpAdjustableArrowCap::Update()
  686. {
  687. GpPointF points[4];
  688. BYTE types[4];
  689. GpPathData pathData;
  690. pathData.Points = &points[0];
  691. pathData.Types = &types[0];
  692. pathData.Count = 3;
  693. BaseCap = LineCapTriangle;
  694. BaseInset = (Width != 0) ? (Height / Width) : 0;
  695. GetPathData(&pathData, Height, Width, MiddleInset, FillState);
  696. GpPath path(FillModeWinding);
  697. path.SetPathData(&pathData);
  698. if(FillState)
  699. {
  700. // Fill path only.
  701. SetFillPath(&path);
  702. SetStrokePath(NULL);
  703. }
  704. else
  705. {
  706. // Stroke path only.
  707. SetStrokePath(&path);
  708. SetFillPath(NULL);
  709. }
  710. return Ok;
  711. }
  712. ObjectType
  713. GpCustomLineCap::GetObjectType() const
  714. {
  715. return ObjectTypeCustomLineCap;
  716. }
  717. #define GDIP_CAPFLAGS_FILLPATH 0x00000001
  718. #define GDIP_CAPFLAGS_STROKEPATH 0x00000002
  719. class CustomLineCapData : public ObjectTypeData
  720. {
  721. public:
  722. INT32 Flags;
  723. INT32 BaseCap;
  724. REAL BaseInset;
  725. INT32 StrokeStartCap;
  726. INT32 StrokeEndCap;
  727. INT32 StrokeJoin;
  728. REAL StrokeMiterLimit;
  729. REAL WidthScale;
  730. GpPointF FillHotSpot;
  731. GpPointF StrokeHotSpot;
  732. };
  733. UINT
  734. GpCustomLineCap::GetDataSize() const
  735. {
  736. ASSERT(IsValid());
  737. UINT size = sizeof(CustomLineCapData);
  738. INT fillPathSize = 0;
  739. INT strokePathSize = 0;
  740. if ((GetFillPointCount() > 2) &&
  741. ((fillPathSize = FillPath->GetDataSize()) > 0))
  742. {
  743. ASSERT((fillPathSize & 0x03) == 0);
  744. size += sizeof(INT32) + fillPathSize;
  745. }
  746. if ((GetStrokePointCount() > 2) &&
  747. ((strokePathSize = StrokePath->GetDataSize()) > 0))
  748. {
  749. ASSERT((strokePathSize & 0x03) == 0);
  750. size += sizeof(INT32) + strokePathSize;
  751. }
  752. return size;
  753. }
  754. GpStatus
  755. GpCustomLineCap::GetData(
  756. IStream * stream
  757. ) const
  758. {
  759. ASSERT(IsValid());
  760. INT flags = 0;
  761. INT fillPathSize = 0;
  762. INT strokePathSize = 0;
  763. if ((GetFillPointCount() > 2) &&
  764. ((fillPathSize = FillPath->GetDataSize()) > 0))
  765. {
  766. ASSERT((fillPathSize & 0x03) == 0);
  767. flags |= GDIP_CAPFLAGS_FILLPATH;
  768. }
  769. if ((GetStrokePointCount() > 2) &&
  770. ((strokePathSize = StrokePath->GetDataSize()) > 0))
  771. {
  772. ASSERT((strokePathSize & 0x03) == 0);
  773. flags |= GDIP_CAPFLAGS_STROKEPATH;
  774. }
  775. CustomLineCapData capData;
  776. capData.Type = GetType();
  777. capData.Flags = flags;
  778. capData.BaseCap = BaseCap;
  779. capData.BaseInset = BaseInset;
  780. capData.StrokeStartCap = StrokeStartCap;
  781. capData.StrokeEndCap = StrokeEndCap;
  782. capData.StrokeJoin = StrokeJoin;
  783. capData.StrokeMiterLimit = StrokeMiterLimit;
  784. capData.WidthScale = WidthScale;
  785. capData.FillHotSpot = FillHotSpot;
  786. capData.StrokeHotSpot = StrokeHotSpot;
  787. stream->Write(&capData, sizeof(capData), NULL);
  788. if (flags & GDIP_CAPFLAGS_FILLPATH)
  789. {
  790. stream->Write(&fillPathSize, sizeof(INT32), NULL);
  791. FillPath->GetData(stream);
  792. }
  793. if (flags & GDIP_CAPFLAGS_STROKEPATH)
  794. {
  795. stream->Write(&strokePathSize, sizeof(INT32), NULL);
  796. StrokePath->GetData(stream);
  797. }
  798. return Ok;
  799. }
  800. GpStatus
  801. GpCustomLineCap::SetData(
  802. const BYTE * dataBuffer,
  803. UINT size
  804. )
  805. {
  806. this->Reset();
  807. if (dataBuffer == NULL)
  808. {
  809. WARNING(("dataBuffer is NULL"));
  810. return InvalidParameter;
  811. }
  812. if (size < sizeof(CustomLineCapData))
  813. {
  814. WARNING(("size too small"));
  815. return InvalidParameter;
  816. }
  817. const CustomLineCapData * capData;
  818. capData = reinterpret_cast<const CustomLineCapData *>(dataBuffer);
  819. ASSERT((CustomLineCapType)(capData->Type) == CustomLineCapTypeDefault);
  820. if (!capData->MajorVersionMatches())
  821. {
  822. WARNING(("Version number mismatch"));
  823. return InvalidParameter;
  824. }
  825. BaseCap = (GpLineCap)capData->BaseCap;
  826. BaseInset = capData->BaseInset;
  827. StrokeStartCap = (GpLineCap)capData->StrokeStartCap;
  828. StrokeEndCap = (GpLineCap)capData->StrokeEndCap;
  829. StrokeJoin = (GpLineJoin)capData->StrokeJoin;
  830. StrokeMiterLimit = capData->StrokeMiterLimit;
  831. WidthScale = capData->WidthScale;
  832. FillHotSpot = capData->FillHotSpot;
  833. StrokeHotSpot = capData->StrokeHotSpot;
  834. dataBuffer += sizeof(CustomLineCapData);
  835. size -= sizeof(CustomLineCapData);
  836. GpStatus status = Ok;
  837. if (capData->Flags & GDIP_CAPFLAGS_FILLPATH)
  838. {
  839. if (size < sizeof(INT32))
  840. {
  841. WARNING(("size too small"));
  842. return InvalidParameter;
  843. }
  844. UINT pathSize = ((INT32 *)dataBuffer)[0];
  845. dataBuffer += sizeof(INT32);
  846. size -= sizeof(INT32);
  847. if (size < pathSize)
  848. {
  849. WARNING(("size too small"));
  850. return InvalidParameter;
  851. }
  852. if ((status = FillPath->SetData(dataBuffer, pathSize)) != Ok)
  853. {
  854. return status;
  855. }
  856. if(Ok == status)
  857. {
  858. status = ComputeFillCapLength();
  859. }
  860. dataBuffer += pathSize;
  861. size -= pathSize;
  862. }
  863. if (capData->Flags & GDIP_CAPFLAGS_STROKEPATH)
  864. {
  865. if (size < sizeof(INT32))
  866. {
  867. WARNING(("size too small"));
  868. return InvalidParameter;
  869. }
  870. UINT pathSize = ((INT32 *)dataBuffer)[0];
  871. dataBuffer += sizeof(INT32);
  872. size -= sizeof(INT32);
  873. if (size < pathSize)
  874. {
  875. WARNING(("size too small"));
  876. return InvalidParameter;
  877. }
  878. status = StrokePath->SetData(dataBuffer, pathSize);
  879. if(Ok == status)
  880. {
  881. status = ComputeStrokeCapLength();
  882. }
  883. dataBuffer += pathSize;
  884. size -= pathSize;
  885. }
  886. UpdateUid();
  887. return status;
  888. }
  889. class AdjustableArrowCapData : public ObjectTypeData
  890. {
  891. public:
  892. REAL Width;
  893. REAL Height;
  894. REAL MiddleInset;
  895. INT32 FillState;
  896. INT32 StrokeStartCap;
  897. INT32 StrokeEndCap;
  898. INT32 StrokeJoin;
  899. REAL StrokeMiterLimit;
  900. REAL WidthScale;
  901. GpPointF FillHotSpot;
  902. GpPointF StrokeHotSpot;
  903. };
  904. UINT
  905. GpAdjustableArrowCap::GetDataSize() const
  906. {
  907. ASSERT(IsValid());
  908. return sizeof(AdjustableArrowCapData);
  909. }
  910. GpStatus
  911. GpAdjustableArrowCap::GetData(
  912. IStream * stream
  913. ) const
  914. {
  915. ASSERT(IsValid());
  916. AdjustableArrowCapData arrowCapData;
  917. arrowCapData.Type = GetType();
  918. arrowCapData.Width = Width;
  919. arrowCapData.Height = Height;
  920. arrowCapData.MiddleInset = MiddleInset;
  921. arrowCapData.FillState = FillState;
  922. arrowCapData.StrokeStartCap = StrokeStartCap;
  923. arrowCapData.StrokeEndCap = StrokeEndCap;
  924. arrowCapData.StrokeJoin = StrokeJoin;
  925. arrowCapData.StrokeMiterLimit = StrokeMiterLimit;
  926. arrowCapData.WidthScale = WidthScale;
  927. arrowCapData.FillHotSpot = FillHotSpot;
  928. arrowCapData.StrokeHotSpot = StrokeHotSpot;
  929. stream->Write(&arrowCapData, sizeof(arrowCapData), NULL);
  930. return Ok;
  931. }
  932. GpStatus
  933. GpAdjustableArrowCap::SetData(
  934. const BYTE * dataBuffer,
  935. UINT size
  936. )
  937. {
  938. this->Reset();
  939. if (dataBuffer == NULL)
  940. {
  941. WARNING(("dataBuffer is NULL"));
  942. return InvalidParameter;
  943. }
  944. if (size < sizeof(AdjustableArrowCapData))
  945. {
  946. WARNING(("size too small"));
  947. return InvalidParameter;
  948. }
  949. const AdjustableArrowCapData * arrowCapData;
  950. arrowCapData = reinterpret_cast<const AdjustableArrowCapData *>(dataBuffer);
  951. ASSERT((CustomLineCapType)(arrowCapData->Type) == CustomLineCapTypeAdjustableArrow);
  952. if (!arrowCapData->MajorVersionMatches())
  953. {
  954. WARNING(("Version number mismatch"));
  955. return InvalidParameter;
  956. }
  957. Width = arrowCapData->Width;
  958. Height = arrowCapData->Height;
  959. MiddleInset = arrowCapData->MiddleInset;
  960. FillState = arrowCapData->FillState;
  961. StrokeStartCap = (GpLineCap)arrowCapData->StrokeStartCap;
  962. StrokeEndCap = (GpLineCap)arrowCapData->StrokeEndCap;
  963. StrokeJoin = (GpLineJoin)arrowCapData->StrokeJoin;
  964. StrokeMiterLimit = arrowCapData->StrokeMiterLimit;
  965. WidthScale = arrowCapData->WidthScale;
  966. FillHotSpot = arrowCapData->FillHotSpot;
  967. StrokeHotSpot = arrowCapData->StrokeHotSpot;
  968. this->Update();
  969. UpdateUid();
  970. return Ok;
  971. }