1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/include/core/SkRegion.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,449 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2005 The Android Open Source Project 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 + 1.13 +#ifndef SkRegion_DEFINED 1.14 +#define SkRegion_DEFINED 1.15 + 1.16 +#include "SkRect.h" 1.17 + 1.18 +class SkPath; 1.19 +class SkRgnBuilder; 1.20 + 1.21 +namespace android { 1.22 + class Region; 1.23 +} 1.24 + 1.25 +#define SkRegion_gEmptyRunHeadPtr ((SkRegion::RunHead*)-1) 1.26 +#define SkRegion_gRectRunHeadPtr 0 1.27 + 1.28 +/** \class SkRegion 1.29 + 1.30 + The SkRegion class encapsulates the geometric region used to specify 1.31 + clipping areas for drawing. 1.32 +*/ 1.33 +class SK_API SkRegion { 1.34 +public: 1.35 + typedef int32_t RunType; 1.36 + enum { 1.37 + kRunTypeSentinel = 0x7FFFFFFF 1.38 + }; 1.39 + 1.40 + SkRegion(); 1.41 + SkRegion(const SkRegion&); 1.42 + explicit SkRegion(const SkIRect&); 1.43 + ~SkRegion(); 1.44 + 1.45 + SkRegion& operator=(const SkRegion&); 1.46 + 1.47 + /** 1.48 + * Return true if the two regions are equal. i.e. The enclose exactly 1.49 + * the same area. 1.50 + */ 1.51 + bool operator==(const SkRegion& other) const; 1.52 + 1.53 + /** 1.54 + * Return true if the two regions are not equal. 1.55 + */ 1.56 + bool operator!=(const SkRegion& other) const { 1.57 + return !(*this == other); 1.58 + } 1.59 + 1.60 + /** 1.61 + * Replace this region with the specified region, and return true if the 1.62 + * resulting region is non-empty. 1.63 + */ 1.64 + bool set(const SkRegion& src) { 1.65 + SkASSERT(&src); 1.66 + *this = src; 1.67 + return !this->isEmpty(); 1.68 + } 1.69 + 1.70 + /** 1.71 + * Swap the contents of this and the specified region. This operation 1.72 + * is gauarenteed to never fail. 1.73 + */ 1.74 + void swap(SkRegion&); 1.75 + 1.76 + /** Return true if this region is empty */ 1.77 + bool isEmpty() const { return fRunHead == SkRegion_gEmptyRunHeadPtr; } 1.78 + 1.79 + /** Return true if this region is a single, non-empty rectangle */ 1.80 + bool isRect() const { return fRunHead == SkRegion_gRectRunHeadPtr; } 1.81 + 1.82 + /** Return true if this region consists of more than 1 rectangular area */ 1.83 + bool isComplex() const { return !this->isEmpty() && !this->isRect(); } 1.84 + 1.85 + /** 1.86 + * Return the bounds of this region. If the region is empty, returns an 1.87 + * empty rectangle. 1.88 + */ 1.89 + const SkIRect& getBounds() const { return fBounds; } 1.90 + 1.91 + /** 1.92 + * Returns a value that grows approximately linearly with the number of 1.93 + * intervals comprised in the region. Empty region will return 0, Rect 1.94 + * will return 1, Complex will return a value > 1. 1.95 + * 1.96 + * Use this to compare two regions, where the larger count likely 1.97 + * indicates a more complex region. 1.98 + */ 1.99 + int computeRegionComplexity() const; 1.100 + 1.101 + /** 1.102 + * Returns true if the region is non-empty, and if so, appends the 1.103 + * boundary(s) of the region to the specified path. 1.104 + * If the region is empty, returns false, and path is left unmodified. 1.105 + */ 1.106 + bool getBoundaryPath(SkPath* path) const; 1.107 + 1.108 + /** 1.109 + * Set the region to be empty, and return false, since the resulting 1.110 + * region is empty 1.111 + */ 1.112 + bool setEmpty(); 1.113 + 1.114 + /** 1.115 + * If rect is non-empty, set this region to that rectangle and return true, 1.116 + * otherwise set this region to empty and return false. 1.117 + */ 1.118 + bool setRect(const SkIRect&); 1.119 + 1.120 + /** 1.121 + * If left < right and top < bottom, set this region to that rectangle and 1.122 + * return true, otherwise set this region to empty and return false. 1.123 + */ 1.124 + bool setRect(int32_t left, int32_t top, int32_t right, int32_t bottom); 1.125 + 1.126 + /** 1.127 + * Set this region to the union of an array of rects. This is generally 1.128 + * faster than calling region.op(rect, kUnion_Op) in a loop. If count is 1.129 + * 0, then this region is set to the empty region. 1.130 + * @return true if the resulting region is non-empty 1.131 + */ 1.132 + bool setRects(const SkIRect rects[], int count); 1.133 + 1.134 + /** 1.135 + * Set this region to the specified region, and return true if it is 1.136 + * non-empty. 1.137 + */ 1.138 + bool setRegion(const SkRegion&); 1.139 + 1.140 + /** 1.141 + * Set this region to the area described by the path, clipped. 1.142 + * Return true if the resulting region is non-empty. 1.143 + * This produces a region that is identical to the pixels that would be 1.144 + * drawn by the path (with no antialiasing) with the specified clip. 1.145 + */ 1.146 + bool setPath(const SkPath&, const SkRegion& clip); 1.147 + 1.148 + /** 1.149 + * Returns true if the specified rectangle has a non-empty intersection 1.150 + * with this region. 1.151 + */ 1.152 + bool intersects(const SkIRect&) const; 1.153 + 1.154 + /** 1.155 + * Returns true if the specified region has a non-empty intersection 1.156 + * with this region. 1.157 + */ 1.158 + bool intersects(const SkRegion&) const; 1.159 + 1.160 + /** 1.161 + * Return true if the specified x,y coordinate is inside the region. 1.162 + */ 1.163 + bool contains(int32_t x, int32_t y) const; 1.164 + 1.165 + /** 1.166 + * Return true if the specified rectangle is completely inside the region. 1.167 + * This works for simple (rectangular) and complex regions, and always 1.168 + * returns the correct result. Note: if either this region or the rectangle 1.169 + * is empty, contains() returns false. 1.170 + */ 1.171 + bool contains(const SkIRect&) const; 1.172 + 1.173 + /** 1.174 + * Return true if the specified region is completely inside the region. 1.175 + * This works for simple (rectangular) and complex regions, and always 1.176 + * returns the correct result. Note: if either region is empty, contains() 1.177 + * returns false. 1.178 + */ 1.179 + bool contains(const SkRegion&) const; 1.180 + 1.181 + /** 1.182 + * Return true if this region is a single rectangle (not complex) and the 1.183 + * specified rectangle is contained by this region. Returning false is not 1.184 + * a guarantee that the rectangle is not contained by this region, but 1.185 + * return true is a guarantee that the rectangle is contained by this region. 1.186 + */ 1.187 + bool quickContains(const SkIRect& r) const { 1.188 + return this->quickContains(r.fLeft, r.fTop, r.fRight, r.fBottom); 1.189 + } 1.190 + 1.191 + /** 1.192 + * Return true if this region is a single rectangle (not complex) and the 1.193 + * specified rectangle is contained by this region. Returning false is not 1.194 + * a guarantee that the rectangle is not contained by this region, but 1.195 + * return true is a guarantee that the rectangle is contained by this 1.196 + * region. 1.197 + */ 1.198 + bool quickContains(int32_t left, int32_t top, int32_t right, 1.199 + int32_t bottom) const { 1.200 + SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region 1.201 + 1.202 + return left < right && top < bottom && 1.203 + fRunHead == SkRegion_gRectRunHeadPtr && // this->isRect() 1.204 + /* fBounds.contains(left, top, right, bottom); */ 1.205 + fBounds.fLeft <= left && fBounds.fTop <= top && 1.206 + fBounds.fRight >= right && fBounds.fBottom >= bottom; 1.207 + } 1.208 + 1.209 + /** 1.210 + * Return true if this region is empty, or if the specified rectangle does 1.211 + * not intersect the region. Returning false is not a guarantee that they 1.212 + * intersect, but returning true is a guarantee that they do not. 1.213 + */ 1.214 + bool quickReject(const SkIRect& rect) const { 1.215 + return this->isEmpty() || rect.isEmpty() || 1.216 + !SkIRect::Intersects(fBounds, rect); 1.217 + } 1.218 + 1.219 + /** 1.220 + * Return true if this region, or rgn, is empty, or if their bounds do not 1.221 + * intersect. Returning false is not a guarantee that they intersect, but 1.222 + * returning true is a guarantee that they do not. 1.223 + */ 1.224 + bool quickReject(const SkRegion& rgn) const { 1.225 + return this->isEmpty() || rgn.isEmpty() || 1.226 + !SkIRect::Intersects(fBounds, rgn.fBounds); 1.227 + } 1.228 + 1.229 + /** Translate the region by the specified (dx, dy) amount. */ 1.230 + void translate(int dx, int dy) { this->translate(dx, dy, this); } 1.231 + 1.232 + /** 1.233 + * Translate the region by the specified (dx, dy) amount, writing the 1.234 + * resulting region into dst. Note: it is legal to pass this region as the 1.235 + * dst parameter, effectively translating the region in place. If dst is 1.236 + * null, nothing happens. 1.237 + */ 1.238 + void translate(int dx, int dy, SkRegion* dst) const; 1.239 + 1.240 + /** 1.241 + * The logical operations that can be performed when combining two regions. 1.242 + */ 1.243 + enum Op { 1.244 + kDifference_Op, //!< subtract the op region from the first region 1.245 + kIntersect_Op, //!< intersect the two regions 1.246 + kUnion_Op, //!< union (inclusive-or) the two regions 1.247 + kXOR_Op, //!< exclusive-or the two regions 1.248 + /** subtract the first region from the op region */ 1.249 + kReverseDifference_Op, 1.250 + kReplace_Op //!< replace the dst region with the op region 1.251 + }; 1.252 + 1.253 + /** 1.254 + * Set this region to the result of applying the Op to this region and the 1.255 + * specified rectangle: this = (this op rect). 1.256 + * Return true if the resulting region is non-empty. 1.257 + */ 1.258 + bool op(const SkIRect& rect, Op op) { return this->op(*this, rect, op); } 1.259 + 1.260 + /** 1.261 + * Set this region to the result of applying the Op to this region and the 1.262 + * specified rectangle: this = (this op rect). 1.263 + * Return true if the resulting region is non-empty. 1.264 + */ 1.265 + bool op(int left, int top, int right, int bottom, Op op) { 1.266 + SkIRect rect; 1.267 + rect.set(left, top, right, bottom); 1.268 + return this->op(*this, rect, op); 1.269 + } 1.270 + 1.271 + /** 1.272 + * Set this region to the result of applying the Op to this region and the 1.273 + * specified region: this = (this op rgn). 1.274 + * Return true if the resulting region is non-empty. 1.275 + */ 1.276 + bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); } 1.277 + 1.278 + /** 1.279 + * Set this region to the result of applying the Op to the specified 1.280 + * rectangle and region: this = (rect op rgn). 1.281 + * Return true if the resulting region is non-empty. 1.282 + */ 1.283 + bool op(const SkIRect& rect, const SkRegion& rgn, Op); 1.284 + 1.285 + /** 1.286 + * Set this region to the result of applying the Op to the specified 1.287 + * region and rectangle: this = (rgn op rect). 1.288 + * Return true if the resulting region is non-empty. 1.289 + */ 1.290 + bool op(const SkRegion& rgn, const SkIRect& rect, Op); 1.291 + 1.292 + /** 1.293 + * Set this region to the result of applying the Op to the specified 1.294 + * regions: this = (rgna op rgnb). 1.295 + * Return true if the resulting region is non-empty. 1.296 + */ 1.297 + bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op); 1.298 + 1.299 +#ifdef SK_BUILD_FOR_ANDROID 1.300 + /** Returns a new char* containing the list of rectangles in this region 1.301 + */ 1.302 + char* toString(); 1.303 +#endif 1.304 + 1.305 + /** 1.306 + * Returns the sequence of rectangles, sorted in Y and X, that make up 1.307 + * this region. 1.308 + */ 1.309 + class SK_API Iterator { 1.310 + public: 1.311 + Iterator() : fRgn(NULL), fDone(true) {} 1.312 + Iterator(const SkRegion&); 1.313 + // if we have a region, reset to it and return true, else return false 1.314 + bool rewind(); 1.315 + // reset the iterator, using the new region 1.316 + void reset(const SkRegion&); 1.317 + bool done() const { return fDone; } 1.318 + void next(); 1.319 + const SkIRect& rect() const { return fRect; } 1.320 + // may return null 1.321 + const SkRegion* rgn() const { return fRgn; } 1.322 + 1.323 + private: 1.324 + const SkRegion* fRgn; 1.325 + const RunType* fRuns; 1.326 + SkIRect fRect; 1.327 + bool fDone; 1.328 + }; 1.329 + 1.330 + /** 1.331 + * Returns the sequence of rectangles, sorted in Y and X, that make up 1.332 + * this region intersected with the specified clip rectangle. 1.333 + */ 1.334 + class SK_API Cliperator { 1.335 + public: 1.336 + Cliperator(const SkRegion&, const SkIRect& clip); 1.337 + bool done() { return fDone; } 1.338 + void next(); 1.339 + const SkIRect& rect() const { return fRect; } 1.340 + 1.341 + private: 1.342 + Iterator fIter; 1.343 + SkIRect fClip; 1.344 + SkIRect fRect; 1.345 + bool fDone; 1.346 + }; 1.347 + 1.348 + /** 1.349 + * Returns the sequence of runs that make up this region for the specified 1.350 + * Y scanline, clipped to the specified left and right X values. 1.351 + */ 1.352 + class Spanerator { 1.353 + public: 1.354 + Spanerator(const SkRegion&, int y, int left, int right); 1.355 + bool next(int* left, int* right); 1.356 + 1.357 + private: 1.358 + const SkRegion::RunType* fRuns; 1.359 + int fLeft, fRight; 1.360 + bool fDone; 1.361 + }; 1.362 + 1.363 + /** 1.364 + * Write the region to the buffer, and return the number of bytes written. 1.365 + * If buffer is NULL, it still returns the number of bytes. 1.366 + */ 1.367 + size_t writeToMemory(void* buffer) const; 1.368 + /** 1.369 + * Initializes the region from the buffer 1.370 + * 1.371 + * @param buffer Memory to read from 1.372 + * @param length Amount of memory available in the buffer 1.373 + * @return number of bytes read (must be a multiple of 4) or 1.374 + * 0 if there was not enough memory available 1.375 + */ 1.376 + size_t readFromMemory(const void* buffer, size_t length); 1.377 + 1.378 + /** 1.379 + * Returns a reference to a global empty region. Just a convenience for 1.380 + * callers that need a const empty region. 1.381 + */ 1.382 + static const SkRegion& GetEmptyRegion(); 1.383 + 1.384 + SkDEBUGCODE(void dump() const;) 1.385 + SkDEBUGCODE(void validate() const;) 1.386 + SkDEBUGCODE(static void UnitTest();) 1.387 + 1.388 + // expose this to allow for regression test on complex regions 1.389 + SkDEBUGCODE(bool debugSetRuns(const RunType runs[], int count);) 1.390 + 1.391 +private: 1.392 + enum { 1.393 + kOpCount = kReplace_Op + 1 1.394 + }; 1.395 + 1.396 + enum { 1.397 + // T 1.398 + // [B N L R S] 1.399 + // S 1.400 + kRectRegionRuns = 7 1.401 + }; 1.402 + 1.403 + friend class android::Region; // needed for marshalling efficiently 1.404 + 1.405 + struct RunHead; 1.406 + 1.407 + // allocate space for count runs 1.408 + void allocateRuns(int count); 1.409 + void allocateRuns(int count, int ySpanCount, int intervalCount); 1.410 + void allocateRuns(const RunHead& src); 1.411 + 1.412 + SkIRect fBounds; 1.413 + RunHead* fRunHead; 1.414 + 1.415 + void freeRuns(); 1.416 + 1.417 + /** 1.418 + * Return the runs from this region, consing up fake runs if the region 1.419 + * is empty or a rect. In those 2 cases, we use tmpStorage to hold the 1.420 + * run data. 1.421 + */ 1.422 + const RunType* getRuns(RunType tmpStorage[], int* intervals) const; 1.423 + 1.424 + // This is called with runs[] that do not yet have their interval-count 1.425 + // field set on each scanline. That is computed as part of this call 1.426 + // (inside ComputeRunBounds). 1.427 + bool setRuns(RunType runs[], int count); 1.428 + 1.429 + int count_runtype_values(int* itop, int* ibot) const; 1.430 + 1.431 + static void BuildRectRuns(const SkIRect& bounds, 1.432 + RunType runs[kRectRegionRuns]); 1.433 + 1.434 + // If the runs define a simple rect, return true and set bounds to that 1.435 + // rect. If not, return false and ignore bounds. 1.436 + static bool RunsAreARect(const SkRegion::RunType runs[], int count, 1.437 + SkIRect* bounds); 1.438 + 1.439 + /** 1.440 + * If the last arg is null, just return if the result is non-empty, 1.441 + * else store the result in the last arg. 1.442 + */ 1.443 + static bool Oper(const SkRegion&, const SkRegion&, SkRegion::Op, SkRegion*); 1.444 + 1.445 + friend struct RunHead; 1.446 + friend class Iterator; 1.447 + friend class Spanerator; 1.448 + friend class SkRgnBuilder; 1.449 + friend class SkFlatRegion; 1.450 +}; 1.451 + 1.452 +#endif