| /* | |
| * 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; | |
| } | |
| } | |
| } |