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
12SkIRect 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
22void SkClipStackDevice::onSave() {
23 fClipStack.save();
24}
25
26void SkClipStackDevice::onRestore() {
27 fClipStack.restore();
28}
29
30void SkClipStackDevice::onClipRect(const SkRect& rect, SkClipOp op, bool aa) {
31 fClipStack.clipRect(rect, this->localToDevice(), op, aa);
32}
33
34void SkClipStackDevice::onClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) {
35 fClipStack.clipRRect(rrect, this->localToDevice(), op, aa);
36}
37
38void SkClipStackDevice::onClipPath(const SkPath& path, SkClipOp op, bool aa) {
39 fClipStack.clipPath(path, this->localToDevice(), op, aa);
40}
41
42void SkClipStackDevice::onClipShader(sk_sp<SkShader> shader) {
43 fClipStack.clipShader(std::move(shader));
44}
45
46void 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
55void 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
61void 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
72bool 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
84bool SkClipStackDevice::onClipIsWideOpen() const {
85 return fClipStack.quickContains(SkRect::MakeIWH(this->width(), this->height()));
86}
87
88void 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
111SkBaseDevice::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