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.

858 lines
20 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1999 Microsoft Corporation
  4. *
  5. * Abstract:
  6. *
  7. * Implementation of XBezier class and its DDA.
  8. *
  9. * History:
  10. *
  11. * 11/08/1999 ikkof
  12. * Created it.
  13. *
  14. \**************************************************************************/
  15. #include "precomp.hpp"
  16. // Path types used for advanced path.
  17. // !!! [asecchia]
  18. // this is a very clumsy hack to enable the XPath stuff to work.
  19. // we should have an internal set of enum values that are different
  20. // from the external ones.
  21. #define PathPointTypeBezier2 2 // quadratic Beizer
  22. #define PathPointTypeBezier4 4 // quartic (4th order) Beizer
  23. #define PathPointTypeBezier5 5 // quintic (5th order) Bezier
  24. #define PathPointTypeBezier6 6 // hexaic (6th order) Bezier
  25. GpXPath::GpXPath(const GpPath* path)
  26. {
  27. InitDefaultState();
  28. if(!path || !path->IsValid())
  29. return;
  30. INT count = path->GetPointCount();
  31. const GpPointF *pts = ((GpPath*) path)->GetPathPoints();
  32. const BYTE *types = ((GpPath*) path)->GetPathTypes();
  33. if(pts && types && count > 0)
  34. {
  35. Types = (BYTE*) GpMalloc(count);
  36. XPoints.Count = count;
  37. XPoints.Dimension = 2;
  38. XPoints.Data = (REALD*) GpMalloc(2*count*sizeof(REALD));
  39. XPoints.IsDataAllocated = TRUE;
  40. if(Types && XPoints.Data)
  41. {
  42. GpMemcpy(Types, types, count);
  43. REALD* data = XPoints.Data;
  44. for(INT i = 0; i < count; i++)
  45. {
  46. *data++ = pts->X;
  47. *data++ = pts->Y;
  48. pts++;
  49. }
  50. SetValid(TRUE);
  51. }
  52. FillMode = ((GpPath*) path)->GetFillMode();
  53. }
  54. }
  55. GpXPath::GpXPath(
  56. const GpPath* path,
  57. const GpRectF& rect,
  58. const GpPointF* points,
  59. INT count,
  60. WarpMode warpMode
  61. )
  62. {
  63. InitDefaultState();
  64. if(warpMode == WarpModePerspective)
  65. ConvertToPerspectivePath(path, rect, points, count);
  66. else if(warpMode == WarpModeBilinear)
  67. ConvertToBilinearPath(path, rect, points, count);
  68. }
  69. GpStatus
  70. GpXPath::ConvertToPerspectivePath(
  71. const GpPath* path,
  72. const GpRectF& rect,
  73. const GpPointF* points,
  74. INT count
  75. )
  76. {
  77. ASSERT(path && path->IsValid());
  78. if(!path || !path->IsValid())
  79. return InvalidParameter;
  80. // Obtain the path points.
  81. const GpPointF* pathPts = ((GpPath*) path)->GetPathPoints();
  82. const BYTE* pathTypes = ((GpPath*) path)->GetPathTypes();
  83. INT pathCount = path->GetPointCount();
  84. BYTE* types = (BYTE*) GpMalloc(pathCount);
  85. if(!types)
  86. return OutOfMemory;
  87. GpMemcpy(types, pathTypes, pathCount);
  88. // Set the perspective transform.
  89. GpPerspectiveTransform trans(rect, points, count);
  90. // Convert the path points to 3D perspective points.
  91. REALD* data = (REALD*) GpMalloc(3*pathCount*sizeof(REALD));
  92. if(!data)
  93. return OutOfMemory;
  94. // Use this data for xpoints.
  95. XPoints.Count = pathCount;
  96. XPoints.Dimension = 3;
  97. XPoints.Data = data;
  98. XPoints.IsDataAllocated = TRUE;
  99. Types = types;
  100. GpStatus status = trans.ConvertPoints(pathPts, pathCount, &XPoints);
  101. if(status == Ok)
  102. SetValid(TRUE);
  103. return status;
  104. }
  105. GpStatus
  106. GpXPath::ConvertToBilinearPath(
  107. const GpPath* path,
  108. const GpRectF& rect,
  109. const GpPointF* points,
  110. INT count
  111. )
  112. {
  113. ASSERT(path && path->IsValid());
  114. if(!path || !path->IsValid())
  115. return InvalidParameter;
  116. // Obtain the path points.
  117. const GpPointF* pathPts = ((GpPath*) path)->GetPathPoints();
  118. const BYTE* pathTypes = ((GpPath*) path)->GetPathTypes();
  119. INT pathCount = path->GetPointCount();
  120. // The maximum data size of the bilinear transform is
  121. // 2*pathCount - 1. Here set it as 2*pathCount.
  122. INT dimension = 2;
  123. INT maxCount = 2*pathCount;
  124. REALD* data = (REALD*) GpMalloc(dimension*maxCount*sizeof(REALD));
  125. BYTE* types = (BYTE*) GpMalloc(maxCount);
  126. if(!data || !types)
  127. {
  128. GpFree(data);
  129. GpFree(types);
  130. return OutOfMemory;
  131. }
  132. GpMemset(types, 0, maxCount);
  133. // Set the bilinear transform.
  134. GpBilinearTransform trans(rect, points, count);
  135. DpPathIterator iter(pathPts, pathTypes, pathCount);
  136. INT startIndex, endIndex;
  137. BOOL isClosed;
  138. GpStatus status = Ok;
  139. REALD* dataPtr = data;
  140. INT totalCount = 0; // Number of control points.
  141. while(
  142. iter.NextSubpath(
  143. &startIndex, &endIndex, &isClosed)
  144. && status == Ok
  145. )
  146. {
  147. INT typeStartIndex, typeEndIndex;
  148. BYTE pathType;
  149. BOOL isFirstPoint = TRUE;
  150. while(
  151. iter.NextPathType(&pathType, &typeStartIndex, &typeEndIndex)
  152. && status == Ok
  153. )
  154. {
  155. // Starting point of the current suptype
  156. // and the number of points.
  157. const GpPointF* pts = pathPts + typeStartIndex;
  158. INT typeCount = typeEndIndex - typeStartIndex + 1;
  159. switch(pathType)
  160. {
  161. case PathPointTypeBezier3:
  162. trans.ConvertCubicBeziers(pts, typeCount, dataPtr);
  163. pts += typeCount - 1;
  164. dataPtr += dimension*2*(typeCount - 1);
  165. if(isFirstPoint)
  166. {
  167. *(types + totalCount) = PathPointTypeStart;
  168. totalCount++;
  169. }
  170. GpMemset(types + totalCount, PathPointTypeBezier6, 2*(typeCount - 1));
  171. totalCount += 2*(typeCount - 1);
  172. isFirstPoint = FALSE;
  173. break;
  174. case PathPointTypeLine:
  175. trans.ConvertLines(pts, typeCount, dataPtr);
  176. pts += typeCount - 1;
  177. dataPtr += dimension*2*(typeCount - 1);
  178. if(isFirstPoint)
  179. {
  180. *(types + totalCount) = PathPointTypeStart;
  181. totalCount++;
  182. }
  183. GpMemset(types + totalCount, PathPointTypeBezier2, 2*(typeCount - 1));
  184. totalCount += 2*(typeCount - 1);
  185. isFirstPoint = FALSE;
  186. break;
  187. case PathPointTypeStart:
  188. case PathPointTypeBezier2:
  189. case PathPointTypeBezier4:
  190. case PathPointTypeBezier5:
  191. case PathPointTypeBezier6:
  192. default:
  193. // Should not have any of those types in GpPath.
  194. ASSERT(0);
  195. break;
  196. }
  197. }
  198. }
  199. Types = types;
  200. XPoints.Count = totalCount;
  201. XPoints.Dimension = dimension;
  202. XPoints.Data = data;
  203. XPoints.IsDataAllocated = TRUE;
  204. SetValid(TRUE);
  205. return Ok;
  206. }
  207. GpStatus
  208. GpXPath::Flatten(
  209. DynByteArray* flattenTypes,
  210. DynPointFArray* flattenPoints,
  211. const GpMatrix *matrix
  212. )
  213. {
  214. GpStatus status = Ok;
  215. ASSERT(matrix);
  216. FPUStateSaver fpuState; // Setup the FPU state.
  217. flattenPoints->Reset(FALSE);
  218. flattenTypes->Reset(FALSE);
  219. INT dimension = XPoints.Dimension;
  220. REALD* data = XPoints.Data;
  221. GpXPathIterator iter(this);
  222. INT startIndex, endIndex;
  223. BOOL isClosed;
  224. GpPointF* ptsBuffer = NULL;
  225. while(
  226. iter.NextSubpath(
  227. &startIndex, &endIndex, &isClosed)
  228. && status == Ok
  229. )
  230. {
  231. INT typeStartIndex, typeEndIndex;
  232. BYTE pathType;
  233. BOOL isFirstPoint = TRUE;
  234. while(
  235. iter.NextPathType(&pathType, &typeStartIndex, &typeEndIndex)
  236. && status == Ok
  237. )
  238. {
  239. INT count, index;
  240. BYTE* types;
  241. GpPointF* pts;
  242. switch(pathType)
  243. {
  244. case PathPointTypeStart:
  245. break;
  246. case PathPointTypeBezier2:
  247. case PathPointTypeBezier3:
  248. case PathPointTypeBezier4:
  249. case PathPointTypeBezier5:
  250. case PathPointTypeBezier6:
  251. {
  252. BOOL dontCopy = FALSE;
  253. GpXBezier bezier;
  254. GpXPoints xpoints;
  255. INT order;
  256. xpoints.SetData(
  257. data + typeStartIndex*dimension,
  258. dimension,
  259. typeEndIndex - typeStartIndex + 1,
  260. dontCopy // Don't copy the data.
  261. );
  262. order = (INT) pathType;
  263. if(bezier.SetBeziers(order, xpoints) == Ok)
  264. {
  265. // Flatten() flattens Bezier.
  266. // The flattened points are already transformed.
  267. DynPointFArray bezierFlattenPts;
  268. bezier.Flatten(&bezierFlattenPts, matrix);
  269. // count = bezier.GetFlattenCount();
  270. count = bezierFlattenPts.GetCount();
  271. // Check if there is already the first point.
  272. if(!isFirstPoint)
  273. count--; // Don't add the first point.
  274. if (count > 0)
  275. {
  276. if((types = flattenTypes->AddMultiple(count)) != NULL)
  277. {
  278. // pts = bezier.GetFlattenData();
  279. pts = bezierFlattenPts.GetDataBuffer();
  280. if(!isFirstPoint)
  281. pts++; // Skip the first point.
  282. flattenPoints->AddMultiple(pts, count);
  283. GpMemset(types, PathPointTypeLine, count);
  284. if(isFirstPoint)
  285. types[0] = PathPointTypeStart;
  286. isFirstPoint = FALSE;
  287. }
  288. else
  289. status = OutOfMemory;
  290. }
  291. }
  292. else
  293. status =InvalidParameter;
  294. }
  295. break;
  296. case PathPointTypeLine:
  297. default:
  298. count = typeEndIndex - typeStartIndex + 1;
  299. if(!isFirstPoint)
  300. count--;
  301. if((types = flattenTypes->AddMultiple(count)) != NULL)
  302. {
  303. // Set the type.
  304. GpMemset(types, PathPointTypeLine, count);
  305. if(isFirstPoint)
  306. types[0] = PathPointTypeStart;
  307. // Get the first data.
  308. REALD* dataPtr = data + typeStartIndex*dimension;
  309. if(!isFirstPoint)
  310. dataPtr += dimension; // Skip the first point.
  311. // Allocate the point buffer to save
  312. // for the flatten points.
  313. pts = (GpPointF*) GpRealloc(ptsBuffer,
  314. count*sizeof(GpPointF));
  315. if(!pts)
  316. {
  317. status = OutOfMemory;
  318. break;
  319. }
  320. else
  321. ptsBuffer = pts;
  322. // Copy the data
  323. GpPointF* ptsPtr = pts;
  324. for(INT k = 0; k < count; k++)
  325. {
  326. // Simply copy the first 2 elments
  327. // of the data as the x and y component.
  328. REALD x, y, w;
  329. x = *dataPtr++;
  330. y = *dataPtr++;
  331. // Do the perspective projection if
  332. // dimension is higher than 2.
  333. if(dimension > 2)
  334. {
  335. w = *dataPtr;
  336. x /= w;
  337. y /= w;
  338. }
  339. ptsPtr->X = TOREAL(x);
  340. ptsPtr->Y = TOREAL(y);
  341. ptsPtr++;
  342. // Skip the rest.
  343. if(dimension > 2)
  344. dataPtr += (dimension - 2);
  345. }
  346. // Add to the flatten points.
  347. index = flattenPoints->GetCount();
  348. flattenPoints->AddMultiple(pts, count);
  349. // Get the data biffer of the flatten points.
  350. pts = flattenPoints->GetDataBuffer();
  351. // Transform the newly added points.
  352. matrix->Transform(pts + index, count);
  353. isFirstPoint = FALSE;
  354. }
  355. break;
  356. }
  357. }
  358. // This is the end of the current subpath. Close subpath
  359. // if necessary.
  360. if(isClosed)
  361. {
  362. BYTE* typeBuffer = flattenTypes->GetDataBuffer();
  363. INT lastCount = flattenTypes->GetCount();
  364. typeBuffer[lastCount - 1] |= PathPointTypeCloseSubpath;
  365. }
  366. }
  367. if(ptsBuffer)
  368. GpFree(ptsBuffer);
  369. return status;
  370. }
  371. /**************************************************************************\
  372. *
  373. * GpXPathIterator class
  374. *
  375. * 11/08/1999 ikkof
  376. * Created it.
  377. *
  378. \**************************************************************************/
  379. GpXPathIterator::GpXPathIterator(GpXPath* xpath)
  380. {
  381. Initialize();
  382. if(xpath && xpath->IsValid())
  383. {
  384. TotalCount = xpath->GetPointCount();
  385. XPoints.SetData(
  386. xpath->GetPathPoints(),
  387. xpath->GetPointDimension(),
  388. TotalCount,
  389. FALSE // Don't copy data.
  390. );
  391. Types = xpath->GetPathTypes();
  392. }
  393. // Check if this path is valid.
  394. if(
  395. XPoints.Data
  396. && XPoints.Dimension > 0
  397. && XPoints.Count > 0
  398. && Types
  399. && TotalCount > 0
  400. )
  401. {
  402. SetValid(TRUE);
  403. }
  404. }
  405. VOID
  406. GpXPathIterator::Initialize()
  407. {
  408. // XPath = NULL;
  409. Types = NULL;
  410. TotalCount = 0;
  411. Index = 0;
  412. SubpathStartIndex = 0;
  413. SubpathEndIndex = 0;
  414. TypeStartIndex = 0;
  415. TypeEndIndex = 0;
  416. SetValid(FALSE);
  417. }
  418. INT
  419. GpXPathIterator::Enumerate(GpXPoints* xpoints, BYTE* types)
  420. {
  421. if(!IsValid())
  422. return 0;
  423. ASSERT(xpoints && types);
  424. if(xpoints == NULL || types == NULL)
  425. return 0;
  426. INT inputSize = xpoints->Dimension*xpoints->Count;
  427. ASSERT(xpoints->Data && inputSize > 0);
  428. if(xpoints->Data == NULL || inputSize <= 0)
  429. return 0;
  430. if(Index >= TotalCount)
  431. return 0;
  432. // Make sure the resultant dimension is the same as
  433. // the internal dimension.
  434. INT dimension = XPoints.Dimension;
  435. if(xpoints->Dimension != dimension)
  436. {
  437. xpoints->Dimension = dimension;
  438. xpoints->Count = inputSize/dimension;
  439. }
  440. INT number = min(TotalCount - Index, xpoints->Count);
  441. GpMemcpy(
  442. xpoints->Data,
  443. XPoints.Data + Index*dimension,
  444. number*dimension*sizeof(REALD));
  445. GpMemcpy(types, Types + Index, number*sizeof(BYTE));
  446. Index += number;
  447. return number;
  448. }
  449. INT
  450. GpXPathIterator::NextSubpath(INT* startIndex, INT* endIndex, BOOL *isClosed)
  451. {
  452. if(!IsValid())
  453. return 0;
  454. INT count = TotalCount;
  455. if(SubpathEndIndex >= count - 1)
  456. return 0;
  457. const BYTE* types = Types;
  458. INT i;
  459. // Set the starting index of the current subpath.
  460. if(SubpathEndIndex == 0)
  461. {
  462. SubpathStartIndex = 0;
  463. i = 1;
  464. }
  465. else
  466. {
  467. SubpathStartIndex = SubpathEndIndex + 1;
  468. SubpathEndIndex = SubpathStartIndex;
  469. i = SubpathStartIndex + 1;
  470. }
  471. BOOL hasData = FALSE;
  472. INT segmentCount = 0;
  473. while(i < count)
  474. {
  475. // Do the move segments.
  476. segmentCount = 0;
  477. while(i < count && (types[i] & PathPointTypePathTypeMask) == PathPointTypeStart)
  478. {
  479. segmentCount++;
  480. if(hasData)
  481. {
  482. break;
  483. }
  484. else
  485. {
  486. SubpathStartIndex = i;
  487. SubpathEndIndex = SubpathStartIndex;
  488. i++;
  489. }
  490. }
  491. if(segmentCount > 0 && hasData)
  492. {
  493. SubpathEndIndex = i - 1;
  494. break;
  495. }
  496. // Do the non-move segments.
  497. segmentCount = 0;
  498. BYTE nextType = types[i] & PathPointTypePathTypeMask;
  499. while(i < count && (types[i] & PathPointTypePathTypeMask) == nextType)
  500. {
  501. i++;
  502. segmentCount++;
  503. }
  504. if(segmentCount > 0)
  505. {
  506. hasData = TRUE;
  507. }
  508. }
  509. *startIndex = SubpathStartIndex;
  510. if(i >= count)
  511. SubpathEndIndex = count - 1; // The last subpath.
  512. *endIndex = SubpathEndIndex;
  513. segmentCount = SubpathEndIndex - SubpathStartIndex + 1;
  514. if(segmentCount <= 1) // Start and end point is the same.
  515. segmentCount = 0;
  516. if(segmentCount > 1)
  517. {
  518. // If there is the close flag or the start and end points match,
  519. // this subpath is closed.
  520. if(
  521. (types[SubpathEndIndex] & PathPointTypeCloseSubpath)
  522. || XPoints.AreEqualPoints(SubpathStartIndex, SubpathEndIndex)
  523. )
  524. {
  525. *isClosed = TRUE;
  526. }
  527. else
  528. *isClosed = FALSE;
  529. }
  530. else
  531. *isClosed = FALSE;
  532. // Set the current index to the starting index of the current subpath.
  533. Index = SubpathStartIndex;
  534. // Set the start and end index of type to be the starting index of
  535. // the current subpath. NextPathType() will start from the
  536. // beginning of the current subpath.
  537. TypeStartIndex = TypeEndIndex = SubpathStartIndex;
  538. return segmentCount;
  539. }
  540. INT
  541. GpXPathIterator::EnumerateSubpath(
  542. GpXPoints* xpoints,
  543. BYTE* types
  544. )
  545. {
  546. if(!IsValid())
  547. return 0;
  548. ASSERT(xpoints && types);
  549. if(xpoints == NULL || types == NULL)
  550. return 0;
  551. INT inputSize = xpoints->Dimension*xpoints->Count;
  552. ASSERT(xpoints->Data && inputSize > 0);
  553. if(xpoints->Data == NULL || inputSize <= 0)
  554. return 0;
  555. if(Index > SubpathEndIndex)
  556. return 0;
  557. // Make sure the resultant dimension is the same as
  558. // the internal dimension.
  559. INT dimension = XPoints.Dimension;
  560. if(xpoints->Dimension != dimension)
  561. {
  562. xpoints->Dimension = dimension;
  563. xpoints->Count = inputSize/dimension;
  564. }
  565. INT number = min(SubpathEndIndex - Index + 1, xpoints->Count);
  566. GpMemcpy(
  567. xpoints->Data,
  568. XPoints.Data + Index*dimension,
  569. number*dimension*sizeof(REALD));
  570. GpMemcpy(types, Types + Index, number*sizeof(BYTE));
  571. Index += number;
  572. return number;
  573. }
  574. INT
  575. GpXPathIterator::NextPathType(
  576. BYTE* pathType,
  577. INT* startIndex,
  578. INT* endIndex
  579. )
  580. {
  581. if(!IsValid())
  582. return 0;
  583. if(TypeEndIndex >= SubpathEndIndex)
  584. return 0; // There is no more segment in the current subpath.
  585. INT count = SubpathEndIndex + 1; // Limit for the ending index.
  586. const BYTE* types = Types;
  587. TypeStartIndex = TypeEndIndex;
  588. INT i = TypeStartIndex;
  589. INT segmentCount = 0;
  590. i++; // Go to the next point.
  591. while(i < count)
  592. {
  593. // Do the move segments.
  594. segmentCount = 0;
  595. while(i < count && (types[i] & PathPointTypePathTypeMask) == PathPointTypeStart)
  596. {
  597. // Move the start and end index.
  598. TypeStartIndex = i;
  599. TypeEndIndex = TypeStartIndex;
  600. i++;
  601. segmentCount++;
  602. }
  603. // Do the non-move segments.
  604. segmentCount = 0;
  605. BYTE nextType = types[i] & PathPointTypePathTypeMask;
  606. while(i < count && (types[i] & PathPointTypePathTypeMask) == nextType)
  607. {
  608. i++;
  609. segmentCount++;
  610. }
  611. if(segmentCount > 0)
  612. {
  613. TypeEndIndex = TypeStartIndex + segmentCount;
  614. *pathType = nextType;
  615. break;
  616. }
  617. }
  618. *startIndex = TypeStartIndex;
  619. *endIndex = TypeEndIndex;
  620. segmentCount = TypeEndIndex - TypeStartIndex + 1;
  621. if(segmentCount <= 1)
  622. {
  623. // Start and End type index is the same. This means there is
  624. // no more segment left.
  625. segmentCount = 0;
  626. }
  627. // Set the current index to the starting index of the current subpath.
  628. Index = TypeStartIndex;
  629. return segmentCount;
  630. }
  631. INT
  632. GpXPathIterator::EnumeratePathType(
  633. GpXPoints* xpoints,
  634. BYTE* types
  635. )
  636. {
  637. if(!IsValid())
  638. return 0;
  639. ASSERT(xpoints && types);
  640. if(xpoints == NULL || types == NULL)
  641. return 0;
  642. INT inputSize = xpoints->Dimension*xpoints->Count;
  643. ASSERT(xpoints->Data && inputSize > 0);
  644. if(xpoints->Data == NULL || inputSize <= 0)
  645. return 0;
  646. if(Index > TypeEndIndex)
  647. return 0;
  648. // Make sure the resultant dimension is the same as
  649. // the internal dimension.
  650. INT dimension = XPoints.Dimension;
  651. if(xpoints->Dimension != dimension)
  652. {
  653. xpoints->Dimension = dimension;
  654. xpoints->Count = inputSize/dimension;
  655. }
  656. INT number = min(TypeEndIndex - Index + 1, xpoints->Count);
  657. GpMemcpy(
  658. xpoints->Data,
  659. XPoints.Data + Index*dimension,
  660. number*dimension*sizeof(REALD));
  661. GpMemcpy(types, Types + Index, number*sizeof(BYTE));
  662. Index += number;
  663. return number;
  664. }