xref: /aosp_15_r20/external/skia/src/core/SkClipStackDevice.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 
10 #include "include/core/SkImageInfo.h"
11 #include "include/core/SkMatrix.h"
12 #include "include/core/SkPath.h"
13 #include "include/core/SkPoint.h"
14 #include "include/core/SkRegion.h"
15 #include "include/core/SkShader.h"
16 #include "include/private/base/SkAssert.h"
17 #include "src/core/SkMatrixPriv.h"
18 
19 #include <utility>
20 
21 class SkRRect;
22 enum class SkClipOp;
23 
devClipBounds() const24 SkIRect SkClipStackDevice::devClipBounds() const {
25     SkIRect r = fClipStack.bounds(this->imageInfo().bounds()).roundOut();
26     if (!r.isEmpty()) {
27         SkASSERT(this->imageInfo().bounds().contains(r));
28     }
29     return r;
30 }
31 
32 ///////////////////////////////////////////////////////////////////////////////////////////////////
33 
pushClipStack()34 void SkClipStackDevice::pushClipStack() {
35     fClipStack.save();
36 }
37 
popClipStack()38 void SkClipStackDevice::popClipStack() {
39     fClipStack.restore();
40 }
41 
clipRect(const SkRect & rect,SkClipOp op,bool aa)42 void SkClipStackDevice::clipRect(const SkRect& rect, SkClipOp op, bool aa) {
43     fClipStack.clipRect(rect, this->localToDevice(), op, aa);
44 }
45 
clipRRect(const SkRRect & rrect,SkClipOp op,bool aa)46 void SkClipStackDevice::clipRRect(const SkRRect& rrect, SkClipOp op, bool aa) {
47     fClipStack.clipRRect(rrect, this->localToDevice(), op, aa);
48 }
49 
clipPath(const SkPath & path,SkClipOp op,bool aa)50 void SkClipStackDevice::clipPath(const SkPath& path, SkClipOp op, bool aa) {
51     fClipStack.clipPath(path, this->localToDevice(), op, aa);
52 }
53 
onClipShader(sk_sp<SkShader> shader)54 void SkClipStackDevice::onClipShader(sk_sp<SkShader> shader) {
55     fClipStack.clipShader(std::move(shader));
56 }
57 
clipRegion(const SkRegion & rgn,SkClipOp op)58 void SkClipStackDevice::clipRegion(const SkRegion& rgn, SkClipOp op) {
59     SkIPoint origin = this->getOrigin();
60     SkRegion tmp;
61     SkPath path;
62     rgn.getBoundaryPath(&path);
63     path.transform(SkMatrix::Translate(-origin));
64     fClipStack.clipPath(path, SkMatrix::I(), op, false);
65 }
66 
replaceClip(const SkIRect & rect)67 void SkClipStackDevice::replaceClip(const SkIRect& rect) {
68     SkRect deviceRect = SkMatrixPriv::MapRect(this->globalToDevice(), SkRect::Make(rect));
69     fClipStack.replaceClip(deviceRect, /*doAA=*/false);
70 }
71 
isClipAntiAliased() const72 bool SkClipStackDevice::isClipAntiAliased() 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 
isClipWideOpen() const84 bool SkClipStackDevice::isClipWideOpen() const {
85     return fClipStack.quickContains(SkRect::MakeIWH(this->width(), this->height()));
86 }
87 
isClipEmpty() const88 bool SkClipStackDevice::isClipEmpty() const {
89     return fClipStack.isEmpty(SkIRect::MakeWH(this->width(), this->height()));
90 }
91 
isClipRect() const92 bool SkClipStackDevice::isClipRect() const {
93     if (this->isClipWideOpen()) {
94         return true;
95     } else if (this->isClipEmpty()) {
96         return false;
97     }
98 
99     SkClipStack::BoundsType boundType;
100     bool isIntersectionOfRects;
101     SkRect bounds;
102     fClipStack.getBounds(&bounds, &boundType, &isIntersectionOfRects);
103     return isIntersectionOfRects && boundType == SkClipStack::kNormal_BoundsType;
104 }
105 
android_utils_clipAsRgn(SkRegion * rgn) const106 void SkClipStackDevice::android_utils_clipAsRgn(SkRegion* rgn) const {
107     SkClipStack::BoundsType boundType;
108     bool isIntersectionOfRects;
109     SkRect bounds;
110     fClipStack.getBounds(&bounds, &boundType, &isIntersectionOfRects);
111     if (isIntersectionOfRects && SkClipStack::kNormal_BoundsType == boundType) {
112         rgn->setRect(bounds.round());
113     } else {
114         SkRegion boundsRgn({0, 0, this->width(), this->height()});
115         SkPath tmpPath;
116 
117         *rgn = boundsRgn;
118         SkClipStack::B2TIter iter(fClipStack);
119         while (auto elem = iter.next()) {
120             tmpPath.rewind();
121             elem->asDeviceSpacePath(&tmpPath);
122             SkRegion tmpRgn;
123             tmpRgn.setPath(tmpPath, boundsRgn);
124             if (elem->isReplaceOp()) {
125                 // All replace elements are rectangles
126                 // TODO: SkClipStack can be simplified to be I,D,R ops now, which means element
127                 // iteration can be from top of the stack to the most recent replace element.
128                 // When that's done, this loop will be simplifiable.
129                 rgn->setRect(elem->getDeviceSpaceRect().round());
130             } else {
131                 rgn->op(tmpRgn, static_cast<SkRegion::Op>(elem->getOp()));
132             }
133         }
134     }
135 }
136