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