• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #ifndef CLIPAREA_H
17 #define CLIPAREA_H
18 
19 #include "Matrix.h"
20 #include "Rect.h"
21 #include "utils/Pair.h"
22 
23 #include <SkRegion.h>
24 
25 namespace android {
26 namespace uirenderer {
27 
28 class LinearAllocator;
29 
30 Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform);
31 
32 class TransformedRectangle {
33 public:
34     TransformedRectangle();
35     TransformedRectangle(const Rect& bounds, const Matrix4& transform);
36 
37     bool canSimplyIntersectWith(const TransformedRectangle& other) const;
38     void intersectWith(const TransformedRectangle& other);
39 
40     bool isEmpty() const;
41 
getBounds()42     const Rect& getBounds() const {
43         return mBounds;
44     }
45 
transformedBounds()46     Rect transformedBounds() const {
47         Rect transformedBounds(transformAndCalculateBounds(mBounds, mTransform));
48         return transformedBounds;
49     }
50 
getTransform()51     const Matrix4& getTransform() const {
52         return mTransform;
53     }
54 
transform(const Matrix4 & transform)55     void transform(const Matrix4& transform) {
56         Matrix4 t;
57         t.loadMultiply(transform, mTransform);
58         mTransform = t;
59     }
60 
61 private:
62     Rect mBounds;
63     Matrix4 mTransform;
64 };
65 
66 class RectangleList {
67 public:
68     RectangleList();
69 
70     bool isEmpty() const;
71     int getTransformedRectanglesCount() const;
72     const TransformedRectangle& getTransformedRectangle(int i) const;
73 
74     void setEmpty();
75     void set(const Rect& bounds, const Matrix4& transform);
76     bool intersectWith(const Rect& bounds, const Matrix4& transform);
77     void transform(const Matrix4& transform);
78 
79     SkRegion convertToRegion(const SkRegion& clip) const;
80     Rect calculateBounds() const;
81 
82     enum {
83         kMaxTransformedRectangles = 5
84     };
85 
86 private:
87     int mTransformedRectanglesCount;
88     TransformedRectangle mTransformedRectangles[kMaxTransformedRectangles];
89 };
90 
91 enum class ClipMode {
92     Rectangle,
93     RectangleList,
94 
95     // region and path - intersected. if either is empty, don't use
96     Region
97 };
98 
99 struct ClipBase {
ClipBaseClipBase100     explicit ClipBase(ClipMode mode)
101             : mode(mode) {}
ClipBaseClipBase102     explicit ClipBase(const Rect& rect)
103             : mode(ClipMode::Rectangle)
104             , rect(rect) {}
105     const ClipMode mode;
106     bool intersectWithRoot = false;
107     // Bounds of the clipping area, used to define the scissor, and define which
108     // portion of the stencil is updated/used
109     Rect rect;
110 
111     void dump() const;
112 };
113 
114 struct ClipRect : ClipBase {
ClipRectClipRect115     explicit ClipRect(const Rect& rect)
116             : ClipBase(rect) {}
117 };
118 
119 struct ClipRectList : ClipBase {
ClipRectListClipRectList120     explicit ClipRectList(const RectangleList& rectList)
121             : ClipBase(ClipMode::RectangleList)
122             , rectList(rectList) {}
123     RectangleList rectList;
124 };
125 
126 struct ClipRegion : ClipBase {
ClipRegionClipRegion127     explicit ClipRegion(const SkRegion& region)
128             : ClipBase(ClipMode::Region)
129             , region(region) {}
ClipRegionClipRegion130     ClipRegion()
131             : ClipBase(ClipMode::Region) {}
132     SkRegion region;
133 };
134 
135 class ClipArea {
136 public:
137     ClipArea();
138 
139     void setViewportDimensions(int width, int height);
140 
isEmpty()141     bool isEmpty() const {
142         return mClipRect.isEmpty();
143     }
144 
145     void setEmpty();
146     void setClip(float left, float top, float right, float bottom);
147     void clipRectWithTransform(const Rect& r, const mat4* transform,
148             SkRegion::Op op);
149     void clipPathWithTransform(const SkPath& path, const mat4* transform,
150             SkRegion::Op op);
151 
getClipRect()152     const Rect& getClipRect() const {
153         return mClipRect;
154     }
155 
getClipRegion()156     const SkRegion& getClipRegion() const {
157         return mClipRegion;
158     }
159 
getRectangleList()160     const RectangleList& getRectangleList() const {
161         return mRectangleList;
162     }
163 
isRegion()164     bool isRegion() const {
165         return ClipMode::Region == mMode;
166     }
167 
isSimple()168     bool isSimple() const {
169         return mMode == ClipMode::Rectangle;
170     }
171 
isRectangleList()172     bool isRectangleList() const {
173         return mMode == ClipMode::RectangleList;
174     }
175 
176     WARN_UNUSED_RESULT const ClipBase* serializeClip(LinearAllocator& allocator);
177     WARN_UNUSED_RESULT const ClipBase* serializeIntersectedClip(LinearAllocator& allocator,
178             const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
179     void applyClip(const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
180 
181     static void applyTransformToRegion(const Matrix4& transform, SkRegion* region);
182 
183 private:
184     void enterRectangleMode();
185     void rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
186 
187     void enterRectangleListMode();
188     void rectangleListModeClipRectWithTransform(const Rect& r,
189             const mat4* transform, SkRegion::Op op);
190 
191     void enterRegionModeFromRectangleMode();
192     void enterRegionModeFromRectangleListMode();
193     void enterRegionMode();
194     void regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
195             SkRegion::Op op);
196 
197     void clipRegion(const SkRegion& region, SkRegion::Op op);
198     void ensureClipRegion();
199     void onClipRegionUpdated();
200 
201     // Called by every state modifying public method.
onClipUpdated()202     void onClipUpdated() {
203         mPostViewportClipObserved = true;
204         mLastSerialization = nullptr;
205         mLastResolutionResult = nullptr;
206     }
207 
createViewportRegion()208     SkRegion createViewportRegion() {
209         return SkRegion(mViewportBounds.toSkIRect());
210     }
211 
regionFromPath(const SkPath & path,SkRegion & pathAsRegion)212     void regionFromPath(const SkPath& path, SkRegion& pathAsRegion) {
213         // TODO: this should not mask every path to the viewport - this makes it impossible to use
214         // paths to clip to larger areas (which is valid e.g. with SkRegion::kReplace_Op)
215         pathAsRegion.setPath(path, createViewportRegion());
216     }
217 
218     ClipMode mMode;
219     bool mPostViewportClipObserved = false;
220     bool mReplaceOpObserved = false;
221 
222     /**
223      * If mLastSerialization is non-null, it represents an already serialized copy
224      * of the current clip state. If null, it has not been computed.
225      */
226     const ClipBase* mLastSerialization = nullptr;
227 
228     /**
229      * This pair of pointers is a single entry cache of most recently seen
230      */
231     const ClipBase* mLastResolutionResult = nullptr;
232     const ClipBase* mLastResolutionClip = nullptr;
233     Matrix4 mLastResolutionTransform;
234 
235     Rect mViewportBounds;
236     Rect mClipRect;
237     SkRegion mClipRegion;
238     RectangleList mRectangleList;
239 };
240 
241 } /* namespace uirenderer */
242 } /* namespace android */
243 
244 #endif /* CLIPAREA_H_ */
245