use SkRasterClip inside canvas (check-point for soft clipping)
git-svn-id: http://skia.googlecode.com/svn/trunk@2462 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkClipStack.h b/include/core/SkClipStack.h
index 0990dcf..fc96f03 100644
--- a/include/core/SkClipStack.h
+++ b/include/core/SkClipStack.h
@@ -34,10 +34,10 @@
SkRegion::Op op = SkRegion::kIntersect_Op) {
SkRect r;
r.set(ir);
- this->clipDevRect(r, op);
+ this->clipDevRect(r, op, false);
}
- void clipDevRect(const SkRect&, SkRegion::Op = SkRegion::kIntersect_Op);
- void clipDevPath(const SkPath&, SkRegion::Op = SkRegion::kIntersect_Op);
+ void clipDevRect(const SkRect&, SkRegion::Op, bool doAA);
+ void clipDevPath(const SkPath&, SkRegion::Op, bool doAA);
class B2FIter {
public:
@@ -55,6 +55,7 @@
const SkRect* fRect; // if non-null, this is a rect clip
const SkPath* fPath; // if non-null, this is a path clip
SkRegion::Op fOp;
+ bool fDoAA;
};
/**
diff --git a/src/core/SkAAClip.cpp b/src/core/SkAAClip.cpp
index 2955b61..32ff7c7 100644
--- a/src/core/SkAAClip.cpp
+++ b/src/core/SkAAClip.cpp
@@ -927,9 +927,9 @@
return this->op(*this, clip, op);
}
-bool SkAAClip::op(const SkRect& r, SkRegion::Op op) {
+bool SkAAClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
SkAAClip clip;
- clip.setRect(r);
+ clip.setRect(r, doAA);
return this->op(*this, clip, op);
}
diff --git a/src/core/SkAAClip.h b/src/core/SkAAClip.h
index 13f414d..723ec6b 100644
--- a/src/core/SkAAClip.h
+++ b/src/core/SkAAClip.h
@@ -40,7 +40,7 @@
// Helpers for op()
bool op(const SkIRect&, SkRegion::Op);
- bool op(const SkRect&, SkRegion::Op);
+ bool op(const SkRect&, SkRegion::Op, bool doAA);
bool op(const SkAAClip&, SkRegion::Op);
bool offset(int dx, int dy);
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index a902b3f..a77d5d9 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -14,6 +14,7 @@
#include "SkDrawFilter.h"
#include "SkDrawLooper.h"
#include "SkPicture.h"
+#include "SkRasterClip.h"
#include "SkScalarCompare.h"
#include "SkTemplates.h"
#include "SkTextFormatParams.h"
@@ -153,9 +154,9 @@
class SkCanvas::MCRec {
public:
MCRec* fNext;
- SkMatrix* fMatrix; // points to either fMatrixStorage or prev MCRec
- SkRegion* fRegion; // points to either fRegionStorage or prev MCRec
- SkDrawFilter* fFilter; // the current filter (or null)
+ SkMatrix* fMatrix; // points to either fMatrixStorage or prev MCRec
+ SkRasterClip* fRasterClip; // points to either fRegionStorage or prev MCRec
+ SkDrawFilter* fFilter; // the current filter (or null)
DeviceCM* fLayer;
/* If there are any layers in the stack, this points to the top-most
@@ -176,10 +177,10 @@
}
if (flags & SkCanvas::kClip_SaveFlag) {
- fRegionStorage = *prev->fRegion;
- fRegion = &fRegionStorage;
+ fRasterClipStorage = *prev->fRasterClip;
+ fRasterClip = &fRasterClipStorage;
} else {
- fRegion = prev->fRegion;
+ fRasterClip = prev->fRasterClip;
}
fFilter = prev->fFilter;
@@ -190,7 +191,7 @@
fMatrixStorage.reset();
fMatrix = &fMatrixStorage;
- fRegion = &fRegionStorage;
+ fRasterClip = &fRasterClipStorage;
fFilter = NULL;
fTopLayer = NULL;
}
@@ -206,8 +207,8 @@
}
private:
- SkMatrix fMatrixStorage;
- SkRegion fRegionStorage;
+ SkMatrix fMatrixStorage;
+ SkRasterClip fRasterClipStorage;
};
class SkDrawIter : public SkDraw {
@@ -517,9 +518,9 @@
*/
if (NULL == device) {
- rec->fRegion->setEmpty();
+ rec->fRasterClip->setEmpty();
while ((rec = (MCRec*)iter.next()) != NULL) {
- (void)rec->fRegion->setEmpty();
+ (void)rec->fRasterClip->setEmpty();
}
fClipStack.reset();
} else {
@@ -529,9 +530,9 @@
bounds.set(0, 0, device->width(), device->height());
// now jam our 1st clip to be bounds, and intersect the rest with that
- rec->fRegion->setRect(bounds);
+ rec->fRasterClip->setRect(bounds);
while ((rec = (MCRec*)iter.next()) != NULL) {
- (void)rec->fRegion->op(bounds, SkRegion::kIntersect_Op);
+ (void)rec->fRasterClip->op(bounds, SkRegion::kIntersect_Op);
}
}
return device;
@@ -697,7 +698,7 @@
// early exit if the layer's bounds are clipped out
if (!ir.intersect(clipBounds)) {
if (bounds_affects_clip(flags)) {
- fMCRec->fRegion->setEmpty();
+ fMCRec->fRasterClip->setEmpty();
}
return count;
}
@@ -708,7 +709,7 @@
fClipStack.clipDevRect(ir, SkRegion::kIntersect_Op);
// early exit if the clip is now empty
if (bounds_affects_clip(flags) &&
- !fMCRec->fRegion->op(ir, SkRegion::kIntersect_Op)) {
+ !fMCRec->fRasterClip->op(ir, SkRegion::kIntersect_Op)) {
return count;
}
@@ -909,12 +910,10 @@
// the region code to scan-convert the path, only to discover that it
// is really just a rect.
SkRect r;
- SkIRect ir;
fMCRec->fMatrix->mapRect(&r, rect);
- fClipStack.clipDevRect(r, op);
- r.round(&ir);
- return fMCRec->fRegion->op(ir, op);
+ fClipStack.clipDevRect(r, op, doAA);
+ return fMCRec->fRasterClip->op(r, op, doAA);
} else {
// since we're rotate or some such thing, we convert the rect to a path
// and clip against that, since it can handle any matrix. However, to
@@ -927,7 +926,7 @@
}
}
-static bool clipPathHelper(const SkCanvas* canvas, SkRegion* currRgn,
+static bool clipPathHelper(const SkCanvas* canvas, SkRasterClip* currClip,
const SkPath& devPath, SkRegion::Op op, bool doAA) {
// base is used to limit the size (and therefore memory allocation) of the
// region that results from scan converting devPath.
@@ -937,24 +936,24 @@
// since we are intersect, we can do better (tighter) with currRgn's
// bounds, than just using the device. However, if currRgn is complex,
// our region blitter may hork, so we do that case in two steps.
- if (currRgn->isRect()) {
- return currRgn->setPath(devPath, *currRgn);
+ if (currClip->isRect()) {
+ return currClip->setPath(devPath, *currClip, doAA);
} else {
- base.setRect(currRgn->getBounds());
- SkRegion rgn;
- rgn.setPath(devPath, base);
- return currRgn->op(rgn, op);
+ base.setRect(currClip->getBounds());
+ SkRasterClip clip;
+ clip.setPath(devPath, base, doAA);
+ return currClip->op(clip, op);
}
} else {
const SkBitmap& bm = canvas->getDevice()->accessBitmap(false);
base.setRect(0, 0, bm.width(), bm.height());
if (SkRegion::kReplace_Op == op) {
- return currRgn->setPath(devPath, base);
+ return currClip->setPath(devPath, base, doAA);
} else {
- SkRegion rgn;
- rgn.setPath(devPath, base);
- return currRgn->op(rgn, op);
+ SkRasterClip clip;
+ clip.setPath(devPath, base, doAA);
+ return currClip->op(clip, op);
}
}
}
@@ -970,9 +969,9 @@
path.transform(*fMCRec->fMatrix, &devPath);
// if we called path.swap() we could avoid a deep copy of this path
- fClipStack.clipDevPath(devPath, op);
+ fClipStack.clipDevPath(devPath, op, doAA);
- return clipPathHelper(this, fMCRec->fRegion, devPath, op, doAA);
+ return clipPathHelper(this, fMCRec->fRasterClip, devPath, op, doAA);
}
bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
@@ -986,7 +985,7 @@
// we have to ignore it, and use the region directly?
fClipStack.clipDevRect(rgn.getBounds());
- return fMCRec->fRegion->op(rgn, op);
+ return fMCRec->fRasterClip->op(rgn, op);
}
#ifdef SK_DEBUG
@@ -995,25 +994,25 @@
const SkDevice* device = this->getDevice();
SkIRect ir;
ir.set(0, 0, device->width(), device->height());
- SkRegion clipRgn(ir);
+ SkRasterClip tmpClip(ir);
SkClipStack::B2FIter iter(fClipStack);
const SkClipStack::B2FIter::Clip* clip;
while ((clip = iter.next()) != NULL) {
if (clip->fPath) {
- clipPathHelper(this, &clipRgn, *clip->fPath, clip->fOp, false);
+ clipPathHelper(this, &tmpClip, *clip->fPath, clip->fOp, clip->fDoAA);
} else if (clip->fRect) {
clip->fRect->round(&ir);
- clipRgn.op(ir, clip->fOp);
+ tmpClip.op(ir, clip->fOp);
} else {
- clipRgn.setEmpty();
+ tmpClip.setEmpty();
}
}
#if 0 // enable this locally for testing
// now compare against the current rgn
const SkRegion& rgn = this->getTotalClip();
- SkASSERT(rgn == clipRgn);
+ SkASSERT(rgn == tmpClip);
#endif
}
#endif
@@ -1044,7 +1043,7 @@
if (!rect.hasValidCoordinates())
return true;
- if (fMCRec->fRegion->isEmpty()) {
+ if (fMCRec->fRasterClip->isEmpty()) {
return true;
}
@@ -1053,7 +1052,7 @@
fMCRec->fMatrix->mapRect(&dst, rect);
SkIRect idst;
dst.roundOut(&idst);
- return !SkIRect::Intersects(idst, fMCRec->fRegion->getBounds());
+ return !SkIRect::Intersects(idst, fMCRec->fRasterClip->getBounds());
} else {
const SkRectCompareType& clipR = this->getLocalClipBoundsCompareType(et);
@@ -1082,7 +1081,7 @@
antialiasing (worst case)
*/
- if (fMCRec->fRegion->isEmpty()) {
+ if (fMCRec->fRasterClip->isEmpty()) {
return true;
}
@@ -1127,7 +1126,7 @@
}
bool SkCanvas::getClipDeviceBounds(SkIRect* bounds) const {
- const SkRegion& clip = *fMCRec->fRegion;
+ const SkRasterClip& clip = *fMCRec->fRasterClip;
if (clip.isEmpty()) {
if (bounds) {
bounds->setEmpty();
@@ -1146,20 +1145,13 @@
}
SkCanvas::ClipType SkCanvas::getClipType() const {
- if (fMCRec->fRegion->isEmpty()) return kEmpty_ClipType;
- if (fMCRec->fRegion->isRect()) return kRect_ClipType;
+ if (fMCRec->fRasterClip->isEmpty()) return kEmpty_ClipType;
+ if (fMCRec->fRasterClip->isRect()) return kRect_ClipType;
return kComplex_ClipType;
}
-bool SkCanvas::getTotalClipBounds(SkIRect* bounds) const {
- if (bounds) {
- *bounds = fMCRec->fRegion->getBounds();
- }
- return !fMCRec->fRegion->isEmpty();
-}
-
const SkRegion& SkCanvas::getTotalClip() const {
- return *fMCRec->fRegion;
+ return fMCRec->fRasterClip->forceGetBW();
}
const SkClipStack& SkCanvas::getTotalClipStack() const {
diff --git a/src/core/SkClipStack.cpp b/src/core/SkClipStack.cpp
index 9b7538f..f885240 100644
--- a/src/core/SkClipStack.cpp
+++ b/src/core/SkClipStack.cpp
@@ -21,22 +21,26 @@
int fSaveCount;
SkRegion::Op fOp;
State fState;
+ bool fDoAA;
- Rec(int saveCount, const SkRect& rect, SkRegion::Op op) : fRect(rect) {
+ Rec(int saveCount, const SkRect& rect, SkRegion::Op op, bool doAA) : fRect(rect) {
fSaveCount = saveCount;
fOp = op;
fState = kRect_State;
+ fDoAA = doAA;
}
- Rec(int saveCount, const SkPath& path, SkRegion::Op op) : fPath(path) {
+ Rec(int saveCount, const SkPath& path, SkRegion::Op op, bool doAA) : fPath(path) {
fRect.setEmpty();
fSaveCount = saveCount;
fOp = op;
fState = kPath_State;
+ fDoAA = doAA;
}
bool operator==(const Rec& b) const {
- if (fSaveCount != b.fSaveCount || fOp != b.fOp || fState != b.fState) {
+ if (fSaveCount != b.fSaveCount || fOp != b.fOp || fState != b.fState ||
+ fDoAA != b.fDoAA) {
return false;
}
switch (fState) {
@@ -138,7 +142,7 @@
}
}
-void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op) {
+void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
Rec* rec = (Rec*)fDeque.back();
if (rec && rec->canBeIntersected(fSaveCount, op)) {
switch (rec->fState) {
@@ -157,10 +161,10 @@
break;
}
}
- new (fDeque.push_back()) Rec(fSaveCount, rect, op);
+ new (fDeque.push_back()) Rec(fSaveCount, rect, op, doAA);
}
-void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op) {
+void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op, bool doAA) {
Rec* rec = (Rec*)fDeque.back();
if (rec && rec->canBeIntersected(fSaveCount, op)) {
const SkRect& pathBounds = path.getBounds();
@@ -181,7 +185,7 @@
break;
}
}
- new (fDeque.push_back()) Rec(fSaveCount, path, op);
+ new (fDeque.push_back()) Rec(fSaveCount, path, op, doAA);
}
///////////////////////////////////////////////////////////////////////////////
@@ -191,7 +195,7 @@
bool operator==(const SkClipStack::B2FIter::Clip& a,
const SkClipStack::B2FIter::Clip& b) {
- return a.fOp == b.fOp &&
+ return a.fOp == b.fOp && a.fDoAA == b.fDoAA &&
((a.fRect == NULL && b.fRect == NULL) ||
(a.fRect != NULL && b.fRect != NULL && *a.fRect == *b.fRect)) &&
((a.fPath == NULL && b.fPath == NULL) ||
@@ -228,6 +232,7 @@
break;
}
fClip.fOp = rec->fOp;
+ fClip.fDoAA = rec->fDoAA;
return &fClip;
}
diff --git a/src/core/SkRasterClip.cpp b/src/core/SkRasterClip.cpp
index b6a8926..004e3fc 100644
--- a/src/core/SkRasterClip.cpp
+++ b/src/core/SkRasterClip.cpp
@@ -112,6 +112,35 @@
}
}
+// return true if x is nearly integral (within 1/256) since that is the highest
+// precision our aa code can have.
+static bool is_integral(SkScalar x) {
+ int ix = SkScalarRoundToInt(x);
+ SkScalar sx = SkIntToScalar(ix);
+ return SkScalarAbs(sx - x) < (SK_Scalar1 / 256);
+}
+
+bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
+ if (doAA) {
+ // check that the rect really needs aa
+ if (is_integral(r.fLeft) && is_integral(r.fTop) &&
+ is_integral(r.fRight) && is_integral(r.fBottom)) {
+ doAA = false;
+ }
+ }
+
+ if (fIsBW && !doAA) {
+ SkIRect ir;
+ r.round(&ir);
+ fBW.op(ir, op);
+ } else {
+ if (fIsBW) {
+ this->convertToAA();
+ }
+ fAA.op(r, op, doAA);
+ }
+}
+
const SkRegion& SkRasterClip::forceGetBW() {
if (!fIsBW) {
fBW.setRect(fAA.getBounds());
diff --git a/src/core/SkRasterClip.h b/src/core/SkRasterClip.h
index 9a335d6..89a0f25 100644
--- a/src/core/SkRasterClip.h
+++ b/src/core/SkRasterClip.h
@@ -36,6 +36,7 @@
bool op(const SkIRect&, SkRegion::Op);
bool op(const SkRegion&, SkRegion::Op);
bool op(const SkRasterClip&, SkRegion::Op);
+ bool op(const SkRect&, SkRegion::Op, bool doAA);
const SkRegion& bwRgn() const { SkASSERT(fIsBW); return fBW; }
const SkAAClip& aaRgn() const { SkASSERT(!fIsBW); return fAA; }
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 420da82..dae0bdb 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -1219,7 +1219,8 @@
synthesizedClipStack = fExistingClipStack;
SkPath clipPath;
clipRegion.getBoundaryPath(&clipPath);
- synthesizedClipStack.clipDevPath(clipPath, SkRegion::kReplace_Op);
+ synthesizedClipStack.clipDevPath(clipPath, SkRegion::kReplace_Op,
+ false);
clipStack = &synthesizedClipStack;
}
}