1SkRegion 2======== 3 4*Regions - set operations with rectangles* 5 6<!-- Updated Mar 4, 2011 --> 7 8Regions are a highly compressed way to represent (integer) areas. Skia 9uses them to represent (internally) the current clip on the 10canvas. Regions take their inspiration from the data type with the 11same name on the original Macintosh (thank you Bill). 12 13Regions are opaque structures, but they can be queried via 14iterators. Best of all, they can be combined with other regions and 15with rectangles (which can be thought of as "simple" regions. If you 16remember Set operations from math class (intersection, union, 17difference, 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 25Regions can be classified into one of three types: empty, rectangular, 26or complex. 27 28Empty regions are just that, empty. All empty regions are equal (using 29operator==). Compare this to rectangles (SkRect or SkIRect). Any 30rectangle with fLeft >= fRight or fTop >= fBottom is consider empty, 31but 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 38Both a and b are empty, but they are definitely not equal to each 39other. However, with regions, all empty regions are equal. If you 40query its bounds, you will always get { 0, 0, 0, 0 }. Even if you 41translate 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 54To initialize a region to something more interesting, use one of the 55set() 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 64This is the first step that SkCanvas performs when one of its 65clip...() methods are called. The clip data is first transformed into 66device coordinates (see SkMatrix), and then a region is build from the 67data (either a rect or a path). The final step is to combine this new 68region 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 81By default, intersect op is used when a clip call is made, but the 82other 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 } 112