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