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.

1189 lines
29 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1999 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * GraphicsClip.cpp
  8. *
  9. * Abstract:
  10. *
  11. * Clipping methods of Graphics class
  12. *
  13. * Created:
  14. *
  15. * 02/05/1999 DCurtis
  16. *
  17. \**************************************************************************/
  18. #include "precomp.hpp"
  19. /**************************************************************************\
  20. *
  21. * Function Description:
  22. *
  23. * Get a copy of the current clipping region. Transform it through the
  24. * inverse of the current world-to-device matrix, so that if this region
  25. * was immediately set as the clipping, then the clipping wouldn't change.
  26. *
  27. * Arguments:
  28. *
  29. * NONE
  30. *
  31. * Return Value:
  32. *
  33. * GpRegion * region - a copy of the current clipping region; must be
  34. * deleted by the application.
  35. *
  36. * Created:
  37. *
  38. * 02/09/1999 DCurtis
  39. *
  40. \**************************************************************************/
  41. GpRegion*
  42. GpGraphics::GetClip() const
  43. {
  44. ASSERT(this->IsValid());
  45. GpRegion * region = new GpRegion(&(Context->AppClip));
  46. if (region != NULL)
  47. {
  48. if (region->IsValid())
  49. {
  50. GpMatrix deviceToWorld;
  51. if ((GetDeviceToWorldTransform(&deviceToWorld) == Ok) &&
  52. (region->Transform(&deviceToWorld) == Ok))
  53. {
  54. return region;
  55. }
  56. }
  57. delete region;
  58. }
  59. return NULL;
  60. }
  61. /**************************************************************************\
  62. *
  63. * Function Description:
  64. *
  65. * Get a copy of the current clipping region. Transform it through the
  66. * inverse of the current world-to-device matrix, so that if this region
  67. * was immediately set as the clipping, then the clipping wouldn't change.
  68. *
  69. * Arguments:
  70. *
  71. * NONE
  72. *
  73. * Return Value:
  74. *
  75. * GpRegion * region - an already created region, we set the contents of it.
  76. *
  77. * Created:
  78. *
  79. * 02/09/1999 DCurtis
  80. *
  81. \**************************************************************************/
  82. GpStatus
  83. GpGraphics::GetClip(GpRegion* region) const
  84. {
  85. ASSERT(this->IsValid());
  86. region->Set(&(Context->AppClip));
  87. if (region->IsValid())
  88. {
  89. GpMatrix deviceToWorld;
  90. if ((GetDeviceToWorldTransform(&deviceToWorld) == Ok) &&
  91. (region->Transform(&deviceToWorld) == Ok))
  92. {
  93. return Ok;
  94. }
  95. }
  96. return GenericError;
  97. }
  98. /**************************************************************************\
  99. *
  100. * Function Description:
  101. *
  102. * Reset the clipping back to its default state.
  103. *
  104. * Arguments:
  105. *
  106. * NONE
  107. *
  108. * Return Value:
  109. *
  110. * GpStatus - Ok or failure status
  111. *
  112. * Created:
  113. *
  114. * 02/09/1999 DCurtis
  115. *
  116. \**************************************************************************/
  117. GpStatus
  118. GpGraphics::ResetClip()
  119. {
  120. ASSERT(this->IsValid());
  121. GpStatus status = Ok;
  122. if (IsRecording())
  123. {
  124. status = Metafile->RecordResetClip();
  125. if (status != Ok)
  126. {
  127. SetValid(FALSE); // Prevent any more recording
  128. return status;
  129. }
  130. }
  131. DoResetClip();
  132. return status;
  133. }
  134. /**************************************************************************\
  135. *
  136. * Function Description:
  137. *
  138. * Set the clipping in the graphics context to be the specified rect.
  139. *
  140. * Arguments:
  141. *
  142. * [IN] rect - the rectangle, in world units
  143. * [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
  144. *
  145. * Return Value:
  146. *
  147. * GpStatus - Ok or failure status
  148. *
  149. * Created:
  150. *
  151. * 02/05/1999 DCurtis
  152. *
  153. \**************************************************************************/
  154. GpStatus
  155. GpGraphics::SetClip(
  156. const GpRectF& rect,
  157. CombineMode combineMode
  158. )
  159. {
  160. ASSERT(this->IsValid());
  161. GpStatus status = Ok;
  162. GpRectF tmpRect = rect;
  163. // handle flipped rects
  164. if (tmpRect.Width < 0)
  165. {
  166. tmpRect.X += tmpRect.Width;
  167. tmpRect.Width = -tmpRect.Width;
  168. }
  169. if (tmpRect.Height < 0)
  170. {
  171. tmpRect.Y += tmpRect.Height;
  172. tmpRect.Height = -tmpRect.Height;
  173. }
  174. // crop to infinity
  175. if (tmpRect.X < INFINITE_MIN)
  176. {
  177. if (tmpRect.Width < INFINITE_SIZE)
  178. {
  179. tmpRect.Width -= (INFINITE_MIN - tmpRect.X);
  180. }
  181. tmpRect.X = INFINITE_MIN;
  182. }
  183. if (tmpRect.Y < INFINITE_MIN)
  184. {
  185. if (tmpRect.Height < INFINITE_SIZE)
  186. {
  187. tmpRect.Height -= (INFINITE_MIN - tmpRect.Y);
  188. }
  189. tmpRect.Y = INFINITE_MIN;
  190. }
  191. if ((tmpRect.Width <= REAL_EPSILON) || (tmpRect.Height <= REAL_EPSILON))
  192. {
  193. GpRegion emptyRegion;
  194. emptyRegion.SetEmpty();
  195. return this->SetClip(&emptyRegion, combineMode);
  196. }
  197. if (tmpRect.Width >= INFINITE_SIZE)
  198. {
  199. if (tmpRect.Height >= INFINITE_SIZE)
  200. {
  201. GpRegion infiniteRegion;
  202. return this->SetClip(&infiniteRegion, combineMode);
  203. }
  204. tmpRect.Width = INFINITE_SIZE; // crop to infinite
  205. }
  206. else if (tmpRect.Height > INFINITE_SIZE)
  207. {
  208. tmpRect.Height = INFINITE_SIZE; // crop to infinite
  209. }
  210. if (IsRecording())
  211. {
  212. status = Metafile->RecordSetClip(rect, combineMode);
  213. if (status != Ok)
  214. {
  215. SetValid(FALSE); // Prevent any more recording
  216. return status;
  217. }
  218. }
  219. if (combineMode != CombineModeReplace)
  220. {
  221. return this->CombineClip(rect, combineMode);
  222. }
  223. if (Context->WorldToDevice.IsTranslateScale())
  224. {
  225. GpRectF transformedRect = rect;
  226. Context->WorldToDevice.TransformRect(transformedRect);
  227. Context->AppClip.Set(transformedRect.X,
  228. transformedRect.Y,
  229. transformedRect.Width,
  230. transformedRect.Height);
  231. // Try to match the GDI+ rasterizer
  232. // In theory, this could cause a floating point exception, but
  233. // the transform would have to be a very big scaling transform to do it.
  234. INT left = RasterizerCeiling(transformedRect.X);
  235. INT top = RasterizerCeiling(transformedRect.Y);
  236. INT right = RasterizerCeiling(transformedRect.GetRight());
  237. INT bottom = RasterizerCeiling(transformedRect.GetBottom());
  238. Context->VisibleClip.Set(left, top, right - left, bottom - top);
  239. goto AndClip;
  240. }
  241. else
  242. {
  243. GpPointF points[4];
  244. REAL left = rect.X;
  245. REAL top = rect.Y;
  246. REAL right = rect.X + rect.Width;
  247. REAL bottom = rect.Y + rect.Height;
  248. points[0].X = left;
  249. points[0].Y = top;
  250. points[1].X = right;
  251. points[1].Y = top;
  252. points[2].X = right;
  253. points[2].Y = bottom;
  254. points[3].X = left;
  255. points[3].Y = bottom;
  256. // Transform the points now so we only have to do it once
  257. Context->WorldToDevice.Transform(points, 4);
  258. GpPath path;
  259. path.AddLines(points, 4);
  260. if (path.IsValid())
  261. {
  262. GpMatrix identityMatrix;
  263. if ((Context->AppClip.Set(&path) == Ok) &&
  264. (Context->VisibleClip.Set(&path, &identityMatrix) == Ok))
  265. {
  266. goto AndClip;
  267. }
  268. }
  269. }
  270. ErrorExit:
  271. DoResetClip();
  272. return GenericError;
  273. AndClip:
  274. if (AndVisibleClip() == Ok)
  275. {
  276. return status;
  277. }
  278. goto ErrorExit;
  279. }
  280. /**************************************************************************\
  281. *
  282. * Function Description:
  283. *
  284. * Set the clipping in the graphics context to be the specified region.
  285. *
  286. * Arguments:
  287. *
  288. * [IN] region - the region to clip to
  289. * [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
  290. *
  291. * Return Value:
  292. *
  293. * GpStatus - Ok or failure status
  294. *
  295. * Created:
  296. *
  297. * 02/05/1999 DCurtis
  298. *
  299. \**************************************************************************/
  300. GpStatus
  301. GpGraphics::SetClip(
  302. GpRegion * region,
  303. CombineMode combineMode
  304. )
  305. {
  306. ASSERT(this->IsValid());
  307. ASSERT((region != NULL) && (region->IsValid()));
  308. GpStatus status = Ok;
  309. if (IsRecording())
  310. {
  311. status = Metafile->RecordSetClip(region, combineMode);
  312. if (status != Ok)
  313. {
  314. SetValid(FALSE); // Prevent any more recording
  315. return status;
  316. }
  317. }
  318. if (combineMode != CombineModeReplace)
  319. {
  320. return this->CombineClip(region, combineMode);
  321. }
  322. if ((Context->AppClip.Set(region) == Ok) &&
  323. (Context->AppClip.Transform(&(Context->WorldToDevice)) == Ok))
  324. {
  325. GpMatrix identityMatrix;
  326. if ((Context->AppClip.UpdateDeviceRegion(&identityMatrix) == Ok) &&
  327. (Context->VisibleClip.Set(&(Context->AppClip.DeviceRegion)) == Ok)&&
  328. (AndVisibleClip() == Ok))
  329. {
  330. return status;
  331. }
  332. }
  333. DoResetClip();
  334. return GenericError;
  335. }
  336. /**************************************************************************\
  337. *
  338. * Function Description:
  339. *
  340. * Set the clipping in the graphics context to be the specified region.
  341. *
  342. * Arguments:
  343. *
  344. * [IN] hRgn - the region to clip to (already in device units)
  345. * [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
  346. *
  347. * Return Value:
  348. *
  349. * GpStatus - Ok or failure status
  350. *
  351. * Created:
  352. *
  353. * 02/05/1999 DCurtis
  354. *
  355. \**************************************************************************/
  356. GpStatus
  357. GpGraphics::SetClip(
  358. HRGN hRgn,
  359. CombineMode combineMode
  360. )
  361. {
  362. ASSERT(this->IsValid());
  363. GpPath path(hRgn);
  364. if (path.IsValid())
  365. {
  366. return this->SetClip(&path, combineMode, TRUE/*isDevicePath*/);
  367. }
  368. return OutOfMemory;
  369. }
  370. /**************************************************************************\
  371. *
  372. * Function Description:
  373. *
  374. * Set the clipping in the graphics context to be the same as what
  375. * the specified graphics has.
  376. *
  377. * Currently, this only works if the other graphics has the same
  378. * resolution as this one does.
  379. *
  380. * Arguments:
  381. *
  382. * [IN] g - the graphics to copy the clipping from
  383. * [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
  384. *
  385. * Return Value:
  386. *
  387. * GpStatus - Ok or failure status
  388. *
  389. * Created:
  390. *
  391. * 02/09/1999 DCurtis
  392. *
  393. \**************************************************************************/
  394. GpStatus
  395. GpGraphics::SetClip(
  396. GpGraphics* g,
  397. CombineMode combineMode
  398. )
  399. {
  400. ASSERT(this->IsValid() && (g != NULL) && g->IsValid());
  401. GpStatus status = GenericError;
  402. GpRegion * region = new GpRegion(&(g->Context->AppClip));
  403. if (region != NULL)
  404. {
  405. if (region->IsValid())
  406. {
  407. GpMatrix deviceToWorld;
  408. if ((GetDeviceToWorldTransform(&deviceToWorld) == Ok) &&
  409. (region->Transform(&deviceToWorld) == Ok))
  410. {
  411. status = this->SetClip(region, combineMode);
  412. }
  413. }
  414. delete region;
  415. }
  416. return status;
  417. }
  418. /**************************************************************************\
  419. *
  420. * Function Description:
  421. *
  422. * Set the clipping in the graphics context to be the specified path.
  423. *
  424. * Arguments:
  425. *
  426. * [IN] path - the path to clip to
  427. * [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
  428. * [IN] isDevicePath- if path is already in device units
  429. *
  430. * Return Value:
  431. *
  432. * GpStatus - Ok or failure status
  433. *
  434. * Created:
  435. *
  436. * 02/09/1999 DCurtis
  437. *
  438. \**************************************************************************/
  439. GpStatus
  440. GpGraphics::SetClip(
  441. GpPath* path,
  442. CombineMode combineMode,
  443. BOOL isDevicePath // if path is already in device units
  444. )
  445. {
  446. ASSERT(this->IsValid() && (path != NULL) && path->IsValid());
  447. GpStatus status = Ok;
  448. if (IsRecording())
  449. {
  450. status = Metafile->RecordSetClip(path, combineMode, isDevicePath);
  451. if (status != Ok)
  452. {
  453. SetValid(FALSE); // Prevent any more recording
  454. return status;
  455. }
  456. }
  457. if (combineMode != CombineModeReplace)
  458. {
  459. return this->CombineClip(path, combineMode, isDevicePath);
  460. }
  461. if ((Context->AppClip.Set(path) == Ok) &&
  462. (isDevicePath ||
  463. (Context->AppClip.Transform(&(Context->WorldToDevice)) == Ok)))
  464. {
  465. GpMatrix identityMatrix;
  466. if ((Context->AppClip.UpdateDeviceRegion(&identityMatrix) == Ok) &&
  467. (Context->VisibleClip.Set(&(Context->AppClip.DeviceRegion)) == Ok)&&
  468. (AndVisibleClip() == Ok))
  469. {
  470. return status;
  471. }
  472. }
  473. DoResetClip();
  474. return GenericError;
  475. }
  476. /**************************************************************************\
  477. *
  478. * Function Description:
  479. *
  480. * Combine the region with the current clipping using the specified
  481. * combine type.
  482. *
  483. * Arguments:
  484. *
  485. * [IN] region - the region to combine the clipping with.
  486. * [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
  487. *
  488. * Return Value:
  489. *
  490. * GpStatus - Ok or failure status
  491. *
  492. * Created:
  493. *
  494. * 02/09/1999 DCurtis
  495. *
  496. \**************************************************************************/
  497. GpStatus
  498. GpGraphics::CombineClip(
  499. GpRegion * region,
  500. CombineMode combineMode
  501. )
  502. {
  503. ASSERT(this->IsValid());
  504. ASSERT((region != NULL) && (region->IsValid()));
  505. ASSERT(CombineModeIsValid(combineMode));
  506. GpRegion regionCopy;
  507. if (!Context->WorldToDevice.IsIdentity())
  508. {
  509. regionCopy.Set(region);
  510. if ((!regionCopy.IsValid()) ||
  511. (regionCopy.Transform(&(Context->WorldToDevice)) != Ok))
  512. {
  513. return GenericError;
  514. }
  515. region = &regionCopy;
  516. }
  517. if (Context->AppClip.Combine(region, combineMode) == Ok)
  518. {
  519. GpMatrix identityMatrix;
  520. if ((Context->AppClip.UpdateDeviceRegion(&identityMatrix) == Ok) &&
  521. (Context->VisibleClip.Set(&(Context->AppClip.DeviceRegion)) == Ok)&&
  522. (AndVisibleClip() == Ok))
  523. {
  524. return Ok;
  525. }
  526. }
  527. DoResetClip();
  528. return GenericError;
  529. }
  530. /**************************************************************************\
  531. *
  532. * Function Description:
  533. *
  534. * Combine the rect with the current clipping using the specified
  535. * combine type.
  536. *
  537. * Arguments:
  538. *
  539. * [IN] path - the path to combine the clipping with.
  540. * [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
  541. *
  542. * Return Value:
  543. *
  544. * GpStatus - Ok or failure status
  545. *
  546. * Created:
  547. *
  548. * 02/09/1999 DCurtis
  549. *
  550. \**************************************************************************/
  551. GpStatus
  552. GpGraphics::CombineClip(
  553. const GpPath * path,
  554. CombineMode combineMode,
  555. BOOL isDevicePath // if path is already in device units
  556. )
  557. {
  558. ASSERT(this->IsValid());
  559. ASSERT((path != NULL) && (path->IsValid()));
  560. ASSERT(CombineModeIsValid(combineMode));
  561. GpPath * pathCopy = NULL;
  562. if (!isDevicePath && (!Context->WorldToDevice.IsIdentity()))
  563. {
  564. pathCopy = path->Clone();
  565. if (!CheckValid(pathCopy))
  566. {
  567. return OutOfMemory;
  568. }
  569. pathCopy->Transform(&(Context->WorldToDevice));
  570. path = pathCopy;
  571. }
  572. GpStatus status = Context->AppClip.Combine(path, combineMode);
  573. delete pathCopy;
  574. if (status == Ok)
  575. {
  576. GpMatrix identityMatrix;
  577. if ((Context->AppClip.UpdateDeviceRegion(&identityMatrix) == Ok) &&
  578. (Context->VisibleClip.Set(&(Context->AppClip.DeviceRegion)) == Ok)&&
  579. (AndVisibleClip() == Ok))
  580. {
  581. return Ok;
  582. }
  583. }
  584. DoResetClip();
  585. return GenericError;
  586. }
  587. /**************************************************************************\
  588. *
  589. * Function Description:
  590. *
  591. * Combine the rect with the current clipping using the specified
  592. * combine type.
  593. *
  594. * Arguments:
  595. *
  596. * [IN] rect - the rect to combine the clipping with.
  597. * [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
  598. *
  599. * Return Value:
  600. *
  601. * GpStatus - Ok or failure status
  602. *
  603. * Created:
  604. *
  605. * 02/09/1999 DCurtis
  606. *
  607. \**************************************************************************/
  608. GpStatus
  609. GpGraphics::CombineClip(
  610. const GpRectF& rect,
  611. CombineMode combineMode
  612. )
  613. {
  614. ASSERT(this->IsValid());
  615. ASSERT(CombineModeIsValid(combineMode));
  616. if (Context->WorldToDevice.IsTranslateScale())
  617. {
  618. GpRectF transformedRect = rect;
  619. Context->WorldToDevice.TransformRect(transformedRect);
  620. if (Context->AppClip.Combine(&transformedRect, combineMode) == Ok)
  621. {
  622. goto SetVisibleClip;
  623. }
  624. }
  625. else
  626. {
  627. GpPointF points[4];
  628. REAL left = rect.X;
  629. REAL top = rect.Y;
  630. REAL right = rect.X + rect.Width;
  631. REAL bottom = rect.Y + rect.Height;
  632. points[0].X = left;
  633. points[0].Y = top;
  634. points[1].X = right;
  635. points[1].Y = top;
  636. points[2].X = right;
  637. points[2].Y = bottom;
  638. points[3].X = left;
  639. points[3].Y = bottom;
  640. Context->WorldToDevice.Transform(points, 4);
  641. GpPath path;
  642. path.AddLines(points, 4);
  643. if (path.IsValid())
  644. {
  645. if ( Context->AppClip.Combine(&path, combineMode) == Ok)
  646. {
  647. goto SetVisibleClip;
  648. }
  649. }
  650. }
  651. ErrorExit:
  652. DoResetClip();
  653. return GenericError;
  654. SetVisibleClip:
  655. {
  656. GpMatrix identityMatrix;
  657. if ((Context->AppClip.UpdateDeviceRegion(&identityMatrix) == Ok) &&
  658. (Context->VisibleClip.Set(&(Context->AppClip.DeviceRegion)) == Ok)&&
  659. (AndVisibleClip() == Ok))
  660. {
  661. return Ok;
  662. }
  663. goto ErrorExit;
  664. }
  665. }
  666. /**************************************************************************\
  667. *
  668. * Function Description:
  669. *
  670. * Offset (translate) the current clipping region by the specified
  671. * world unit amounts.
  672. *
  673. * Arguments:
  674. *
  675. * [IN] dx - the amount of X to offset the region by, in world units
  676. * [IN] dy - the amount of Y to offset the region by, in world units
  677. *
  678. * Return Value:
  679. *
  680. * GpStatus - Ok or failure status
  681. *
  682. * Created:
  683. *
  684. * 02/09/1999 DCurtis
  685. *
  686. \**************************************************************************/
  687. GpStatus
  688. GpGraphics::OffsetClip(
  689. REAL dx,
  690. REAL dy
  691. )
  692. {
  693. ASSERT(this->IsValid());
  694. GpStatus status = Ok;
  695. if (IsRecording())
  696. {
  697. status = Metafile->RecordOffsetClip(dx, dy);
  698. if (status != Ok)
  699. {
  700. SetValid(FALSE); // Prevent any more recording
  701. return status;
  702. }
  703. }
  704. GpPointF offset(dx, dy);
  705. Context->WorldToDevice.VectorTransform(&offset);
  706. if (Context->AppClip.Offset(offset.X, offset.Y) == Ok)
  707. {
  708. GpMatrix identityMatrix;
  709. if ((Context->AppClip.UpdateDeviceRegion(&identityMatrix) == Ok) &&
  710. (Context->VisibleClip.Set(&(Context->AppClip.DeviceRegion)) == Ok)&&
  711. (AndVisibleClip() == Ok))
  712. {
  713. return status;
  714. }
  715. }
  716. DoResetClip();
  717. return GenericError;
  718. }
  719. /**************************************************************************\
  720. *
  721. * Function Description:
  722. *
  723. * Determine if the specified rect is completely outside the current
  724. * clipping region.
  725. *
  726. * Arguments:
  727. *
  728. * [IN] rect - the rect to check, in device units
  729. *
  730. * Return Value:
  731. *
  732. * TRUE - the rect is completely outside the current clipping region
  733. * FALSE - the rect is at least partially visible
  734. *
  735. * Created:
  736. *
  737. * 02/05/1999 DCurtis
  738. *
  739. \**************************************************************************/
  740. BOOL
  741. GpGraphics::IsTotallyClipped(
  742. GpRect * rect // rect in device units
  743. ) const
  744. {
  745. ASSERT(rect != NULL);
  746. return !(Context->VisibleClip.RectVisible(rect));
  747. }
  748. /**************************************************************************\
  749. *
  750. * Function Description:
  751. *
  752. * Determine if the current clipping is empty or not
  753. *
  754. * Arguments:
  755. *
  756. * NONE
  757. *
  758. * Return Value:
  759. *
  760. * BOOL - whether or not the current clipping area is empty.
  761. *
  762. * Created:
  763. *
  764. * 02/09/1999 DCurtis
  765. *
  766. \**************************************************************************/
  767. BOOL
  768. GpGraphics::IsClipEmpty() const
  769. {
  770. ASSERT(this->IsValid());
  771. GpMatrix identityMatrix;
  772. BOOL isEmpty = FALSE;
  773. Context->AppClip.IsEmpty(&identityMatrix, &isEmpty);
  774. return isEmpty;
  775. }
  776. /**************************************************************************\
  777. *
  778. * Function Description:
  779. *
  780. * Return a rect with the bounds (in world units) of the current clip region.
  781. *
  782. * Arguments:
  783. *
  784. * [OUT] rect - the bounds of the current clip region, in world units
  785. *
  786. * Return Value:
  787. *
  788. * NONE
  789. *
  790. * Created:
  791. *
  792. * 02/09/1999 DCurtis
  793. *
  794. \**************************************************************************/
  795. VOID
  796. GpGraphics::GetClipBounds(
  797. GpRectF& rect
  798. ) const
  799. {
  800. ASSERT(this->IsValid());
  801. GpRect deviceRect;
  802. GpMatrix identityMatrix;
  803. // We keep AppClip in device units
  804. Context->AppClip.GetBounds(&identityMatrix, &deviceRect);
  805. DeviceToWorldTransformRect(deviceRect, rect);
  806. }
  807. /**************************************************************************\
  808. *
  809. * Function Description:
  810. *
  811. * Transform a device units rect to a world units rect.
  812. *
  813. * Arguments:
  814. *
  815. * [IN] deviceRect - the bounds in device units
  816. * [OUT] rect - the bounds, in world units
  817. *
  818. * Return Value:
  819. *
  820. * NONE
  821. *
  822. * Created:
  823. *
  824. * 04/07/1999 DCurtis
  825. *
  826. \**************************************************************************/
  827. VOID
  828. GpGraphics::DeviceToWorldTransformRect(
  829. const GpRect & deviceRect,
  830. GpRectF & rect
  831. ) const
  832. {
  833. if (Context->WorldToDevice.IsIdentity())
  834. {
  835. rect.X = LTOF(deviceRect.X);
  836. rect.Y = LTOF(deviceRect.Y);
  837. rect.Width = LTOF(deviceRect.Width);
  838. rect.Height = LTOF(deviceRect.Height);
  839. }
  840. else
  841. {
  842. GpMatrix deviceToWorld;
  843. if (GetDeviceToWorldTransform(&deviceToWorld) != Ok)
  844. {
  845. rect.X = rect.Y = rect.Width = rect.Height = 0;
  846. return;
  847. }
  848. if (deviceToWorld.IsTranslateScale())
  849. {
  850. rect.X = LTOF(deviceRect.X);
  851. rect.Y = LTOF(deviceRect.Y);
  852. rect.Width = LTOF(deviceRect.Width);
  853. rect.Height = LTOF(deviceRect.Height);
  854. deviceToWorld.TransformRect(rect);
  855. }
  856. else
  857. {
  858. GpPointF points[4];
  859. REAL left = LTOF(deviceRect.X);
  860. REAL top = LTOF(deviceRect.Y);
  861. REAL right = LTOF(deviceRect.X + deviceRect.Width);
  862. REAL bottom = LTOF(deviceRect.Y + deviceRect.Height);
  863. points[0].X = left;
  864. points[0].Y = top;
  865. points[1].X = right;
  866. points[1].Y = top;
  867. points[2].X = right;
  868. points[2].Y = bottom;
  869. points[3].X = left;
  870. points[3].Y = bottom;
  871. deviceToWorld.Transform(points, 4);
  872. REAL value;
  873. left = points[0].X;
  874. right = left;
  875. top = points[0].Y;
  876. bottom = top;
  877. INT count = 3;
  878. do
  879. {
  880. value = points[count].X;
  881. if (value < left)
  882. {
  883. left = value;
  884. }
  885. else if (value > right)
  886. {
  887. right = value;
  888. }
  889. value = points[count].Y;
  890. if (value < top)
  891. {
  892. top = value;
  893. }
  894. else if (value > bottom)
  895. {
  896. bottom = value;
  897. }
  898. } while (--count > 0);
  899. rect.X = left;
  900. rect.Y = top;
  901. rect.Width = right - left;
  902. rect.Height = bottom - top;
  903. }
  904. }
  905. }
  906. /**************************************************************************\
  907. *
  908. * Function Description:
  909. *
  910. * Return a rect with the bounds (in world units) of the current
  911. * visible clip region.
  912. *
  913. * Arguments:
  914. *
  915. * [OUT] rect - the bounds of the current clip region, in world units
  916. *
  917. * Return Value:
  918. *
  919. * NONE
  920. *
  921. * Created:
  922. *
  923. * 02/09/1999 DCurtis
  924. *
  925. \**************************************************************************/
  926. VOID
  927. GpGraphics::GetVisibleClipBounds(
  928. GpRectF& rect
  929. ) const
  930. {
  931. ASSERT(this->IsValid());
  932. GpRect deviceRect;
  933. Context->VisibleClip.GetBounds(&deviceRect);
  934. DeviceToWorldTransformRect(deviceRect, rect);
  935. }
  936. /**************************************************************************\
  937. *
  938. * Function Description:
  939. *
  940. * Determine if the current visible clipping is empty or not
  941. *
  942. * Arguments:
  943. *
  944. * NONE
  945. *
  946. * Return Value:
  947. *
  948. * BOOL - whether or not the current clipping area is empty.
  949. *
  950. * Created:
  951. *
  952. * 02/09/1999 DCurtis
  953. *
  954. \**************************************************************************/
  955. BOOL
  956. GpGraphics::IsVisibleClipEmpty() const
  957. {
  958. ASSERT(this->IsValid());
  959. return Context->VisibleClip.IsEmpty();
  960. }
  961. /**************************************************************************\
  962. *
  963. * Function Description:
  964. *
  965. * Determine if the specified point is visible within the current clip region.
  966. *
  967. * Arguments:
  968. *
  969. * point - the point to test, in world units.
  970. *
  971. * Return Value:
  972. *
  973. * BOOL - whether or not the point is inside the current clipping.
  974. *
  975. * Created:
  976. *
  977. * 02/09/1999 DCurtis
  978. *
  979. \**************************************************************************/
  980. BOOL
  981. GpGraphics::IsVisible(
  982. const GpPointF& point
  983. ) const
  984. {
  985. ASSERT(this->IsValid());
  986. GpPointF pointCopy = point;
  987. Context->WorldToDevice.Transform(&pointCopy);
  988. return Context->VisibleClip.PointInside(GpRound(pointCopy.X),
  989. GpRound(pointCopy.Y));
  990. }
  991. /**************************************************************************\
  992. *
  993. * Function Description:
  994. *
  995. * Determine if the specified rect is visible within the current clip region.
  996. *
  997. * Arguments:
  998. *
  999. * rect - the rect to test, in world units.
  1000. *
  1001. * Return Value:
  1002. *
  1003. * BOOL - whether or not the rect is inside/overlaps the current clipping.
  1004. *
  1005. * Created:
  1006. *
  1007. * 02/09/1999 DCurtis
  1008. *
  1009. \**************************************************************************/
  1010. BOOL
  1011. GpGraphics::IsVisible(
  1012. const GpRectF& rect
  1013. ) const
  1014. {
  1015. ASSERT(this->IsValid());
  1016. if (Context->WorldToDevice.IsTranslateScale())
  1017. {
  1018. GpRectF transformedRect = rect;
  1019. Context->WorldToDevice.TransformRect(transformedRect);
  1020. // use ceiling to match rasterizer
  1021. return Context->VisibleClip.RectVisible(
  1022. GpCeiling(transformedRect.X),
  1023. GpCeiling(transformedRect.Y),
  1024. GpCeiling(transformedRect.GetRight()),
  1025. GpCeiling(transformedRect.GetBottom()));
  1026. }
  1027. else
  1028. {
  1029. GpRectF bounds;
  1030. GpRect deviceBounds;
  1031. GpRect clipBounds;
  1032. TransformBounds(&(Context->WorldToDevice),
  1033. rect.X, rect.Y,
  1034. rect.GetRight(), rect.GetBottom(),
  1035. &bounds);
  1036. GpStatus status = BoundsFToRect(&bounds, &deviceBounds);
  1037. Context->VisibleClip.GetBounds(&clipBounds);
  1038. // try trivial reject
  1039. if (status == Ok && clipBounds.IntersectsWith(deviceBounds))
  1040. {
  1041. // couldn't reject, so do full test
  1042. GpRegion region(&rect);
  1043. if (region.IsValid() &&
  1044. (region.UpdateDeviceRegion(&(Context->WorldToDevice)) == Ok))
  1045. {
  1046. return Context->VisibleClip.RegionVisible(&region.DeviceRegion);
  1047. }
  1048. }
  1049. }
  1050. return FALSE;
  1051. }