1 /* 2 * Copyright 2017 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "src/core/SkClipStackDevice.h" 9 #include "src/core/SkDraw.h" 10 #include "src/core/SkRasterClip.h" 11 onDevClipBounds() const12 SkIRect SkClipStackDevice::onDevClipBounds() const { 13 SkIRect r = fClipStack.bounds(this->imageInfo().bounds()).roundOut(); 14 if (!r.isEmpty()) { 15 SkASSERT(this->imageInfo().bounds().contains(r)); 16 } 17 return r; 18 } 19 20 /////////////////////////////////////////////////////////////////////////////////////////////////// 21 onSave()22 void SkClipStackDevice::onSave() { 23 fClipStack.save(); 24 } 25 onRestore()26 void SkClipStackDevice::onRestore() { 27 fClipStack.restore(); 28 } 29 onClipRect(const SkRect & rect,SkClipOp op,bool aa)30 void SkClipStackDevice::onClipRect(const SkRect& rect, SkClipOp op, bool aa) { 31 fClipStack.clipRect(rect, this->localToDevice(), op, aa); 32 } 33 onClipRRect(const SkRRect & rrect,SkClipOp op,bool aa)34 void SkClipStackDevice::onClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) { 35 fClipStack.clipRRect(rrect, this->localToDevice(), op, aa); 36 } 37 onClipPath(const SkPath & path,SkClipOp op,bool aa)38 void SkClipStackDevice::onClipPath(const SkPath& path, SkClipOp op, bool aa) { 39 fClipStack.clipPath(path, this->localToDevice(), op, aa); 40 } 41 onClipShader(sk_sp<SkShader> shader)42 void SkClipStackDevice::onClipShader(sk_sp<SkShader> shader) { 43 fClipStack.clipShader(std::move(shader)); 44 } 45 onClipRegion(const SkRegion & rgn,SkClipOp op)46 void SkClipStackDevice::onClipRegion(const SkRegion& rgn, SkClipOp op) { 47 SkIPoint origin = this->getOrigin(); 48 SkRegion tmp; 49 SkPath path; 50 rgn.getBoundaryPath(&path); 51 path.transform(SkMatrix::Translate(-origin)); 52 fClipStack.clipPath(path, SkMatrix::I(), op, false); 53 } 54 onReplaceClip(const SkIRect & rect)55 void SkClipStackDevice::onReplaceClip(const SkIRect& rect) { 56 SkRect deviceRect = SkMatrixPriv::MapRect(this->globalToDevice(), SkRect::Make(rect)); 57 fClipStack.replaceClip(deviceRect, /*doAA=*/false); 58 } 59 onClipIsAA() const60 bool SkClipStackDevice::onClipIsAA() const { 61 SkClipStack::B2TIter iter(fClipStack); 62 const SkClipStack::Element* element; 63 64 while ((element = iter.next()) != nullptr) { 65 if (element->isAA()) { 66 return true; 67 } 68 } 69 return false; 70 } 71 onClipIsWideOpen() const72 bool SkClipStackDevice::onClipIsWideOpen() const { 73 return fClipStack.quickContains(SkRect::MakeIWH(this->width(), this->height())); 74 } 75 onAsRgnClip(SkRegion * rgn) const76 void SkClipStackDevice::onAsRgnClip(SkRegion* rgn) const { 77 SkClipStack::BoundsType boundType; 78 bool isIntersectionOfRects; 79 SkRect bounds; 80 fClipStack.getBounds(&bounds, &boundType, &isIntersectionOfRects); 81 if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) { 82 rgn->setRect(bounds.round()); 83 } else { 84 SkRegion boundsRgn({0, 0, this->width(), this->height()}); 85 SkPath tmpPath; 86 87 *rgn = boundsRgn; 88 SkClipStack::B2TIter iter(fClipStack); 89 while (auto elem = iter.next()) { 90 tmpPath.rewind(); 91 elem->asDeviceSpacePath(&tmpPath); 92 SkRegion tmpRgn; 93 tmpRgn.setPath(tmpPath, boundsRgn); 94 if (elem->isReplaceOp()) { 95 // All replace elements are rectangles 96 // TODO: SkClipStack can be simplified to be I,D,R ops now, which means element 97 // iteration can be from top of the stack to the most recent replace element. 98 // When that's done, this loop will be simplifiable. 99 rgn->setRect(elem->getDeviceSpaceRect().round()); 100 } else { 101 rgn->op(tmpRgn, static_cast<SkRegion::Op>(elem->getOp())); 102 } 103 } 104 } 105 } 106 onGetClipType() const107 SkBaseDevice::ClipType SkClipStackDevice::onGetClipType() const { 108 if (fClipStack.isWideOpen()) { 109 return ClipType::kRect; 110 } 111 if (fClipStack.isEmpty(SkIRect::MakeWH(this->width(), this->height()))) { 112 return ClipType::kEmpty; 113 } else { 114 SkClipStack::BoundsType boundType; 115 bool isIntersectionOfRects; 116 SkRect bounds; 117 fClipStack.getBounds(&bounds, &boundType, &isIntersectionOfRects); 118 if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) { 119 return ClipType::kRect; 120 } else { 121 return ClipType::kComplex; 122 } 123 } 124 } 125