aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar robertphillips@google.com <robertphillips@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-07-24 22:07:50 +0000
committerGravatar robertphillips@google.com <robertphillips@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-07-24 22:07:50 +0000
commit4c2a2f7c5e8ec77771153f94c454adf21fd33805 (patch)
tree5754ec12ff7ad604086a9623be1bbade880a1ba9
parentdcba4c2cc30cc64f08def991376c6dab65cfb51c (diff)
Added isIntersectionOfRects to SkClipStack
-rw-r--r--include/core/SkClipStack.h20
-rw-r--r--src/core/SkClipStack.cpp45
-rw-r--r--src/gpu/SkGpuDevice.cpp7
-rw-r--r--tests/ClipStackTest.cpp30
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"