diff options
Diffstat (limited to 'src/core/SkRegionPriv.h')
-rw-r--r-- | src/core/SkRegionPriv.h | 140 |
1 files changed, 130 insertions, 10 deletions
diff --git a/src/core/SkRegionPriv.h b/src/core/SkRegionPriv.h index fe0dfbe488..84c726d0e0 100644 --- a/src/core/SkRegionPriv.h +++ b/src/core/SkRegionPriv.h @@ -18,7 +18,25 @@ //SkDEBUGCODE(extern int32_t gRgnAllocCounter;) +#ifdef SK_DEBUG +// Given the first interval (just past the interval-count), compute the +// interval count, by search for the x-sentinel +// +static int compute_intervalcount(const SkRegion::RunType runs[]) { + const SkRegion::RunType* curr = runs; + while (*curr < SkRegion::kRunTypeSentinel) { + SkASSERT(curr[0] < curr[1]); + SkASSERT(curr[1] < SkRegion::kRunTypeSentinel); + curr += 2; + } + return (curr - runs) >> 1; +} +#endif + struct SkRegion::RunHead { +private: + +public: int32_t fRefCnt; int32_t fRunCount; @@ -41,16 +59,6 @@ struct SkRegion::RunHead { return fIntervalCount; } - void updateYSpanCount(int n) { - SkASSERT(n > 0); - fYSpanCount = n; - } - - void updateIntervalCount(int n) { - SkASSERT(n > 1); - fIntervalCount = n; - } - static RunHead* Alloc(int count) { //SkDEBUGCODE(sk_atomic_inc(&gRgnAllocCounter);) //SkDEBUGF(("************** gRgnAllocCounter::alloc %d\n", gRgnAllocCounter)); @@ -112,6 +120,118 @@ struct SkRegion::RunHead { } return writable; } + + /** + * Given a scanline (including its Bottom value at runs[0]), return the next + * scanline. Asserts that there is one (i.e. runs[0] < Sentinel) + */ + static SkRegion::RunType* SkipEntireScanline(const SkRegion::RunType runs[]) { + // we are not the Y Sentinel + SkASSERT(runs[0] < SkRegion::kRunTypeSentinel); + + const int intervals = runs[1]; + SkASSERT(runs[2 + intervals * 2] == SkRegion::kRunTypeSentinel); +#ifdef SK_DEBUG + { + int n = compute_intervalcount(&runs[2]); + SkASSERT(n == intervals); + } +#endif + + // skip the entire line [B N [L R] S] + runs += 1 + 1 + intervals * 2 + 1; + return const_cast<SkRegion::RunType*>(runs); + } + + + /** + * Return the scanline that contains the Y value. This requires that the Y + * value is already known to be contained within the bounds of the region, + * and so this routine never returns NULL. + * + * It returns the beginning of the scanline, starting with its Bottom value. + */ + SkRegion::RunType* findScanline(int y) const { + const RunType* runs = this->readonly_runs(); + + // if the top-check fails, we didn't do a quick check on the bounds + SkASSERT(y >= runs[0]); + + runs += 1; // skip top-Y + for (;;) { + int bottom = runs[0]; + // If we hit this, we've walked off the region, and our bounds check + // failed. + SkASSERT(bottom < SkRegion::kRunTypeSentinel); + if (y < bottom) { + break; + } + runs = SkipEntireScanline(runs); + } + return const_cast<SkRegion::RunType*>(runs); + } + + // Copy src runs into us, computing interval counts and bounds along the way + void computeRunBounds(SkIRect* bounds) { + RunType* runs = this->writable_runs(); + bounds->fTop = *runs++; + + int bot; + int ySpanCount = 0; + int intervalCount = 0; + int left = SK_MaxS32; + int rite = SK_MinS32; + + do { + bot = *runs++; + SkASSERT(bot < SkRegion::kRunTypeSentinel); + ySpanCount += 1; + + const int intervals = *runs++; + SkASSERT(intervals >= 0); + SkASSERT(intervals < SkRegion::kRunTypeSentinel); + + if (intervals > 0) { +#ifdef SK_DEBUG + { + int n = compute_intervalcount(runs); + SkASSERT(n == intervals); + } +#endif + RunType L = runs[0]; + SkASSERT(L < SkRegion::kRunTypeSentinel); + if (left > L) { + left = L; + } + + runs += intervals * 2; + RunType R = runs[-1]; + SkASSERT(R < SkRegion::kRunTypeSentinel); + if (rite < R) { + rite = R; + } + + intervalCount += intervals; + } + SkASSERT(SkRegion::kRunTypeSentinel == *runs); + runs += 1; // skip x-sentinel + + // test Y-sentinel + } while (SkRegion::kRunTypeSentinel > *runs); + +#ifdef SK_DEBUG + // +1 to skip the last Y-sentinel + int runCount = runs - this->writable_runs() + 1; + SkASSERT(runCount == fRunCount); +#endif + + fYSpanCount = ySpanCount; + fIntervalCount = intervalCount; + + bounds->fLeft = left; + bounds->fRight = rite; + bounds->fBottom = bot; + } private: int32_t fYSpanCount; |