OLD | NEW |
(Empty) | |
| 1 SkRegion |
| 2 ======== |
| 3 |
| 4 *Regions - set operations with rectangles* |
| 5 |
| 6 <!-- Updated Mar 4, 2011 --> |
| 7 |
| 8 Regions are a highly compressed way to represent (integer) areas. Skia |
| 9 uses them to represent (internally) the current clip on the |
| 10 canvas. Regions take their inspiration from the data type with the |
| 11 same name on the original Macintosh (thank you Bill). |
| 12 |
| 13 Regions are opaque structures, but they can be queried via |
| 14 iterators. Best of all, they can be combined with other regions and |
| 15 with rectangles (which can be thought of as "simple" regions. If you |
| 16 remember Set operations from math class (intersection, union, |
| 17 difference, etc.), then you're all ready to use regions. |
| 18 |
| 19 <!--?prettify lang=cc?--> |
| 20 |
| 21 bool SkRegion::isEmpty(); |
| 22 bool SkRegion::isRect(); |
| 23 bool SkRegion::isComplex(); |
| 24 |
| 25 Regions can be classified into one of three types: empty, rectangular, |
| 26 or complex. |
| 27 |
| 28 Empty regions are just that, empty. All empty regions are equal (using |
| 29 operator==). Compare this to rectangles (SkRect or SkIRect). Any |
| 30 rectangle with fLeft >= fRight or fTop >= fBottom is consider empty, |
| 31 but clearly there are different empty rectangles that are not equal. |
| 32 |
| 33 <!--?prettify lang=cc?--> |
| 34 |
| 35 SkRect a = { 0, 0, 0, 0 }; |
| 36 SkRect b = { 1, 1, 1, 1 }; |
| 37 |
| 38 Both a and b are empty, but they are definitely not equal to each |
| 39 other. However, with regions, all empty regions are equal. If you |
| 40 query its bounds, you will always get { 0, 0, 0, 0 }. Even if you |
| 41 translate it, it will still be all zeros. |
| 42 |
| 43 <!--?prettify lang=cc?--> |
| 44 |
| 45 <!--?prettify lang=cc?--> |
| 46 |
| 47 SkRegion a, b; // regions default to empty |
| 48 assert(a == b); |
| 49 a.offset(10, 20); |
| 50 assert(a == b); |
| 51 assert(a.getBounds() == { 0, 0, 0, 0 }); // not legal C++, but you get the
point |
| 52 assert(b.getBounds() == { 0, 0, 0, 0 }); |
| 53 |
| 54 To initialize a region to something more interesting, use one of the |
| 55 set() methods |
| 56 |
| 57 <!--?prettify lang=cc?--> |
| 58 |
| 59 SkRegion a, b; |
| 60 a.setRect(10, 10, 50, 50); |
| 61 b.setRect(rect); // see SkIRect |
| 62 c.setPath(path); // see SkPath |
| 63 |
| 64 This is the first step that SkCanvas performs when one of its |
| 65 clip...() methods are called. The clip data is first transformed into |
| 66 device coordinates (see SkMatrix), and then a region is build from the |
| 67 data (either a rect or a path). The final step is to combine this new |
| 68 region with the existing clip using the specified operator. |
| 69 |
| 70 <!--?prettify lang=cc?--> |
| 71 |
| 72 enum Op { |
| 73 kUnion_Op, |
| 74 kIntersect_Op, |
| 75 kDifference_Op, |
| 76 kXor_Op, |
| 77 kReverseDifference_Op, |
| 78 kReplace_Op |
| 79 }; |
| 80 |
| 81 By default, intersect op is used when a clip call is made, but the |
| 82 other operators are equally valid. |
| 83 |
| 84 <!--?prettify lang=cc?--> |
| 85 |
| 86 // returns true if the resulting clip is non-empty (i.e. drawing can |
| 87 // still occur) |
| 88 bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op) { |
| 89 SkRegion rgn; |
| 90 |
| 91 // peek at the CTM (current transformation matrix on the canvas) |
| 92 const SkMatrix& m = this->getTotalMatrix(); |
| 93 |
| 94 if (m.rectStaysRect()) { // check if a transformed rect can be |
| 95 // represented as another rect |
| 96 |
| 97 SkRect deviceRect; |
| 98 m.mapRect(&deviceRect, rect); |
| 99 SkIRect intRect; |
| 100 deviceRect.round(&intRect); |
| 101 rgn.setRect(intRect); |
| 102 } else { // matrix rotates or skew (or is perspective) |
| 103 SkPath path; |
| 104 path.addRect(rect); |
| 105 path.transform(m); |
| 106 rgn.setPath(path); |
| 107 } |
| 108 |
| 109 // now combine the new region with the current one, using the specified
*op* |
| 110 return fCurrentClip.op(rgn, op); |
| 111 } |
OLD | NEW |