/*
|
* Copyright 2010 Google Inc.
|
*
|
* Use of this source code is governed by a BSD-style license that can be
|
* found in the LICENSE file.
|
*/
|
|
#ifndef SkRasterClip_DEFINED
|
#define SkRasterClip_DEFINED
|
|
#include "SkAAClip.h"
|
#include "SkMacros.h"
|
#include "SkRegion.h"
|
|
class SkRRect;
|
|
class SkConservativeClip {
|
SkIRect fBounds;
|
const SkIRect* fClipRestrictionRect;
|
|
inline void applyClipRestriction(SkRegion::Op op, SkIRect* bounds) {
|
if (op >= SkRegion::kUnion_Op && fClipRestrictionRect
|
&& !fClipRestrictionRect->isEmpty()) {
|
if (!bounds->intersect(*fClipRestrictionRect)) {
|
bounds->setEmpty();
|
}
|
}
|
}
|
|
public:
|
SkConservativeClip() : fBounds(SkIRect::MakeEmpty()), fClipRestrictionRect(nullptr) {}
|
|
bool isEmpty() const { return fBounds.isEmpty(); }
|
bool isRect() const { return true; }
|
const SkIRect& getBounds() const { return fBounds; }
|
|
void setEmpty() { fBounds.setEmpty(); }
|
void setRect(const SkIRect& r) { fBounds = r; }
|
void setDeviceClipRestriction(const SkIRect* rect) {
|
fClipRestrictionRect = rect;
|
}
|
|
void opRect(const SkRect&, const SkMatrix&, const SkIRect& limit, SkRegion::Op, bool isAA);
|
void opRRect(const SkRRect&, const SkMatrix&, const SkIRect& limit, SkRegion::Op, bool isAA);
|
void opPath(const SkPath&, const SkMatrix&, const SkIRect& limit, SkRegion::Op, bool isAA);
|
void opRegion(const SkRegion&, SkRegion::Op);
|
void opIRect(const SkIRect&, SkRegion::Op);
|
};
|
|
/**
|
* 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();
|
SkRasterClip(const SkIRect&);
|
SkRasterClip(const SkRegion&);
|
SkRasterClip(const SkRasterClip&);
|
~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);
|
}
|
|
bool isBW() const { return fIsBW; }
|
bool isAA() const { return !fIsBW; }
|
const SkRegion& bwRgn() const { SkASSERT(fIsBW); return fBW; }
|
const SkAAClip& aaRgn() const { SkASSERT(!fIsBW); return fAA; }
|
|
bool isEmpty() const {
|
SkASSERT(this->computeIsEmpty() == fIsEmpty);
|
return fIsEmpty;
|
}
|
|
bool isRect() const {
|
SkASSERT(this->computeIsRect() == fIsRect);
|
return fIsRect;
|
}
|
|
bool isComplex() const;
|
const SkIRect& getBounds() const;
|
|
bool setEmpty();
|
bool setRect(const SkIRect&);
|
|
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);
|
|
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;
|
bool quickContains(int left, int top, int right, int bottom) const {
|
return quickContains(SkIRect::MakeLTRB(left, top, right, bottom));
|
}
|
|
/**
|
* Return true if this region is empty, or if the specified rectangle does
|
* not intersect the region. Returning false is not a guarantee that they
|
* intersect, but returning true is a guarantee that they do not.
|
*/
|
bool quickReject(const SkIRect& rect) const {
|
return !SkIRect::Intersects(this->getBounds(), rect);
|
}
|
|
// hack for SkCanvas::getTotalClip
|
const SkRegion& forceGetBW();
|
|
#ifdef SK_DEBUG
|
void validate() const;
|
#else
|
void validate() const {}
|
#endif
|
|
void setDeviceClipRestriction(const SkIRect* rect) {
|
fClipRestrictionRect = rect;
|
}
|
|
private:
|
SkRegion fBW;
|
SkAAClip fAA;
|
bool fIsBW;
|
// these 2 are caches based on querying the right obj based on fIsBW
|
bool fIsEmpty;
|
bool fIsRect;
|
const SkIRect* fClipRestrictionRect = nullptr;
|
|
bool computeIsEmpty() const {
|
return fIsBW ? fBW.isEmpty() : fAA.isEmpty();
|
}
|
|
bool computeIsRect() const {
|
return fIsBW ? fBW.isRect() : fAA.isRect();
|
}
|
|
bool updateCacheAndReturnNonEmpty(bool detectAARect = true) {
|
fIsEmpty = this->computeIsEmpty();
|
|
// detect that our computed AA is really just a (hard-edged) rect
|
if (detectAARect && !fIsEmpty && !fIsBW && fAA.isRect()) {
|
fBW.setRect(fAA.getBounds());
|
fAA.setEmpty(); // don't need this guy anymore
|
fIsBW = true;
|
}
|
|
fIsRect = this->computeIsRect();
|
return !fIsEmpty;
|
}
|
|
void convertToAA();
|
|
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);
|
|
inline void applyClipRestriction(SkRegion::Op op, SkIRect* bounds) {
|
if (op >= SkRegion::kUnion_Op && fClipRestrictionRect
|
&& !fClipRestrictionRect->isEmpty()) {
|
if (!bounds->intersect(*fClipRestrictionRect)) {
|
bounds->setEmpty();
|
}
|
}
|
}
|
|
inline void applyClipRestriction(SkRegion::Op op, SkRect* bounds) {
|
if (op >= SkRegion::kUnion_Op && fClipRestrictionRect
|
&& !fClipRestrictionRect->isEmpty()) {
|
if (!bounds->intersect(SkRect::Make(*fClipRestrictionRect))) {
|
bounds->setEmpty();
|
}
|
}
|
}
|
};
|
|
class SkAutoRasterClipValidate : SkNoncopyable {
|
public:
|
SkAutoRasterClipValidate(const SkRasterClip& rc) : fRC(rc) {
|
fRC.validate();
|
}
|
~SkAutoRasterClipValidate() {
|
fRC.validate();
|
}
|
private:
|
const SkRasterClip& fRC;
|
};
|
#define SkAutoRasterClipValidate(...) SK_REQUIRE_LOCAL_VAR(SkAutoRasterClipValidate)
|
|
#ifdef SK_DEBUG
|
#define AUTO_RASTERCLIP_VALIDATE(rc) SkAutoRasterClipValidate arcv(rc)
|
#else
|
#define AUTO_RASTERCLIP_VALIDATE(rc)
|
#endif
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
/**
|
* Encapsulates the logic of deciding if we need to change/wrap the blitter
|
* for aaclipping. If so, getRgn and getBlitter return modified values. If
|
* not, they return the raw blitter and (bw) clip region.
|
*
|
* We need to keep the constructor/destructor cost as small as possible, so we
|
* can freely put this guy on the stack, and not pay too much for the case when
|
* we're really BW anyways.
|
*/
|
class SkAAClipBlitterWrapper {
|
public:
|
SkAAClipBlitterWrapper();
|
SkAAClipBlitterWrapper(const SkRasterClip&, SkBlitter*);
|
SkAAClipBlitterWrapper(const SkAAClip*, SkBlitter*);
|
|
void init(const SkRasterClip&, SkBlitter*);
|
|
const SkIRect& getBounds() const {
|
SkASSERT(fClipRgn);
|
return fClipRgn->getBounds();
|
}
|
const SkRegion& getRgn() const {
|
SkASSERT(fClipRgn);
|
return *fClipRgn;
|
}
|
SkBlitter* getBlitter() {
|
SkASSERT(fBlitter);
|
return fBlitter;
|
}
|
|
private:
|
SkRegion fBWRgn;
|
SkAAClipBlitter fAABlitter;
|
// what we return
|
const SkRegion* fClipRgn;
|
SkBlitter* fBlitter;
|
};
|
|
#endif
|