1/*
2 * Copyright (C) 2011 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 _UI_SPRITES_H
18#define _UI_SPRITES_H
19
20#include <utils/RefBase.h>
21#include <utils/Looper.h>
22
23#include <gui/SurfaceComposerClient.h>
24
25#include <SkBitmap.h>
26
27namespace android {
28
29/*
30 * Transformation matrix for a sprite.
31 */
32struct SpriteTransformationMatrix {
33    inline SpriteTransformationMatrix() : dsdx(1.0f), dtdx(0.0f), dsdy(0.0f), dtdy(1.0f) { }
34    inline SpriteTransformationMatrix(float dsdx, float dtdx, float dsdy, float dtdy) :
35            dsdx(dsdx), dtdx(dtdx), dsdy(dsdy), dtdy(dtdy) { }
36
37    float dsdx;
38    float dtdx;
39    float dsdy;
40    float dtdy;
41
42    inline bool operator== (const SpriteTransformationMatrix& other) {
43        return dsdx == other.dsdx
44                && dtdx == other.dtdx
45                && dsdy == other.dsdy
46                && dtdy == other.dtdy;
47    }
48
49    inline bool operator!= (const SpriteTransformationMatrix& other) {
50        return !(*this == other);
51    }
52};
53
54/*
55 * Icon that a sprite displays, including its hotspot.
56 */
57struct SpriteIcon {
58    inline SpriteIcon() : hotSpotX(0), hotSpotY(0) { }
59    inline SpriteIcon(const SkBitmap& bitmap, float hotSpotX, float hotSpotY) :
60            bitmap(bitmap), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { }
61
62    SkBitmap bitmap;
63    float hotSpotX;
64    float hotSpotY;
65
66    inline SpriteIcon copy() const {
67        SkBitmap bitmapCopy;
68        if (bitmapCopy.tryAllocPixels(bitmap.info().makeColorType(kN32_SkColorType))) {
69            bitmap.readPixels(bitmapCopy.info(), bitmapCopy.getPixels(), bitmapCopy.rowBytes(),
70                    0, 0);
71        }
72        return SpriteIcon(bitmapCopy, hotSpotX, hotSpotY);
73    }
74
75    inline void reset() {
76        bitmap.reset();
77        hotSpotX = 0;
78        hotSpotY = 0;
79    }
80
81    inline bool isValid() const {
82        return !bitmap.isNull() && !bitmap.empty();
83    }
84};
85
86/*
87 * A sprite is a simple graphical object that is displayed on-screen above other layers.
88 * The basic sprite class is an interface.
89 * The implementation is provided by the sprite controller.
90 */
91class Sprite : public RefBase {
92protected:
93    Sprite() { }
94    virtual ~Sprite() { }
95
96public:
97    enum {
98        // The base layer for pointer sprites.
99        BASE_LAYER_POINTER = 0, // reserve space for 1 pointer
100
101        // The base layer for spot sprites.
102        BASE_LAYER_SPOT = 1, // reserve space for MAX_POINTER_ID spots
103    };
104
105    /* Sets the bitmap that is drawn by the sprite.
106     * The sprite retains a copy of the bitmap for subsequent rendering. */
107    virtual void setIcon(const SpriteIcon& icon) = 0;
108
109    inline void clearIcon() {
110        setIcon(SpriteIcon());
111    }
112
113    /* Sets whether the sprite is visible. */
114    virtual void setVisible(bool visible) = 0;
115
116    /* Sets the sprite position on screen, relative to the sprite's hot spot. */
117    virtual void setPosition(float x, float y) = 0;
118
119    /* Sets the layer of the sprite, relative to the system sprite overlay layer.
120     * Layer 0 is the overlay layer, > 0 appear above this layer. */
121    virtual void setLayer(int32_t layer) = 0;
122
123    /* Sets the sprite alpha blend ratio between 0.0 and 1.0. */
124    virtual void setAlpha(float alpha) = 0;
125
126    /* Sets the sprite transformation matrix. */
127    virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix) = 0;
128};
129
130/*
131 * Displays sprites on the screen.
132 *
133 * This interface is used by PointerController and SpotController to draw pointers or
134 * spot representations of fingers.  It is not intended for general purpose use
135 * by other components.
136 *
137 * All sprite position updates and rendering is performed asynchronously.
138 *
139 * Clients are responsible for animating sprites by periodically updating their properties.
140 */
141class SpriteController : public MessageHandler {
142protected:
143    virtual ~SpriteController();
144
145public:
146    SpriteController(const sp<Looper>& looper, int32_t overlayLayer);
147
148    /* Creates a new sprite, initially invisible. */
149    sp<Sprite> createSprite();
150
151    /* Opens or closes a transaction to perform a batch of sprite updates as part of
152     * a single operation such as setPosition and setAlpha.  It is not necessary to
153     * open a transaction when updating a single property.
154     * Calls to openTransaction() nest and must be matched by an equal number
155     * of calls to closeTransaction(). */
156    void openTransaction();
157    void closeTransaction();
158
159private:
160    enum {
161        MSG_UPDATE_SPRITES,
162        MSG_DISPOSE_SURFACES,
163    };
164
165    enum {
166        DIRTY_BITMAP = 1 << 0,
167        DIRTY_ALPHA = 1 << 1,
168        DIRTY_POSITION = 1 << 2,
169        DIRTY_TRANSFORMATION_MATRIX = 1 << 3,
170        DIRTY_LAYER = 1 << 4,
171        DIRTY_VISIBILITY = 1 << 5,
172        DIRTY_HOTSPOT = 1 << 6,
173    };
174
175    /* Describes the state of a sprite.
176     * This structure is designed so that it can be copied during updates so that
177     * surfaces can be resized and redrawn without blocking the client by holding a lock
178     * on the sprites for a long time.
179     * Note that the SkBitmap holds a reference to a shared (and immutable) pixel ref. */
180    struct SpriteState {
181        inline SpriteState() :
182                dirty(0), visible(false),
183                positionX(0), positionY(0), layer(0), alpha(1.0f),
184                surfaceWidth(0), surfaceHeight(0), surfaceDrawn(false), surfaceVisible(false) {
185        }
186
187        uint32_t dirty;
188
189        SpriteIcon icon;
190        bool visible;
191        float positionX;
192        float positionY;
193        int32_t layer;
194        float alpha;
195        SpriteTransformationMatrix transformationMatrix;
196
197        sp<SurfaceControl> surfaceControl;
198        int32_t surfaceWidth;
199        int32_t surfaceHeight;
200        bool surfaceDrawn;
201        bool surfaceVisible;
202
203        inline bool wantSurfaceVisible() const {
204            return visible && alpha > 0.0f && icon.isValid();
205        }
206    };
207
208    /* Client interface for a sprite.
209     * Requests acquire a lock on the controller, update local state and request the
210     * controller to invalidate the sprite.
211     * The real heavy lifting of creating, resizing and redrawing surfaces happens
212     * asynchronously with no locks held except in short critical section to copy
213     * the sprite state before the work and update the sprite surface control afterwards.
214     */
215    class SpriteImpl : public Sprite {
216    protected:
217        virtual ~SpriteImpl();
218
219    public:
220        explicit SpriteImpl(const sp<SpriteController> controller);
221
222        virtual void setIcon(const SpriteIcon& icon);
223        virtual void setVisible(bool visible);
224        virtual void setPosition(float x, float y);
225        virtual void setLayer(int32_t layer);
226        virtual void setAlpha(float alpha);
227        virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix);
228
229        inline const SpriteState& getStateLocked() const {
230            return mLocked.state;
231        }
232
233        inline void resetDirtyLocked() {
234            mLocked.state.dirty = 0;
235        }
236
237        inline void setSurfaceLocked(const sp<SurfaceControl>& surfaceControl,
238                int32_t width, int32_t height, bool drawn, bool visible) {
239            mLocked.state.surfaceControl = surfaceControl;
240            mLocked.state.surfaceWidth = width;
241            mLocked.state.surfaceHeight = height;
242            mLocked.state.surfaceDrawn = drawn;
243            mLocked.state.surfaceVisible = visible;
244        }
245
246    private:
247        sp<SpriteController> mController;
248
249        struct Locked {
250            SpriteState state;
251        } mLocked; // guarded by mController->mLock
252
253        void invalidateLocked(uint32_t dirty);
254    };
255
256    /* Stores temporary information collected during the sprite update cycle. */
257    struct SpriteUpdate {
258        inline SpriteUpdate() : surfaceChanged(false) { }
259        inline SpriteUpdate(const sp<SpriteImpl> sprite, const SpriteState& state) :
260                sprite(sprite), state(state), surfaceChanged(false) {
261        }
262
263        sp<SpriteImpl> sprite;
264        SpriteState state;
265        bool surfaceChanged;
266    };
267
268    mutable Mutex mLock;
269
270    sp<Looper> mLooper;
271    const int32_t mOverlayLayer;
272    sp<WeakMessageHandler> mHandler;
273
274    sp<SurfaceComposerClient> mSurfaceComposerClient;
275
276    struct Locked {
277        Vector<sp<SpriteImpl> > invalidatedSprites;
278        Vector<sp<SurfaceControl> > disposedSurfaces;
279        uint32_t transactionNestingCount;
280        bool deferredSpriteUpdate;
281    } mLocked; // guarded by mLock
282
283    void invalidateSpriteLocked(const sp<SpriteImpl>& sprite);
284    void disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl);
285
286    void handleMessage(const Message& message);
287    void doUpdateSprites();
288    void doDisposeSurfaces();
289
290    void ensureSurfaceComposerClient();
291    sp<SurfaceControl> obtainSurface(int32_t width, int32_t height);
292};
293
294} // namespace android
295
296#endif // _UI_SPRITES_H
297