зеркало из https://github.com/mozilla/moz-skia.git
Revert of Revert of allow canvas to force conservative clips (for speed) (patchset #1 id:1 of https://codereview.chromium.org/554033003/)
Reason for revert: May just rebaseline, plus want to see the results of the chrome tests, so re-trying this CL. Original issue's description: > Revert of allow canvas to force conservative clips (for speed) (patchset #7 id:120001 of https://codereview.chromium.org/541593005/) > > Reason for revert: > multipicturedraw failed on nvprmsaa -- don't know why yet > > Original issue's description: > > Allow SkCanvas to be initialized to force conservative rasterclips. This has the following effects: > > > > 1. Queries to the current clip will be conservatively large. This can mean the quickReject may return false more often. > > > > 2. The conservative clips mean less work is done. > > > > 3. Enabled by default for Gpu, Record, and NoSaveLayer canvases. > > > > 4. API is private for now. > > > > Committed: https://skia.googlesource.com/skia/+/27a5e656c3d6ef22f9cb34de18e1b960da3aa241 > > TBR=robertphillips@google.com,bsalomon@google.com,mtklein@google.com,junov@google.com > NOTREECHECKS=true > NOTRY=true > > Committed: https://skia.googlesource.com/skia/+/6f09709519b79a1159f3826645f1c5fbc101ee11 R=robertphillips@google.com, bsalomon@google.com, mtklein@google.com, junov@google.com, reed@google.com TBR=bsalomon@google.com, junov@google.com, mtklein@google.com, reed@google.com, robertphillips@google.com NOTREECHECKS=true NOTRY=true Author: reed@chromium.org Review URL: https://codereview.chromium.org/560713002
This commit is contained in:
Родитель
87a79236f5
Коммит
d954498c01
|
@ -1265,11 +1265,6 @@ protected:
|
|||
SkIRect* intersection,
|
||||
const SkImageFilter* imageFilter = NULL);
|
||||
|
||||
// Called by child classes that override clipPath and clipRRect to only
|
||||
// track fast conservative clip bounds, rather than exact clips.
|
||||
void updateClipConservativelyUsingBounds(const SkRect&, SkRegion::Op,
|
||||
bool inverseFilled);
|
||||
|
||||
// notify our surface (if we have one) that we are about to draw, so it
|
||||
// can perform copy-on-write or invalidate any cached images
|
||||
void predrawNotify();
|
||||
|
@ -1309,13 +1304,22 @@ private:
|
|||
friend class SkDebugCanvas; // needs experimental fAllowSimplifyClip
|
||||
friend class SkDeferredDevice; // needs getTopDevice()
|
||||
friend class SkSurface_Raster; // needs getDevice()
|
||||
friend class SkRecorder; // InitFlags
|
||||
friend class SkNoSaveLayerCanvas; // InitFlags
|
||||
|
||||
enum InitFlags {
|
||||
kDefault_InitFlags = 0,
|
||||
kConservativeRasterClip_InitFlag = 1 << 0,
|
||||
};
|
||||
SkCanvas(int width, int height, InitFlags flags);
|
||||
SkCanvas(SkBaseDevice*, InitFlags flags);
|
||||
|
||||
// needs gettotalclip()
|
||||
friend SkCanvasState* SkCanvasStateUtils::CaptureCanvasState(SkCanvas*);
|
||||
|
||||
SkBaseDevice* createLayerDevice(const SkImageInfo&);
|
||||
|
||||
SkBaseDevice* init(SkBaseDevice*);
|
||||
SkBaseDevice* init(SkBaseDevice*, InitFlags);
|
||||
|
||||
/**
|
||||
* DEPRECATED
|
||||
|
@ -1365,6 +1369,7 @@ private:
|
|||
mutable bool fCachedLocalClipBoundsDirty;
|
||||
bool fAllowSoftClip;
|
||||
bool fAllowSimplifyClip;
|
||||
bool fConservativeRasterClip;
|
||||
|
||||
const SkRect& getLocalClipBounds() const {
|
||||
if (fCachedLocalClipBoundsDirty) {
|
||||
|
|
|
@ -372,6 +372,8 @@ private:
|
|||
// TODO: move to SkBitmapDevice
|
||||
virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) {}
|
||||
|
||||
virtual bool forceConservativeRasterClip() const { return false; }
|
||||
|
||||
// just called by SkCanvas when built as a layer
|
||||
void setOrigin(int x, int y) { fOrigin.set(x, y); }
|
||||
// just called by SkCanvas for saveLayer
|
||||
|
|
|
@ -152,6 +152,7 @@ private:
|
|||
virtual SkSurface* newSurface(const SkImageInfo&) SK_OVERRIDE;
|
||||
|
||||
virtual SkImageFilter::Cache* getImageFilterCache() SK_OVERRIDE;
|
||||
virtual bool forceConservativeRasterClip() const SK_OVERRIDE { return true; }
|
||||
|
||||
// sets the render target, clip, and matrix on GrContext. Use forceIdenity to override
|
||||
// SkDraw's matrix and draw in device coords.
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
// It also simplifies the clipping calls to only use rectangles.
|
||||
class SK_API SkNoSaveLayerCanvas : public SkCanvas {
|
||||
public:
|
||||
SkNoSaveLayerCanvas(SkBaseDevice* device) : INHERITED(device) {}
|
||||
SkNoSaveLayerCanvas(SkBaseDevice* device) : INHERITED(device, kConservativeRasterClip_InitFlag)
|
||||
{}
|
||||
|
||||
protected:
|
||||
virtual SaveLayerStrategy willSaveLayer(const SkRect* bounds, const SkPaint* paint,
|
||||
|
@ -25,21 +26,6 @@ protected:
|
|||
return kNoLayer_SaveLayerStrategy;
|
||||
}
|
||||
|
||||
// disable aa for speed
|
||||
virtual void onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
|
||||
this->INHERITED::onClipRect(rect, op, kHard_ClipEdgeStyle);
|
||||
}
|
||||
|
||||
// for speed, just respect the bounds, and disable AA. May give us a few
|
||||
// false positives and negatives.
|
||||
virtual void onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
|
||||
this->updateClipConservativelyUsingBounds(path.getBounds(), op,
|
||||
path.isInverseFillType());
|
||||
}
|
||||
virtual void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
|
||||
this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef SkCanvas INHERITED;
|
||||
};
|
||||
|
|
|
@ -81,9 +81,12 @@ struct DeviceCM {
|
|||
const SkMatrix* fMatrix;
|
||||
SkPaint* fPaint; // may be null (in the future)
|
||||
|
||||
DeviceCM(SkBaseDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas)
|
||||
: fNext(NULL) {
|
||||
if (device) {
|
||||
DeviceCM(SkBaseDevice* device, int x, int y, const SkPaint* paint, SkCanvas* canvas,
|
||||
bool conservativeRasterClip)
|
||||
: fNext(NULL)
|
||||
, fClip(conservativeRasterClip)
|
||||
{
|
||||
if (NULL != device) {
|
||||
device->ref();
|
||||
device->onAttachToCanvas(canvas);
|
||||
}
|
||||
|
@ -151,11 +154,10 @@ private:
|
|||
*/
|
||||
class SkCanvas::MCRec {
|
||||
public:
|
||||
SkMatrix fMatrix;
|
||||
SkRasterClip fRasterClip;
|
||||
SkMatrix fMatrix;
|
||||
SkDrawFilter* fFilter; // the current filter (or null)
|
||||
|
||||
DeviceCM* fLayer;
|
||||
DeviceCM* fLayer;
|
||||
/* If there are any layers in the stack, this points to the top-most
|
||||
one that is at or below this level in the stack (so we know what
|
||||
bitmap/device to draw into from this level. This value is NOT
|
||||
|
@ -164,22 +166,21 @@ public:
|
|||
*/
|
||||
DeviceCM* fTopLayer;
|
||||
|
||||
MCRec(const MCRec* prev) {
|
||||
if (prev) {
|
||||
fMatrix = prev->fMatrix;
|
||||
fRasterClip = prev->fRasterClip;
|
||||
|
||||
fFilter = prev->fFilter;
|
||||
SkSafeRef(fFilter);
|
||||
|
||||
fTopLayer = prev->fTopLayer;
|
||||
} else { // no prev
|
||||
fMatrix.reset();
|
||||
fFilter = NULL;
|
||||
fTopLayer = NULL;
|
||||
}
|
||||
MCRec(bool conservativeRasterClip) : fRasterClip(conservativeRasterClip) {
|
||||
fMatrix.reset();
|
||||
fFilter = NULL;
|
||||
fLayer = NULL;
|
||||
fTopLayer = NULL;
|
||||
|
||||
// don't bother initializing fNext
|
||||
inc_rec();
|
||||
}
|
||||
MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip) {
|
||||
fMatrix = prev.fMatrix;
|
||||
fFilter = SkSafeRef(prev.fFilter);
|
||||
fLayer = NULL;
|
||||
|
||||
fTopLayer = prev.fTopLayer;
|
||||
|
||||
// don't bother initializing fNext
|
||||
inc_rec();
|
||||
}
|
||||
|
@ -381,7 +382,8 @@ bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkBaseDevice* SkCanvas::init(SkBaseDevice* device) {
|
||||
SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
|
||||
fConservativeRasterClip = SkToBool(flags & kConservativeRasterClip_InitFlag);
|
||||
fCachedLocalClipBounds.setEmpty();
|
||||
fCachedLocalClipBoundsDirty = true;
|
||||
fAllowSoftClip = true;
|
||||
|
@ -391,10 +393,14 @@ SkBaseDevice* SkCanvas::init(SkBaseDevice* device) {
|
|||
fCullCount = 0;
|
||||
fMetaData = NULL;
|
||||
|
||||
if (device && device->forceConservativeRasterClip()) {
|
||||
fConservativeRasterClip = true;
|
||||
}
|
||||
|
||||
fMCRec = (MCRec*)fMCStack.push_back();
|
||||
new (fMCRec) MCRec(NULL);
|
||||
new (fMCRec) MCRec(fConservativeRasterClip);
|
||||
|
||||
fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL));
|
||||
fMCRec->fLayer = SkNEW_ARGS(DeviceCM, (NULL, 0, 0, NULL, NULL, fConservativeRasterClip));
|
||||
fMCRec->fTopLayer = fMCRec->fLayer;
|
||||
|
||||
fSurfaceBase = NULL;
|
||||
|
@ -412,25 +418,54 @@ SkCanvas::SkCanvas()
|
|||
{
|
||||
inc_canvas();
|
||||
|
||||
this->init(NULL);
|
||||
this->init(NULL, kDefault_InitFlags);
|
||||
}
|
||||
|
||||
static SkBitmap make_nopixels(int width, int height) {
|
||||
SkBitmap bitmap;
|
||||
bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
class SkNoPixelsBitmapDevice : public SkBitmapDevice {
|
||||
public:
|
||||
SkNoPixelsBitmapDevice(int width, int height) : INHERITED(make_nopixels(width, height)) {}
|
||||
|
||||
private:
|
||||
|
||||
typedef SkBitmapDevice INHERITED;
|
||||
};
|
||||
|
||||
SkCanvas::SkCanvas(int width, int height)
|
||||
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
|
||||
{
|
||||
inc_canvas();
|
||||
|
||||
this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (width, height)), kDefault_InitFlags)->unref();
|
||||
}
|
||||
|
||||
SkBitmap bitmap;
|
||||
bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
|
||||
this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref();
|
||||
SkCanvas::SkCanvas(int width, int height, InitFlags flags)
|
||||
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
|
||||
{
|
||||
inc_canvas();
|
||||
|
||||
this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (width, height)), flags)->unref();
|
||||
}
|
||||
|
||||
SkCanvas::SkCanvas(SkBaseDevice* device, InitFlags flags)
|
||||
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
|
||||
{
|
||||
inc_canvas();
|
||||
|
||||
this->init(device, flags);
|
||||
}
|
||||
|
||||
SkCanvas::SkCanvas(SkBaseDevice* device)
|
||||
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
|
||||
{
|
||||
inc_canvas();
|
||||
|
||||
this->init(device);
|
||||
|
||||
this->init(device, kDefault_InitFlags);
|
||||
}
|
||||
|
||||
SkCanvas::SkCanvas(const SkBitmap& bitmap)
|
||||
|
@ -438,7 +473,7 @@ SkCanvas::SkCanvas(const SkBitmap& bitmap)
|
|||
{
|
||||
inc_canvas();
|
||||
|
||||
this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)))->unref();
|
||||
this->init(SkNEW_ARGS(SkBitmapDevice, (bitmap)), kDefault_InitFlags)->unref();
|
||||
}
|
||||
|
||||
SkCanvas::~SkCanvas() {
|
||||
|
@ -734,7 +769,7 @@ int SkCanvas::internalSave() {
|
|||
int saveCount = this->getSaveCount(); // record this before the actual save
|
||||
|
||||
MCRec* newTop = (MCRec*)fMCStack.push_back();
|
||||
new (newTop) MCRec(fMCRec); // balanced in restore()
|
||||
new (newTop) MCRec(*fMCRec); // balanced in restore()
|
||||
fMCRec = newTop;
|
||||
|
||||
fClipStack.save();
|
||||
|
@ -866,7 +901,8 @@ int SkCanvas::internalSaveLayer(const SkRect* bounds, const SkPaint* paint, Save
|
|||
}
|
||||
|
||||
device->setOrigin(ir.fLeft, ir.fTop);
|
||||
DeviceCM* layer = SkNEW_ARGS(DeviceCM, (device, ir.fLeft, ir.fTop, paint, this));
|
||||
DeviceCM* layer = SkNEW_ARGS(DeviceCM,
|
||||
(device, ir.fLeft, ir.fTop, paint, this, fConservativeRasterClip));
|
||||
device->unref();
|
||||
|
||||
layer->fNext = fMCRec->fTopLayer;
|
||||
|
@ -1286,7 +1322,7 @@ void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edg
|
|||
|
||||
fMCRec->fMatrix.mapRect(&r, rect);
|
||||
fClipStack.clipDevRect(r, op, kSoft_ClipEdgeStyle == edgeStyle);
|
||||
fMCRec->fRasterClip.op(r, op, kSoft_ClipEdgeStyle == edgeStyle);
|
||||
fMCRec->fRasterClip.op(r, this->getBaseLayerSize(), op, kSoft_ClipEdgeStyle == edgeStyle);
|
||||
} else {
|
||||
// since we're rotated or some such thing, we convert the rect to a path
|
||||
// and clip against that, since it can handle any matrix. However, to
|
||||
|
@ -1421,82 +1457,6 @@ void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edg
|
|||
rasterclip_path(&fMCRec->fRasterClip, this, devPath, op, edgeStyle);
|
||||
}
|
||||
|
||||
void SkCanvas::updateClipConservativelyUsingBounds(const SkRect& bounds, SkRegion::Op op,
|
||||
bool inverseFilled) {
|
||||
// This is for updating the clip conservatively using only bounds
|
||||
// information.
|
||||
// Contract:
|
||||
// The current clip must contain the true clip. The true
|
||||
// clip is the clip that would have normally been computed
|
||||
// by calls to clipPath and clipRRect
|
||||
// Objective:
|
||||
// Keep the current clip as small as possible without
|
||||
// breaking the contract, using only clip bounding rectangles
|
||||
// (for performance).
|
||||
|
||||
// N.B.: This *never* calls back through a virtual on canvas, so subclasses
|
||||
// don't have to worry about getting caught in a loop. Thus anywhere
|
||||
// we call a virtual method, we explicitly prefix it with
|
||||
// SkCanvas:: to be sure to call the base-class.
|
||||
|
||||
if (inverseFilled) {
|
||||
switch (op) {
|
||||
case SkRegion::kIntersect_Op:
|
||||
case SkRegion::kDifference_Op:
|
||||
// These ops can only shrink the current clip. So leaving
|
||||
// the clip unchanged conservatively respects the contract.
|
||||
break;
|
||||
case SkRegion::kUnion_Op:
|
||||
case SkRegion::kReplace_Op:
|
||||
case SkRegion::kReverseDifference_Op:
|
||||
case SkRegion::kXOR_Op: {
|
||||
// These ops can grow the current clip up to the extents of
|
||||
// the input clip, which is inverse filled, so we just set
|
||||
// the current clip to the device bounds.
|
||||
SkRect deviceBounds;
|
||||
SkIRect deviceIBounds;
|
||||
this->getDevice()->getGlobalBounds(&deviceIBounds);
|
||||
deviceBounds = SkRect::Make(deviceIBounds);
|
||||
|
||||
// set the clip in device space
|
||||
SkMatrix savedMatrix = this->getTotalMatrix();
|
||||
this->SkCanvas::setMatrix(SkMatrix::I());
|
||||
this->SkCanvas::onClipRect(deviceBounds, SkRegion::kReplace_Op,
|
||||
kHard_ClipEdgeStyle);
|
||||
this->setMatrix(savedMatrix);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
SkASSERT(0); // unhandled op?
|
||||
}
|
||||
} else {
|
||||
// Not inverse filled
|
||||
switch (op) {
|
||||
case SkRegion::kIntersect_Op:
|
||||
case SkRegion::kUnion_Op:
|
||||
case SkRegion::kReplace_Op:
|
||||
this->SkCanvas::onClipRect(bounds, op, kHard_ClipEdgeStyle);
|
||||
break;
|
||||
case SkRegion::kDifference_Op:
|
||||
// Difference can only shrink the current clip.
|
||||
// Leaving clip unchanged conservatively fullfills the contract.
|
||||
break;
|
||||
case SkRegion::kReverseDifference_Op:
|
||||
// To reverse, we swap in the bounds with a replace op.
|
||||
// As with difference, leave it unchanged.
|
||||
this->SkCanvas::onClipRect(bounds, SkRegion::kReplace_Op, kHard_ClipEdgeStyle);
|
||||
break;
|
||||
case SkRegion::kXOR_Op:
|
||||
// Be conservative, based on (A XOR B) always included in (A union B),
|
||||
// which is always included in (bounds(A) union bounds(B))
|
||||
this->SkCanvas::onClipRect(bounds, SkRegion::kUnion_Op, kHard_ClipEdgeStyle);
|
||||
break;
|
||||
default:
|
||||
SkASSERT(0); // unhandled op?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
|
||||
this->onClipRegion(rgn, op);
|
||||
}
|
||||
|
@ -1525,7 +1485,7 @@ void SkCanvas::validateClip() const {
|
|||
|
||||
SkIRect ir;
|
||||
ir.set(0, 0, device->width(), device->height());
|
||||
SkRasterClip tmpClip(ir);
|
||||
SkRasterClip tmpClip(ir, fConservativeRasterClip);
|
||||
|
||||
SkClipStack::B2TIter iter(fClipStack);
|
||||
const SkClipStack::Element* element;
|
||||
|
@ -1569,7 +1529,6 @@ bool SkCanvas::isClipRect() const {
|
|||
}
|
||||
|
||||
bool SkCanvas::quickReject(const SkRect& rect) const {
|
||||
|
||||
if (!rect.isFinite())
|
||||
return true;
|
||||
|
||||
|
|
|
@ -10,9 +10,10 @@
|
|||
SkDeviceLooper::SkDeviceLooper(const SkBitmap& base,
|
||||
const SkRasterClip& rc,
|
||||
const SkIRect& bounds, bool aa)
|
||||
: fBaseBitmap(base)
|
||||
, fBaseRC(rc)
|
||||
, fDelta(aa ? kAA_Delta : kBW_Delta)
|
||||
: fBaseBitmap(base)
|
||||
, fBaseRC(rc)
|
||||
, fSubsetRC(rc.isForceConservativeRects())
|
||||
, fDelta(aa ? kAA_Delta : kBW_Delta)
|
||||
{
|
||||
// sentinels that next() has not yet been called, and so our mapper functions
|
||||
// should not be called either.
|
||||
|
|
|
@ -788,7 +788,7 @@ size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool
|
|||
|
||||
void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
|
||||
this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
|
||||
this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
|
||||
this->INHERITED::onClipRRect(rrect, op, edgeStyle);
|
||||
}
|
||||
|
||||
size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
|
||||
|
@ -810,9 +810,7 @@ size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, b
|
|||
void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
|
||||
int pathID = this->addPathToHeap(path);
|
||||
this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
|
||||
|
||||
this->updateClipConservativelyUsingBounds(path.getBounds(), op,
|
||||
path.isInverseFillType());
|
||||
this->INHERITED::onClipPath(path, op, edgeStyle);
|
||||
}
|
||||
|
||||
size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
|
||||
|
|
|
@ -6,18 +6,12 @@
|
|||
*/
|
||||
|
||||
#include "SkRasterClip.h"
|
||||
|
||||
|
||||
SkRasterClip::SkRasterClip() {
|
||||
fIsBW = true;
|
||||
fIsEmpty = true;
|
||||
fIsRect = false;
|
||||
SkDEBUGCODE(this->validate();)
|
||||
}
|
||||
#include "SkPath.h"
|
||||
|
||||
SkRasterClip::SkRasterClip(const SkRasterClip& src) {
|
||||
AUTO_RASTERCLIP_VALIDATE(src);
|
||||
|
||||
fForceConservativeRects = src.fForceConservativeRects;
|
||||
fIsBW = src.fIsBW;
|
||||
if (fIsBW) {
|
||||
fBW = src.fBW;
|
||||
|
@ -30,13 +24,22 @@ SkRasterClip::SkRasterClip(const SkRasterClip& src) {
|
|||
SkDEBUGCODE(this->validate();)
|
||||
}
|
||||
|
||||
SkRasterClip::SkRasterClip(const SkIRect& bounds) : fBW(bounds) {
|
||||
SkRasterClip::SkRasterClip(const SkIRect& bounds, bool forceConservativeRects) : fBW(bounds) {
|
||||
fForceConservativeRects = forceConservativeRects;
|
||||
fIsBW = true;
|
||||
fIsEmpty = this->computeIsEmpty(); // bounds might be empty, so compute
|
||||
fIsRect = !fIsEmpty;
|
||||
SkDEBUGCODE(this->validate();)
|
||||
}
|
||||
|
||||
SkRasterClip::SkRasterClip(bool forceConservativeRects) {
|
||||
fForceConservativeRects = forceConservativeRects;
|
||||
fIsBW = true;
|
||||
fIsEmpty = true;
|
||||
fIsRect = false;
|
||||
SkDEBUGCODE(this->validate();)
|
||||
}
|
||||
|
||||
SkRasterClip::~SkRasterClip() {
|
||||
SkDEBUGCODE(this->validate();)
|
||||
}
|
||||
|
@ -70,9 +73,84 @@ bool SkRasterClip::setRect(const SkIRect& rect) {
|
|||
return fIsRect;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SkRasterClip::setConservativeRect(const SkRect& r, const SkIRect& clipR, bool isInverse) {
|
||||
SkIRect ir;
|
||||
r.roundOut(&ir);
|
||||
|
||||
SkRegion::Op op;
|
||||
if (isInverse) {
|
||||
op = SkRegion::kDifference_Op;
|
||||
} else {
|
||||
op = SkRegion::kIntersect_Op;
|
||||
}
|
||||
fBW.setRect(clipR);
|
||||
fBW.op(ir, op);
|
||||
return this->updateCacheAndReturnNonEmpty();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum MutateResult {
|
||||
kDoNothing_MutateResult,
|
||||
kReplaceClippedAgainstGlobalBounds_MutateResult,
|
||||
kContinue_MutateResult,
|
||||
};
|
||||
|
||||
static MutateResult mutate_conservative_op(SkRegion::Op* op, bool inverseFilled) {
|
||||
if (inverseFilled) {
|
||||
switch (*op) {
|
||||
case SkRegion::kIntersect_Op:
|
||||
case SkRegion::kDifference_Op:
|
||||
// These ops can only shrink the current clip. So leaving
|
||||
// the clip unchanged conservatively respects the contract.
|
||||
return kDoNothing_MutateResult;
|
||||
case SkRegion::kUnion_Op:
|
||||
case SkRegion::kReplace_Op:
|
||||
case SkRegion::kReverseDifference_Op:
|
||||
case SkRegion::kXOR_Op: {
|
||||
// These ops can grow the current clip up to the extents of
|
||||
// the input clip, which is inverse filled, so we just set
|
||||
// the current clip to the device bounds.
|
||||
*op = SkRegion::kReplace_Op;
|
||||
return kReplaceClippedAgainstGlobalBounds_MutateResult;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Not inverse filled
|
||||
switch (*op) {
|
||||
case SkRegion::kIntersect_Op:
|
||||
case SkRegion::kUnion_Op:
|
||||
case SkRegion::kReplace_Op:
|
||||
return kContinue_MutateResult;
|
||||
case SkRegion::kDifference_Op:
|
||||
// Difference can only shrink the current clip.
|
||||
// Leaving clip unchanged conservatively fullfills the contract.
|
||||
return kDoNothing_MutateResult;
|
||||
case SkRegion::kReverseDifference_Op:
|
||||
// To reverse, we swap in the bounds with a replace op.
|
||||
// As with difference, leave it unchanged.
|
||||
*op = SkRegion::kReplace_Op;
|
||||
return kContinue_MutateResult;
|
||||
case SkRegion::kXOR_Op:
|
||||
// Be conservative, based on (A XOR B) always included in (A union B),
|
||||
// which is always included in (bounds(A) union bounds(B))
|
||||
*op = SkRegion::kUnion_Op;
|
||||
return kContinue_MutateResult;
|
||||
}
|
||||
}
|
||||
SkFAIL("should not get here");
|
||||
return kDoNothing_MutateResult;
|
||||
}
|
||||
|
||||
bool SkRasterClip::setPath(const SkPath& path, const SkRegion& clip, bool doAA) {
|
||||
AUTO_RASTERCLIP_VALIDATE(*this);
|
||||
|
||||
if (fForceConservativeRects) {
|
||||
return this->setConservativeRect(path.getBounds(), clip.getBounds(), path.isInverseFillType());
|
||||
}
|
||||
|
||||
if (this->isBW() && !doAA) {
|
||||
(void)fBW.setPath(path, clip);
|
||||
} else {
|
||||
|
@ -90,7 +168,22 @@ bool SkRasterClip::op(const SkPath& path, const SkISize& size, SkRegion::Op op,
|
|||
// base is used to limit the size (and therefore memory allocation) of the
|
||||
// region that results from scan converting devPath.
|
||||
SkRegion base;
|
||||
|
||||
|
||||
if (fForceConservativeRects) {
|
||||
SkIRect ir;
|
||||
switch (mutate_conservative_op(&op, path.isInverseFillType())) {
|
||||
case kDoNothing_MutateResult:
|
||||
return !this->isEmpty();
|
||||
case kReplaceClippedAgainstGlobalBounds_MutateResult:
|
||||
ir = SkIRect::MakeSize(size);
|
||||
break;
|
||||
case kContinue_MutateResult:
|
||||
path.getBounds().roundOut(&ir);
|
||||
break;
|
||||
}
|
||||
return this->op(ir, op);
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -102,7 +195,7 @@ bool SkRasterClip::op(const SkPath& path, const SkISize& size, SkRegion::Op op,
|
|||
return this->setPath(path, this->bwRgn(), doAA);
|
||||
} else {
|
||||
base.setRect(this->getBounds());
|
||||
SkRasterClip clip;
|
||||
SkRasterClip clip(fForceConservativeRects);
|
||||
clip.setPath(path, base, doAA);
|
||||
return this->op(clip, op);
|
||||
}
|
||||
|
@ -112,7 +205,7 @@ bool SkRasterClip::op(const SkPath& path, const SkISize& size, SkRegion::Op op,
|
|||
if (SkRegion::kReplace_Op == op) {
|
||||
return this->setPath(path, base, doAA);
|
||||
} else {
|
||||
SkRasterClip clip;
|
||||
SkRasterClip clip(fForceConservativeRects);
|
||||
clip.setPath(path, base, doAA);
|
||||
return this->op(clip, op);
|
||||
}
|
||||
|
@ -182,9 +275,24 @@ static bool nearly_integral(SkScalar x) {
|
|||
return x - SkScalarFloorToScalar(x) < domain;
|
||||
}
|
||||
|
||||
bool SkRasterClip::op(const SkRect& r, SkRegion::Op op, bool doAA) {
|
||||
bool SkRasterClip::op(const SkRect& r, const SkISize& size, SkRegion::Op op, bool doAA) {
|
||||
AUTO_RASTERCLIP_VALIDATE(*this);
|
||||
|
||||
if (fForceConservativeRects) {
|
||||
SkIRect ir;
|
||||
switch (mutate_conservative_op(&op, false)) {
|
||||
case kDoNothing_MutateResult:
|
||||
return !this->isEmpty();
|
||||
case kReplaceClippedAgainstGlobalBounds_MutateResult:
|
||||
ir = SkIRect::MakeSize(size);
|
||||
break;
|
||||
case kContinue_MutateResult:
|
||||
r.roundOut(&ir);
|
||||
break;
|
||||
}
|
||||
return this->op(ir, op);
|
||||
}
|
||||
|
||||
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?
|
||||
|
@ -251,7 +359,9 @@ const SkRegion& SkRasterClip::forceGetBW() {
|
|||
|
||||
void SkRasterClip::convertToAA() {
|
||||
AUTO_RASTERCLIP_VALIDATE(*this);
|
||||
|
||||
|
||||
SkASSERT(!fForceConservativeRects);
|
||||
|
||||
SkASSERT(fIsBW);
|
||||
fAA.setRegion(fBW);
|
||||
fIsBW = false;
|
||||
|
|
|
@ -13,11 +13,13 @@
|
|||
|
||||
class SkRasterClip {
|
||||
public:
|
||||
SkRasterClip();
|
||||
SkRasterClip(const SkIRect&);
|
||||
SkRasterClip(bool forceConservativeRects = false);
|
||||
SkRasterClip(const SkIRect&, bool forceConservativeRects = false);
|
||||
SkRasterClip(const SkRasterClip&);
|
||||
~SkRasterClip();
|
||||
|
||||
bool isForceConservativeRects() const { return fForceConservativeRects; }
|
||||
|
||||
bool isBW() const { return fIsBW; }
|
||||
bool isAA() const { return !fIsBW; }
|
||||
const SkRegion& bwRgn() const { SkASSERT(fIsBW); return fBW; }
|
||||
|
@ -41,7 +43,7 @@ public:
|
|||
|
||||
bool op(const SkIRect&, SkRegion::Op);
|
||||
bool op(const SkRegion&, SkRegion::Op);
|
||||
bool op(const SkRect&, SkRegion::Op, bool doAA);
|
||||
bool op(const SkRect&, const SkISize&, SkRegion::Op, bool doAA);
|
||||
bool op(const SkPath&, const SkISize&, SkRegion::Op, bool doAA);
|
||||
|
||||
void translate(int dx, int dy, SkRasterClip* dst) const;
|
||||
|
@ -75,6 +77,7 @@ public:
|
|||
private:
|
||||
SkRegion fBW;
|
||||
SkAAClip fAA;
|
||||
bool fForceConservativeRects;
|
||||
bool fIsBW;
|
||||
// these 2 are caches based on querying the right obj based on fIsBW
|
||||
bool fIsEmpty;
|
||||
|
@ -107,6 +110,7 @@ private:
|
|||
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 {
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
// SkCanvas will fail in mysterious ways if it doesn't know the real width and height.
|
||||
SkRecorder::SkRecorder(SkRecord* record, int width, int height)
|
||||
: SkCanvas(width, height)
|
||||
: SkCanvas(width, height, SkCanvas::kConservativeRasterClip_InitFlag)
|
||||
, fRecord(record)
|
||||
, fSaveLayerCount(0) {}
|
||||
|
||||
|
@ -280,12 +280,12 @@ void SkRecorder::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle e
|
|||
}
|
||||
|
||||
void SkRecorder::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
|
||||
INHERITED(updateClipConservativelyUsingBounds, rrect.getBounds(), op, false);
|
||||
INHERITED(onClipRRect, rrect, op, edgeStyle);
|
||||
APPEND(ClipRRect, this->devBounds(), rrect, op, edgeStyle == kSoft_ClipEdgeStyle);
|
||||
}
|
||||
|
||||
void SkRecorder::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
|
||||
INHERITED(updateClipConservativelyUsingBounds, path.getBounds(), op, path.isInverseFillType());
|
||||
INHERITED(onClipPath, path, op, edgeStyle);
|
||||
APPEND(ClipPath, this->devBounds(), delay_copy(path), op, edgeStyle == kSoft_ClipEdgeStyle);
|
||||
}
|
||||
|
||||
|
|
|
@ -371,6 +371,7 @@ static bool operator==(const SkRasterClip& a, const SkRasterClip& b) {
|
|||
|
||||
static void did_dx_affect(skiatest::Reporter* reporter, const SkScalar dx[],
|
||||
size_t count, bool changed) {
|
||||
const SkISize baseSize = SkISize::Make(10, 10);
|
||||
SkIRect ir = { 0, 0, 10, 10 };
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
|
@ -381,11 +382,11 @@ static void did_dx_affect(skiatest::Reporter* reporter, const SkScalar dx[],
|
|||
SkRasterClip rc1(ir);
|
||||
SkRasterClip rc2(ir);
|
||||
|
||||
rc0.op(r, SkRegion::kIntersect_Op, false);
|
||||
rc0.op(r, baseSize, SkRegion::kIntersect_Op, false);
|
||||
r.offset(dx[i], 0);
|
||||
rc1.op(r, SkRegion::kIntersect_Op, true);
|
||||
rc1.op(r, baseSize, SkRegion::kIntersect_Op, true);
|
||||
r.offset(-2*dx[i], 0);
|
||||
rc2.op(r, SkRegion::kIntersect_Op, true);
|
||||
rc2.op(r, baseSize, SkRegion::kIntersect_Op, true);
|
||||
|
||||
REPORTER_ASSERT(reporter, changed != (rc0 == rc1));
|
||||
REPORTER_ASSERT(reporter, changed != (rc0 == rc2));
|
||||
|
|
|
@ -1570,8 +1570,8 @@ static void test_clip_bound_opt(skiatest::Reporter* reporter) {
|
|||
path2.addOval(rect3);
|
||||
SkIRect clipBounds;
|
||||
SkPictureRecorder recorder;
|
||||
// Minimalist test set for 100% code coverage of
|
||||
// SkPictureRecord::updateClipConservativelyUsingBounds
|
||||
|
||||
// Testing conservative-raster-clip that is enabled by PictureRecord
|
||||
{
|
||||
SkCanvas* canvas = recorder.beginRecording(10, 10);
|
||||
canvas->clipPath(invPath, SkRegion::kIntersect_Op);
|
||||
|
|
Загрузка…
Ссылка в новой задаче