SkRegion.h revision 137a4ca42423bbb6d683067ea544c9a48f18f06c
1/* 2 * Copyright (C) 2005 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#ifndef SkRegion_DEFINED 18#define SkRegion_DEFINED 19 20#include "SkRect.h" 21 22class SkPath; 23class SkRgnBuilder; 24 25namespace android { 26 class Region; 27} 28 29#define SkRegion_gEmptyRunHeadPtr ((SkRegion::RunHead*)-1) 30#define SkRegion_gRectRunHeadPtr 0 31 32/** \class SkRegion 33 34 The SkRegion class encapsulates the geometric region used to specify 35 clipping areas for drawing. 36*/ 37class SK_API SkRegion { 38public: 39 typedef int32_t RunType; 40 enum { 41 kRunTypeSentinel = 0x7FFFFFFF 42 }; 43 44 SkRegion(); 45 SkRegion(const SkRegion&); 46 explicit SkRegion(const SkIRect&); 47 ~SkRegion(); 48 49 SkRegion& operator=(const SkRegion&); 50 51 friend int operator==(const SkRegion& a, const SkRegion& b); 52 friend int operator!=(const SkRegion& a, const SkRegion& b) { 53 return !(a == b); 54 } 55 56 /** Replace this region with the specified region, and return true if the 57 resulting region is non-empty. 58 */ 59 bool set(const SkRegion& src) { 60 SkASSERT(&src); 61 *this = src; 62 return !this->isEmpty(); 63 } 64 65 /** Swap the contents of this and the specified region. This operation 66 is gauarenteed to never fail. 67 */ 68 void swap(SkRegion&); 69 70 /** Return true if this region is empty */ 71 bool isEmpty() const { return fRunHead == SkRegion_gEmptyRunHeadPtr; } 72 /** Return true if this region is a single, non-empty rectangle */ 73 bool isRect() const { return fRunHead == SkRegion_gRectRunHeadPtr; } 74 /** Return true if this region consists of more than 1 rectangular area */ 75 bool isComplex() const { return !this->isEmpty() && !this->isRect(); } 76 /** Return the bounds of this region. If the region is empty, returns an 77 empty rectangle. 78 */ 79 const SkIRect& getBounds() const { return fBounds; } 80 81 /** Returns true if the region is non-empty, and if so, sets the specified 82 path to the boundary(s) of the region. 83 */ 84 bool getBoundaryPath(SkPath* path) const; 85 86 /** Set the region to be empty, and return false, since the resulting 87 region is empty 88 */ 89 bool setEmpty(); 90 91 /** If rect is non-empty, set this region to that rectangle and return true, 92 otherwise set this region to empty and return false. 93 */ 94 bool setRect(const SkIRect&); 95 96 /** If left < right and top < bottom, set this region to that rectangle and 97 return true, otherwise set this region to empty and return false. 98 */ 99 bool setRect(int32_t left, int32_t top, int32_t right, int32_t bottom); 100 101 /** Set this region to the union of an array of rects. This is generally 102 faster than calling region.op(rect, kUnion_Op) in a loop. If count is 103 0, then this region is set to the empty region. 104 @return true if the resulting region is non-empty 105 */ 106 bool setRects(const SkIRect rects[], int count); 107 108 /** Set this region to the specified region, and return true if it is 109 non-empty. */ 110 bool setRegion(const SkRegion&); 111 112 /** Set this region to the area described by the path, clipped. 113 Return true if the resulting region is non-empty. 114 This produces a region that is identical to the pixels that would be 115 drawn by the path (with no antialiasing) with the specified clip. 116 */ 117 bool setPath(const SkPath&, const SkRegion& clip); 118 119 /** Returns true if the specified rectangle has a non-empty intersection 120 with this region. 121 */ 122 bool intersects(const SkIRect&) const; 123 124 /** Returns true if the specified region has a non-empty intersection 125 with this region. 126 */ 127 bool intersects(const SkRegion&) const; 128 129 /** Return true if the specified x,y coordinate is inside the region. 130 */ 131 bool contains(int32_t x, int32_t y) const; 132 133 /** Return true if the specified rectangle is completely inside the region. 134 This works for simple (rectangular) and complex regions, and always 135 returns the correct result. Note: if either this region or the rectangle 136 is empty, contains() returns false. 137 */ 138 bool contains(const SkIRect&) const; 139 140 /** Return true if the specified region is completely inside the region. 141 This works for simple (rectangular) and complex regions, and always 142 returns the correct result. Note: if either region is empty, contains() 143 returns false. 144 */ 145 bool contains(const SkRegion&) const; 146 147 /** Return true if this region is a single rectangle (not complex) and the 148 specified rectangle is contained by this region. Returning false is not 149 a guarantee that the rectangle is not contained by this region, but 150 return true is a guarantee that the rectangle is contained by this region. 151 */ 152 bool quickContains(const SkIRect& r) const { 153 return this->quickContains(r.fLeft, r.fTop, r.fRight, r.fBottom); 154 } 155 156 /** Return true if this region is a single rectangle (not complex) and the 157 specified rectangle is contained by this region. Returning false is not 158 a guarantee that the rectangle is not contained by this region, but 159 return true is a guarantee that the rectangle is contained by this 160 region. 161 */ 162 bool quickContains(int32_t left, int32_t top, int32_t right, 163 int32_t bottom) const { 164 SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region 165 166 return left < right && top < bottom && 167 fRunHead == SkRegion_gRectRunHeadPtr && // this->isRect() 168 /* fBounds.contains(left, top, right, bottom); */ 169 fBounds.fLeft <= left && fBounds.fTop <= top && 170 fBounds.fRight >= right && fBounds.fBottom >= bottom; 171 } 172 173 /** Return true if this region is empty, or if the specified rectangle does 174 not intersect the region. Returning false is not a guarantee that they 175 intersect, but returning true is a guarantee that they do not. 176 */ 177 bool quickReject(const SkIRect& rect) const 178 { 179 return this->isEmpty() || rect.isEmpty() || 180 !SkIRect::Intersects(fBounds, rect); 181 } 182 183 /** Return true if this region, or rgn, is empty, or if their bounds do not 184 intersect. Returning false is not a guarantee that they intersect, but 185 returning true is a guarantee that they do not. 186 */ 187 bool quickReject(const SkRegion& rgn) const { 188 return this->isEmpty() || rgn.isEmpty() || 189 !SkIRect::Intersects(fBounds, rgn.fBounds); 190 } 191 192 /** Translate the region by the specified (dx, dy) amount. 193 */ 194 void translate(int dx, int dy) { this->translate(dx, dy, this); } 195 196 /** Translate the region by the specified (dx, dy) amount, writing the 197 resulting region into dst. Note: it is legal to pass this region as the 198 dst parameter, effectively translating the region in place. If dst is 199 null, nothing happens. 200 */ 201 void translate(int dx, int dy, SkRegion* dst) const; 202 203 /** The logical operations that can be performed when combining two regions. 204 */ 205 enum Op { 206 kDifference_Op, //!< subtract the op region from the first region 207 kIntersect_Op, //!< intersect the two regions 208 kUnion_Op, //!< union (inclusive-or) the two regions 209 kXOR_Op, //!< exclusive-or the two regions 210 /** subtract the first region from the op region */ 211 kReverseDifference_Op, 212 kReplace_Op //!< replace the dst region with the op region 213 }; 214 215 /** Set this region to the result of applying the Op to this region and the 216 specified rectangle: this = (this op rect). 217 Return true if the resulting region is non-empty. 218 */ 219 bool op(const SkIRect& rect, Op op) { return this->op(*this, rect, op); } 220 221 /** Set this region to the result of applying the Op to this region and the 222 specified rectangle: this = (this op rect). 223 Return true if the resulting region is non-empty. 224 */ 225 bool op(int left, int top, int right, int bottom, Op op) { 226 SkIRect rect; 227 rect.set(left, top, right, bottom); 228 return this->op(*this, rect, op); 229 } 230 231 /** Set this region to the result of applying the Op to this region and the 232 specified region: this = (this op rgn). 233 Return true if the resulting region is non-empty. 234 */ 235 bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); } 236 /** Set this region to the result of applying the Op to the specified 237 rectangle and region: this = (rect op rgn). 238 Return true if the resulting region is non-empty. 239 */ 240 bool op(const SkIRect& rect, const SkRegion& rgn, Op); 241 /** Set this region to the result of applying the Op to the specified 242 region and rectangle: this = (rgn op rect). 243 Return true if the resulting region is non-empty. 244 */ 245 bool op(const SkRegion& rgn, const SkIRect& rect, Op); 246 /** Set this region to the result of applying the Op to the specified 247 regions: this = (rgna op rgnb). 248 Return true if the resulting region is non-empty. 249 */ 250 bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op); 251 252#ifdef ANDROID 253 /** Returns a new char* containing the list of rectangles in this region 254 */ 255 char* toString(); 256#endif 257 258 /** Returns the sequence of rectangles, sorted in Y and X, that make up 259 this region. 260 */ 261 class SK_API Iterator { 262 public: 263 Iterator() : fRgn(NULL), fDone(true) {} 264 Iterator(const SkRegion&); 265 // if we have a region, reset to it and return true, else return false 266 bool rewind(); 267 // reset the iterator, using the new region 268 void reset(const SkRegion&); 269 bool done() const { return fDone; } 270 void next(); 271 const SkIRect& rect() const { return fRect; } 272 // may return null 273 const SkRegion* rgn() const { return fRgn; } 274 private: 275 const SkRegion* fRgn; 276 const RunType* fRuns; 277 SkIRect fRect; 278 bool fDone; 279 }; 280 281 /** Returns the sequence of rectangles, sorted in Y and X, that make up 282 this region intersected with the specified clip rectangle. 283 */ 284 class SK_API Cliperator { 285 public: 286 Cliperator(const SkRegion&, const SkIRect& clip); 287 bool done() { return fDone; } 288 void next(); 289 const SkIRect& rect() const { return fRect; } 290 291 private: 292 Iterator fIter; 293 SkIRect fClip; 294 SkIRect fRect; 295 bool fDone; 296 }; 297 298 /** Returns the sequence of runs that make up this region for the specified 299 Y scanline, clipped to the specified left and right X values. 300 */ 301 class Spanerator { 302 public: 303 Spanerator(const SkRegion&, int y, int left, int right); 304 bool next(int* left, int* right); 305 306 private: 307 const SkRegion::RunType* fRuns; 308 int fLeft, fRight; 309 bool fDone; 310 }; 311 312 /** Write the region to the buffer, and return the number of bytes written. 313 If buffer is NULL, it still returns the number of bytes. 314 */ 315 uint32_t flatten(void* buffer) const; 316 /** Initialized the region from the buffer, returning the number 317 of bytes actually read. 318 */ 319 uint32_t unflatten(const void* buffer); 320 321 SkDEBUGCODE(void dump() const;) 322 SkDEBUGCODE(void validate() const;) 323 SkDEBUGCODE(static void UnitTest();) 324 325 // expose this to allow for regression test on complex regions 326 SkDEBUGCODE(bool debugSetRuns(const RunType runs[], int count);) 327 328private: 329 enum { 330 kOpCount = kReplace_Op + 1 331 }; 332 333 enum { 334 kRectRegionRuns = 6 // need to store a region of a rect [T B L R S S] 335 }; 336 337 friend class android::Region; // needed for marshalling efficiently 338 void allocateRuns(int count); // allocate space for count runs 339 340 struct RunHead; 341 342 SkIRect fBounds; 343 RunHead* fRunHead; 344 345 void freeRuns(); 346 const RunType* getRuns(RunType tmpStorage[], int* count) const; 347 bool setRuns(RunType runs[], int count); 348 349 int count_runtype_values(int* itop, int* ibot) const; 350 351 static void BuildRectRuns(const SkIRect& bounds, 352 RunType runs[kRectRegionRuns]); 353 // returns true if runs are just a rect 354 static bool ComputeRunBounds(const RunType runs[], int count, 355 SkIRect* bounds); 356 357 friend struct RunHead; 358 friend class Iterator; 359 friend class Spanerator; 360 friend class SkRgnBuilder; 361 friend class SkFlatRegion; 362}; 363 364 365#endif 366 367