/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _UI_SPRITES_H
#define _UI_SPRITES_H
#include <utils/RefBase.h>
#include <utils/Looper.h>
#include <gui/SurfaceComposerClient.h>
#include <SkBitmap.h>
namespace android {
/*
* Transformation matrix for a sprite.
*/
struct SpriteTransformationMatrix {
inline SpriteTransformationMatrix() : dsdx(1.0f), dtdx(0.0f), dsdy(0.0f), dtdy(1.0f) { }
inline SpriteTransformationMatrix(float dsdx, float dtdx, float dsdy, float dtdy) :
dsdx(dsdx), dtdx(dtdx), dsdy(dsdy), dtdy(dtdy) { }
float dsdx;
float dtdx;
float dsdy;
float dtdy;
inline bool operator== (const SpriteTransformationMatrix& other) {
return dsdx == other.dsdx
&& dtdx == other.dtdx
&& dsdy == other.dsdy
&& dtdy == other.dtdy;
}
inline bool operator!= (const SpriteTransformationMatrix& other) {
return !(*this == other);
}
};
/*
* Icon that a sprite displays, including its hotspot.
*/
struct SpriteIcon {
inline SpriteIcon() : hotSpotX(0), hotSpotY(0) { }
inline SpriteIcon(const SkBitmap& bitmap, float hotSpotX, float hotSpotY) :
bitmap(bitmap), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { }
SkBitmap bitmap;
float hotSpotX;
float hotSpotY;
inline SpriteIcon copy() const {
SkBitmap bitmapCopy;
bitmap.copyTo(&bitmapCopy, SkBitmap::kARGB_8888_Config);
return SpriteIcon(bitmapCopy, hotSpotX, hotSpotY);
}
inline void reset() {
bitmap.reset();
hotSpotX = 0;
hotSpotY = 0;
}
inline bool isValid() const {
return !bitmap.isNull() && !bitmap.empty();
}
};
/*
* A sprite is a simple graphical object that is displayed on-screen above other layers.
* The basic sprite class is an interface.
* The implementation is provided by the sprite controller.
*/
class Sprite : public RefBase {
protected:
Sprite() { }
virtual ~Sprite() { }
public:
enum {
// The base layer for pointer sprites.
BASE_LAYER_POINTER = 0, // reserve space for 1 pointer
// The base layer for spot sprites.
BASE_LAYER_SPOT = 1, // reserve space for MAX_POINTER_ID spots
};
/* Sets the bitmap that is drawn by the sprite.
* The sprite retains a copy of the bitmap for subsequent rendering. */
virtual void setIcon(const SpriteIcon& icon) = 0;
inline void clearIcon() {
setIcon(SpriteIcon());
}
/* Sets whether the sprite is visible. */
virtual void setVisible(bool visible) = 0;
/* Sets the sprite position on screen, relative to the sprite's hot spot. */
virtual void setPosition(float x, float y) = 0;
/* Sets the layer of the sprite, relative to the system sprite overlay layer.
* Layer 0 is the overlay layer, > 0 appear above this layer. */
virtual void setLayer(int32_t layer) = 0;
/* Sets the sprite alpha blend ratio between 0.0 and 1.0. */
virtual void setAlpha(float alpha) = 0;
/* Sets the sprite transformation matrix. */
virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix) = 0;
};
/*
* Displays sprites on the screen.
*
* This interface is used by PointerController and SpotController to draw pointers or
* spot representations of fingers. It is not intended for general purpose use
* by other components.
*
* All sprite position updates and rendering is performed asynchronously.
*
* Clients are responsible for animating sprites by periodically updating their properties.
*/
class SpriteController : public MessageHandler {
protected:
virtual ~SpriteController();
public:
SpriteController(const sp<Looper>& looper, int32_t overlayLayer);
/* Creates a new sprite, initially invisible. */
sp<Sprite> createSprite();
/* Opens or closes a transaction to perform a batch of sprite updates as part of
* a single operation such as setPosition and setAlpha. It is not necessary to
* open a transaction when updating a single property.
* Calls to openTransaction() nest and must be matched by an equal number
* of calls to closeTransaction(). */
void openTransaction();
void closeTransaction();
private:
enum {
MSG_UPDATE_SPRITES,
MSG_DISPOSE_SURFACES,
};
enum {
DIRTY_BITMAP = 1 << 0,
DIRTY_ALPHA = 1 << 1,
DIRTY_POSITION = 1 << 2,
DIRTY_TRANSFORMATION_MATRIX = 1 << 3,
DIRTY_LAYER = 1 << 4,
DIRTY_VISIBILITY = 1 << 5,
DIRTY_HOTSPOT = 1 << 6,
};
/* Describes the state of a sprite.
* This structure is designed so that it can be copied during updates so that
* surfaces can be resized and redrawn without blocking the client by holding a lock
* on the sprites for a long time.
* Note that the SkBitmap holds a reference to a shared (and immutable) pixel ref. */
struct SpriteState {
inline SpriteState() :
dirty(0), visible(false),
positionX(0), positionY(0), layer(0), alpha(1.0f),
surfaceWidth(0), surfaceHeight(0), surfaceDrawn(false), surfaceVisible(false) {
}
uint32_t dirty;
SpriteIcon icon;
bool visible;
float positionX;
float positionY;
int32_t layer;
float alpha;
SpriteTransformationMatrix transformationMatrix;
sp<SurfaceControl> surfaceControl;
int32_t surfaceWidth;
int32_t surfaceHeight;
bool surfaceDrawn;
bool surfaceVisible;
inline bool wantSurfaceVisible() const {
return visible && alpha > 0.0f && icon.isValid();
}
};
/* Client interface for a sprite.
* Requests acquire a lock on the controller, update local state and request the
* controller to invalidate the sprite.
* The real heavy lifting of creating, resizing and redrawing surfaces happens
* asynchronously with no locks held except in short critical section to copy
* the sprite state before the work and update the sprite surface control afterwards.
*/
class SpriteImpl : public Sprite {
protected:
virtual ~SpriteImpl();
public:
SpriteImpl(const sp<SpriteController> controller);
virtual void setIcon(const SpriteIcon& icon);
virtual void setVisible(bool visible);
virtual void setPosition(float x, float y);
virtual void setLayer(int32_t layer);
virtual void setAlpha(float alpha);
virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix);
inline const SpriteState& getStateLocked() const {
return mLocked.state;
}
inline void resetDirtyLocked() {
mLocked.state.dirty = 0;
}
inline void setSurfaceLocked(const sp<SurfaceControl>& surfaceControl,
int32_t width, int32_t height, bool drawn, bool visible) {
mLocked.state.surfaceControl = surfaceControl;
mLocked.state.surfaceWidth = width;
mLocked.state.surfaceHeight = height;
mLocked.state.surfaceDrawn = drawn;
mLocked.state.surfaceVisible = visible;
}
private:
sp<SpriteController> mController;
struct Locked {
SpriteState state;
} mLocked; // guarded by mController->mLock
void invalidateLocked(uint32_t dirty);
};
/* Stores temporary information collected during the sprite update cycle. */
struct SpriteUpdate {
inline SpriteUpdate() : surfaceChanged(false) { }
inline SpriteUpdate(const sp<SpriteImpl> sprite, const SpriteState& state) :
sprite(sprite), state(state), surfaceChanged(false) {
}
sp<SpriteImpl> sprite;
SpriteState state;
bool surfaceChanged;
};
mutable Mutex mLock;
sp<Looper> mLooper;
const int32_t mOverlayLayer;
sp<WeakMessageHandler> mHandler;
sp<SurfaceComposerClient> mSurfaceComposerClient;
struct Locked {
Vector<sp<SpriteImpl> > invalidatedSprites;
Vector<sp<SurfaceControl> > disposedSurfaces;
uint32_t transactionNestingCount;
bool deferredSpriteUpdate;
} mLocked; // guarded by mLock
void invalidateSpriteLocked(const sp<SpriteImpl>& sprite);
void disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl);
void handleMessage(const Message& message);
void doUpdateSprites();
void doDisposeSurfaces();
void ensureSurfaceComposerClient();
sp<SurfaceControl> obtainSurface(int32_t width, int32_t height);
};
} // namespace android
#endif // _UI_SPRITES_H