/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkClipStackDevice.h"
#include "SkDraw.h"
#include "SkRasterClip.h"
SkIRect SkClipStackDevice::devClipBounds() const {
SkIRect r = fClipStack.bounds(this->imageInfo().bounds()).roundOut();
if (!r.isEmpty()) {
SkASSERT(this->imageInfo().bounds().contains(r));
}
return r;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void SkClipStackDevice::onSave() {
fClipStack.save();
}
void SkClipStackDevice::onRestore() {
fClipStack.restore();
}
void SkClipStackDevice::onClipRect(const SkRect& rect, SkClipOp op, bool aa) {
fClipStack.clipRect(rect, this->ctm(), op, aa);
}
void SkClipStackDevice::onClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) {
fClipStack.clipRRect(rrect, this->ctm(), op, aa);
}
void SkClipStackDevice::onClipPath(const SkPath& path, SkClipOp op, bool aa) {
fClipStack.clipPath(path, this->ctm(), op, aa);
}
void SkClipStackDevice::onClipRegion(const SkRegion& rgn, SkClipOp op) {
SkIPoint origin = this->getOrigin();
SkRegion tmp;
const SkRegion* ptr = &rgn;
if (origin.fX | origin.fY) {
// translate from "global/canvas" coordinates to relative to this device
rgn.translate(-origin.fX, -origin.fY, &tmp);
ptr = &tmp;
}
fClipStack.clipDevRect(ptr->getBounds(), op);
}
void SkClipStackDevice::onSetDeviceClipRestriction(SkIRect* clipRestriction) {
if (clipRestriction->isEmpty()) {
fClipStack.setDeviceClipRestriction(*clipRestriction);
} else {
SkIPoint origin = this->getOrigin();
SkIRect rect = clipRestriction->makeOffset(-origin.x(), -origin.y());
fClipStack.setDeviceClipRestriction(rect);
fClipStack.clipDevRect(rect, SkClipOp::kIntersect);
}
}
bool SkClipStackDevice::onClipIsAA() const {
SkClipStack::B2TIter iter(fClipStack);
const SkClipStack::Element* element;
while ((element = iter.next()) != nullptr) {
if (element->isAA()) {
return true;
}
}
return false;
}
void SkClipStackDevice::onAsRgnClip(SkRegion* rgn) const {
SkClipStack::BoundsType boundType;
bool isIntersectionOfRects;
SkRect bounds;
fClipStack.getBounds(&bounds, &boundType, &isIntersectionOfRects);
if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) {
rgn->setRect(bounds.round());
} else {
SkPath path;
fClipStack.asPath(&path);
rgn->setPath(path, SkRegion(SkIRect::MakeWH(this->width(), this->height())));
}
}
SkBaseDevice::ClipType SkClipStackDevice::onGetClipType() const {
if (fClipStack.isWideOpen()) {
return kRect_ClipType;
}
if (fClipStack.isEmpty(SkIRect::MakeWH(this->width(), this->height()))) {
return kEmpty_ClipType;
} else {
SkClipStack::BoundsType boundType;
bool isIntersectionOfRects;
SkRect bounds;
fClipStack.getBounds(&bounds, &boundType, &isIntersectionOfRects);
if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) {
return kRect_ClipType;
} else {
return kComplex_ClipType;
}
}
}