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