Rename methods and enum on SkClipStack::Element to indicate "device space"

Change-Id: I83056843b530f76590f755f97e3d0a5a58f371fa
Reviewed-on: https://skia-review.googlesource.com/39402
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Brian Salomon 2017-08-30 11:37:57 -04:00 committed by Skia Commit-Bot
parent f9810666bd
commit f3b46e5193
8 changed files with 275 additions and 246 deletions

View File

@ -79,17 +79,17 @@ void WindowRectanglesGM::onCoverClipStack(const SkClipStack& stack, SkCanvas* ca
for (const SkClipStack::Element* element = iter.next(); element; element = iter.next()) {
SkClipOp op = element->getOp();
bool isAA = element->isAA();
switch (element->getType()) {
case SkClipStack::Element::kPath_Type:
canvas->clipPath(element->getPath(), op, isAA);
switch (element->getDeviceSpaceType()) {
case SkClipStack::Element::DeviceSpaceType::kPath:
canvas->clipPath(element->getDeviceSpacePath(), op, isAA);
break;
case SkClipStack::Element::kRRect_Type:
canvas->clipRRect(element->getRRect(), op, isAA);
case SkClipStack::Element::DeviceSpaceType::kRRect:
canvas->clipRRect(element->getDeviceSpaceRRect(), op, isAA);
break;
case SkClipStack::Element::kRect_Type:
canvas->clipRect(element->getRect(), op, isAA);
case SkClipStack::Element::DeviceSpaceType::kRect:
canvas->clipRect(element->getDeviceSpaceRect(), op, isAA);
break;
case SkClipStack::Element::kEmpty_Type:
case SkClipStack::Element::DeviceSpaceType::kEmpty:
canvas->clipRect({ 0, 0, 0, 0 }, kIntersect_SkClipOp, false);
break;
}

View File

@ -20,24 +20,24 @@ static const int32_t kFirstUnreservedGenID = 3;
int32_t SkClipStack::gGenID = kFirstUnreservedGenID;
SkClipStack::Element::Element(const Element& that) {
switch (that.getType()) {
case kEmpty_Type:
fRRect.setEmpty();
fPath.reset();
switch (that.getDeviceSpaceType()) {
case DeviceSpaceType::kEmpty:
fDeviceSpaceRRect.setEmpty();
fDeviceSpacePath.reset();
break;
case kRect_Type: // Rect uses rrect
case kRRect_Type:
fPath.reset();
fRRect = that.fRRect;
case DeviceSpaceType::kRect: // Rect uses rrect
case DeviceSpaceType::kRRect:
fDeviceSpacePath.reset();
fDeviceSpaceRRect = that.fDeviceSpaceRRect;
break;
case kPath_Type:
fPath.set(that.getPath());
case DeviceSpaceType::kPath:
fDeviceSpacePath.set(that.getDeviceSpacePath());
break;
}
fSaveCount = that.fSaveCount;
fOp = that.fOp;
fType = that.fType;
fDeviceSpaceType = that.fDeviceSpaceType;
fDoAA = that.fDoAA;
fFiniteBoundType = that.fFiniteBoundType;
fFiniteBound = that.fFiniteBound;
@ -49,20 +49,18 @@ bool SkClipStack::Element::operator== (const Element& element) const {
if (this == &element) {
return true;
}
if (fOp != element.fOp ||
fType != element.fType ||
fDoAA != element.fDoAA ||
fSaveCount != element.fSaveCount) {
if (fOp != element.fOp || fDeviceSpaceType != element.fDeviceSpaceType ||
fDoAA != element.fDoAA || fSaveCount != element.fSaveCount) {
return false;
}
switch (fType) {
case kPath_Type:
return this->getPath() == element.getPath();
case kRRect_Type:
return fRRect == element.fRRect;
case kRect_Type:
return this->getRect() == element.getRect();
case kEmpty_Type:
switch (fDeviceSpaceType) {
case DeviceSpaceType::kPath:
return this->getDeviceSpacePath() == element.getDeviceSpacePath();
case DeviceSpaceType::kRRect:
return fDeviceSpaceRRect == element.fDeviceSpaceRRect;
case DeviceSpaceType::kRect:
return this->getDeviceSpaceRect() == element.getDeviceSpaceRect();
case DeviceSpaceType::kEmpty:
return true;
default:
SkDEBUGFAIL("Unexpected type.");
@ -72,13 +70,13 @@ bool SkClipStack::Element::operator== (const Element& element) const {
const SkRect& SkClipStack::Element::getBounds() const {
static const SkRect kEmpty = {0, 0, 0, 0};
switch (fType) {
case kRect_Type: // fallthrough
case kRRect_Type:
return fRRect.getBounds();
case kPath_Type:
return fPath.get()->getBounds();
case kEmpty_Type:
switch (fDeviceSpaceType) {
case DeviceSpaceType::kRect: // fallthrough
case DeviceSpaceType::kRRect:
return fDeviceSpaceRRect.getBounds();
case DeviceSpaceType::kPath:
return fDeviceSpacePath.get()->getBounds();
case DeviceSpaceType::kEmpty:
return kEmpty;
default:
SkDEBUGFAIL("Unexpected type.");
@ -87,14 +85,14 @@ const SkRect& SkClipStack::Element::getBounds() const {
}
bool SkClipStack::Element::contains(const SkRect& rect) const {
switch (fType) {
case kRect_Type:
return this->getRect().contains(rect);
case kRRect_Type:
return fRRect.contains(rect);
case kPath_Type:
return fPath.get()->conservativelyContainsRect(rect);
case kEmpty_Type:
switch (fDeviceSpaceType) {
case DeviceSpaceType::kRect:
return this->getDeviceSpaceRect().contains(rect);
case DeviceSpaceType::kRRect:
return fDeviceSpaceRRect.contains(rect);
case DeviceSpaceType::kPath:
return fDeviceSpacePath.get()->conservativelyContainsRect(rect);
case DeviceSpaceType::kEmpty:
return false;
default:
SkDEBUGFAIL("Unexpected type.");
@ -103,15 +101,15 @@ bool SkClipStack::Element::contains(const SkRect& rect) const {
}
bool SkClipStack::Element::contains(const SkRRect& rrect) const {
switch (fType) {
case kRect_Type:
return this->getRect().contains(rrect.getBounds());
case kRRect_Type:
switch (fDeviceSpaceType) {
case DeviceSpaceType::kRect:
return this->getDeviceSpaceRect().contains(rrect.getBounds());
case DeviceSpaceType::kRRect:
// We don't currently have a generalized rrect-rrect containment.
return fRRect.contains(rrect.getBounds()) || rrect == fRRect;
case kPath_Type:
return fPath.get()->conservativelyContainsRect(rrect.getBounds());
case kEmpty_Type:
return fDeviceSpaceRRect.contains(rrect.getBounds()) || rrect == fDeviceSpaceRRect;
case DeviceSpaceType::kPath:
return fDeviceSpacePath.get()->conservativelyContainsRect(rrect.getBounds());
case DeviceSpaceType::kEmpty:
return false;
default:
SkDEBUGFAIL("Unexpected type.");
@ -120,23 +118,23 @@ bool SkClipStack::Element::contains(const SkRRect& rrect) const {
}
void SkClipStack::Element::invertShapeFillType() {
switch (fType) {
case kRect_Type:
fPath.init();
fPath.get()->addRect(this->getRect());
fPath.get()->setFillType(SkPath::kInverseEvenOdd_FillType);
fType = kPath_Type;
switch (fDeviceSpaceType) {
case DeviceSpaceType::kRect:
fDeviceSpacePath.init();
fDeviceSpacePath.get()->addRect(this->getDeviceSpaceRect());
fDeviceSpacePath.get()->setFillType(SkPath::kInverseEvenOdd_FillType);
fDeviceSpaceType = DeviceSpaceType::kPath;
break;
case kRRect_Type:
fPath.init();
fPath.get()->addRRect(fRRect);
fPath.get()->setFillType(SkPath::kInverseEvenOdd_FillType);
fType = kPath_Type;
case DeviceSpaceType::kRRect:
fDeviceSpacePath.init();
fDeviceSpacePath.get()->addRRect(fDeviceSpaceRRect);
fDeviceSpacePath.get()->setFillType(SkPath::kInverseEvenOdd_FillType);
fDeviceSpaceType = DeviceSpaceType::kPath;
break;
case kPath_Type:
fPath.get()->toggleInverseFillType();
case DeviceSpaceType::kPath:
fDeviceSpacePath.get()->toggleInverseFillType();
break;
case kEmpty_Type:
case DeviceSpaceType::kEmpty:
// Should this set to an empty, inverse filled path?
break;
}
@ -159,8 +157,8 @@ void SkClipStack::Element::initRect(int saveCount, const SkRect& rect, const SkM
if (m.rectStaysRect()) {
SkRect devRect;
m.mapRect(&devRect, rect);
fRRect.setRect(devRect);
fType = kRect_Type;
fDeviceSpaceRRect.setRect(devRect);
fDeviceSpaceType = DeviceSpaceType::kRect;
this->initCommon(saveCount, op, doAA);
return;
}
@ -172,12 +170,12 @@ void SkClipStack::Element::initRect(int saveCount, const SkRect& rect, const SkM
void SkClipStack::Element::initRRect(int saveCount, const SkRRect& rrect, const SkMatrix& m,
SkClipOp op, bool doAA) {
if (rrect.transform(m, &fRRect)) {
SkRRect::Type type = fRRect.getType();
if (rrect.transform(m, &fDeviceSpaceRRect)) {
SkRRect::Type type = fDeviceSpaceRRect.getType();
if (SkRRect::kRect_Type == type || SkRRect::kEmpty_Type == type) {
fType = kRect_Type;
fDeviceSpaceType = DeviceSpaceType::kRect;
} else {
fType = kRRect_Type;
fDeviceSpaceType = DeviceSpaceType::kRRect;
}
this->initCommon(saveCount, op, doAA);
return;
@ -209,42 +207,42 @@ void SkClipStack::Element::initPath(int saveCount, const SkPath& path, const SkM
void SkClipStack::Element::initAsPath(int saveCount, const SkPath& path, const SkMatrix& m,
SkClipOp op, bool doAA) {
path.transform(m, fPath.init());
fPath.get()->setIsVolatile(true);
fType = kPath_Type;
path.transform(m, fDeviceSpacePath.init());
fDeviceSpacePath.get()->setIsVolatile(true);
fDeviceSpaceType = DeviceSpaceType::kPath;
this->initCommon(saveCount, op, doAA);
}
void SkClipStack::Element::asPath(SkPath* path) const {
switch (fType) {
case kEmpty_Type:
void SkClipStack::Element::asDeviceSpacePath(SkPath* path) const {
switch (fDeviceSpaceType) {
case DeviceSpaceType::kEmpty:
path->reset();
path->setIsVolatile(true);
break;
case kRect_Type:
case DeviceSpaceType::kRect:
path->reset();
path->addRect(this->getRect());
path->addRect(this->getDeviceSpaceRect());
path->setIsVolatile(true);
break;
case kRRect_Type:
case DeviceSpaceType::kRRect:
path->reset();
path->addRRect(fRRect);
path->addRRect(fDeviceSpaceRRect);
path->setIsVolatile(true);
break;
case kPath_Type:
*path = *fPath.get();
case DeviceSpaceType::kPath:
*path = *fDeviceSpacePath.get();
break;
}
path->setIsVolatile(true);
}
void SkClipStack::Element::setEmpty() {
fType = kEmpty_Type;
fDeviceSpaceType = DeviceSpaceType::kEmpty;
fFiniteBound.setEmpty();
fFiniteBoundType = kNormal_BoundsType;
fIsIntersectionOfRects = false;
fRRect.setEmpty();
fPath.reset();
fDeviceSpaceRRect.setEmpty();
fDeviceSpacePath.reset();
fGenID = kEmptyGenID;
SkDEBUGCODE(this->checkEmpty();)
}
@ -254,12 +252,12 @@ void SkClipStack::Element::checkEmpty() const {
SkASSERT(kNormal_BoundsType == fFiniteBoundType);
SkASSERT(!fIsIntersectionOfRects);
SkASSERT(kEmptyGenID == fGenID);
SkASSERT(fRRect.isEmpty());
SkASSERT(!fPath.isValid());
SkASSERT(fDeviceSpaceRRect.isEmpty());
SkASSERT(!fDeviceSpacePath.isValid());
}
bool SkClipStack::Element::canBeIntersectedInPlace(int saveCount, SkClipOp op) const {
if (kEmpty_Type == fType &&
if (DeviceSpaceType::kEmpty == fDeviceSpaceType &&
(kDifference_SkClipOp == op || kIntersect_SkClipOp == op)) {
return true;
}
@ -271,19 +269,19 @@ bool SkClipStack::Element::canBeIntersectedInPlace(int saveCount, SkClipOp op) c
}
bool SkClipStack::Element::rectRectIntersectAllowed(const SkRect& newR, bool newAA) const {
SkASSERT(kRect_Type == fType);
SkASSERT(DeviceSpaceType::kRect == fDeviceSpaceType);
if (fDoAA == newAA) {
// if the AA setting is the same there is no issue
return true;
}
if (!SkRect::Intersects(this->getRect(), newR)) {
if (!SkRect::Intersects(this->getDeviceSpaceRect(), newR)) {
// The calling code will correctly set the result to the empty clip
return true;
}
if (this->getRect().contains(newR)) {
if (this->getDeviceSpaceRect().contains(newR)) {
// if the new rect carves out a portion of the old one there is no
// issue
return true;
@ -476,32 +474,31 @@ void SkClipStack::Element::updateBoundAndGenID(const Element* prior) {
// First, optimistically update the current Element's bound information
// with the current clip's bound
fIsIntersectionOfRects = false;
switch (fType) {
case kRect_Type:
fFiniteBound = this->getRect();
switch (fDeviceSpaceType) {
case DeviceSpaceType::kRect:
fFiniteBound = this->getDeviceSpaceRect();
fFiniteBoundType = kNormal_BoundsType;
if (kReplace_SkClipOp == fOp ||
(kIntersect_SkClipOp == fOp && nullptr == prior) ||
if (kReplace_SkClipOp == fOp || (kIntersect_SkClipOp == fOp && nullptr == prior) ||
(kIntersect_SkClipOp == fOp && prior->fIsIntersectionOfRects &&
prior->rectRectIntersectAllowed(this->getRect(), fDoAA))) {
prior->rectRectIntersectAllowed(this->getDeviceSpaceRect(), fDoAA))) {
fIsIntersectionOfRects = true;
}
break;
case kRRect_Type:
fFiniteBound = fRRect.getBounds();
case DeviceSpaceType::kRRect:
fFiniteBound = fDeviceSpaceRRect.getBounds();
fFiniteBoundType = kNormal_BoundsType;
break;
case kPath_Type:
fFiniteBound = fPath.get()->getBounds();
case DeviceSpaceType::kPath:
fFiniteBound = fDeviceSpacePath.get()->getBounds();
if (fPath.get()->isInverseFillType()) {
if (fDeviceSpacePath.get()->isInverseFillType()) {
fFiniteBoundType = kInsideOut_BoundsType;
} else {
fFiniteBoundType = kNormal_BoundsType;
}
break;
case kEmpty_Type:
case DeviceSpaceType::kEmpty:
SkDEBUGFAIL("We shouldn't get here with an empty element.");
break;
}
@ -763,8 +760,8 @@ bool SkClipStack::asPath(SkPath *path) const {
SkClipStack::Iter iter(*this, SkClipStack::Iter::kBottom_IterStart);
while (const SkClipStack::Element* element = iter.next()) {
SkPath operand;
if (element->getType() != SkClipStack::Element::kEmpty_Type) {
element->asPath(&operand);
if (element->getDeviceSpaceType() != SkClipStack::Element::DeviceSpaceType::kEmpty) {
element->asDeviceSpacePath(&operand);
}
SkClipOp elementOp = element->getOp();
@ -790,20 +787,22 @@ void SkClipStack::pushElement(const Element& element) {
if (prior) {
if (prior->canBeIntersectedInPlace(fSaveCount, element.getOp())) {
switch (prior->fType) {
case Element::kEmpty_Type:
switch (prior->fDeviceSpaceType) {
case Element::DeviceSpaceType::kEmpty:
SkDEBUGCODE(prior->checkEmpty();)
return;
case Element::kRect_Type:
if (Element::kRect_Type == element.getType()) {
if (prior->rectRectIntersectAllowed(element.getRect(), element.isAA())) {
case Element::DeviceSpaceType::kRect:
if (Element::DeviceSpaceType::kRect == element.getDeviceSpaceType()) {
if (prior->rectRectIntersectAllowed(element.getDeviceSpaceRect(),
element.isAA())) {
SkRect isectRect;
if (!isectRect.intersect(prior->getRect(), element.getRect())) {
if (!isectRect.intersect(prior->getDeviceSpaceRect(),
element.getDeviceSpaceRect())) {
prior->setEmpty();
return;
}
prior->fRRect.setRect(isectRect);
prior->fDeviceSpaceRRect.setRect(isectRect);
prior->fDoAA = element.isAA();
Element* priorPrior = (Element*) iter.prev();
prior->updateBoundAndGenID(priorPrior);
@ -971,19 +970,19 @@ bool SkClipStack::isRRect(const SkRect& bounds, SkRRect* rrect, bool* aa) const
return false;
}
const Element* back = static_cast<const Element*>(fDeque.back());
if (back->getType() != SkClipStack::Element::kRect_Type &&
back->getType() != SkClipStack::Element::kRRect_Type) {
if (back->getDeviceSpaceType() != SkClipStack::Element::DeviceSpaceType::kRect &&
back->getDeviceSpaceType() != SkClipStack::Element::DeviceSpaceType::kRRect) {
return false;
}
if (back->getOp() == kReplace_SkClipOp) {
*rrect = back->asRRect();
*rrect = back->asDeviceSpaceRRect();
*aa = back->isAA();
return true;
}
if (back->getOp() == kIntersect_SkClipOp) {
SkRect backBounds;
if (!backBounds.intersect(bounds, back->asRRect().rect())) {
if (!backBounds.intersect(bounds, back->asDeviceSpaceRRect().rect())) {
return false;
}
if (cnt > 1) {
@ -1000,7 +999,7 @@ bool SkClipStack::isRRect(const SkRect& bounds, SkRRect* rrect, bool* aa) const
}
}
}
*rrect = back->asRRect();
*rrect = back->asDeviceSpaceRRect();
*aa = back->isAA();
return true;
}
@ -1036,11 +1035,11 @@ void SkClipStack::Element::dump() const {
"rrect",
"path"
};
static_assert(0 == kEmpty_Type, "type_str");
static_assert(1 == kRect_Type, "type_str");
static_assert(2 == kRRect_Type, "type_str");
static_assert(3 == kPath_Type, "type_str");
static_assert(SK_ARRAY_COUNT(kTypeStrings) == kTypeCnt, "type_str");
static_assert(0 == static_cast<int>(DeviceSpaceType::kEmpty), "enum mismatch");
static_assert(1 == static_cast<int>(DeviceSpaceType::kRect), "enum mismatch");
static_assert(2 == static_cast<int>(DeviceSpaceType::kRRect), "enum mismatch");
static_assert(3 == static_cast<int>(DeviceSpaceType::kPath), "enum mismatch");
static_assert(SK_ARRAY_COUNT(kTypeStrings) == kTypeCnt, "enum mismatch");
static const char* kOpStrings[] = {
"difference",
@ -1050,30 +1049,30 @@ void SkClipStack::Element::dump() const {
"reverse-difference",
"replace",
};
static_assert(0 == static_cast<int>(kDifference_SkClipOp), "op_str");
static_assert(1 == static_cast<int>(kIntersect_SkClipOp), "op_str");
static_assert(2 == static_cast<int>(kUnion_SkClipOp), "op_str");
static_assert(3 == static_cast<int>(kXOR_SkClipOp), "op_str");
static_assert(4 == static_cast<int>(kReverseDifference_SkClipOp), "op_str");
static_assert(5 == static_cast<int>(kReplace_SkClipOp), "op_str");
static_assert(SK_ARRAY_COUNT(kOpStrings) == SkRegion::kOpCnt, "op_str");
static_assert(0 == static_cast<int>(kDifference_SkClipOp), "enum mismatch");
static_assert(1 == static_cast<int>(kIntersect_SkClipOp), "enum mismatch");
static_assert(2 == static_cast<int>(kUnion_SkClipOp), "enum mismatch");
static_assert(3 == static_cast<int>(kXOR_SkClipOp), "enum mismatch");
static_assert(4 == static_cast<int>(kReverseDifference_SkClipOp), "enum mismatch");
static_assert(5 == static_cast<int>(kReplace_SkClipOp), "enum mismatch");
static_assert(SK_ARRAY_COUNT(kOpStrings) == SkRegion::kOpCnt, "enum mismatch");
SkDebugf("Type: %s, Op: %s, AA: %s, Save Count: %d\n", kTypeStrings[fType],
SkDebugf("Type: %s, Op: %s, AA: %s, Save Count: %d\n", kTypeStrings[(int)fDeviceSpaceType],
kOpStrings[static_cast<int>(fOp)], (fDoAA ? "yes" : "no"), fSaveCount);
switch (fType) {
case kEmpty_Type:
switch (fDeviceSpaceType) {
case DeviceSpaceType::kEmpty:
SkDebugf("\n");
break;
case kRect_Type:
this->getRect().dump();
case DeviceSpaceType::kRect:
this->getDeviceSpaceRect().dump();
SkDebugf("\n");
break;
case kRRect_Type:
this->getRRect().dump();
case DeviceSpaceType::kRRect:
this->getDeviceSpaceRRect().dump();
SkDebugf("\n");
break;
case kPath_Type:
this->getPath().dump(nullptr, true, false);
case DeviceSpaceType::kPath:
this->getDeviceSpacePath().dump(nullptr, true, false);
break;
}
}

View File

@ -41,21 +41,26 @@ public:
kInsideOut_BoundsType
};
/**
* An element of the clip stack. It represents a shape combined with the prevoius clip using a
* set operator. Each element can be antialiased or not.
*/
class Element {
public:
enum Type {
/** This indicates the shape type of the clip element in device space. */
enum class DeviceSpaceType {
//!< This element makes the clip empty (regardless of previous elements).
kEmpty_Type,
//!< This element combines a rect with the current clip using a set operation
kRect_Type,
//!< This element combines a round-rect with the current clip using a set operation
kRRect_Type,
//!< This element combines a path with the current clip using a set operation
kPath_Type,
kEmpty,
//!< This element combines a device space rect with the current clip.
kRect,
//!< This element combines a device space round-rect with the current clip.
kRRect,
//!< This element combines a device space path with the current clip.
kPath,
kLastType = kPath_Type
kLastType = kPath
};
static const int kTypeCnt = kLastType + 1;
static const int kTypeCnt = (int)DeviceSpaceType::kLastType + 1;
Element() {
this->initCommon(0, kReplace_SkClipOp, false);
@ -88,31 +93,42 @@ public:
bool operator!= (const Element& element) const { return !(*this == element); }
//!< Call to get the type of the clip element.
Type getType() const { return fType; }
DeviceSpaceType getDeviceSpaceType() const { return fDeviceSpaceType; }
//!< Call to get the save count associated with this clip element.
int getSaveCount() const { return fSaveCount; }
//!< Call if getType() is kPath to get the path.
const SkPath& getPath() const { SkASSERT(kPath_Type == fType); return *fPath.get(); }
//!< Call if getType() is kRRect to get the round-rect.
const SkRRect& getRRect() const { SkASSERT(kRRect_Type == fType); return fRRect; }
//!< Call if getType() is kRect to get the rect.
const SkRect& getRect() const {
SkASSERT(kRect_Type == fType && (fRRect.isRect() || fRRect.isEmpty()));
return fRRect.getBounds();
//!< Call if getDeviceSpaceType() is kPath to get the path.
const SkPath& getDeviceSpacePath() const {
SkASSERT(DeviceSpaceType::kPath == fDeviceSpaceType);
return *fDeviceSpacePath.get();
}
//!< Call if getType() is not kEmpty to get the set operation used to combine this element.
//!< Call if getDeviceSpaceType() is kRRect to get the round-rect.
const SkRRect& getDeviceSpaceRRect() const {
SkASSERT(DeviceSpaceType::kRRect == fDeviceSpaceType);
return fDeviceSpaceRRect;
}
//!< Call if getDeviceSpaceType() is kRect to get the rect.
const SkRect& getDeviceSpaceRect() const {
SkASSERT(DeviceSpaceType::kRect == fDeviceSpaceType &&
(fDeviceSpaceRRect.isRect() || fDeviceSpaceRRect.isEmpty()));
return fDeviceSpaceRRect.getBounds();
}
//!< Call if getDeviceSpaceType() is not kEmpty to get the set operation used to combine
//!< this element.
SkClipOp getOp() const { return fOp; }
//!< Call to get the element as a path, regardless of its type.
void asPath(SkPath* path) const;
void asDeviceSpacePath(SkPath* path) const;
//!< Call if getType() is not kPath to get the element as a round rect.
const SkRRect& asRRect() const { SkASSERT(kPath_Type != fType); return fRRect; }
const SkRRect& asDeviceSpaceRRect() const {
SkASSERT(DeviceSpaceType::kPath != fDeviceSpaceType);
return fDeviceSpaceRRect;
}
/** If getType() is not kEmpty this indicates whether the clip shape should be anti-aliased
when it is rasterized. */
@ -148,7 +164,8 @@ public:
* Is the clip shape inverse filled.
*/
bool isInverseFilled() const {
return kPath_Type == fType && fPath.get()->isInverseFillType();
return DeviceSpaceType::kPath == fDeviceSpaceType &&
fDeviceSpacePath.get()->isInverseFillType();
}
#ifdef SK_DEBUG
@ -173,11 +190,11 @@ public:
private:
friend class SkClipStack;
SkTLazy<SkPath> fPath;
SkRRect fRRect;
SkTLazy<SkPath> fDeviceSpacePath;
SkRRect fDeviceSpaceRRect;
int fSaveCount; // save count of stack when this element was added.
SkClipOp fOp;
Type fType;
DeviceSpaceType fDeviceSpaceType;
bool fDoAA;
/* fFiniteBoundType and fFiniteBound are used to incrementally update the clip stack's

View File

@ -90,7 +90,7 @@ bool GrClipStackClip::PathNeedsSWRenderer(GrContext* context,
const Element* element,
GrPathRenderer** prOut,
bool needsStencil) {
if (Element::kRect_Type == element->getType()) {
if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) {
// rects can always be drawn directly w/o using the software path
// TODO: skip rrects once we're drawing them directly.
if (prOut) {
@ -99,11 +99,11 @@ bool GrClipStackClip::PathNeedsSWRenderer(GrContext* context,
return false;
} else {
// We shouldn't get here with an empty clip element.
SkASSERT(Element::kEmpty_Type != element->getType());
SkASSERT(Element::DeviceSpaceType::kEmpty != element->getDeviceSpaceType());
// the gpu alpha mask will draw the inverse paths as non-inverse to a temp buffer
SkPath path;
element->asPath(&path);
element->asDeviceSpacePath(&path);
if (path.isInverseFillType()) {
path.toggleInverseFillType();
}
@ -213,16 +213,19 @@ static bool get_analytic_clip_processor(const ElementList& elements,
invert ? kInverseFillBW_GrProcessorEdgeType : kFillBW_GrProcessorEdgeType;
}
switch (iter.get()->getType()) {
case SkClipStack::Element::kPath_Type:
fps.emplace_back(GrConvexPolyEffect::Make(edgeType, iter.get()->getPath()));
switch (iter.get()->getDeviceSpaceType()) {
case SkClipStack::Element::DeviceSpaceType::kPath:
fps.emplace_back(
GrConvexPolyEffect::Make(edgeType, iter.get()->getDeviceSpacePath()));
break;
case SkClipStack::Element::kRRect_Type: {
fps.emplace_back(GrRRectEffect::Make(edgeType, iter.get()->getRRect()));
case SkClipStack::Element::DeviceSpaceType::kRRect: {
fps.emplace_back(
GrRRectEffect::Make(edgeType, iter.get()->getDeviceSpaceRRect()));
break;
}
case SkClipStack::Element::kRect_Type: {
fps.emplace_back(GrConvexPolyEffect::Make(edgeType, iter.get()->getRect()));
case SkClipStack::Element::DeviceSpaceType::kRect: {
fps.emplace_back(
GrConvexPolyEffect::Make(edgeType, iter.get()->getDeviceSpaceRect()));
break;
}
default:
@ -462,7 +465,7 @@ sk_sp<GrTextureProxy> GrClipStackClip::createSoftwareClipMask(
helper.drawRect(temp, SkRegion::kXOR_Op, GrAA::kNo, 0xFF);
}
SkPath clipPath;
element->asPath(&clipPath);
element->asDeviceSpacePath(&clipPath);
clipPath.toggleInverseFillType();
GrShape shape(clipPath, GrStyle::SimpleFill());
helper.drawShape(shape, SkRegion::kReplace_Op, aa, 0x00);
@ -471,11 +474,11 @@ sk_sp<GrTextureProxy> GrClipStackClip::createSoftwareClipMask(
// The other ops (union, xor, diff) only affect pixels inside
// the geometry so they can just be drawn normally
if (Element::kRect_Type == element->getType()) {
helper.drawRect(element->getRect(), (SkRegion::Op)op, aa, 0xFF);
if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) {
helper.drawRect(element->getDeviceSpaceRect(), (SkRegion::Op)op, aa, 0xFF);
} else {
SkPath path;
element->asPath(&path);
element->asDeviceSpacePath(&path);
GrShape shape(path, GrStyle::SimpleFill());
helper.drawShape(shape, (SkRegion::Op)op, aa, 0xFF);
}

View File

@ -171,8 +171,9 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound
} else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
skippable = true;
} else if (fWindowRects.count() < maxWindowRectangles && !embiggens &&
!element->isAA() && Element::kRect_Type == element->getType()) {
this->addWindowRectangle(element->getRect(), false);
!element->isAA() &&
Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) {
this->addWindowRectangle(element->getDeviceSpaceRect(), false);
skippable = true;
}
}
@ -198,11 +199,11 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound
initialTriState = InitialTriState::kAllOut;
skippable = true;
} else if (!embiggens && !element->isAA() &&
Element::kRect_Type == element->getType()) {
Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) {
// fIBounds and queryBounds have already acccounted for this element via
// clip stack bounds; here we just apply the non-aa rounding effect.
SkIRect nonaaRect;
element->getRect().round(&nonaaRect);
element->getDeviceSpaceRect().round(&nonaaRect);
if (!this->intersectIBounds(nonaaRect)) {
return;
}
@ -304,11 +305,11 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound
initialTriState = InitialTriState::kAllOut;
skippable = true;
} else if (!embiggens && !element->isAA() &&
Element::kRect_Type == element->getType()) {
Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) {
// fIBounds and queryBounds have already acccounted for this element via
// clip stack bounds; here we just apply the non-aa rounding effect.
SkIRect nonaaRect;
element->getRect().round(&nonaaRect);
element->getDeviceSpaceRect().round(&nonaaRect);
if (!this->intersectIBounds(nonaaRect)) {
return;
}
@ -458,18 +459,18 @@ void GrReducedClip::addInteriorWindowRectangles(int maxWindowRectangles) {
continue;
}
if (Element::kRect_Type == element->getType()) {
if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) {
SkASSERT(element->isAA());
this->addWindowRectangle(element->getRect(), true);
this->addWindowRectangle(element->getDeviceSpaceRect(), true);
if (fWindowRects.count() >= maxWindowRectangles) {
return;
}
continue;
}
if (Element::kRRect_Type == element->getType()) {
if (Element::DeviceSpaceType::kRRect == element->getDeviceSpaceType()) {
// For round rects we add two overlapping windows in the shape of a plus.
const SkRRect& clipRRect = element->getRRect();
const SkRRect& clipRRect = element->getDeviceSpaceRRect();
SkVector insetTL = clipRRect.radii(SkRRect::kUpperLeft_Corner);
SkVector insetBR = clipRRect.radii(SkRRect::kLowerRight_Corner);
if (SkRRect::kComplex_Type == clipRRect.getType()) {
@ -538,19 +539,18 @@ static bool stencil_element(GrRenderTargetContext* rtc,
const SkMatrix& viewMatrix,
const SkClipStack::Element* element) {
GrAA aa = GrBoolToAA(element->isAA());
switch (element->getType()) {
case Element::kEmpty_Type:
switch (element->getDeviceSpaceType()) {
case Element::DeviceSpaceType::kEmpty:
SkDEBUGFAIL("Should never get here with an empty element.");
break;
case Element::kRect_Type:
return rtc->priv().drawAndStencilRect(clip, ss,
(SkRegion::Op)element->getOp(),
case Element::DeviceSpaceType::kRect:
return rtc->priv().drawAndStencilRect(clip, ss, (SkRegion::Op)element->getOp(),
element->isInverseFilled(), aa, viewMatrix,
element->getRect());
element->getDeviceSpaceRect());
break;
default: {
SkPath path;
element->asPath(&path);
element->asDeviceSpacePath(&path);
if (path.isInverseFillType()) {
path.toggleInverseFillType();
}
@ -571,16 +571,16 @@ static void draw_element(GrRenderTargetContext* rtc,
const SkMatrix& viewMatrix,
const SkClipStack::Element* element) {
// TODO: Draw rrects directly here.
switch (element->getType()) {
case Element::kEmpty_Type:
switch (element->getDeviceSpaceType()) {
case Element::DeviceSpaceType::kEmpty:
SkDEBUGFAIL("Should never get here with an empty element.");
break;
case Element::kRect_Type:
rtc->drawRect(clip, std::move(paint), aa, viewMatrix, element->getRect());
case Element::DeviceSpaceType::kRect:
rtc->drawRect(clip, std::move(paint), aa, viewMatrix, element->getDeviceSpaceRect());
break;
default: {
SkPath path;
element->asPath(&path);
element->asDeviceSpacePath(&path);
if (path.isInverseFillType()) {
path.toggleInverseFillType();
}
@ -730,11 +730,11 @@ bool GrReducedClip::drawStencilClipMask(GrContext* context,
GrPathRenderer* pr = nullptr;
SkPath clipPath;
if (Element::kRect_Type == element->getType()) {
if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) {
stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport;
fillInverted = false;
} else {
element->asPath(&clipPath);
element->asDeviceSpacePath(&clipPath);
fillInverted = clipPath.isInverseFillType();
if (fillInverted) {
clipPath.toggleInverseFillType();
@ -777,9 +777,10 @@ bool GrReducedClip::drawStencilClipMask(GrContext* context,
GrUserStencilOp::kIncMaybeClamp,
0xffff>()
);
if (Element::kRect_Type == element->getType()) {
if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) {
renderTargetContext->priv().stencilRect(stencilClip.fixedClip(), &kDrawToStencil,
aaType, SkMatrix::I(), element->getRect());
aaType, SkMatrix::I(),
element->getDeviceSpaceRect());
} else {
if (!clipPath.isEmpty()) {
GrShape shape(clipPath, GrStyle::SimpleFill());
@ -815,9 +816,10 @@ bool GrReducedClip::drawStencilClipMask(GrContext* context,
// element directly or a bounding rect of the entire clip.
for (GrUserStencilSettings const* const* pass = stencilPasses; *pass; ++pass) {
if (drawDirectToClip) {
if (Element::kRect_Type == element->getType()) {
if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) {
renderTargetContext->priv().stencilRect(stencilClip, *pass, aaType,
SkMatrix::I(), element->getRect());
SkMatrix::I(),
element->getDeviceSpaceRect());
} else {
GrShape shape(clipPath, GrStyle::SimpleFill());
GrPaint paint;

View File

@ -301,12 +301,12 @@ static bool get_clip_stack_path(const SkMatrix& transform,
iter.reset(clipStack, SkClipStack::Iter::kBottom_IterStart);
for (clipEntry = iter.next(); clipEntry; clipEntry = iter.next()) {
SkPath entryPath;
if (SkClipStack::Element::kEmpty_Type == clipEntry->getType()) {
if (SkClipStack::Element::DeviceSpaceType::kEmpty == clipEntry->getDeviceSpaceType()) {
outClipPath->reset();
outClipPath->setFillType(SkPath::kInverseWinding_FillType);
continue;
} else {
clipEntry->asPath(&entryPath);
clipEntry->asDeviceSpacePath(&entryPath);
}
entryPath.transform(transform);
if (!apply_clip(clipEntry->getOp(), *outClipPath, entryPath, outClipPath)) {

View File

@ -158,8 +158,9 @@ static void test_iterators(skiatest::Reporter* reporter) {
int i;
for (i = 0, element = iter.next(); element; ++i, element = iter.next()) {
REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
REPORTER_ASSERT(reporter, element->getRect() == gRects[i]);
REPORTER_ASSERT(reporter, SkClipStack::Element::DeviceSpaceType::kRect ==
element->getDeviceSpaceType());
REPORTER_ASSERT(reporter, element->getDeviceSpaceRect() == gRects[i]);
}
SkASSERT(i == 4);
@ -173,8 +174,9 @@ static void test_iterators(skiatest::Reporter* reporter) {
int i;
for (i = 3, element = iter.prev(); element; --i, element = iter.prev()) {
REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
REPORTER_ASSERT(reporter, element->getRect() == gRects[i]);
REPORTER_ASSERT(reporter, SkClipStack::Element::DeviceSpaceType::kRect ==
element->getDeviceSpaceType());
REPORTER_ASSERT(reporter, element->getDeviceSpaceRect() == gRects[i]);
}
SkASSERT(i == -1);
@ -187,13 +189,15 @@ static void test_iterators(skiatest::Reporter* reporter) {
SkClipStack::Iter iter(stack, SkClipStack::Iter::kBottom_IterStart);
element = iter.skipToTopmost(kUnion_SkClipOp);
REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
REPORTER_ASSERT(reporter, element->getRect() == gRects[3]);
REPORTER_ASSERT(reporter, SkClipStack::Element::DeviceSpaceType::kRect ==
element->getDeviceSpaceType());
REPORTER_ASSERT(reporter, element->getDeviceSpaceRect() == gRects[3]);
}
}
// Exercise the SkClipStack's getConservativeBounds computation
static void test_bounds(skiatest::Reporter* reporter, SkClipStack::Element::Type primType) {
static void test_bounds(skiatest::Reporter* reporter,
SkClipStack::Element::DeviceSpaceType primType) {
static const int gNumCases = 20;
static const SkRect gAnswerRectsBW[gNumCases] = {
// A op B
@ -252,7 +256,7 @@ static void test_bounds(skiatest::Reporter* reporter, SkClipStack::Element::Type
bool isIntersectionOfRects = false;
int testCase = 0;
int numBitTests = SkClipStack::Element::kPath_Type == primType ? 4 : 1;
int numBitTests = SkClipStack::Element::DeviceSpaceType::kPath == primType ? 4 : 1;
for (int invBits = 0; invBits < numBitTests; ++invBits) {
for (size_t op = 0; op < SK_ARRAY_COUNT(gOps); ++op) {
@ -266,18 +270,18 @@ static void test_bounds(skiatest::Reporter* reporter, SkClipStack::Element::Type
SkPath::kEvenOdd_FillType);
switch (primType) {
case SkClipStack::Element::kEmpty_Type:
case SkClipStack::Element::DeviceSpaceType::kEmpty:
SkDEBUGFAIL("Don't call this with kEmpty.");
break;
case SkClipStack::Element::kRect_Type:
case SkClipStack::Element::DeviceSpaceType::kRect:
stack.clipRect(rectA, SkMatrix::I(), kIntersect_SkClipOp, false);
stack.clipRect(rectB, SkMatrix::I(), gOps[op], false);
break;
case SkClipStack::Element::kRRect_Type:
case SkClipStack::Element::DeviceSpaceType::kRRect:
stack.clipRRect(rrectA, SkMatrix::I(), kIntersect_SkClipOp, false);
stack.clipRRect(rrectB, SkMatrix::I(), gOps[op], false);
break;
case SkClipStack::Element::kPath_Type:
case SkClipStack::Element::DeviceSpaceType::kPath:
stack.clipPath(pathA, SkMatrix::I(), kIntersect_SkClipOp, false);
stack.clipPath(pathB, SkMatrix::I(), gOps[op], false);
break;
@ -289,7 +293,7 @@ static void test_bounds(skiatest::Reporter* reporter, SkClipStack::Element::Type
stack.getConservativeBounds(0, 0, 100, 100, &devClipBound,
&isIntersectionOfRects);
if (SkClipStack::Element::kRect_Type == primType) {
if (SkClipStack::Element::DeviceSpaceType::kRect == primType) {
REPORTER_ASSERT(reporter, isIntersectionOfRects ==
(gOps[op] == kIntersect_SkClipOp));
} else {
@ -810,12 +814,12 @@ static void set_region_to_stack(const SkClipStack& stack, const SkIRect& bounds,
SkRegion boundsRgn(bounds);
SkPath path;
switch (element->getType()) {
case SkClipStack::Element::kEmpty_Type:
switch (element->getDeviceSpaceType()) {
case SkClipStack::Element::DeviceSpaceType::kEmpty:
elemRegion.setEmpty();
break;
default:
element->asPath(&path);
element->asDeviceSpacePath(&path);
elemRegion.setPath(path, boundsRgn);
break;
}
@ -899,17 +903,20 @@ static void add_oval(const SkRect& rect, bool invert, SkClipOp op, SkClipStack*
};
static void add_elem_to_stack(const SkClipStack::Element& element, SkClipStack* stack) {
switch (element.getType()) {
case SkClipStack::Element::kRect_Type:
stack->clipRect(element.getRect(), SkMatrix::I(), element.getOp(), element.isAA());
switch (element.getDeviceSpaceType()) {
case SkClipStack::Element::DeviceSpaceType::kRect:
stack->clipRect(element.getDeviceSpaceRect(), SkMatrix::I(), element.getOp(),
element.isAA());
break;
case SkClipStack::Element::kRRect_Type:
stack->clipRRect(element.getRRect(), SkMatrix::I(), element.getOp(), element.isAA());
case SkClipStack::Element::DeviceSpaceType::kRRect:
stack->clipRRect(element.getDeviceSpaceRRect(), SkMatrix::I(), element.getOp(),
element.isAA());
break;
case SkClipStack::Element::kPath_Type:
stack->clipPath(element.getPath(), SkMatrix::I(), element.getOp(), element.isAA());
case SkClipStack::Element::DeviceSpaceType::kPath:
stack->clipPath(element.getDeviceSpacePath(), SkMatrix::I(), element.getOp(),
element.isAA());
break;
case SkClipStack::Element::kEmpty_Type:
case SkClipStack::Element::DeviceSpaceType::kEmpty:
SkDEBUGFAIL("Why did the reducer produce an explicit empty.");
stack->clipEmpty();
break;
@ -1413,9 +1420,10 @@ DEF_TEST(ClipStack, reporter) {
answer.iset(25, 25, 75, 75);
REPORTER_ASSERT(reporter, element);
REPORTER_ASSERT(reporter, SkClipStack::Element::kRect_Type == element->getType());
REPORTER_ASSERT(reporter,
SkClipStack::Element::DeviceSpaceType::kRect == element->getDeviceSpaceType());
REPORTER_ASSERT(reporter, kIntersect_SkClipOp == element->getOp());
REPORTER_ASSERT(reporter, element->getRect() == answer);
REPORTER_ASSERT(reporter, element->getDeviceSpaceRect() == answer);
// now check that we only had one in our iterator
REPORTER_ASSERT(reporter, !iter.next());
@ -1425,9 +1433,9 @@ DEF_TEST(ClipStack, reporter) {
test_assign_and_comparison(reporter);
test_iterators(reporter);
test_bounds(reporter, SkClipStack::Element::kRect_Type);
test_bounds(reporter, SkClipStack::Element::kRRect_Type);
test_bounds(reporter, SkClipStack::Element::kPath_Type);
test_bounds(reporter, SkClipStack::Element::DeviceSpaceType::kRect);
test_bounds(reporter, SkClipStack::Element::DeviceSpaceType::kRRect);
test_bounds(reporter, SkClipStack::Element::DeviceSpaceType::kPath);
test_isWideOpen(reporter);
test_rect_merging(reporter);
test_rect_replace(reporter);

View File

@ -251,10 +251,10 @@ void SkDebugCanvas::drawTo(SkCanvas* originalCanvas, int index, int m) {
const SkClipStack::Element* element;
SkPath devPath;
while ((element = iter.next())) {
SkClipStack::Element::Type type = element->getType();
SkClipStack::Element::DeviceSpaceType type = element->getDeviceSpaceType();
SkPath operand;
if (type != SkClipStack::Element::kEmpty_Type) {
element->asPath(&operand);
if (type != SkClipStack::Element::DeviceSpaceType::kEmpty) {
element->asDeviceSpacePath(&operand);
}
SkClipOp elementOp = element->getOp();
this->addClipStackData(devPath, operand, elementOp);