diff options
author | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-04-30 13:29:02 +0000 |
---|---|---|
committer | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2012-04-30 13:29:02 +0000 |
commit | 7d4aee34e23e536e1115f132d20a20fb629bb66a (patch) | |
tree | 5d232e05115c084cba460eb7c212babf7a3a326f /src/core | |
parent | 6720d50d3329bd12b5986c4713e46b2b04423c52 (diff) |
Variant of SkRegion::op (called Oper) that either writes the result into a 3rd
region (normal mode) or does a quick-return if the result will be non-empty
(called for predicates like contains() and intersects()).
git-svn-id: http://skia.googlecode.com/svn/trunk@3791 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/SkRegion.cpp | 129 |
1 files changed, 85 insertions, 44 deletions
diff --git a/src/core/SkRegion.cpp b/src/core/SkRegion.cpp index dee652ba3b..81854de209 100644 --- a/src/core/SkRegion.cpp +++ b/src/core/SkRegion.cpp @@ -230,12 +230,16 @@ int SkRegion::count_runtype_values(int* itop, int* ibot) const return maxT; } +static bool isRunCountEmpty(int count) { + return count <= 2; +} + bool SkRegion::setRuns(RunType runs[], int count) { SkDEBUGCODE(this->validate();) SkASSERT(count > 0); - if (count <= 2) + if (isRunCountEmpty(count)) { // SkDEBUGF(("setRuns: empty\n")); assert_sentinel(runs[count-1], true); @@ -384,10 +388,11 @@ bool SkRegion::contains(const SkRegion& rgn) const if (this->isRect()) return true; - SkRegion tmp; - - tmp.op(*this, rgn, kUnion_Op); - return tmp == *this; + /* + * A contains B is equivalent to + * B - A == 0 + */ + return !Oper(rgn, *this, kDifference_Op, NULL); } const SkRegion::RunType* SkRegion::getRuns(RunType tmpStorage[], int* count) const @@ -429,8 +434,7 @@ bool SkRegion::intersects(const SkIRect& r) const { } // we are complex - SkRegion tmp; - return tmp.op(*this, r, kIntersect_Op); + return Oper(*this, SkRegion(r), kIntersect_Op, NULL); } bool SkRegion::intersects(const SkRegion& rgn) const { @@ -447,10 +451,7 @@ bool SkRegion::intersects(const SkRegion& rgn) const { } // one or both of us is complex - // TODO: write a faster version that aborts as soon as we write the first - // non-empty span, to avoid build the entire result - SkRegion tmp; - return tmp.op(*this, rgn, kIntersect_Op); + return Oper(*this, rgn, kIntersect_Op, NULL); } ///////////////////////////////////////////////////////////////////////////////////// @@ -764,6 +765,8 @@ public: return (int)(fPrevDst - fStartDst + fPrevLen + 1); } + bool isEmpty() const { return 0 == fPrevLen; } + uint8_t fMin, fMax; private: @@ -773,10 +776,14 @@ private: SkRegion::RunType fTop; }; +// want a unique value to signal that we exited due to quickExit +#define QUICK_EXIT_TRUE_COUNT (-1) + static int operate(const SkRegion::RunType a_runs[], const SkRegion::RunType b_runs[], SkRegion::RunType dst[], - SkRegion::Op op) { + SkRegion::Op op, + bool quickExit) { const SkRegion::RunType gSentinel[] = { SkRegion::kRunTypeSentinel, // just need a 2nd value, since spanRec.init() reads 2 values, even @@ -846,6 +853,10 @@ static int operate(const SkRegion::RunType a_runs[], oper.addSpan(bot, run0, run1); firstInterval = false; + if (quickExit && !oper.isEmpty()) { + return QUICK_EXIT_TRUE_COUNT; + } + if (a_flush) { a_runs = skip_scanline(a_runs); a_top = a_bot; @@ -905,14 +916,25 @@ static int compute_worst_case_count(int a_count, int b_count) { return intervals_to_count(intervals); } -bool SkRegion::op(const SkRegion& rgnaOrig, const SkRegion& rgnbOrig, Op op) -{ - SkDEBUGCODE(this->validate();) +static bool setEmptyCheck(SkRegion* result) { + return result ? result->setEmpty() : false; +} + +static bool setRectCheck(SkRegion* result, const SkIRect& rect) { + return result ? result->setRect(rect) : !rect.isEmpty(); +} +static bool setRegionCheck(SkRegion* result, const SkRegion& rgn) { + return result ? result->setRegion(rgn) : !rgn.isEmpty(); +} + +bool SkRegion::Oper(const SkRegion& rgnaOrig, const SkRegion& rgnbOrig, Op op, + SkRegion* result) { SkASSERT((unsigned)op < kOpCount); - if (kReplace_Op == op) - return this->set(rgnbOrig); + if (kReplace_Op == op) { + return setRegionCheck(result, rgnbOrig); + } // swith to using pointers, so we can swap them as needed const SkRegion* rgna = &rgnaOrig; @@ -920,8 +942,7 @@ bool SkRegion::op(const SkRegion& rgnaOrig, const SkRegion& rgnbOrig, Op op) // after this point, do not refer to rgnaOrig or rgnbOrig!!! // collaps difference and reverse-difference into just difference - if (kReverseDifference_Op == op) - { + if (kReverseDifference_Op == op) { SkTSwap<const SkRegion*>(rgna, rgnb); op = kDifference_Op; } @@ -934,40 +955,50 @@ bool SkRegion::op(const SkRegion& rgnaOrig, const SkRegion& rgnbOrig, Op op) switch (op) { case kDifference_Op: - if (a_empty) - return this->setEmpty(); - if (b_empty || !SkIRect::Intersects(rgna->fBounds, rgnb->fBounds)) - return this->setRegion(*rgna); + if (a_empty) { + return setEmptyCheck(result); + } + if (b_empty || !SkIRect::Intersects(rgna->fBounds, rgnb->fBounds)) { + return setRegionCheck(result, *rgna); + } break; case kIntersect_Op: if ((a_empty | b_empty) - || !bounds.intersect(rgna->fBounds, rgnb->fBounds)) - return this->setEmpty(); - if (a_rect & b_rect) - return this->setRect(bounds); + || !bounds.intersect(rgna->fBounds, rgnb->fBounds)) { + return setEmptyCheck(result); + } + if (a_rect & b_rect) { + return setRectCheck(result, bounds); + } break; case kUnion_Op: - if (a_empty) - return this->setRegion(*rgnb); - if (b_empty) - return this->setRegion(*rgna); - if (a_rect && rgna->fBounds.contains(rgnb->fBounds)) - return this->setRegion(*rgna); - if (b_rect && rgnb->fBounds.contains(rgna->fBounds)) - return this->setRegion(*rgnb); + if (a_empty) { + return setRegionCheck(result, *rgnb); + } + if (b_empty) { + return setRegionCheck(result, *rgna); + } + if (a_rect && rgna->fBounds.contains(rgnb->fBounds)) { + return setRegionCheck(result, *rgna); + } + if (b_rect && rgnb->fBounds.contains(rgna->fBounds)) { + return setRegionCheck(result, *rgnb); + } break; case kXOR_Op: - if (a_empty) - return this->setRegion(*rgnb); - if (b_empty) - return this->setRegion(*rgna); + if (a_empty) { + return setRegionCheck(result, *rgnb); + } + if (b_empty) { + return setRegionCheck(result, *rgna); + } break; default: SkDEBUGFAIL("unknown region op"); - return !this->isEmpty(); + return false; } RunType tmpA[kRectRegionRuns]; @@ -978,14 +1009,24 @@ bool SkRegion::op(const SkRegion& rgnaOrig, const SkRegion& rgnbOrig, Op op) const RunType* b_runs = rgnb->getRuns(tmpB, &b_count); int dstCount = compute_worst_case_count(a_count, b_count); - SkAutoSTMalloc<32, RunType> array(dstCount); + SkAutoSTMalloc<64, RunType> array(dstCount); - int count = operate(a_runs, b_runs, array.get(), op); + int count = operate(a_runs, b_runs, array.get(), op, NULL == result); SkASSERT(count <= dstCount); - return this->setRuns(array.get(), count); + if (result) { + SkASSERT(count >= 0); + return result->setRuns(array.get(), count); + } else { + return (QUICK_EXIT_TRUE_COUNT == count) || !isRunCountEmpty(count); + } } -////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool SkRegion::op(const SkRegion& rgna, const SkRegion& rgnb, Op op) { + SkDEBUGCODE(this->validate();) + return SkRegion::Oper(rgna, rgnb, op, this); +} + +/////////////////////////////////////////////////////////////////////////////// #include "SkBuffer.h" |