ClipArea.h revision e4db79de127cfe961195f52907af8451026eaa20
1ce0537b80087a6225273040a987414b1dd081aa0Romain Guy/*
2ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * Copyright (C) 2015 The Android Open Source Project
3ce0537b80087a6225273040a987414b1dd081aa0Romain Guy *
4ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * Licensed under the Apache License, Version 2.0 (the "License");
5ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * you may not use this file except in compliance with the License.
6ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * You may obtain a copy of the License at
7ce0537b80087a6225273040a987414b1dd081aa0Romain Guy *
8ce0537b80087a6225273040a987414b1dd081aa0Romain Guy *      http://www.apache.org/licenses/LICENSE-2.0
9ce0537b80087a6225273040a987414b1dd081aa0Romain Guy *
10ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * Unless required by applicable law or agreed to in writing, software
11ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * distributed under the License is distributed on an "AS IS" BASIS,
12ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * See the License for the specific language governing permissions and
14ce0537b80087a6225273040a987414b1dd081aa0Romain Guy * limitations under the License.
15ce0537b80087a6225273040a987414b1dd081aa0Romain Guy */
16ce0537b80087a6225273040a987414b1dd081aa0Romain Guy#ifndef CLIPAREA_H
175b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy#define CLIPAREA_H
185b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
19ce0537b80087a6225273040a987414b1dd081aa0Romain Guy#include "Matrix.h"
20ce0537b80087a6225273040a987414b1dd081aa0Romain Guy#include "Rect.h"
21ce0537b80087a6225273040a987414b1dd081aa0Romain Guy#include "utils/Pair.h"
22ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
2321b028a44f3e0bd9b0f0432b8b92c45f661d22a4Romain Guy#include <SkRegion.h>
24ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
25ce0537b80087a6225273040a987414b1dd081aa0Romain Guynamespace android {
26ce0537b80087a6225273040a987414b1dd081aa0Romain Guynamespace uirenderer {
27ce0537b80087a6225273040a987414b1dd081aa0Romain Guy
28d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haaseclass LinearAllocator;
29d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase
30d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet HaaseRect transformAndCalculateBounds(const Rect& r, const Matrix4& transform);
31d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase
32d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haaseclass TransformedRectangle {
33d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haasepublic:
34d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase    TransformedRectangle();
35d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase    TransformedRectangle(const Rect& bounds, const Matrix4& transform);
36d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase
37d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase    bool canSimplyIntersectWith(const TransformedRectangle& other) const;
38d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase    void intersectWith(const TransformedRectangle& other);
39d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase
40d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase    bool isEmpty() const;
41d98aa2de9ab18e09c2be1997f41212740f51f6e6Chet Haase
429e10841c27d973b930e1b49a099c69d866659505Romain Guy    const Rect& getBounds() const {
439e10841c27d973b930e1b49a099c69d866659505Romain Guy        return mBounds;
449e10841c27d973b930e1b49a099c69d866659505Romain Guy    }
459e10841c27d973b930e1b49a099c69d866659505Romain Guy
46121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    Rect transformedBounds() const {
47121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy        Rect transformedBounds(transformAndCalculateBounds(mBounds, mTransform));
48121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy        return transformedBounds;
49121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    }
50121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy
51ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    const Matrix4& getTransform() const {
52ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        return mTransform;
53fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    }
547d139ba2c331f11e9b485753cc727a0ff202f2a4Romain Guy
55ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    void transform(const Matrix4& transform) {
56ce0537b80087a6225273040a987414b1dd081aa0Romain Guy        Matrix4 t;
57121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy        t.loadMultiply(transform, mTransform);
58121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy        mTransform = t;
59121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    }
60121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy
61dda570201ac851dd85af3861f7e575721d3345daRomain Guyprivate:
62ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    Rect mBounds;
63121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    Matrix4 mTransform;
64121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy};
65121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy
66121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guyclass RectangleList {
67ce0537b80087a6225273040a987414b1dd081aa0Romain Guypublic:
68121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    RectangleList();
69121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy
70121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    bool isEmpty() const;
71121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    int getTransformedRectanglesCount() const;
72121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    const TransformedRectangle& getTransformedRectangle(int i) const;
73121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy
74121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    void setEmpty();
75121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    void set(const Rect& bounds, const Matrix4& transform);
76ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    bool intersectWith(const Rect& bounds, const Matrix4& transform);
77ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    void transform(const Matrix4& transform);
78121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy
79121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    SkRegion convertToRegion(const SkRegion& clip) const;
80121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    Rect calculateBounds() const;
817d139ba2c331f11e9b485753cc727a0ff202f2a4Romain Guy
82121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    enum {
83121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy        kMaxTransformedRectangles = 5
84121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    };
857d139ba2c331f11e9b485753cc727a0ff202f2a4Romain Guy
86121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guyprivate:
87121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    int mTransformedRectanglesCount;
88121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    TransformedRectangle mTransformedRectangles[kMaxTransformedRectangles];
897d139ba2c331f11e9b485753cc727a0ff202f2a4Romain Guy};
90121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy
91ce0537b80087a6225273040a987414b1dd081aa0Romain Guyenum class ClipMode {
92121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    Rectangle,
93121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    RectangleList,
94121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy
95121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    // region and path - intersected. if either is empty, don't use
96121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    Region
97121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy};
98fe8809471a40cac8acc984adfa51c39e13e83947Romain Guy
99ce0537b80087a6225273040a987414b1dd081aa0Romain Guystruct ClipBase {
1005b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy    ClipBase(ClipMode mode)
1018c749f87d29e1a363ddf9027c3a51753c612d510Romain Guy            : mode(mode) {}
1028c749f87d29e1a363ddf9027c3a51753c612d510Romain Guy    ClipBase(const Rect& rect)
1038c749f87d29e1a363ddf9027c3a51753c612d510Romain Guy            : mode(ClipMode::Rectangle)
104fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy            , rect(rect) {}
105fb8b763f762ae21923c58d64caa729b012f40e05Romain Guy    const ClipMode mode;
1066c81893c626499e58c8eeb20d6c35ec4e1ce808bRomain Guy    // Bounds of the clipping area, used to define the scissor, and define which
107121e2242565d5f09ad83a2d33ecd2225838802c5Romain Guy    // portion of the stencil is updated/used
1087d139ba2c331f11e9b485753cc727a0ff202f2a4Romain Guy    Rect rect;
1097d139ba2c331f11e9b485753cc727a0ff202f2a4Romain Guy};
110163935113919a184122b8b3bd672ef08c8df65dcRomain Guy
1119aaa8269a3e7291aab84d01c3fc9c744d8f2d2f4Romain Guystruct ClipRect : ClipBase {
112a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy    ClipRect(const Rect& rect)
113a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy            : ClipBase(rect) {}
114a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy};
115a2341a9f6addcd79723965ec5b1a1c5ae0f8bd65Romain Guy
1169aaa8269a3e7291aab84d01c3fc9c744d8f2d2f4Romain Guystruct ClipRectList : ClipBase {
117ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    ClipRectList(const RectangleList& rectList)
118ce0537b80087a6225273040a987414b1dd081aa0Romain Guy            : ClipBase(ClipMode::RectangleList)
119ce0537b80087a6225273040a987414b1dd081aa0Romain Guy            , rectList(rectList) {}
120ce0537b80087a6225273040a987414b1dd081aa0Romain Guy    RectangleList rectList;
121ce0537b80087a6225273040a987414b1dd081aa0Romain Guy};
1225b3b35296e8b2c8d3f07d32bb645d5414db41a1dRomain Guy
123struct ClipRegion : ClipBase {
124    ClipRegion(const SkRegion& region)
125            : ClipBase(ClipMode::Region)
126            , region(region) {}
127    ClipRegion()
128            : ClipBase(ClipMode::Region) {}
129    SkRegion region;
130};
131
132class ClipArea {
133public:
134    ClipArea();
135
136    void setViewportDimensions(int width, int height);
137
138    bool isEmpty() const {
139        return mClipRect.isEmpty();
140    }
141
142    void setEmpty();
143    void setClip(float left, float top, float right, float bottom);
144    void clipRectWithTransform(const Rect& r, const mat4* transform,
145            SkRegion::Op op);
146    void clipRegion(const SkRegion& region, SkRegion::Op op);
147    void clipPathWithTransform(const SkPath& path, const mat4* transform,
148            SkRegion::Op op);
149
150    const Rect& getClipRect() const {
151        return mClipRect;
152    }
153
154    const SkRegion& getClipRegion() const {
155        return mClipRegion;
156    }
157
158    const RectangleList& getRectangleList() const {
159        return mRectangleList;
160    }
161
162    bool isRegion() const {
163        return ClipMode::Region == mMode;
164    }
165
166    bool isSimple() const {
167        return mMode == ClipMode::Rectangle;
168    }
169
170    bool isRectangleList() const {
171        return mMode == ClipMode::RectangleList;
172    }
173
174    const ClipBase* serializeClip(LinearAllocator& allocator);
175    const ClipBase* serializeIntersectedClip(LinearAllocator& allocator,
176            const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
177    void applyClip(const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
178
179private:
180    void enterRectangleMode();
181    void rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
182
183    void enterRectangleListMode();
184    void rectangleListModeClipRectWithTransform(const Rect& r,
185            const mat4* transform, SkRegion::Op op);
186
187    void enterRegionModeFromRectangleMode();
188    void enterRegionModeFromRectangleListMode();
189    void enterRegionMode();
190    void regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
191            SkRegion::Op op);
192
193    void ensureClipRegion();
194    void onClipRegionUpdated();
195
196    // Called by every state modifying public method.
197    void onClipUpdated() {
198        mPostViewportClipObserved = true;
199        mLastSerialization = nullptr;
200        mLastResolutionResult = nullptr;
201    }
202
203    SkRegion createViewportRegion() {
204        return SkRegion(mViewportBounds.toSkIRect());
205    }
206
207    void regionFromPath(const SkPath& path, SkRegion& pathAsRegion) {
208        // TODO: this should not mask every path to the viewport - this makes it impossible to use
209        // paths to clip to larger areas (which is valid e.g. with SkRegion::kReplace_Op)
210        pathAsRegion.setPath(path, createViewportRegion());
211    }
212
213    ClipMode mMode;
214    bool mPostViewportClipObserved = false;
215
216    /**
217     * If mLastSerialization is non-null, it represents an already serialized copy
218     * of the current clip state. If null, it has not been computed.
219     */
220    const ClipBase* mLastSerialization = nullptr;
221
222    /**
223     * This pair of pointers is a single entry cache of most recently seen
224     */
225    const ClipBase* mLastResolutionResult = nullptr;
226    const ClipBase* mLastResolutionClip = nullptr;
227    Matrix4 mLastResolutionTransform;
228
229    Rect mViewportBounds;
230    Rect mClipRect;
231    SkRegion mClipRegion;
232    RectangleList mRectangleList;
233};
234
235} /* namespace uirenderer */
236} /* namespace android */
237
238#endif /* CLIPAREA_H_ */
239