use SkRasterClip inside canvas (check-point for soft clipping)
git-svn-id: http://skia.googlecode.com/svn/trunk@2462 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
58af9a6470
commit
0017708a5b
@ -34,10 +34,10 @@ public:
|
||||
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 @@ public:
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -927,9 +927,9 @@ bool SkAAClip::op(const SkIRect& r, SkRegion::Op op) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ public:
|
||||
|
||||
// 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);
|
||||
|
@ -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 @@ private:
|
||||
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 @@ public:
|
||||
}
|
||||
|
||||
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 @@ public:
|
||||
fMatrixStorage.reset();
|
||||
|
||||
fMatrix = &fMatrixStorage;
|
||||
fRegion = &fRegionStorage;
|
||||
fRasterClip = &fRasterClipStorage;
|
||||
fFilter = NULL;
|
||||
fTopLayer = NULL;
|
||||
}
|
||||
@ -206,8 +207,8 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
SkMatrix fMatrixStorage;
|
||||
SkRegion fRegionStorage;
|
||||
SkMatrix fMatrixStorage;
|
||||
SkRasterClip fRasterClipStorage;
|
||||
};
|
||||
|
||||
class SkDrawIter : public SkDraw {
|
||||
@ -517,9 +518,9 @@ SkDevice* SkCanvas::setDevice(SkDevice* device) {
|
||||
*/
|
||||
|
||||
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 @@ SkDevice* SkCanvas::setDevice(SkDevice* device) {
|
||||
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 @@ int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
|
||||
// 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 @@ int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
|
||||
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 @@ bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
|
||||
// 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 @@ bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ static bool clipPathHelper(const SkCanvas* canvas, SkRegion* currRgn,
|
||||
// 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 @@ bool SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
|
||||
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 @@ bool SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
|
||||
// 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 @@ void SkCanvas::validateClip() const {
|
||||
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 @@ bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const {
|
||||
if (!rect.hasValidCoordinates())
|
||||
return true;
|
||||
|
||||
if (fMCRec->fRegion->isEmpty()) {
|
||||
if (fMCRec->fRasterClip->isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1053,7 +1052,7 @@ bool SkCanvas::quickReject(const SkRect& rect, EdgeType et) const {
|
||||
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 @@ bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom, EdgeType et) const {
|
||||
antialiasing (worst case)
|
||||
*/
|
||||
|
||||
if (fMCRec->fRegion->isEmpty()) {
|
||||
if (fMCRec->fRasterClip->isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1127,7 +1126,7 @@ bool SkCanvas::getClipBounds(SkRect* bounds, EdgeType et) const {
|
||||
}
|
||||
|
||||
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 @@ const SkMatrix& SkCanvas::getTotalMatrix() const {
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -21,22 +21,26 @@ struct SkClipStack::Rec {
|
||||
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::restore() {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ void SkClipStack::clipDevRect(const SkRect& rect, SkRegion::Op op) {
|
||||
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 @@ void SkClipStack::clipDevPath(const SkPath& path, SkRegion::Op op) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
new (fDeque.push_back()) Rec(fSaveCount, path, op);
|
||||
new (fDeque.push_back()) Rec(fSaveCount, path, op, doAA);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -191,7 +195,7 @@ SkClipStack::B2FIter::B2FIter() {
|
||||
|
||||
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 @@ const SkClipStack::B2FIter::Clip* SkClipStack::B2FIter::next() {
|
||||
break;
|
||||
}
|
||||
fClip.fOp = rec->fOp;
|
||||
fClip.fDoAA = rec->fDoAA;
|
||||
return &fClip;
|
||||
}
|
||||
|
||||
|
@ -112,6 +112,35 @@ bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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());
|
||||
|
@ -36,6 +36,7 @@ public:
|
||||
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; }
|
||||
|
@ -1219,7 +1219,8 @@ ContentEntry* SkPDFDevice::setUpContentEntry(const SkClipStack* clipStack,
|
||||
synthesizedClipStack = fExistingClipStack;
|
||||
SkPath clipPath;
|
||||
clipRegion.getBoundaryPath(&clipPath);
|
||||
synthesizedClipStack.clipDevPath(clipPath, SkRegion::kReplace_Op);
|
||||
synthesizedClipStack.clipDevPath(clipPath, SkRegion::kReplace_Op,
|
||||
false);
|
||||
clipStack = &synthesizedClipStack;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user