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::onClipRegion(const SkRegion& rgn, SkClipOp op) { |
43 | SkIPoint origin = this->getOrigin(); |
44 | SkRegion tmp; |
45 | SkPath path; |
46 | rgn.getBoundaryPath(&path); |
47 | path.transform(SkMatrix::MakeTrans(-origin)); |
48 | fClipStack.clipPath(path, SkMatrix::I(), op, false); |
49 | } |
50 | |
51 | void SkClipStackDevice::onSetDeviceClipRestriction(SkIRect* clipRestriction) { |
52 | if (clipRestriction->isEmpty()) { |
53 | fClipStack.setDeviceClipRestriction(*clipRestriction); |
54 | } else { |
55 | SkIPoint origin = this->getOrigin(); |
56 | SkIRect rect = clipRestriction->makeOffset(-origin); |
57 | fClipStack.setDeviceClipRestriction(rect); |
58 | fClipStack.clipDevRect(rect, SkClipOp::kIntersect); |
59 | } |
60 | } |
61 | |
62 | bool SkClipStackDevice::onClipIsAA() const { |
63 | SkClipStack::B2TIter iter(fClipStack); |
64 | const SkClipStack::Element* element; |
65 | |
66 | while ((element = iter.next()) != nullptr) { |
67 | if (element->isAA()) { |
68 | return true; |
69 | } |
70 | } |
71 | return false; |
72 | } |
73 | |
74 | bool SkClipStackDevice::onClipIsWideOpen() const { |
75 | return fClipStack.quickContains(SkRect::MakeIWH(this->width(), this->height())); |
76 | } |
77 | |
78 | void SkClipStackDevice::onAsRgnClip(SkRegion* rgn) const { |
79 | SkClipStack::BoundsType boundType; |
80 | bool isIntersectionOfRects; |
81 | SkRect bounds; |
82 | fClipStack.getBounds(&bounds, &boundType, &isIntersectionOfRects); |
83 | if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) { |
84 | rgn->setRect(bounds.round()); |
85 | } else { |
86 | SkRegion boundsRgn({0, 0, this->width(), this->height()}); |
87 | SkPath tmpPath; |
88 | |
89 | *rgn = boundsRgn; |
90 | SkClipStack::B2TIter iter(fClipStack); |
91 | while (auto elem = iter.next()) { |
92 | tmpPath.rewind(); |
93 | elem->asDeviceSpacePath(&tmpPath); |
94 | SkRegion tmpRgn; |
95 | tmpRgn.setPath(tmpPath, boundsRgn); |
96 | rgn->op(tmpRgn, SkRegion::Op(elem->getOp())); |
97 | } |
98 | } |
99 | } |
100 | |
101 | SkBaseDevice::ClipType SkClipStackDevice::onGetClipType() const { |
102 | if (fClipStack.isWideOpen()) { |
103 | return ClipType::kRect; |
104 | } |
105 | if (fClipStack.isEmpty(SkIRect::MakeWH(this->width(), this->height()))) { |
106 | return ClipType::kEmpty; |
107 | } else { |
108 | SkClipStack::BoundsType boundType; |
109 | bool isIntersectionOfRects; |
110 | SkRect bounds; |
111 | fClipStack.getBounds(&bounds, &boundType, &isIntersectionOfRects); |
112 | if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) { |
113 | return ClipType::kRect; |
114 | } else { |
115 | return ClipType::kComplex; |
116 | } |
117 | } |
118 | } |
119 | |