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 22 class SkPath; 23 class SkRgnBuilder; 24 25 namespace 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 */ 37 class SK_API SkRegion { 38 public: 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 /** 52 * Return true if the two regions are equal. i.e. The enclose exactly 53 * the same area. 54 */ 55 friend bool operator==(const SkRegion& a, const SkRegion& b); 56 57 /** 58 * Return true if the two regions are not equal. 59 */ 60 friend bool operator!=(const SkRegion& a, const SkRegion& b) { 61 return !(a == b); 62 } 63 64 /** 65 * Replace this region with the specified region, and return true if the 66 * resulting region is non-empty. 67 */ set(const SkRegion & src)68 bool set(const SkRegion& src) { 69 SkASSERT(&src); 70 *this = src; 71 return !this->isEmpty(); 72 } 73 74 /** 75 * Swap the contents of this and the specified region. This operation 76 * is gauarenteed to never fail. 77 */ 78 void swap(SkRegion&); 79 80 /** Return true if this region is empty */ isEmpty()81 bool isEmpty() const { return fRunHead == SkRegion_gEmptyRunHeadPtr; } 82 83 /** Return true if this region is a single, non-empty rectangle */ isRect()84 bool isRect() const { return fRunHead == SkRegion_gRectRunHeadPtr; } 85 86 /** Return true if this region consists of more than 1 rectangular area */ isComplex()87 bool isComplex() const { return !this->isEmpty() && !this->isRect(); } 88 89 /** 90 * Return the bounds of this region. If the region is empty, returns an 91 * empty rectangle. 92 */ getBounds()93 const SkIRect& getBounds() const { return fBounds; } 94 95 /** 96 * Returns true if the region is non-empty, and if so, sets the specified 97 * path to the boundary(s) of the region. If the region is empty, then 98 * this returns false, and path is left unmodified. 99 */ 100 bool getBoundaryPath(SkPath* path) const; 101 102 /** 103 * Set the region to be empty, and return false, since the resulting 104 * region is empty 105 */ 106 bool setEmpty(); 107 108 /** 109 * If rect is non-empty, set this region to that rectangle and return true, 110 * otherwise set this region to empty and return false. 111 */ 112 bool setRect(const SkIRect&); 113 114 /** 115 * If left < right and top < bottom, set this region to that rectangle and 116 * return true, otherwise set this region to empty and return false. 117 */ 118 bool setRect(int32_t left, int32_t top, int32_t right, int32_t bottom); 119 120 /** 121 * Set this region to the union of an array of rects. This is generally 122 * faster than calling region.op(rect, kUnion_Op) in a loop. If count is 123 * 0, then this region is set to the empty region. 124 * @return true if the resulting region is non-empty 125 */ 126 bool setRects(const SkIRect rects[], int count); 127 128 /** 129 * Set this region to the specified region, and return true if it is 130 * non-empty. 131 */ 132 bool setRegion(const SkRegion&); 133 134 /** 135 * Set this region to the area described by the path, clipped. 136 * Return true if the resulting region is non-empty. 137 * This produces a region that is identical to the pixels that would be 138 * drawn by the path (with no antialiasing) with the specified clip. 139 */ 140 bool setPath(const SkPath&, const SkRegion& clip); 141 142 /** 143 * Returns true if the specified rectangle has a non-empty intersection 144 * with this region. 145 */ 146 bool intersects(const SkIRect&) const; 147 148 /** 149 * Returns true if the specified region has a non-empty intersection 150 * with this region. 151 */ 152 bool intersects(const SkRegion&) const; 153 154 /** 155 * Return true if the specified x,y coordinate is inside the region. 156 */ 157 bool contains(int32_t x, int32_t y) const; 158 159 /** 160 * Return true if the specified rectangle is completely inside the region. 161 * This works for simple (rectangular) and complex regions, and always 162 * returns the correct result. Note: if either this region or the rectangle 163 * is empty, contains() returns false. 164 */ 165 bool contains(const SkIRect&) const; 166 167 /** 168 * Return true if the specified region is completely inside the region. 169 * This works for simple (rectangular) and complex regions, and always 170 * returns the correct result. Note: if either region is empty, contains() 171 * returns false. 172 */ 173 bool contains(const SkRegion&) const; 174 175 /** 176 * Return true if this region is a single rectangle (not complex) and the 177 * specified rectangle is contained by this region. Returning false is not 178 * a guarantee that the rectangle is not contained by this region, but 179 * return true is a guarantee that the rectangle is contained by this region. 180 */ quickContains(const SkIRect & r)181 bool quickContains(const SkIRect& r) const { 182 return this->quickContains(r.fLeft, r.fTop, r.fRight, r.fBottom); 183 } 184 185 /** 186 * Return true if this region is a single rectangle (not complex) and the 187 * specified rectangle is contained by this region. Returning false is not 188 * a guarantee that the rectangle is not contained by this region, but 189 * return true is a guarantee that the rectangle is contained by this 190 * region. 191 */ quickContains(int32_t left,int32_t top,int32_t right,int32_t bottom)192 bool quickContains(int32_t left, int32_t top, int32_t right, 193 int32_t bottom) const { 194 SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region 195 196 return left < right && top < bottom && 197 fRunHead == SkRegion_gRectRunHeadPtr && // this->isRect() 198 /* fBounds.contains(left, top, right, bottom); */ 199 fBounds.fLeft <= left && fBounds.fTop <= top && 200 fBounds.fRight >= right && fBounds.fBottom >= bottom; 201 } 202 203 /** 204 * Return true if this region is empty, or if the specified rectangle does 205 * not intersect the region. Returning false is not a guarantee that they 206 * intersect, but returning true is a guarantee that they do not. 207 */ quickReject(const SkIRect & rect)208 bool quickReject(const SkIRect& rect) const { 209 return this->isEmpty() || rect.isEmpty() || 210 !SkIRect::Intersects(fBounds, rect); 211 } 212 213 /** 214 * Return true if this region, or rgn, is empty, or if their bounds do not 215 * intersect. Returning false is not a guarantee that they intersect, but 216 * returning true is a guarantee that they do not. 217 */ quickReject(const SkRegion & rgn)218 bool quickReject(const SkRegion& rgn) const { 219 return this->isEmpty() || rgn.isEmpty() || 220 !SkIRect::Intersects(fBounds, rgn.fBounds); 221 } 222 223 /** Translate the region by the specified (dx, dy) amount. */ translate(int dx,int dy)224 void translate(int dx, int dy) { this->translate(dx, dy, this); } 225 226 /** 227 * Translate the region by the specified (dx, dy) amount, writing the 228 * resulting region into dst. Note: it is legal to pass this region as the 229 * dst parameter, effectively translating the region in place. If dst is 230 * null, nothing happens. 231 */ 232 void translate(int dx, int dy, SkRegion* dst) const; 233 234 /** 235 * The logical operations that can be performed when combining two regions. 236 */ 237 enum Op { 238 kDifference_Op, //!< subtract the op region from the first region 239 kIntersect_Op, //!< intersect the two regions 240 kUnion_Op, //!< union (inclusive-or) the two regions 241 kXOR_Op, //!< exclusive-or the two regions 242 /** subtract the first region from the op region */ 243 kReverseDifference_Op, 244 kReplace_Op //!< replace the dst region with the op region 245 }; 246 247 /** 248 * Set this region to the result of applying the Op to this region and the 249 * specified rectangle: this = (this op rect). 250 * Return true if the resulting region is non-empty. 251 */ op(const SkIRect & rect,Op op)252 bool op(const SkIRect& rect, Op op) { return this->op(*this, rect, op); } 253 254 /** 255 * Set this region to the result of applying the Op to this region and the 256 * specified rectangle: this = (this op rect). 257 * Return true if the resulting region is non-empty. 258 */ op(int left,int top,int right,int bottom,Op op)259 bool op(int left, int top, int right, int bottom, Op op) { 260 SkIRect rect; 261 rect.set(left, top, right, bottom); 262 return this->op(*this, rect, op); 263 } 264 265 /** 266 * Set this region to the result of applying the Op to this region and the 267 * specified region: this = (this op rgn). 268 * Return true if the resulting region is non-empty. 269 */ op(const SkRegion & rgn,Op op)270 bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); } 271 272 /** 273 * Set this region to the result of applying the Op to the specified 274 * rectangle and region: this = (rect op rgn). 275 * Return true if the resulting region is non-empty. 276 */ 277 bool op(const SkIRect& rect, const SkRegion& rgn, Op); 278 279 /** 280 * Set this region to the result of applying the Op to the specified 281 * region and rectangle: this = (rgn op rect). 282 * Return true if the resulting region is non-empty. 283 */ 284 bool op(const SkRegion& rgn, const SkIRect& rect, Op); 285 286 /** 287 * Set this region to the result of applying the Op to the specified 288 * regions: this = (rgna op rgnb). 289 * Return true if the resulting region is non-empty. 290 */ 291 bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op); 292 293 #ifdef ANDROID 294 /** Returns a new char* containing the list of rectangles in this region 295 */ 296 char* toString(); 297 #endif 298 299 /** 300 * Returns the sequence of rectangles, sorted in Y and X, that make up 301 * this region. 302 */ 303 class SK_API Iterator { 304 public: Iterator()305 Iterator() : fRgn(NULL), fDone(true) {} 306 Iterator(const SkRegion&); 307 // if we have a region, reset to it and return true, else return false 308 bool rewind(); 309 // reset the iterator, using the new region 310 void reset(const SkRegion&); done()311 bool done() const { return fDone; } 312 void next(); rect()313 const SkIRect& rect() const { return fRect; } 314 // may return null rgn()315 const SkRegion* rgn() const { return fRgn; } 316 317 private: 318 const SkRegion* fRgn; 319 const RunType* fRuns; 320 SkIRect fRect; 321 bool fDone; 322 }; 323 324 /** 325 * Returns the sequence of rectangles, sorted in Y and X, that make up 326 * this region intersected with the specified clip rectangle. 327 */ 328 class SK_API Cliperator { 329 public: 330 Cliperator(const SkRegion&, const SkIRect& clip); done()331 bool done() { return fDone; } 332 void next(); rect()333 const SkIRect& rect() const { return fRect; } 334 335 private: 336 Iterator fIter; 337 SkIRect fClip; 338 SkIRect fRect; 339 bool fDone; 340 }; 341 342 /** 343 * Returns the sequence of runs that make up this region for the specified 344 * Y scanline, clipped to the specified left and right X values. 345 */ 346 class Spanerator { 347 public: 348 Spanerator(const SkRegion&, int y, int left, int right); 349 bool next(int* left, int* right); 350 351 private: 352 const SkRegion::RunType* fRuns; 353 int fLeft, fRight; 354 bool fDone; 355 }; 356 357 /** 358 * Write the region to the buffer, and return the number of bytes written. 359 * If buffer is NULL, it still returns the number of bytes. 360 */ 361 uint32_t flatten(void* buffer) const; 362 363 /** 364 * Initialized the region from the buffer, returning the number 365 * of bytes actually read. 366 */ 367 uint32_t unflatten(const void* buffer); 368 369 /** 370 * Returns a reference to a global empty region. Just a convenience for 371 * callers that need a const empty region. 372 */ 373 static const SkRegion& GetEmptyRegion(); 374 375 SkDEBUGCODE(void dump() const;) 376 SkDEBUGCODE(void validate() const;) 377 SkDEBUGCODE(static void UnitTest();) 378 379 // expose this to allow for regression test on complex regions 380 SkDEBUGCODE(bool debugSetRuns(const RunType runs[], int count);) 381 382 private: 383 enum { 384 kOpCount = kReplace_Op + 1 385 }; 386 387 enum { 388 kRectRegionRuns = 6 // need to store a region of a rect [T B L R S S] 389 }; 390 391 friend class android::Region; // needed for marshalling efficiently 392 void allocateRuns(int count); // allocate space for count runs 393 394 struct RunHead; 395 396 SkIRect fBounds; 397 RunHead* fRunHead; 398 399 void freeRuns(); 400 const RunType* getRuns(RunType tmpStorage[], int* count) const; 401 bool setRuns(RunType runs[], int count); 402 403 int count_runtype_values(int* itop, int* ibot) const; 404 405 static void BuildRectRuns(const SkIRect& bounds, 406 RunType runs[kRectRegionRuns]); 407 // returns true if runs are just a rect 408 static bool ComputeRunBounds(const RunType runs[], int count, 409 SkIRect* bounds); 410 411 friend struct RunHead; 412 friend class Iterator; 413 friend class Spanerator; 414 friend class SkRgnBuilder; 415 friend class SkFlatRegion; 416 }; 417 418 #endif 419