Make SkClipStack::Element public.
R=robertphillips@google.com
Review URL: https://codereview.appspot.com/6858096
git-svn-id: http://skia.googlecode.com/svn/trunk@6617 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkClipStack.cpp b/src/core/SkClipStack.cpp
index 9c1d58c..d86761c 100644
--- a/src/core/SkClipStack.cpp
+++ b/src/core/SkClipStack.cpp
@@ -16,439 +16,346 @@
static const int32_t kFirstUnreservedGenID = 3;
int32_t SkClipStack::gGenID = kFirstUnreservedGenID;
-struct SkClipStack::Element {
- enum Type {
- //!< This element makes the clip empty (regardless of previous elements).
- kEmpty_Type,
- //!< This element combines a rect with the current clip using a set operation
- kRect_Type,
- //!< This element combines a path with the current clip using a set operation
- kPath_Type,
- };
+void SkClipStack::Element::checkEmpty() const {
+ SkASSERT(fFiniteBound.isEmpty());
+ SkASSERT(kNormal_BoundsType == fFiniteBoundType);
+ SkASSERT(!fIsIntersectionOfRects);
+ SkASSERT(kEmptyGenID == fGenID);
+ SkASSERT(fPath.isEmpty());
+}
- SkPath fPath;
- SkRect fRect;
- int fSaveCount;
- SkRegion::Op fOp;
- Type fType;
- bool fDoAA;
-
- // fFiniteBoundType and fFiniteBound are used to incrementally update
- // the clip stack's bound. When fFiniteBoundType is kNormal_BoundsType,
- // fFiniteBound represents the conservative bounding box of the pixels
- // that aren't clipped (i.e., any pixels that can be drawn to are inside
- // the bound). When fFiniteBoundType is kInsideOut_BoundsType (which occurs
- // when a clip is inverse filled), fFiniteBound represents the
- // conservative bounding box of the pixels that _are_ clipped (i.e., any
- // pixels that cannot be drawn to are inside the bound). When
- // fFiniteBoundType is kInsideOut_BoundsType the actual bound is
- // the infinite plane. This behavior of fFiniteBoundType and
- // fFiniteBound is required so that we can capture the cancelling out
- // of the extensions to infinity when two inverse filled clips are
- // Booleaned together.
- SkClipStack::BoundsType fFiniteBoundType;
- SkRect fFiniteBound;
- bool fIsIntersectionOfRects;
-
- int fGenID;
-
- Element(int saveCount)
- : fGenID(kInvalidGenID) {
- fSaveCount = saveCount;
- this->setEmpty();
- }
-
- Element(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA)
- : fRect(rect)
- , fGenID(kInvalidGenID) {
- fSaveCount = saveCount;
- fOp = op;
- fType = kRect_Type;
- fDoAA = doAA;
- // bounding box members are updated in a following updateBoundAndGenID call
- }
-
- Element(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA)
- : fPath(path)
- , fGenID(kInvalidGenID) {
- fRect.setEmpty();
- fSaveCount = saveCount;
- fOp = op;
- fType = kPath_Type;
- fDoAA = doAA;
- // bounding box members are updated in a following updateBoundAndGenID call
- }
-
- void setEmpty() {
- fType = kEmpty_Type;
- fFiniteBound.setEmpty();
- fFiniteBoundType = kNormal_BoundsType;
- fIsIntersectionOfRects = false;
- fGenID = kEmptyGenID;
- }
-
- void checkEmpty() const {
- SkASSERT(fFiniteBound.isEmpty());
- SkASSERT(kNormal_BoundsType == fFiniteBoundType);
- SkASSERT(!fIsIntersectionOfRects);
- SkASSERT(kEmptyGenID == fGenID);
- }
-
- bool operator==(const Element& b) const {
- if (fSaveCount != b.fSaveCount ||
- fOp != b.fOp ||
- fType != b.fType ||
- fDoAA != b.fDoAA) {
- return false;
- }
- switch (fType) {
- case kEmpty_Type:
- return true;
- case kRect_Type:
- return fRect == b.fRect;
- case kPath_Type:
- return fPath == b.fPath;
- }
- return false; // Silence the compiler.
- }
-
- bool operator!=(const Element& b) const {
- return !(*this == b);
- }
-
-
- /**
- * Returns true if this Element can be intersected in place with a new clip
- */
- bool canBeIntersectedInPlace(int saveCount, SkRegion::Op op) const {
- if (kEmpty_Type == fType && (
- SkRegion::kDifference_Op == op ||
- SkRegion::kIntersect_Op == op)) {
- return true;
- }
- // Only clips within the same save/restore frame (as captured by
- // the save count) can be merged
- return fSaveCount == saveCount &&
- SkRegion::kIntersect_Op == op &&
- (SkRegion::kIntersect_Op == fOp || SkRegion::kReplace_Op == fOp);
- }
-
- /**
- * This method checks to see if two rect clips can be safely merged into
- * one. The issue here is that to be strictly correct all the edges of
- * the resulting rect must have the same anti-aliasing.
- */
- bool rectRectIntersectAllowed(const SkRect& newR, bool newAA) const {
- SkASSERT(kRect_Type == fType);
-
- if (fDoAA == newAA) {
- // if the AA setting is the same there is no issue
- return true;
- }
-
- if (!SkRect::Intersects(fRect, newR)) {
- // The calling code will correctly set the result to the empty clip
- return true;
- }
-
- if (fRect.contains(newR)) {
- // if the new rect carves out a portion of the old one there is no
- // issue
- return true;
- }
-
- // So either the two overlap in some complex manner or newR contains oldR.
- // In the first, case the edges will require different AA. In the second,
- // the AA setting that would be carried forward is incorrect (e.g., oldR
- // is AA while newR is BW but since newR contains oldR, oldR will be
- // drawn BW) since the new AA setting will predominate.
+bool SkClipStack::Element::operator==(const Element& b) const {
+ if (fSaveCount != b.fSaveCount ||
+ fOp != b.fOp ||
+ fType != b.fType ||
+ fDoAA != b.fDoAA) {
return false;
}
+ switch (fType) {
+ case kEmpty_Type:
+ return true;
+ case kRect_Type:
+ return fRect == b.fRect;
+ case kPath_Type:
+ return fPath == b.fPath;
+ }
+ return false; // Silence the compiler.
+}
+bool SkClipStack::Element::operator!=(const Element& b) const {
+ return !(*this == b);
+}
- /**
- * The different combination of fill & inverse fill when combining
- * bounding boxes
- */
- enum FillCombo {
- kPrev_Cur_FillCombo,
- kPrev_InvCur_FillCombo,
- kInvPrev_Cur_FillCombo,
- kInvPrev_InvCur_FillCombo
- };
+bool SkClipStack::Element::canBeIntersectedInPlace(int saveCount, SkRegion::Op op) const {
+ if (kEmpty_Type == fType &&
+ (SkRegion::kDifference_Op == op || SkRegion::kIntersect_Op == op)) {
+ return true;
+ }
+ // Only clips within the same save/restore frame (as captured by
+ // the save count) can be merged
+ return fSaveCount == saveCount &&
+ SkRegion::kIntersect_Op == op &&
+ (SkRegion::kIntersect_Op == fOp || SkRegion::kReplace_Op == fOp);
+}
- // a mirror of combineBoundsRevDiff
- void combineBoundsDiff(FillCombo combination, const SkRect& prevFinite) {
- switch (combination) {
- case kInvPrev_InvCur_FillCombo:
- // In this case the only pixels that can remain set
- // are inside the current clip rect since the extensions
- // to infinity of both clips cancel out and whatever
- // is outside of the current clip is removed
- fFiniteBoundType = kNormal_BoundsType;
- break;
- case kInvPrev_Cur_FillCombo:
- // In this case the current op is finite so the only pixels
- // that aren't set are whatever isn't set in the previous
- // clip and whatever this clip carves out
- fFiniteBound.join(prevFinite);
- fFiniteBoundType = kInsideOut_BoundsType;
- break;
- case kPrev_InvCur_FillCombo:
- // In this case everything outside of this clip's bound
- // is erased, so the only pixels that can remain set
- // occur w/in the intersection of the two finite bounds
- if (!fFiniteBound.intersect(prevFinite)) {
- fFiniteBound.setEmpty();
- fGenID = kEmptyGenID;
- }
- fFiniteBoundType = kNormal_BoundsType;
- break;
- case kPrev_Cur_FillCombo:
- // The most conservative result bound is that of the
- // prior clip. This could be wildly incorrect if the
- // second clip either exactly matches the first clip
- // (which should yield the empty set) or reduces the
- // size of the prior bound (e.g., if the second clip
- // exactly matched the bottom half of the prior clip).
- // We ignore these two possibilities.
- fFiniteBound = prevFinite;
- break;
- default:
- SkDEBUGFAIL("SkClipStack::Element::combineBoundsDiff Invalid fill combination");
- break;
- }
+bool SkClipStack::Element::rectRectIntersectAllowed(const SkRect& newR, bool newAA) const {
+ SkASSERT(kRect_Type == fType);
+
+ if (fDoAA == newAA) {
+ // if the AA setting is the same there is no issue
+ return true;
}
- void combineBoundsXOR(int combination, const SkRect& prevFinite) {
-
- switch (combination) {
- case kInvPrev_Cur_FillCombo: // fall through
- case kPrev_InvCur_FillCombo:
- // With only one of the clips inverted the result will always
- // extend to infinity. The only pixels that may be un-writeable
- // lie within the union of the two finite bounds
- fFiniteBound.join(prevFinite);
- fFiniteBoundType = kInsideOut_BoundsType;
- break;
- case kInvPrev_InvCur_FillCombo:
- // The only pixels that can survive are within the
- // union of the two bounding boxes since the extensions
- // to infinity of both clips cancel out
- // fall through!
- case kPrev_Cur_FillCombo:
- // The most conservative bound for xor is the
- // union of the two bounds. If the two clips exactly overlapped
- // the xor could yield the empty set. Similarly the xor
- // could reduce the size of the original clip's bound (e.g.,
- // if the second clip exactly matched the bottom half of the
- // first clip). We ignore these two cases.
- fFiniteBound.join(prevFinite);
- fFiniteBoundType = kNormal_BoundsType;
- break;
- default:
- SkDEBUGFAIL("SkClipStack::Element::combineBoundsXOR Invalid fill combination");
- break;
- }
+ if (!SkRect::Intersects(fRect, newR)) {
+ // The calling code will correctly set the result to the empty clip
+ return true;
}
- // a mirror of combineBoundsIntersection
- void combineBoundsUnion(int combination, const SkRect& prevFinite) {
-
- switch (combination) {
- case kInvPrev_InvCur_FillCombo:
- if (!fFiniteBound.intersect(prevFinite)) {
- fFiniteBound.setEmpty();
- fGenID = kWideOpenGenID;
- }
- fFiniteBoundType = kInsideOut_BoundsType;
- break;
- case kInvPrev_Cur_FillCombo:
- // The only pixels that won't be drawable are inside
- // the prior clip's finite bound
- fFiniteBound = prevFinite;
- fFiniteBoundType = kInsideOut_BoundsType;
- break;
- case kPrev_InvCur_FillCombo:
- // The only pixels that won't be drawable are inside
- // this clip's finite bound
- break;
- case kPrev_Cur_FillCombo:
- fFiniteBound.join(prevFinite);
- break;
- default:
- SkDEBUGFAIL("SkClipStack::Element::combineBoundsUnion Invalid fill combination");
- break;
- }
+ if (fRect.contains(newR)) {
+ // if the new rect carves out a portion of the old one there is no
+ // issue
+ return true;
}
- // a mirror of combineBoundsUnion
- void combineBoundsIntersection(int combination, const SkRect& prevFinite) {
+ // So either the two overlap in some complex manner or newR contains oldR.
+ // In the first, case the edges will require different AA. In the second,
+ // the AA setting that would be carried forward is incorrect (e.g., oldR
+ // is AA while newR is BW but since newR contains oldR, oldR will be
+ // drawn BW) since the new AA setting will predominate.
+ return false;
+}
- switch (combination) {
- case kInvPrev_InvCur_FillCombo:
- // The only pixels that aren't writable in this case
- // occur in the union of the two finite bounds
- fFiniteBound.join(prevFinite);
- fFiniteBoundType = kInsideOut_BoundsType;
- break;
- case kInvPrev_Cur_FillCombo:
- // In this case the only pixels that will remain writeable
- // are within the current clip
- break;
- case kPrev_InvCur_FillCombo:
- // In this case the only pixels that will remain writeable
- // are with the previous clip
- fFiniteBound = prevFinite;
- fFiniteBoundType = kNormal_BoundsType;
- break;
- case kPrev_Cur_FillCombo:
- if (!fFiniteBound.intersect(prevFinite)) {
- fFiniteBound.setEmpty();
- fGenID = kEmptyGenID;
- }
- break;
- default:
- SkDEBUGFAIL("SkClipStack::Element::combineBoundsIntersection Invalid fill combination");
- break;
- }
- }
-
- // a mirror of combineBoundsDiff
- void combineBoundsRevDiff(int combination, const SkRect& prevFinite) {
-
- switch (combination) {
- case kInvPrev_InvCur_FillCombo:
- // The only pixels that can survive are in the
- // previous bound since the extensions to infinity in
- // both clips cancel out
- fFiniteBound = prevFinite;
- fFiniteBoundType = kNormal_BoundsType;
- break;
- case kInvPrev_Cur_FillCombo:
- if (!fFiniteBound.intersect(prevFinite)) {
- fFiniteBound.setEmpty();
- fGenID = kEmptyGenID;
- }
- fFiniteBoundType = kNormal_BoundsType;
- break;
- case kPrev_InvCur_FillCombo:
- fFiniteBound.join(prevFinite);
- fFiniteBoundType = kInsideOut_BoundsType;
- break;
- case kPrev_Cur_FillCombo:
- // Fall through - as with the kDifference_Op case, the
- // most conservative result bound is the bound of the
- // current clip. The prior clip could reduce the size of this
- // bound (as in the kDifference_Op case) but we are ignoring
- // those cases.
- break;
- default:
- SkDEBUGFAIL("SkClipStack::Element::combineBoundsRevDiff Invalid fill combination");
- break;
- }
- }
-
- void updateBoundAndGenID(const Element* prior) {
- // We set this first here but we may overwrite it later if we determine that the clip is
- // either wide-open or empty.
- fGenID = GetNextGenID();
-
- // First, optimistically update the current Element's bound information
- // with the current clip's bound
- fIsIntersectionOfRects = false;
- if (kRect_Type == fType) {
- fFiniteBound = fRect;
+// a mirror of combineBoundsRevDiff
+void SkClipStack::Element::combineBoundsDiff(FillCombo combination, const SkRect& prevFinite) {
+ switch (combination) {
+ case kInvPrev_InvCur_FillCombo:
+ // In this case the only pixels that can remain set
+ // are inside the current clip rect since the extensions
+ // to infinity of both clips cancel out and whatever
+ // is outside of the current clip is removed
fFiniteBoundType = kNormal_BoundsType;
-
- if (SkRegion::kReplace_Op == fOp ||
- (SkRegion::kIntersect_Op == fOp && NULL == prior) ||
- (SkRegion::kIntersect_Op == fOp && prior->fIsIntersectionOfRects &&
- prior->rectRectIntersectAllowed(fRect, fDoAA))) {
- fIsIntersectionOfRects = true;
+ break;
+ case kInvPrev_Cur_FillCombo:
+ // In this case the current op is finite so the only pixels
+ // that aren't set are whatever isn't set in the previous
+ // clip and whatever this clip carves out
+ fFiniteBound.join(prevFinite);
+ fFiniteBoundType = kInsideOut_BoundsType;
+ break;
+ case kPrev_InvCur_FillCombo:
+ // In this case everything outside of this clip's bound
+ // is erased, so the only pixels that can remain set
+ // occur w/in the intersection of the two finite bounds
+ if (!fFiniteBound.intersect(prevFinite)) {
+ fFiniteBound.setEmpty();
+ fGenID = kEmptyGenID;
}
+ fFiniteBoundType = kNormal_BoundsType;
+ break;
+ case kPrev_Cur_FillCombo:
+ // The most conservative result bound is that of the
+ // prior clip. This could be wildly incorrect if the
+ // second clip either exactly matches the first clip
+ // (which should yield the empty set) or reduces the
+ // size of the prior bound (e.g., if the second clip
+ // exactly matched the bottom half of the prior clip).
+ // We ignore these two possibilities.
+ fFiniteBound = prevFinite;
+ break;
+ default:
+ SkDEBUGFAIL("SkClipStack::Element::combineBoundsDiff Invalid fill combination");
+ break;
+ }
+}
- } else {
- SkASSERT(kPath_Type == fType);
+void SkClipStack::Element::combineBoundsXOR(int combination, const SkRect& prevFinite) {
- fFiniteBound = fPath.getBounds();
+ switch (combination) {
+ case kInvPrev_Cur_FillCombo: // fall through
+ case kPrev_InvCur_FillCombo:
+ // With only one of the clips inverted the result will always
+ // extend to infinity. The only pixels that may be un-writeable
+ // lie within the union of the two finite bounds
+ fFiniteBound.join(prevFinite);
+ fFiniteBoundType = kInsideOut_BoundsType;
+ break;
+ case kInvPrev_InvCur_FillCombo:
+ // The only pixels that can survive are within the
+ // union of the two bounding boxes since the extensions
+ // to infinity of both clips cancel out
+ // fall through!
+ case kPrev_Cur_FillCombo:
+ // The most conservative bound for xor is the
+ // union of the two bounds. If the two clips exactly overlapped
+ // the xor could yield the empty set. Similarly the xor
+ // could reduce the size of the original clip's bound (e.g.,
+ // if the second clip exactly matched the bottom half of the
+ // first clip). We ignore these two cases.
+ fFiniteBound.join(prevFinite);
+ fFiniteBoundType = kNormal_BoundsType;
+ break;
+ default:
+ SkDEBUGFAIL("SkClipStack::Element::combineBoundsXOR Invalid fill combination");
+ break;
+ }
+}
- if (fPath.isInverseFillType()) {
- fFiniteBoundType = kInsideOut_BoundsType;
- } else {
- fFiniteBoundType = kNormal_BoundsType;
+// a mirror of combineBoundsIntersection
+void SkClipStack::Element::combineBoundsUnion(int combination, const SkRect& prevFinite) {
+
+ switch (combination) {
+ case kInvPrev_InvCur_FillCombo:
+ if (!fFiniteBound.intersect(prevFinite)) {
+ fFiniteBound.setEmpty();
+ fGenID = kWideOpenGenID;
}
+ fFiniteBoundType = kInsideOut_BoundsType;
+ break;
+ case kInvPrev_Cur_FillCombo:
+ // The only pixels that won't be drawable are inside
+ // the prior clip's finite bound
+ fFiniteBound = prevFinite;
+ fFiniteBoundType = kInsideOut_BoundsType;
+ break;
+ case kPrev_InvCur_FillCombo:
+ // The only pixels that won't be drawable are inside
+ // this clip's finite bound
+ break;
+ case kPrev_Cur_FillCombo:
+ fFiniteBound.join(prevFinite);
+ break;
+ default:
+ SkDEBUGFAIL("SkClipStack::Element::combineBoundsUnion Invalid fill combination");
+ break;
+ }
+}
+
+// a mirror of combineBoundsUnion
+void SkClipStack::Element::combineBoundsIntersection(int combination, const SkRect& prevFinite) {
+
+ switch (combination) {
+ case kInvPrev_InvCur_FillCombo:
+ // The only pixels that aren't writable in this case
+ // occur in the union of the two finite bounds
+ fFiniteBound.join(prevFinite);
+ fFiniteBoundType = kInsideOut_BoundsType;
+ break;
+ case kInvPrev_Cur_FillCombo:
+ // In this case the only pixels that will remain writeable
+ // are within the current clip
+ break;
+ case kPrev_InvCur_FillCombo:
+ // In this case the only pixels that will remain writeable
+ // are with the previous clip
+ fFiniteBound = prevFinite;
+ fFiniteBoundType = kNormal_BoundsType;
+ break;
+ case kPrev_Cur_FillCombo:
+ if (!fFiniteBound.intersect(prevFinite)) {
+ fFiniteBound.setEmpty();
+ fGenID = kEmptyGenID;
+ }
+ break;
+ default:
+ SkDEBUGFAIL("SkClipStack::Element::combineBoundsIntersection Invalid fill combination");
+ break;
+ }
+}
+
+// a mirror of combineBoundsDiff
+void SkClipStack::Element::combineBoundsRevDiff(int combination, const SkRect& prevFinite) {
+
+ switch (combination) {
+ case kInvPrev_InvCur_FillCombo:
+ // The only pixels that can survive are in the
+ // previous bound since the extensions to infinity in
+ // both clips cancel out
+ fFiniteBound = prevFinite;
+ fFiniteBoundType = kNormal_BoundsType;
+ break;
+ case kInvPrev_Cur_FillCombo:
+ if (!fFiniteBound.intersect(prevFinite)) {
+ fFiniteBound.setEmpty();
+ fGenID = kEmptyGenID;
+ }
+ fFiniteBoundType = kNormal_BoundsType;
+ break;
+ case kPrev_InvCur_FillCombo:
+ fFiniteBound.join(prevFinite);
+ fFiniteBoundType = kInsideOut_BoundsType;
+ break;
+ case kPrev_Cur_FillCombo:
+ // Fall through - as with the kDifference_Op case, the
+ // most conservative result bound is the bound of the
+ // current clip. The prior clip could reduce the size of this
+ // bound (as in the kDifference_Op case) but we are ignoring
+ // those cases.
+ break;
+ default:
+ SkDEBUGFAIL("SkClipStack::Element::combineBoundsRevDiff Invalid fill combination");
+ break;
+ }
+}
+
+void SkClipStack::Element::updateBoundAndGenID(const Element* prior) {
+ // We set this first here but we may overwrite it later if we determine that the clip is
+ // either wide-open or empty.
+ fGenID = GetNextGenID();
+
+ // First, optimistically update the current Element's bound information
+ // with the current clip's bound
+ fIsIntersectionOfRects = false;
+ if (kRect_Type == fType) {
+ fFiniteBound = fRect;
+ fFiniteBoundType = kNormal_BoundsType;
+
+ if (SkRegion::kReplace_Op == fOp ||
+ (SkRegion::kIntersect_Op == fOp && NULL == prior) ||
+ (SkRegion::kIntersect_Op == fOp && prior->fIsIntersectionOfRects &&
+ prior->rectRectIntersectAllowed(fRect, fDoAA))) {
+ fIsIntersectionOfRects = true;
}
- if (!fDoAA) {
- // Here we mimic a non-anti-aliased scanline system. If there is
- // no anti-aliasing we can integerize the bounding box to exclude
- // fractional parts that won't be rendered.
- // Note: the left edge is handled slightly differently below. We
- // are a bit more generous in the rounding since we don't want to
- // risk missing the left pixels when fLeft is very close to .5
- fFiniteBound.set(SkIntToScalar(SkScalarFloorToInt(fFiniteBound.fLeft+0.45f)),
- SkIntToScalar(SkScalarRound(fFiniteBound.fTop)),
- SkIntToScalar(SkScalarRound(fFiniteBound.fRight)),
- SkIntToScalar(SkScalarRound(fFiniteBound.fBottom)));
- }
+ } else {
+ SkASSERT(kPath_Type == fType);
- // Now set up the previous Element's bound information taking into
- // account that there may be no previous clip
- SkRect prevFinite;
- SkClipStack::BoundsType prevType;
+ fFiniteBound = fPath.getBounds();
- if (NULL == prior) {
- // no prior clip means the entire plane is writable
- prevFinite.setEmpty(); // there are no pixels that cannot be drawn to
- prevType = kInsideOut_BoundsType;
+ if (fPath.isInverseFillType()) {
+ fFiniteBoundType = kInsideOut_BoundsType;
} else {
- prevFinite = prior->fFiniteBound;
- prevType = prior->fFiniteBoundType;
- }
-
- FillCombo combination = kPrev_Cur_FillCombo;
- if (kInsideOut_BoundsType == fFiniteBoundType) {
- combination = (FillCombo) (combination | 0x01);
- }
- if (kInsideOut_BoundsType == prevType) {
- combination = (FillCombo) (combination | 0x02);
- }
-
- SkASSERT(kInvPrev_InvCur_FillCombo == combination ||
- kInvPrev_Cur_FillCombo == combination ||
- kPrev_InvCur_FillCombo == combination ||
- kPrev_Cur_FillCombo == combination);
-
- // Now integrate with clip with the prior clips
- switch (fOp) {
- case SkRegion::kDifference_Op:
- this->combineBoundsDiff(combination, prevFinite);
- break;
- case SkRegion::kXOR_Op:
- this->combineBoundsXOR(combination, prevFinite);
- break;
- case SkRegion::kUnion_Op:
- this->combineBoundsUnion(combination, prevFinite);
- break;
- case SkRegion::kIntersect_Op:
- this->combineBoundsIntersection(combination, prevFinite);
- break;
- case SkRegion::kReverseDifference_Op:
- this->combineBoundsRevDiff(combination, prevFinite);
- break;
- case SkRegion::kReplace_Op:
- // Replace just ignores everything prior
- // The current clip's bound information is already filled in
- // so nothing to do
- break;
- default:
- SkDebugf("SkRegion::Op error/n");
- SkASSERT(0);
- break;
+ fFiniteBoundType = kNormal_BoundsType;
}
}
-};
+
+ if (!fDoAA) {
+ // Here we mimic a non-anti-aliased scanline system. If there is
+ // no anti-aliasing we can integerize the bounding box to exclude
+ // fractional parts that won't be rendered.
+ // Note: the left edge is handled slightly differently below. We
+ // are a bit more generous in the rounding since we don't want to
+ // risk missing the left pixels when fLeft is very close to .5
+ fFiniteBound.set(SkIntToScalar(SkScalarFloorToInt(fFiniteBound.fLeft+0.45f)),
+ SkIntToScalar(SkScalarRound(fFiniteBound.fTop)),
+ SkIntToScalar(SkScalarRound(fFiniteBound.fRight)),
+ SkIntToScalar(SkScalarRound(fFiniteBound.fBottom)));
+ }
+
+ // Now determine the previous Element's bound information taking into
+ // account that there may be no previous clip
+ SkRect prevFinite;
+ SkClipStack::BoundsType prevType;
+
+ if (NULL == prior) {
+ // no prior clip means the entire plane is writable
+ prevFinite.setEmpty(); // there are no pixels that cannot be drawn to
+ prevType = kInsideOut_BoundsType;
+ } else {
+ prevFinite = prior->fFiniteBound;
+ prevType = prior->fFiniteBoundType;
+ }
+
+ FillCombo combination = kPrev_Cur_FillCombo;
+ if (kInsideOut_BoundsType == fFiniteBoundType) {
+ combination = (FillCombo) (combination | 0x01);
+ }
+ if (kInsideOut_BoundsType == prevType) {
+ combination = (FillCombo) (combination | 0x02);
+ }
+
+ SkASSERT(kInvPrev_InvCur_FillCombo == combination ||
+ kInvPrev_Cur_FillCombo == combination ||
+ kPrev_InvCur_FillCombo == combination ||
+ kPrev_Cur_FillCombo == combination);
+
+ // Now integrate with clip with the prior clips
+ switch (fOp) {
+ case SkRegion::kDifference_Op:
+ this->combineBoundsDiff(combination, prevFinite);
+ break;
+ case SkRegion::kXOR_Op:
+ this->combineBoundsXOR(combination, prevFinite);
+ break;
+ case SkRegion::kUnion_Op:
+ this->combineBoundsUnion(combination, prevFinite);
+ break;
+ case SkRegion::kIntersect_Op:
+ this->combineBoundsIntersection(combination, prevFinite);
+ break;
+ case SkRegion::kReverseDifference_Op:
+ this->combineBoundsRevDiff(combination, prevFinite);
+ break;
+ case SkRegion::kReplace_Op:
+ // Replace just ignores everything prior
+ // The current clip's bound information is already filled in
+ // so nothing to do
+ break;
+ default:
+ SkDebugf("SkRegion::Op error/n");
+ SkASSERT(0);
+ break;
+ }
+}
// This constant determines how many Element's are allocated together as a block in
// the deque. As such it needs to balance allocating too much memory vs.