Revert "Simplify SkRasterClip now that it's only intersect/diff"
This reverts commit 75bab9249d
.
Reason for revert: Experiment to see if blocking Chrome roll
Original change's description:
> Simplify SkRasterClip now that it's only intersect/diff
>
> Bug: skia:10205
> Change-Id: Id29a63783bd38e5977e94bf8e8d7fbb4fe16cb51
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/442279
> Reviewed-by: Mike Reed <reed@google.com>
> Commit-Queue: Michael Ludwig <michaelludwig@google.com>
TBR=reed@google.com,michaelludwig@google.com,skcq-be@skia-corp.google.com.iam.gserviceaccount.com
Change-Id: I1ceeccf880a139dc9236b7df17e3599f8cae611f
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:10205
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/443414
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
cadd5dbded
commit
9a0302cd9d
@ -42,16 +42,16 @@ public:
|
||||
}
|
||||
|
||||
void clipRect(const SkRect& r, SkClipOp op) override {
|
||||
fRC.op(r, fCTM, op, false);
|
||||
fRC.op(r, fCTM, fBounds, (SkRegion::Op)op, false);
|
||||
fCache.reset(nullptr);
|
||||
}
|
||||
|
||||
void clipRRect(const SkRRect& rr, SkClipOp op) override {
|
||||
fRC.op(rr, fCTM, op, false);
|
||||
fRC.op(rr, fCTM, fBounds, (SkRegion::Op)op, false);
|
||||
fCache.reset(nullptr);
|
||||
}
|
||||
void clipPath(const SkPath& p, SkClipOp op) override {
|
||||
fRC.op(p, fCTM, op, false);
|
||||
fRC.op(p, fCTM, fBounds, (SkRegion::Op)op, false);
|
||||
fCache.reset(nullptr);
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,7 @@ private:
|
||||
SkIntToScalar(-fOrigin.y()));
|
||||
fDevice->fRCStack.rc().translate(-fOrigin.x(), -fOrigin.y(), &fTileRC);
|
||||
fTileRC.op(SkIRect::MakeWH(fDraw.fDst.width(), fDraw.fDst.height()),
|
||||
SkClipOp::kIntersect);
|
||||
SkRegion::kIntersect_Op);
|
||||
}
|
||||
};
|
||||
|
||||
@ -708,7 +708,7 @@ SkBaseDevice::ClipType SkBitmapDevice::onGetClipType() const {
|
||||
const SkRasterClip& rc = fRCStack.rc();
|
||||
if (rc.isEmpty()) {
|
||||
return ClipType::kEmpty;
|
||||
} else if (rc.isRect() && !SkToBool(rc.clipShader())) {
|
||||
} else if (rc.isRect()) {
|
||||
return ClipType::kRect;
|
||||
} else {
|
||||
return ClipType::kComplex;
|
||||
|
@ -1058,7 +1058,7 @@ static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip,
|
||||
}
|
||||
|
||||
static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y, const SkPixmap& pmap) {
|
||||
return clip.isBW() || clip.quickContains(SkIRect::MakeXYWH(x, y, pmap.width(), pmap.height()));
|
||||
return clip.isBW() || clip.quickContains(x, y, x + pmap.width(), y + pmap.height());
|
||||
}
|
||||
|
||||
void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
|
||||
|
@ -64,20 +64,6 @@ SkRasterClip::SkRasterClip() {
|
||||
SkDEBUGCODE(this->validate();)
|
||||
}
|
||||
|
||||
SkRasterClip::SkRasterClip(const SkPath& path, const SkIRect& bounds, bool doAA) {
|
||||
SkRegion clip(bounds);
|
||||
if (doAA) {
|
||||
fIsBW = false;
|
||||
fAA.setPath(path, &clip, true);
|
||||
} else {
|
||||
fIsBW = true;
|
||||
fBW.setPath(path, clip);
|
||||
}
|
||||
fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
|
||||
fIsRect = this->computeIsRect();
|
||||
SkDEBUGCODE(this->validate();)
|
||||
}
|
||||
|
||||
SkRasterClip::~SkRasterClip() {
|
||||
SkDEBUGCODE(this->validate();)
|
||||
}
|
||||
@ -96,6 +82,14 @@ bool SkRasterClip::operator==(const SkRasterClip& other) const {
|
||||
return isEqual;
|
||||
}
|
||||
|
||||
bool SkRasterClip::isComplex() const {
|
||||
return fIsBW ? fBW.isComplex() : !fAA.isEmpty();
|
||||
}
|
||||
|
||||
const SkIRect& SkRasterClip::getBounds() const {
|
||||
return fIsBW ? fBW.getBounds() : fAA.getBounds();
|
||||
}
|
||||
|
||||
bool SkRasterClip::setEmpty() {
|
||||
AUTO_RASTERCLIP_VALIDATE(*this);
|
||||
|
||||
@ -119,82 +113,51 @@ bool SkRasterClip::setRect(const SkIRect& rect) {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SkRasterClip::op(const SkIRect& rect, SkClipOp op) {
|
||||
AUTO_RASTERCLIP_VALIDATE(*this);
|
||||
|
||||
if (fIsBW) {
|
||||
fBW.op(rect, (SkRegion::Op) op);
|
||||
bool SkRasterClip::setConservativeRect(const SkRect& r, const SkIRect& clipR, bool isInverse) {
|
||||
SkRegion::Op op;
|
||||
if (isInverse) {
|
||||
op = SkRegion::kDifference_Op;
|
||||
} else {
|
||||
fAA.op(rect, (SkRegion::Op) op);
|
||||
op = SkRegion::kIntersect_Op;
|
||||
}
|
||||
fBW.setRect(clipR);
|
||||
fBW.op(r.roundOut(), op);
|
||||
return this->updateCacheAndReturnNonEmpty();
|
||||
}
|
||||
|
||||
bool SkRasterClip::op(const SkRegion& rgn, SkClipOp op) {
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
|
||||
AUTO_RASTERCLIP_VALIDATE(*this);
|
||||
|
||||
if (fIsBW) {
|
||||
(void)fBW.op(rgn, (SkRegion::Op) op);
|
||||
if (this->isBW() && !doAA) {
|
||||
(void)fBW.setPath(path, clip);
|
||||
} else {
|
||||
SkAAClip tmp;
|
||||
tmp.setRegion(rgn);
|
||||
(void)fAA.op(tmp, (SkRegion::Op) op);
|
||||
}
|
||||
return this->updateCacheAndReturnNonEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Our antialiasing currently has a granularity of 1/4 of a pixel along each
|
||||
* axis. Thus we can treat an axis coordinate as an integer if it differs
|
||||
* from its nearest int by < half of that value (1/8 in this case).
|
||||
*/
|
||||
static bool nearly_integral(SkScalar x) {
|
||||
static const SkScalar domain = SK_Scalar1 / 4;
|
||||
static const SkScalar halfDomain = domain / 2;
|
||||
|
||||
x += halfDomain;
|
||||
return x - SkScalarFloorToScalar(x) < domain;
|
||||
}
|
||||
|
||||
bool SkRasterClip::op(const SkRect& localRect, const SkMatrix& matrix, SkClipOp op, bool doAA) {
|
||||
AUTO_RASTERCLIP_VALIDATE(*this);
|
||||
|
||||
const bool isScaleTrans = matrix.isScaleTranslate();
|
||||
if (!isScaleTrans) {
|
||||
SkPath path = SkPath::Rect(localRect);
|
||||
path.setIsVolatile(true);
|
||||
return this->op(path, matrix, op, doAA);
|
||||
}
|
||||
|
||||
SkRect devRect = matrix.mapRect(localRect);
|
||||
if (fIsBW && doAA) {
|
||||
// check that the rect really needs aa, or is it close enought to
|
||||
// integer boundaries that we can just treat it as a BW rect?
|
||||
if (nearly_integral(devRect.fLeft) && nearly_integral(devRect.fTop) &&
|
||||
nearly_integral(devRect.fRight) && nearly_integral(devRect.fBottom)) {
|
||||
doAA = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (fIsBW && !doAA) {
|
||||
(void)fBW.op(devRect.round(), (SkRegion::Op) op);
|
||||
} else {
|
||||
if (fIsBW) {
|
||||
// TODO: since we are going to over-write fAA completely (aren't we?)
|
||||
// we should just clear our BW data (if any) and set fIsAA=true
|
||||
if (this->isBW()) {
|
||||
this->convertToAA();
|
||||
}
|
||||
(void)fAA.op(devRect, (SkRegion::Op) op, doAA);
|
||||
(void)fAA.setPath(path, &clip, doAA);
|
||||
}
|
||||
return this->updateCacheAndReturnNonEmpty();
|
||||
}
|
||||
|
||||
bool SkRasterClip::op(const SkRRect& rrect, const SkMatrix& matrix, SkClipOp op, bool doAA) {
|
||||
return this->op(SkPath::RRect(rrect), matrix, op, doAA);
|
||||
bool SkRasterClip::op(const SkRRect& rrect, const SkMatrix& matrix, const SkIRect& devBounds,
|
||||
SkRegion::Op op, bool doAA) {
|
||||
SkIRect bounds(devBounds);
|
||||
return this->op(SkPath::RRect(rrect), matrix, bounds, op, doAA);
|
||||
}
|
||||
|
||||
bool SkRasterClip::op(const SkPath& path, const SkMatrix& matrix, SkClipOp op, bool doAA) {
|
||||
bool SkRasterClip::op(const SkPath& path, const SkMatrix& matrix, const SkIRect& devBounds,
|
||||
SkRegion::Op op, bool doAA) {
|
||||
AUTO_RASTERCLIP_VALIDATE(*this);
|
||||
SkIRect bounds(devBounds);
|
||||
|
||||
// base is used to limit the size (and therefore memory allocation) of the
|
||||
// region that results from scan converting devPath.
|
||||
SkRegion base;
|
||||
|
||||
// Transform into device space
|
||||
SkPath devPath;
|
||||
if (matrix.isIdentity()) {
|
||||
devPath = path;
|
||||
@ -202,30 +165,66 @@ bool SkRasterClip::op(const SkPath& path, const SkMatrix& matrix, SkClipOp op, b
|
||||
path.transform(matrix, &devPath);
|
||||
devPath.setIsVolatile(true);
|
||||
}
|
||||
if (SkRegion::kIntersect_Op == op) {
|
||||
// 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 (this->isRect()) {
|
||||
// FIXME: we should also be able to do this when this->isBW(),
|
||||
// but relaxing the test above triggers GM asserts in
|
||||
// SkRgnBuilder::blitH(). We need to investigate what's going on.
|
||||
return this->setPath(devPath, this->bwRgn(), doAA);
|
||||
} else {
|
||||
base.setRect(this->getBounds());
|
||||
SkRasterClip clip;
|
||||
clip.setPath(devPath, base, doAA);
|
||||
return this->op(clip, op);
|
||||
}
|
||||
} else {
|
||||
base.setRect(bounds);
|
||||
|
||||
// Since op is either intersect or difference, the clip is always shrinking; that means we can
|
||||
// always use our current bounds as the limiting factor for region/aaclip operations
|
||||
SkRasterClip clip(devPath, this->getBounds(), doAA);
|
||||
return this->op(clip, op);
|
||||
if (SkRegion::kReplace_Op == op) {
|
||||
return this->setPath(devPath, base, doAA);
|
||||
} else {
|
||||
SkRasterClip clip;
|
||||
clip.setPath(devPath, base, doAA);
|
||||
return this->op(clip, op);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SkRasterClip::op(sk_sp<SkShader> sh) {
|
||||
bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) {
|
||||
SkRegion tmp;
|
||||
tmp.setRect(clip);
|
||||
return this->setPath(path, tmp, doAA);
|
||||
}
|
||||
|
||||
bool SkRasterClip::op(const SkIRect& rect, SkRegion::Op op) {
|
||||
AUTO_RASTERCLIP_VALIDATE(*this);
|
||||
|
||||
if (!fShader) {
|
||||
fShader = sh;
|
||||
} else {
|
||||
fShader = SkShaders::Blend(SkBlendMode::kSrcIn, sh, fShader);
|
||||
}
|
||||
return !this->isEmpty();
|
||||
fIsBW ? fBW.op(rect, op) : fAA.op(rect, op);
|
||||
return this->updateCacheAndReturnNonEmpty();
|
||||
}
|
||||
|
||||
bool SkRasterClip::op(const SkRasterClip& clip, SkClipOp op) {
|
||||
bool SkRasterClip::op(const SkRegion& rgn, SkRegion::Op op) {
|
||||
AUTO_RASTERCLIP_VALIDATE(*this);
|
||||
|
||||
if (fIsBW) {
|
||||
(void)fBW.op(rgn, op);
|
||||
} else {
|
||||
SkAAClip tmp;
|
||||
tmp.setRegion(rgn);
|
||||
(void)fAA.op(tmp, op);
|
||||
}
|
||||
return this->updateCacheAndReturnNonEmpty();
|
||||
}
|
||||
|
||||
bool SkRasterClip::op(const SkRasterClip& clip, SkRegion::Op op) {
|
||||
AUTO_RASTERCLIP_VALIDATE(*this);
|
||||
clip.validate();
|
||||
|
||||
if (this->isBW() && clip.isBW()) {
|
||||
(void)fBW.op(clip.fBW, (SkRegion::Op) op);
|
||||
(void)fBW.op(clip.fBW, op);
|
||||
} else {
|
||||
SkAAClip tmp;
|
||||
const SkAAClip* other;
|
||||
@ -239,7 +238,68 @@ bool SkRasterClip::op(const SkRasterClip& clip, SkClipOp op) {
|
||||
} else {
|
||||
other = &clip.aaRgn();
|
||||
}
|
||||
(void)fAA.op(*other, (SkRegion::Op) op);
|
||||
(void)fAA.op(*other, op);
|
||||
}
|
||||
return this->updateCacheAndReturnNonEmpty();
|
||||
}
|
||||
|
||||
bool SkRasterClip::op(sk_sp<SkShader> sh) {
|
||||
AUTO_RASTERCLIP_VALIDATE(*this);
|
||||
|
||||
if (!fShader) {
|
||||
fShader = sh;
|
||||
} else {
|
||||
fShader = SkShaders::Blend(SkBlendMode::kSrcIn, sh, fShader);
|
||||
}
|
||||
return !this->isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Our antialiasing currently has a granularity of 1/4 of a pixel along each
|
||||
* axis. Thus we can treat an axis coordinate as an integer if it differs
|
||||
* from its nearest int by < half of that value (1.8 in this case).
|
||||
*/
|
||||
static bool nearly_integral(SkScalar x) {
|
||||
static const SkScalar domain = SK_Scalar1 / 4;
|
||||
static const SkScalar halfDomain = domain / 2;
|
||||
|
||||
x += halfDomain;
|
||||
return x - SkScalarFloorToScalar(x) < domain;
|
||||
}
|
||||
|
||||
bool SkRasterClip::op(const SkRect& localRect, const SkMatrix& matrix, const SkIRect& devBounds,
|
||||
SkRegion::Op op, bool doAA) {
|
||||
AUTO_RASTERCLIP_VALIDATE(*this);
|
||||
SkRect devRect;
|
||||
|
||||
const bool isScaleTrans = matrix.isScaleTranslate();
|
||||
if (!isScaleTrans) {
|
||||
SkPath path;
|
||||
path.addRect(localRect);
|
||||
path.setIsVolatile(true);
|
||||
return this->op(path, matrix, devBounds, op, doAA);
|
||||
}
|
||||
|
||||
matrix.mapRect(&devRect, localRect);
|
||||
|
||||
if (fIsBW && doAA) {
|
||||
// check that the rect really needs aa, or is it close enought to
|
||||
// integer boundaries that we can just treat it as a BW rect?
|
||||
if (nearly_integral(devRect.fLeft) && nearly_integral(devRect.fTop) &&
|
||||
nearly_integral(devRect.fRight) && nearly_integral(devRect.fBottom)) {
|
||||
doAA = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (fIsBW && !doAA) {
|
||||
SkIRect ir;
|
||||
devRect.round(&ir);
|
||||
(void)fBW.op(ir, op);
|
||||
} else {
|
||||
if (fIsBW) {
|
||||
this->convertToAA();
|
||||
}
|
||||
(void)fAA.op(devRect, op, doAA);
|
||||
}
|
||||
return this->updateCacheAndReturnNonEmpty();
|
||||
}
|
||||
@ -271,6 +331,21 @@ void SkRasterClip::translate(int dx, int dy, SkRasterClip* dst) const {
|
||||
dst->updateCacheAndReturnNonEmpty();
|
||||
}
|
||||
|
||||
bool SkRasterClip::quickContains(const SkIRect& ir) const {
|
||||
return fIsBW ? fBW.quickContains(ir) : fAA.quickContains(ir);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const SkRegion& SkRasterClip::forceGetBW() {
|
||||
AUTO_RASTERCLIP_VALIDATE(*this);
|
||||
|
||||
if (!fIsBW) {
|
||||
fBW.setRect(fAA.getBounds());
|
||||
}
|
||||
return fBW;
|
||||
}
|
||||
|
||||
void SkRasterClip::convertToAA() {
|
||||
AUTO_RASTERCLIP_VALIDATE(*this);
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
#ifndef SkRasterClip_DEFINED
|
||||
#define SkRasterClip_DEFINED
|
||||
|
||||
#include "include/core/SkClipOp.h"
|
||||
#include "include/core/SkRegion.h"
|
||||
#include "include/core/SkShader.h"
|
||||
#include "include/private/SkMacros.h"
|
||||
@ -19,19 +18,23 @@ class SkRRect;
|
||||
/**
|
||||
* Wraps a SkRegion and SkAAClip, so we have a single object that can represent either our
|
||||
* BW or antialiased clips.
|
||||
*
|
||||
* This class is optimized for the raster backend of canvas, but can be expense to keep up2date,
|
||||
* so it supports a runtime option (force-conservative-rects) to turn it into a super-fast
|
||||
* rect-only tracker. The gpu backend uses this since it does not need the result (it uses
|
||||
* SkClipStack instead).
|
||||
*/
|
||||
class SkRasterClip {
|
||||
public:
|
||||
SkRasterClip();
|
||||
explicit SkRasterClip(const SkIRect&);
|
||||
explicit SkRasterClip(const SkRegion&);
|
||||
explicit SkRasterClip(const SkRasterClip&);
|
||||
SkRasterClip(const SkPath& path, const SkIRect& bounds, bool doAA);
|
||||
|
||||
SkRasterClip(const SkIRect&);
|
||||
SkRasterClip(const SkRegion&);
|
||||
SkRasterClip(const SkRasterClip&);
|
||||
SkRasterClip& operator=(const SkRasterClip&);
|
||||
~SkRasterClip();
|
||||
|
||||
SkRasterClip& operator=(const SkRasterClip&);
|
||||
|
||||
// Only compares the current state. Does not compare isForceConservativeRects(), so that field
|
||||
// could be different but this could still return true.
|
||||
bool operator==(const SkRasterClip&) const;
|
||||
bool operator!=(const SkRasterClip& other) const {
|
||||
return !(*this == other);
|
||||
@ -52,27 +55,27 @@ public:
|
||||
return fIsRect;
|
||||
}
|
||||
|
||||
bool isComplex() const {
|
||||
return fIsBW ? fBW.isComplex() : !fAA.isEmpty();
|
||||
}
|
||||
const SkIRect& getBounds() const {
|
||||
return fIsBW ? fBW.getBounds() : fAA.getBounds();
|
||||
}
|
||||
bool isComplex() const;
|
||||
const SkIRect& getBounds() const;
|
||||
|
||||
bool setEmpty();
|
||||
bool setRect(const SkIRect&);
|
||||
|
||||
bool op(const SkIRect&, SkClipOp);
|
||||
bool op(const SkRegion&, SkClipOp);
|
||||
bool op(const SkRect&, const SkMatrix& matrix, SkClipOp, bool doAA);
|
||||
bool op(const SkRRect&, const SkMatrix& matrix, SkClipOp, bool doAA);
|
||||
bool op(const SkPath&, const SkMatrix& matrix, SkClipOp, bool doAA);
|
||||
bool op(const SkIRect&, SkRegion::Op);
|
||||
bool op(const SkRegion&, SkRegion::Op);
|
||||
bool op(const SkRect&, const SkMatrix& matrix, const SkIRect&, SkRegion::Op, bool doAA);
|
||||
bool op(const SkRRect&, const SkMatrix& matrix, const SkIRect&, SkRegion::Op, bool doAA);
|
||||
bool op(const SkPath&, const SkMatrix& matrix, const SkIRect&, SkRegion::Op, bool doAA);
|
||||
bool op(sk_sp<SkShader>);
|
||||
|
||||
void translate(int dx, int dy, SkRasterClip* dst) const;
|
||||
void translate(int dx, int dy) {
|
||||
this->translate(dx, dy, this);
|
||||
}
|
||||
|
||||
bool quickContains(const SkIRect& rect) const {
|
||||
return fIsBW ? fBW.quickContains(rect) : fAA.quickContains(rect);
|
||||
bool quickContains(const SkIRect& rect) const;
|
||||
bool quickContains(int left, int top, int right, int bottom) const {
|
||||
return quickContains(SkIRect::MakeLTRB(left, top, right, bottom));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -84,6 +87,9 @@ public:
|
||||
return !SkIRect::Intersects(this->getBounds(), rect);
|
||||
}
|
||||
|
||||
// hack for SkCanvas::getTotalClip
|
||||
const SkRegion& forceGetBW();
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
void validate() const;
|
||||
#else
|
||||
@ -126,7 +132,10 @@ private:
|
||||
|
||||
void convertToAA();
|
||||
|
||||
bool op(const SkRasterClip&, SkClipOp);
|
||||
bool setPath(const SkPath& path, const SkRegion& clip, bool doAA);
|
||||
bool setPath(const SkPath& path, const SkIRect& clip, bool doAA);
|
||||
bool op(const SkRasterClip&, SkRegion::Op);
|
||||
bool setConservativeRect(const SkRect& r, const SkIRect& clipR, bool isInverse);
|
||||
};
|
||||
|
||||
class SkAutoRasterClipValidate : SkNoncopyable {
|
||||
|
@ -9,16 +9,68 @@
|
||||
#define SkRasterClipStack_DEFINED
|
||||
|
||||
#include "include/core/SkClipOp.h"
|
||||
#include "include/private/SkDeque.h"
|
||||
#include "src/core/SkRasterClip.h"
|
||||
#include "src/core/SkScan.h"
|
||||
#include "src/core/SkTBlockList.h"
|
||||
#include <new>
|
||||
|
||||
template <typename T> class SkTStack {
|
||||
public:
|
||||
SkTStack(void* storage, size_t size) : fDeque(sizeof(T), storage, size), fTop(nullptr) {}
|
||||
~SkTStack() {
|
||||
while (!fDeque.empty()) {
|
||||
((T*)fDeque.back())->~T();
|
||||
fDeque.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
bool empty() const { return fDeque.empty(); }
|
||||
|
||||
int count() const { return fDeque.count(); }
|
||||
|
||||
const T& top() const {
|
||||
SkASSERT(fTop);
|
||||
return *fTop;
|
||||
}
|
||||
|
||||
T& top() {
|
||||
SkASSERT(fTop);
|
||||
return *fTop;
|
||||
}
|
||||
|
||||
T* push_raw() { return (T*)fDeque.push_back(); }
|
||||
T& push() {
|
||||
fTop = this->push_raw();
|
||||
new (fTop) T();
|
||||
return *fTop;
|
||||
}
|
||||
T& push(const T& src) {
|
||||
fTop = this->push_raw();
|
||||
new (fTop) T(src);
|
||||
return *fTop;
|
||||
}
|
||||
|
||||
void pop() {
|
||||
fTop->~T();
|
||||
fDeque.pop_back();
|
||||
fTop = fDeque.empty() ? nullptr : (T*)fDeque.back();
|
||||
}
|
||||
|
||||
private:
|
||||
SkDeque fDeque;
|
||||
T* fTop;
|
||||
};
|
||||
|
||||
class SkRasterClipStack : SkNoncopyable {
|
||||
int fCounter = 0;
|
||||
public:
|
||||
SkRasterClipStack(int width, int height)
|
||||
: fRootBounds(SkIRect::MakeWH(width, height))
|
||||
, fDisableAA(SkScan::DowngradeClipAA(fRootBounds)) {
|
||||
fStack.emplace_back(SkRasterClip(fRootBounds));
|
||||
: fStack(fStorage, sizeof(fStorage))
|
||||
, fRootBounds(SkIRect::MakeWH(width, height))
|
||||
, fDisableAA(SkScan::DowngradeClipAA(fRootBounds)) {
|
||||
Rec& rec = fStack.push();
|
||||
rec.fRC.setRect(fRootBounds);
|
||||
rec.fDeferredCount = 0;
|
||||
SkASSERT(fStack.count() == 1);
|
||||
}
|
||||
|
||||
@ -26,42 +78,43 @@ public:
|
||||
fRootBounds.setXYWH(0, 0, w, h);
|
||||
|
||||
SkASSERT(fStack.count() == 1);
|
||||
Rec& rec = fStack.back();
|
||||
Rec& rec = fStack.top();
|
||||
SkASSERT(rec.fDeferredCount == 0);
|
||||
rec.fRC.setRect(fRootBounds);
|
||||
}
|
||||
|
||||
const SkRasterClip& rc() const { return fStack.back().fRC; }
|
||||
const SkRasterClip& rc() const { return fStack.top().fRC; }
|
||||
|
||||
void save() {
|
||||
SkDEBUGCODE(fCounter += 1);
|
||||
SkASSERT(fStack.back().fDeferredCount >= 0);
|
||||
fStack.back().fDeferredCount += 1;
|
||||
fCounter += 1;
|
||||
SkASSERT(fStack.top().fDeferredCount >= 0);
|
||||
fStack.top().fDeferredCount += 1;
|
||||
}
|
||||
|
||||
void restore() {
|
||||
SkDEBUGCODE(fCounter -= 1);
|
||||
SkASSERT(fCounter >= 0);
|
||||
|
||||
if (--fStack.back().fDeferredCount < 0) {
|
||||
SkASSERT(fStack.back().fDeferredCount == -1);
|
||||
fCounter -= 1; SkASSERT(fCounter >= 0);
|
||||
if (--fStack.top().fDeferredCount < 0) {
|
||||
SkASSERT(fStack.top().fDeferredCount == -1);
|
||||
SkASSERT(fStack.count() > 1);
|
||||
fStack.pop_back();
|
||||
fStack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void clipRect(const SkMatrix& ctm, const SkRect& rect, SkClipOp op, bool aa) {
|
||||
this->writable_rc().op(rect, ctm, op, this->finalAA(aa));
|
||||
this->writable_rc().op(rect, ctm, fRootBounds, (SkRegion::Op)op, this->finalAA(aa));
|
||||
this->trimIfExpanding(op);
|
||||
this->validate();
|
||||
}
|
||||
|
||||
void clipRRect(const SkMatrix& ctm, const SkRRect& rrect, SkClipOp op, bool aa) {
|
||||
this->writable_rc().op(rrect, ctm, op, this->finalAA(aa));
|
||||
this->writable_rc().op(rrect, ctm, fRootBounds, (SkRegion::Op)op, this->finalAA(aa));
|
||||
this->trimIfExpanding(op);
|
||||
this->validate();
|
||||
}
|
||||
|
||||
void clipPath(const SkMatrix& ctm, const SkPath& path, SkClipOp op, bool aa) {
|
||||
this->writable_rc().op(path, ctm, op, this->finalAA(aa));
|
||||
this->writable_rc().op(path, ctm, fRootBounds, (SkRegion::Op)op, this->finalAA(aa));
|
||||
this->trimIfExpanding(op);
|
||||
this->validate();
|
||||
}
|
||||
|
||||
@ -71,7 +124,8 @@ public:
|
||||
}
|
||||
|
||||
void clipRegion(const SkRegion& rgn, SkClipOp op) {
|
||||
this->writable_rc().op(rgn, op);
|
||||
this->writable_rc().op(rgn, (SkRegion::Op)op);
|
||||
this->trimIfExpanding(op);
|
||||
this->validate();
|
||||
}
|
||||
|
||||
@ -97,27 +151,38 @@ public:
|
||||
|
||||
private:
|
||||
struct Rec {
|
||||
SkRasterClip fRC;
|
||||
int fDeferredCount; // 0 for a "normal" entry
|
||||
|
||||
Rec(const SkRasterClip& rc) : fRC(rc), fDeferredCount(0) {}
|
||||
SkRasterClip fRC;
|
||||
int fDeferredCount; // 0 for a "normal" entry
|
||||
};
|
||||
|
||||
SkTBlockList<Rec, 16> fStack;
|
||||
SkIRect fRootBounds;
|
||||
bool fDisableAA;
|
||||
SkDEBUGCODE(int fCounter = 0);
|
||||
enum {
|
||||
ELEM_COUNT = 16,
|
||||
PTR_COUNT = ELEM_COUNT * sizeof(Rec) / sizeof(void*)
|
||||
};
|
||||
void* fStorage[PTR_COUNT];
|
||||
SkTStack<Rec> fStack;
|
||||
SkIRect fRootBounds;
|
||||
bool fDisableAA;
|
||||
|
||||
SkRasterClip& writable_rc() {
|
||||
SkASSERT(fStack.back().fDeferredCount >= 0);
|
||||
if (fStack.back().fDeferredCount > 0) {
|
||||
fStack.back().fDeferredCount -= 1;
|
||||
fStack.emplace_back(fStack.back().fRC);
|
||||
SkASSERT(fStack.top().fDeferredCount >= 0);
|
||||
if (fStack.top().fDeferredCount > 0) {
|
||||
fStack.top().fDeferredCount -= 1;
|
||||
fStack.push(fStack.top());
|
||||
fStack.top().fDeferredCount = 0;
|
||||
}
|
||||
return fStack.back().fRC;
|
||||
return fStack.top().fRC;
|
||||
}
|
||||
|
||||
bool finalAA(bool aa) const { return aa && !fDisableAA; }
|
||||
|
||||
void trimIfExpanding(SkClipOp op) {
|
||||
if ((int)op > (int)SkClipOp::kIntersect) {
|
||||
Rec& rec = fStack.top();
|
||||
SkASSERT(rec.fDeferredCount == 0);
|
||||
rec.fRC.op(fRootBounds, SkRegion::kIntersect_Op);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -356,6 +356,7 @@ static void test_really_a_rect(skiatest::Reporter* reporter) {
|
||||
|
||||
static void did_dx_affect(skiatest::Reporter* reporter, const SkScalar dx[],
|
||||
size_t count, bool changed) {
|
||||
const SkIRect baseBounds = SkIRect::MakeXYWH(0, 0, 10, 10);
|
||||
SkIRect ir = { 0, 0, 10, 10 };
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
@ -366,11 +367,11 @@ static void did_dx_affect(skiatest::Reporter* reporter, const SkScalar dx[],
|
||||
SkRasterClip rc1(ir);
|
||||
SkRasterClip rc2(ir);
|
||||
|
||||
rc0.op(r, SkMatrix::I(), SkClipOp::kIntersect, false);
|
||||
rc0.op(r, SkMatrix::I(), baseBounds, SkRegion::kIntersect_Op, false);
|
||||
r.offset(dx[i], 0);
|
||||
rc1.op(r, SkMatrix::I(), SkClipOp::kIntersect, true);
|
||||
rc1.op(r, SkMatrix::I(), baseBounds, SkRegion::kIntersect_Op, true);
|
||||
r.offset(-2*dx[i], 0);
|
||||
rc2.op(r, SkMatrix::I(), SkClipOp::kIntersect, true);
|
||||
rc2.op(r, SkMatrix::I(), baseBounds, SkRegion::kIntersect_Op, true);
|
||||
|
||||
REPORTER_ASSERT(reporter, changed != (rc0 == rc1));
|
||||
REPORTER_ASSERT(reporter, changed != (rc0 == rc2));
|
||||
@ -416,7 +417,7 @@ static void test_crbug_422693(skiatest::Reporter* reporter) {
|
||||
SkRasterClip rc(SkIRect::MakeLTRB(-25000, -25000, 25000, 25000));
|
||||
SkPath path;
|
||||
path.addCircle(50, 50, 50);
|
||||
rc.op(path, SkMatrix::I(), SkClipOp::kIntersect, true);
|
||||
rc.op(path, SkMatrix::I(), rc.getBounds(), SkRegion::kIntersect_Op, true);
|
||||
}
|
||||
|
||||
static void test_huge(skiatest::Reporter* reporter) {
|
||||
|
Loading…
Reference in New Issue
Block a user