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 <SkRegion.h>
20 
21 #include "Matrix.h"
22 #include "Rect.h"
23 #include "utils/Pair.h"
24 
25 namespace android {
26 namespace uirenderer {
27 
28 Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform);
29 
30 class TransformedRectangle {
31 public:
32     TransformedRectangle();
33     TransformedRectangle(const Rect& bounds, const Matrix4& transform);
34 
35     bool canSimplyIntersectWith(const TransformedRectangle& other) const;
36     bool intersectWith(const TransformedRectangle& other);
37 
38     bool isEmpty() const;
39 
getBounds()40     const Rect& getBounds() const {
41         return mBounds;
42     }
43 
transformedBounds()44     Rect transformedBounds() const {
45         Rect transformedBounds(transformAndCalculateBounds(mBounds, mTransform));
46         return transformedBounds;
47     }
48 
getTransform()49     const Matrix4& getTransform() const {
50         return mTransform;
51     }
52 
53 private:
54     Rect mBounds;
55     Matrix4 mTransform;
56 };
57 
58 class RectangleList {
59 public:
60     RectangleList();
61 
62     bool isEmpty() const;
63     int getTransformedRectanglesCount() const;
64     const TransformedRectangle& getTransformedRectangle(int i) const;
65 
66     void setEmpty();
67     void set(const Rect& bounds, const Matrix4& transform);
68     bool intersectWith(const Rect& bounds, const Matrix4& transform);
69 
70     SkRegion convertToRegion(const SkRegion& clip) const;
71     Rect calculateBounds() const;
72 
73 private:
74     enum {
75         kMaxTransformedRectangles = 5
76     };
77 
78     int mTransformedRectanglesCount;
79     TransformedRectangle mTransformedRectangles[kMaxTransformedRectangles];
80 };
81 
82 class ClipArea {
83 public:
84     ClipArea();
85 
86     void setViewportDimensions(int width, int height);
87 
isEmpty()88     bool isEmpty() const {
89         return mClipRect.isEmpty();
90     }
91 
92     void setEmpty();
93     void setClip(float left, float top, float right, float bottom);
94     bool clipRectWithTransform(float left, float top, float right, float bottom,
95             const mat4* transform, SkRegion::Op op = SkRegion::kIntersect_Op);
96     bool clipRectWithTransform(const Rect& r, const mat4* transform,
97             SkRegion::Op op = SkRegion::kIntersect_Op);
98     bool clipRegion(const SkRegion& region, SkRegion::Op op = SkRegion::kIntersect_Op);
99     bool clipPathWithTransform(const SkPath& path, const mat4* transform,
100             SkRegion::Op op);
101 
getClipRect()102     const Rect& getClipRect() const {
103         return mClipRect;
104     }
105 
getClipRegion()106     const SkRegion& getClipRegion() const {
107         return mClipRegion;
108     }
109 
getRectangleList()110     const RectangleList& getRectangleList() const {
111         return mRectangleList;
112     }
113 
isRegion()114     bool isRegion() const {
115         return kModeRegion == mMode;
116     }
117 
isSimple()118     bool isSimple() const {
119         return mMode == kModeRectangle;
120     }
121 
isRectangleList()122     bool isRectangleList() const {
123         return mMode == kModeRectangleList;
124     }
125 
126 private:
127     void enterRectangleMode();
128     bool rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
129     bool rectangleModeClipRectWithTransform(float left, float top, float right,
130             float bottom, const mat4* transform, SkRegion::Op op);
131 
132     void enterRectangleListMode();
133     bool rectangleListModeClipRectWithTransform(float left, float top,
134             float right, float bottom, const mat4* transform, SkRegion::Op op);
135     bool rectangleListModeClipRectWithTransform(const Rect& r,
136             const mat4* transform, SkRegion::Op op);
137 
138     void enterRegionModeFromRectangleMode();
139     void enterRegionModeFromRectangleListMode();
140     void enterRegionMode();
141     bool regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
142             SkRegion::Op op);
143     bool regionModeClipRectWithTransform(float left, float top, float right,
144             float bottom, const mat4* transform, SkRegion::Op op);
145 
146     void ensureClipRegion();
147     void onClipRegionUpdated();
148     bool clipRegionOp(float left, float top, float right, float bottom,
149             SkRegion::Op op);
150 
createViewportRegion()151     SkRegion createViewportRegion() {
152         return SkRegion(mViewportBounds.toSkIRect());
153     }
154 
regionFromPath(const SkPath & path,SkRegion & pathAsRegion)155     void regionFromPath(const SkPath& path, SkRegion& pathAsRegion) {
156         // TODO: this should not mask every path to the viewport - this makes it impossible to use
157         // paths to clip to larger areas (which is valid e.g. with SkRegion::kReplace_Op)
158         pathAsRegion.setPath(path, createViewportRegion());
159     }
160 
161     enum Mode {
162         kModeRectangle,
163         kModeRegion,
164         kModeRectangleList
165     };
166 
167     Mode mMode;
168     Rect mViewportBounds;
169     Rect mClipRect;
170     SkRegion mClipRegion;
171     RectangleList mRectangleList;
172 };
173 
174 } /* namespace uirenderer */
175 } /* namespace android */
176 
177 #endif /* CLIPAREA_H_ */
178