1/*
2 * Copyright (C) 2010 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
17#ifndef ANDROID_HWUI_SNAPSHOT_H
18#define ANDROID_HWUI_SNAPSHOT_H
19
20#include <GLES2/gl2.h>
21#include <GLES2/gl2ext.h>
22
23#include <utils/LinearAllocator.h>
24#include <utils/RefBase.h>
25#include <ui/Region.h>
26
27#include <SkRegion.h>
28
29#include "Layer.h"
30#include "Matrix.h"
31#include "Outline.h"
32#include "Rect.h"
33#include "utils/Macros.h"
34
35namespace android {
36namespace uirenderer {
37
38/**
39 * Temporary structure holding information for a single outline clip.
40 *
41 * These structures are treated as immutable once created, and only exist for a single frame, which
42 * is why they may only be allocated with a LinearAllocator.
43 */
44class RoundRectClipState {
45public:
46    /** static void* operator new(size_t size); PURPOSELY OMITTED, allocator only **/
47    static void* operator new(size_t size, LinearAllocator& allocator) {
48        return allocator.alloc(size);
49    }
50
51    bool areaRequiresRoundRectClip(const Rect& rect) const {
52        return rect.intersects(dangerRects[0])
53                || rect.intersects(dangerRects[1])
54                || rect.intersects(dangerRects[2])
55                || rect.intersects(dangerRects[3]);
56    }
57
58    bool highPriority;
59    Matrix4 matrix;
60    Rect dangerRects[4];
61    Rect innerRect;
62    float radius;
63};
64
65/**
66 * A snapshot holds information about the current state of the rendering
67 * surface. A snapshot is usually created whenever the user calls save()
68 * and discarded when the user calls restore(). Once a snapshot is created,
69 * it can hold information for deferred rendering.
70 *
71 * Each snapshot has a link to a previous snapshot, indicating the previous
72 * state of the renderer.
73 */
74class Snapshot: public LightRefBase<Snapshot> {
75public:
76
77    Snapshot();
78    Snapshot(const sp<Snapshot>& s, int saveFlags);
79
80    /**
81     * Various flags set on ::flags.
82     */
83    enum Flags {
84        /**
85         * Indicates that the clip region was modified. When this
86         * snapshot is restored so must the clip.
87         */
88        kFlagClipSet = 0x1,
89        /**
90         * Indicates that this snapshot was created when saving
91         * a new layer.
92         */
93        kFlagIsLayer = 0x2,
94        /**
95         * Indicates that this snapshot is a special type of layer
96         * backed by an FBO. This flag only makes sense when the
97         * flag kFlagIsLayer is also set.
98         *
99         * Viewport has been modified to fit the new Fbo, and must be
100         * restored when this snapshot is restored.
101         */
102        kFlagIsFboLayer = 0x4,
103        /**
104         * Indicates that this snapshot or an ancestor snapshot is
105         * an FBO layer.
106         */
107        kFlagFboTarget = 0x8,
108    };
109
110    /**
111     * Modifies the current clip with the new clip rectangle and
112     * the specified operation. The specified rectangle is transformed
113     * by this snapshot's trasnformation.
114     */
115    bool clip(float left, float top, float right, float bottom,
116            SkRegion::Op op = SkRegion::kIntersect_Op);
117
118    /**
119     * Modifies the current clip with the new clip rectangle and
120     * the specified operation. The specified rectangle is considered
121     * already transformed.
122     */
123    bool clipTransformed(const Rect& r, SkRegion::Op op = SkRegion::kIntersect_Op);
124
125    /**
126     * Modifies the current clip with the specified region and operation.
127     * The specified region is considered already transformed.
128     */
129    bool clipRegionTransformed(const SkRegion& region, SkRegion::Op op);
130
131    /**
132     * Sets the current clip.
133     */
134    void setClip(float left, float top, float right, float bottom);
135
136    /**
137     * Returns the current clip in local coordinates. The clip rect is
138     * transformed by the inverse transform matrix.
139     */
140    ANDROID_API const Rect& getLocalClip();
141
142    /**
143     * Returns the current clip in render target coordinates.
144     */
145    const Rect& getRenderTargetClip() { return *clipRect; }
146
147    /**
148     * Resets the clip to the specified rect.
149     */
150    void resetClip(float left, float top, float right, float bottom);
151
152    /**
153     * Resets the current transform to a pure 3D translation.
154     */
155    void resetTransform(float x, float y, float z);
156
157    void initializeViewport(int width, int height) {
158        mViewportData.initialize(width, height);
159    }
160
161    int getViewportWidth() const { return mViewportData.mWidth; }
162    int getViewportHeight() const { return mViewportData.mHeight; }
163    const Matrix4& getOrthoMatrix() const { return mViewportData.mOrthoMatrix; }
164
165    const Vector3& getRelativeLightCenter() const { return mRelativeLightCenter; }
166    void setRelativeLightCenter(const Vector3& lightCenter) { mRelativeLightCenter = lightCenter; }
167
168    /**
169     * Sets (and replaces) the current clipping outline
170     *
171     * If the current round rect clip is high priority, the incoming clip is ignored.
172     */
173    void setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds,
174            float radius, bool highPriority);
175
176    /**
177     * Indicates whether this snapshot should be ignored. A snapshot
178     * is typicalled ignored if its layer is invisible or empty.
179     */
180    bool isIgnored() const;
181
182    /**
183     * Indicates whether the current transform has perspective components.
184     */
185    bool hasPerspectiveTransform() const;
186
187    /**
188     * Dirty flags.
189     */
190    int flags;
191
192    /**
193     * Previous snapshot.
194     */
195    sp<Snapshot> previous;
196
197    /**
198     * A pointer to the currently active layer.
199     *
200     * This snapshot does not own the layer, this pointer must not be freed.
201     */
202    Layer* layer;
203
204    /**
205     * Target FBO used for rendering. Set to 0 when rendering directly
206     * into the framebuffer.
207     */
208    GLuint fbo;
209
210    /**
211     * Indicates that this snapshot is invisible and nothing should be drawn
212     * inside it. This flag is set only when the layer clips drawing to its
213     * bounds and is passed to subsequent snapshots.
214     */
215    bool invisible;
216
217    /**
218     * If set to true, the layer will not be composited. This is similar to
219     * invisible but this flag is not passed to subsequent snapshots.
220     */
221    bool empty;
222
223    /**
224     * Local transformation. Holds the current translation, scale and
225     * rotation values.
226     *
227     * This is a reference to a matrix owned by this snapshot or another
228     *  snapshot. This pointer must not be freed. See ::mTransformRoot.
229     */
230    mat4* transform;
231
232    /**
233     * Current clip rect. The clip is stored in canvas-space coordinates,
234     * (screen-space coordinates in the regular case.)
235     *
236     * This is a reference to a rect owned by this snapshot or another
237     * snapshot. This pointer must not be freed. See ::mClipRectRoot.
238     */
239    Rect* clipRect;
240
241    /**
242     * Current clip region. The clip is stored in canvas-space coordinates,
243     * (screen-space coordinates in the regular case.)
244     *
245     * This is a reference to a region owned by this snapshot or another
246     * snapshot. This pointer must not be freed. See ::mClipRegionRoot.
247     */
248    SkRegion* clipRegion;
249
250    /**
251     * The ancestor layer's dirty region.
252     *
253     * This is a reference to a region owned by a layer. This pointer must
254     * not be freed.
255     */
256    Region* region;
257
258    /**
259     * Current alpha value. This value is 1 by default, but may be set by a DisplayList which
260     * has translucent rendering in a non-overlapping View. This value will be used by
261     * the renderer to set the alpha in the current color being used for ensuing drawing
262     * operations. The value is inherited by child snapshots because the same value should
263     * be applied to descendents of the current DisplayList (for example, a TextView contains
264     * the base alpha value which should be applied to the child DisplayLists used for drawing
265     * the actual text).
266     */
267    float alpha;
268
269    /**
270     * Current clipping round rect.
271     *
272     * Points to data not owned by the snapshot, and may only be replaced by subsequent RR clips,
273     * never modified.
274     */
275    const RoundRectClipState* roundRectClipState;
276
277    void dump() const;
278
279private:
280    struct ViewportData {
281        ViewportData() : mWidth(0), mHeight(0) {}
282        void initialize(int width, int height) {
283            mWidth = width;
284            mHeight = height;
285            mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
286        }
287
288        /*
289         * Width and height of current viewport.
290         *
291         * The viewport is always defined to be (0, 0, width, height).
292         */
293        int mWidth;
294        int mHeight;
295        /**
296         * Contains the current orthographic, projection matrix.
297         */
298        mat4 mOrthoMatrix;
299    };
300
301    void ensureClipRegion();
302    void copyClipRectFromRegion();
303
304    bool clipRegionOp(float left, float top, float right, float bottom, SkRegion::Op op);
305
306    mat4 mTransformRoot;
307    Rect mClipRectRoot;
308    Rect mLocalClip; // don't use directly, call getLocalClip() which initializes this
309
310    SkRegion mClipRegionRoot;
311    ViewportData mViewportData;
312    Vector3 mRelativeLightCenter;
313
314}; // class Snapshot
315
316}; // namespace uirenderer
317}; // namespace android
318
319#endif // ANDROID_HWUI_SNAPSHOT_H
320