diff options
author | 2012-07-24 22:07:50 +0000 | |
---|---|---|
committer | 2012-07-24 22:07:50 +0000 | |
commit | 4c2a2f7c5e8ec77771153f94c454adf21fd33805 (patch) | |
tree | 5754ec12ff7ad604086a9623be1bbade880a1ba9 | |
parent | dcba4c2cc30cc64f08def991376c6dab65cfb51c (diff) |
Added isIntersectionOfRects to SkClipStack
http://codereview.appspot.com/6434050/
git-svn-id: http://skia.googlecode.com/svn/trunk@4745 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | include/core/SkClipStack.h | 20 | ||||
-rw-r--r-- | src/core/SkClipStack.cpp | 45 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 7 | ||||
-rw-r--r-- | tests/ClipStackTest.cpp | 30 |
4 files changed, 83 insertions, 19 deletions
diff --git a/include/core/SkClipStack.h b/include/core/SkClipStack.h index fbdcb36c84..71b68cebde 100644 --- a/include/core/SkClipStack.h +++ b/include/core/SkClipStack.h @@ -14,6 +14,12 @@ struct SkRect; class SkPath; +// Because a single save/restore state can have multiple clips, this class +// stores the stack depth (fSaveCount) and clips (fDeque) separately. +// Each clip in fDeque stores the stack state to which it belongs +// (i.e., the fSaveCount in force when it was added). Restores are thus +// implemented by removing clips from fDeque that have an fSaveCount larger +// then the freshly decremented count. class SK_API SkClipStack { public: SkClipStack(); @@ -44,12 +50,15 @@ public: /** * getBounds places the current finite bound in its first parameter. In its * second, it indicates which kind of bound is being returned. If - * 'finiteBound' is a normal bounding box then it encloses are writeable + * 'finiteBound' is a normal bounding box then it encloses all writeable * pixels. If 'finiteBound' is an inside out bounding box then it * encloses all the un-writeable pixels and the true/normal bound is the - * infinite plane. + * infinite plane. isIntersectionOfRects is an optional parameter + * that is true if 'finiteBound' resulted from an intersection of rects. */ - void getBounds(SkRect* finiteBound, BoundsType* boundType) const; + void getBounds(SkRect* finiteBound, + BoundsType* boundType, + bool* isIntersectionOfRects = NULL) const; void clipDevRect(const SkIRect& ir, SkRegion::Op op) { SkRect r; @@ -165,12 +174,15 @@ public: * drawing areas (i.e., those resulting from a saveLayer). For finite bounds, * the translation (+offsetX, +offsetY) is applied before the clamp to the * maximum rectangle: [0,maxWidth) x [0,maxHeight). + * isIntersectionOfRects is an optional parameter that is true when + * 'bounds' is the result of an intersection of rects. */ void getConservativeBounds(int offsetX, int offsetY, int maxWidth, int maxHeight, - SkRect* bounds) const; + SkRect* bounds, + bool* isIntersectionOfRects = NULL) const; private: friend class Iter; diff --git a/src/core/SkClipStack.cpp b/src/core/SkClipStack.cpp index 2676f3b078..7857bdf539 100644 --- a/src/core/SkClipStack.cpp +++ b/src/core/SkClipStack.cpp @@ -38,13 +38,15 @@ struct SkClipStack::Rec { // of the extensions to infinity when two inverse filled clips are // Booleaned together. SkClipStack::BoundsType fFiniteBoundType; - SkRect fFiniteBound; + SkRect fFiniteBound; + bool fIsIntersectionOfRects; Rec(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) : fRect(rect) { fSaveCount = saveCount; fOp = op; fState = kRect_State; fDoAA = doAA; + // bounding box members are updated in a following updateBound call } Rec(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) : fPath(path) { @@ -53,6 +55,7 @@ struct SkClipStack::Rec { fOp = op; fState = kPath_State; fDoAA = doAA; + // bounding box members are updated in a following updateBound call } bool operator==(const Rec& b) const { @@ -273,9 +276,17 @@ struct SkClipStack::Rec { // First, optimistically update the current Rec's bound information // with the current clip's bound + fIsIntersectionOfRects = false; if (kRect_State == fState) { fFiniteBound = fRect; fFiniteBoundType = kNormal_BoundsType; + + if (SkRegion::kReplace_Op == fOp || + (SkRegion::kIntersect_Op == fOp && NULL == prior) || + (SkRegion::kIntersect_Op == fOp && prior->fIsIntersectionOfRects)) { + fIsIntersectionOfRects = true; + } + } else { fFiniteBound = fPath.getBounds(); @@ -432,7 +443,9 @@ void SkClipStack::restore() { } } -void SkClipStack::getBounds(SkRect* finiteBound, BoundsType* boundType) const { +void SkClipStack::getBounds(SkRect* finiteBound, + BoundsType* boundType, + bool* isIntersectionOfRects) const { SkASSERT(NULL != finiteBound && NULL != boundType); Rec* rec = (Rec*)fDeque.back(); @@ -441,36 +454,50 @@ void SkClipStack::getBounds(SkRect* finiteBound, BoundsType* boundType) const { // the clip is wide open - the infinite plane w/ no pixels un-writeable finiteBound->setEmpty(); *boundType = kInsideOut_BoundsType; + if (NULL != isIntersectionOfRects) { + *isIntersectionOfRects = false; + } return; } *finiteBound = rec->fFiniteBound; *boundType = rec->fFiniteBoundType; + if (NULL != isIntersectionOfRects) { + *isIntersectionOfRects = rec->fIsIntersectionOfRects; + } } void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) { - Rec* rec = (Rec*)fDeque.back(); + + SkDeque::Iter iter(fDeque, SkDeque::Iter::kBack_IterStart); + Rec* rec = (Rec*) iter.prev(); + if (rec && rec->canBeIntersected(fSaveCount, op)) { switch (rec->fState) { case Rec::kEmpty_State: SkASSERT(rec->fFiniteBound.isEmpty()); SkASSERT(kNormal_BoundsType == rec->fFiniteBoundType); + SkASSERT(!rec->fIsIntersectionOfRects); return; - case Rec::kRect_State: + case Rec::kRect_State: { if (!rec->fRect.intersect(rect)) { rec->fState = Rec::kEmpty_State; rec->fFiniteBound.setEmpty(); rec->fFiniteBoundType = kNormal_BoundsType; + rec->fIsIntersectionOfRects = false; return; } - rec->updateBound(NULL); + Rec* prev = (Rec*) iter.prev(); + rec->updateBound(prev); return; + } case Rec::kPath_State: if (!SkRect::Intersects(rec->fPath.getBounds(), rect)) { rec->fState = Rec::kEmpty_State; rec->fFiniteBound.setEmpty(); rec->fFiniteBoundType = kNormal_BoundsType; + rec->fIsIntersectionOfRects = false; return; } break; @@ -492,12 +519,14 @@ void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) { case Rec::kEmpty_State: SkASSERT(rec->fFiniteBound.isEmpty()); SkASSERT(kNormal_BoundsType == rec->fFiniteBoundType); + SkASSERT(!rec->fIsIntersectionOfRects); return; case Rec::kRect_State: if (!SkRect::Intersects(rec->fRect, pathBounds)) { rec->fState = Rec::kEmpty_State; rec->fFiniteBound.setEmpty(); rec->fFiniteBoundType = kNormal_BoundsType; + rec->fIsIntersectionOfRects = false; return; } break; @@ -506,6 +535,7 @@ void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) { rec->fState = Rec::kEmpty_State; rec->fFiniteBound.setEmpty(); rec->fFiniteBoundType = kNormal_BoundsType; + rec->fIsIntersectionOfRects = false; return; } break; @@ -627,7 +657,8 @@ void SkClipStack::getConservativeBounds(int offsetX, int offsetY, int maxWidth, int maxHeight, - SkRect* bounds) const { + SkRect* bounds, + bool* isIntersectionOfRects) const { SkASSERT(NULL != bounds); bounds->setLTRB(0, 0, @@ -636,7 +667,7 @@ void SkClipStack::getConservativeBounds(int offsetX, SkRect temp; SkClipStack::BoundsType boundType; - this->getBounds(&temp, &boundType); + this->getBounds(&temp, &boundType, isIntersectionOfRects); if (SkClipStack::kInsideOut_BoundsType == boundType) { return; } diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index c92af64bc8..57d9fbd1cc 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -409,14 +409,19 @@ static void convert_matrixclip(GrContext* context, const SkMatrix& matrix, #endif SkRect bounds; + bool isIntersectionOfRects = false; clipStack.getConservativeBounds(-origin.fX, -origin.fY, renderTargetWidth, renderTargetHeight, - &bounds); + &bounds, + &isIntersectionOfRects); GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()), bounds); + + GrAssert(grc.isRect() == isIntersectionOfRects); + context->setClip(grc); } diff --git a/tests/ClipStackTest.cpp b/tests/ClipStackTest.cpp index e5001f1100..02fa8cfbf3 100644 --- a/tests/ClipStackTest.cpp +++ b/tests/ClipStackTest.cpp @@ -183,7 +183,7 @@ static void test_iterators(skiatest::Reporter* reporter) { } } -static void test_bounds(skiatest::Reporter* reporter) { +static void test_bounds(skiatest::Reporter* reporter, bool useRects) { static const int gNumCases = 20; static const SkRect gAnswerRectsBW[gNumCases] = { @@ -236,9 +236,11 @@ static void test_bounds(skiatest::Reporter* reporter) { SkClipStack stack; SkRect bound; + bool isIntersectionOfRects = false; int testCase = 0; - for (int invBits = 0; invBits < 4; ++invBits) { + int numBitTests = useRects ? 1 : 4; + for (int invBits = 0; invBits < numBitTests; ++invBits) { for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); ++op) { stack.save(); @@ -250,13 +252,26 @@ static void test_bounds(skiatest::Reporter* reporter) { clipB.setFillType(doInvB ? SkPath::kInverseEvenOdd_FillType : SkPath::kEvenOdd_FillType); - stack.clipDevPath(clipA, SkRegion::kIntersect_Op, false); - stack.clipDevPath(clipB, gOps[op], false); + if (useRects) { + stack.clipDevRect(rectA, SkRegion::kIntersect_Op, false); + stack.clipDevRect(rectB, gOps[op], false); + } else { + stack.clipDevPath(clipA, SkRegion::kIntersect_Op, false); + stack.clipDevPath(clipB, gOps[op], false); + } - stack.getConservativeBounds(0, 0, 100, 100, &bound); + stack.getConservativeBounds(0, 0, 100, 100, &bound, + &isIntersectionOfRects); + + if (useRects) { + REPORTER_ASSERT(reporter, isIntersectionOfRects == + (gOps[op] == SkRegion::kIntersect_Op)); + } else { + REPORTER_ASSERT(reporter, !isIntersectionOfRects); + } SkASSERT(testCase < gNumCases); - SkASSERT(bound == gAnswerRectsBW[testCase]); + REPORTER_ASSERT(reporter, bound == gAnswerRectsBW[testCase]); ++testCase; stack.restore(); @@ -300,7 +315,8 @@ static void TestClipStack(skiatest::Reporter* reporter) { test_assign_and_comparison(reporter); test_iterators(reporter); - test_bounds(reporter); + test_bounds(reporter, true); + test_bounds(reporter, false); } #include "TestClassDef.h" |