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 // FIXME When the deprecated clip ops are completely removed, SkClipStack will need to be
57 // updated to have a better way of tracking replacement.
58 fClipStack.clipRect(SkRect::Make(rect), this->globalToDevice(), kReplace_SkClipOp, false);
59 }
60
onSetDeviceClipRestriction(SkIRect * clipRestriction)61 void SkClipStackDevice::onSetDeviceClipRestriction(SkIRect* clipRestriction) {
62 if (clipRestriction->isEmpty()) {
63 fClipStack.setDeviceClipRestriction(*clipRestriction);
64 } else {
65 SkIPoint origin = this->getOrigin();
66 SkIRect rect = clipRestriction->makeOffset(-origin);
67 fClipStack.setDeviceClipRestriction(rect);
68 fClipStack.clipDevRect(rect, SkClipOp::kIntersect);
69 }
70 }
71
onClipIsAA() const72 bool SkClipStackDevice::onClipIsAA() const {
73 SkClipStack::B2TIter iter(fClipStack);
74 const SkClipStack::Element* element;
75
76 while ((element = iter.next()) != nullptr) {
77 if (element->isAA()) {
78 return true;
79 }
80 }
81 return false;
82 }
83
onClipIsWideOpen() const84 bool SkClipStackDevice::onClipIsWideOpen() const {
85 return fClipStack.quickContains(SkRect::MakeIWH(this->width(), this->height()));
86 }
87
onAsRgnClip(SkRegion * rgn) const88 void SkClipStackDevice::onAsRgnClip(SkRegion* rgn) const {
89 SkClipStack::BoundsType boundType;
90 bool isIntersectionOfRects;
91 SkRect bounds;
92 fClipStack.getBounds(&bounds, &boundType, &isIntersectionOfRects);
93 if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) {
94 rgn->setRect(bounds.round());
95 } else {
96 SkRegion boundsRgn({0, 0, this->width(), this->height()});
97 SkPath tmpPath;
98
99 *rgn = boundsRgn;
100 SkClipStack::B2TIter iter(fClipStack);
101 while (auto elem = iter.next()) {
102 tmpPath.rewind();
103 elem->asDeviceSpacePath(&tmpPath);
104 SkRegion tmpRgn;
105 tmpRgn.setPath(tmpPath, boundsRgn);
106 rgn->op(tmpRgn, SkRegion::Op(elem->getOp()));
107 }
108 }
109 }
110
onGetClipType() const111 SkBaseDevice::ClipType SkClipStackDevice::onGetClipType() const {
112 if (fClipStack.isWideOpen()) {
113 return ClipType::kRect;
114 }
115 if (fClipStack.isEmpty(SkIRect::MakeWH(this->width(), this->height()))) {
116 return ClipType::kEmpty;
117 } else {
118 SkClipStack::BoundsType boundType;
119 bool isIntersectionOfRects;
120 SkRect bounds;
121 fClipStack.getBounds(&bounds, &boundType, &isIntersectionOfRects);
122 if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) {
123 return ClipType::kRect;
124 } else {
125 return ClipType::kComplex;
126 }
127 }
128 }
129