Index: site/user/api/skregion.md |
diff --git a/site/user/api/skregion.md b/site/user/api/skregion.md |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f4f46c951b5c8dbde42d49c26d8eed836a2ba4e3 |
--- /dev/null |
+++ b/site/user/api/skregion.md |
@@ -0,0 +1,111 @@ |
+SkRegion |
+======== |
+ |
+*Regions - set operations with rectangles* |
+ |
+<!-- Updated Mar 4, 2011 --> |
+ |
+Regions are a highly compressed way to represent (integer) areas. Skia |
+uses them to represent (internally) the current clip on the |
+canvas. Regions take their inspiration from the data type with the |
+same name on the original Macintosh (thank you Bill). |
+ |
+Regions are opaque structures, but they can be queried via |
+iterators. Best of all, they can be combined with other regions and |
+with rectangles (which can be thought of as "simple" regions. If you |
+remember Set operations from math class (intersection, union, |
+difference, etc.), then you're all ready to use regions. |
+ |
+<!--?prettify lang=cc?--> |
+ |
+ bool SkRegion::isEmpty(); |
+ bool SkRegion::isRect(); |
+ bool SkRegion::isComplex(); |
+ |
+Regions can be classified into one of three types: empty, rectangular, |
+or complex. |
+ |
+Empty regions are just that, empty. All empty regions are equal (using |
+operator==). Compare this to rectangles (SkRect or SkIRect). Any |
+rectangle with fLeft >= fRight or fTop >= fBottom is consider empty, |
+but clearly there are different empty rectangles that are not equal. |
+ |
+<!--?prettify lang=cc?--> |
+ |
+ SkRect a = { 0, 0, 0, 0 }; |
+ SkRect b = { 1, 1, 1, 1 }; |
+ |
+Both a and b are empty, but they are definitely not equal to each |
+other. However, with regions, all empty regions are equal. If you |
+query its bounds, you will always get { 0, 0, 0, 0 }. Even if you |
+translate it, it will still be all zeros. |
+ |
+<!--?prettify lang=cc?--> |
+ |
+<!--?prettify lang=cc?--> |
+ |
+ SkRegion a, b; // regions default to empty |
+ assert(a == b); |
+ a.offset(10, 20); |
+ assert(a == b); |
+ assert(a.getBounds() == { 0, 0, 0, 0 }); // not legal C++, but you get the point |
+ assert(b.getBounds() == { 0, 0, 0, 0 }); |
+ |
+To initialize a region to something more interesting, use one of the |
+set() methods |
+ |
+<!--?prettify lang=cc?--> |
+ |
+ SkRegion a, b; |
+ a.setRect(10, 10, 50, 50); |
+ b.setRect(rect); // see SkIRect |
+ c.setPath(path); // see SkPath |
+ |
+This is the first step that SkCanvas performs when one of its |
+clip...() methods are called. The clip data is first transformed into |
+device coordinates (see SkMatrix), and then a region is build from the |
+data (either a rect or a path). The final step is to combine this new |
+region with the existing clip using the specified operator. |
+ |
+<!--?prettify lang=cc?--> |
+ |
+ enum Op { |
+ kUnion_Op, |
+ kIntersect_Op, |
+ kDifference_Op, |
+ kXor_Op, |
+ kReverseDifference_Op, |
+ kReplace_Op |
+ }; |
+ |
+By default, intersect op is used when a clip call is made, but the |
+other operators are equally valid. |
+ |
+<!--?prettify lang=cc?--> |
+ |
+ // returns true if the resulting clip is non-empty (i.e. drawing can |
+ // still occur) |
+ bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op) { |
+ SkRegion rgn; |
+ |
+ // peek at the CTM (current transformation matrix on the canvas) |
+ const SkMatrix& m = this->getTotalMatrix(); |
+ |
+ if (m.rectStaysRect()) { // check if a transformed rect can be |
+ // represented as another rect |
+ |
+ SkRect deviceRect; |
+ m.mapRect(&deviceRect, rect); |
+ SkIRect intRect; |
+ deviceRect.round(&intRect); |
+ rgn.setRect(intRect); |
+ } else { // matrix rotates or skew (or is perspective) |
+ SkPath path; |
+ path.addRect(rect); |
+ path.transform(m); |
+ rgn.setPath(path); |
+ } |
+ |
+ // now combine the new region with the current one, using the specified *op* |
+ return fCurrentClip.op(rgn, op); |
+ } |