widget/gonk/libui/SpriteController.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*
michael@0 2 * Copyright (C) 2011 The Android Open Source Project
michael@0 3 *
michael@0 4 * Licensed under the Apache License, Version 2.0 (the "License");
michael@0 5 * you may not use this file except in compliance with the License.
michael@0 6 * You may obtain a copy of the License at
michael@0 7 *
michael@0 8 * http://www.apache.org/licenses/LICENSE-2.0
michael@0 9 *
michael@0 10 * Unless required by applicable law or agreed to in writing, software
michael@0 11 * distributed under the License is distributed on an "AS IS" BASIS,
michael@0 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
michael@0 13 * See the License for the specific language governing permissions and
michael@0 14 * limitations under the License.
michael@0 15 */
michael@0 16
michael@0 17 #define LOG_TAG "Sprites"
michael@0 18
michael@0 19 //#define LOG_NDEBUG 0
michael@0 20
michael@0 21 #include "SpriteController.h"
michael@0 22
michael@0 23 #include "cutils_log.h"
michael@0 24 #include <utils/String8.h>
michael@0 25 #ifdef HAVE_ANDROID_OS
michael@0 26 #include <gui/Surface.h>
michael@0 27 #endif
michael@0 28
michael@0 29 #include <SkBitmap.h>
michael@0 30 #include <SkCanvas.h>
michael@0 31 #include <SkColor.h>
michael@0 32 #include <SkPaint.h>
michael@0 33 #include <SkXfermode.h>
michael@0 34 #include <android/native_window.h>
michael@0 35
michael@0 36 namespace android {
michael@0 37
michael@0 38 // --- SpriteController ---
michael@0 39
michael@0 40 SpriteController::SpriteController(const sp<Looper>& looper, int32_t overlayLayer) :
michael@0 41 mLooper(looper), mOverlayLayer(overlayLayer) {
michael@0 42 #ifdef HAVE_ANDROID_OS
michael@0 43 mHandler = new WeakMessageHandler(this);
michael@0 44 #endif
michael@0 45
michael@0 46 mLocked.transactionNestingCount = 0;
michael@0 47 mLocked.deferredSpriteUpdate = false;
michael@0 48 }
michael@0 49
michael@0 50 SpriteController::~SpriteController() {
michael@0 51 #ifdef HAVE_ANDROID_OS
michael@0 52 mLooper->removeMessages(mHandler);
michael@0 53
michael@0 54 if (mSurfaceComposerClient != NULL) {
michael@0 55 mSurfaceComposerClient->dispose();
michael@0 56 mSurfaceComposerClient.clear();
michael@0 57 }
michael@0 58 #endif
michael@0 59 }
michael@0 60
michael@0 61 sp<Sprite> SpriteController::createSprite() {
michael@0 62 return new SpriteImpl(this);
michael@0 63 }
michael@0 64
michael@0 65 void SpriteController::openTransaction() {
michael@0 66 AutoMutex _l(mLock);
michael@0 67
michael@0 68 mLocked.transactionNestingCount += 1;
michael@0 69 }
michael@0 70
michael@0 71 void SpriteController::closeTransaction() {
michael@0 72 AutoMutex _l(mLock);
michael@0 73
michael@0 74 LOG_ALWAYS_FATAL_IF(mLocked.transactionNestingCount == 0,
michael@0 75 "Sprite closeTransaction() called but there is no open sprite transaction");
michael@0 76
michael@0 77 mLocked.transactionNestingCount -= 1;
michael@0 78 if (mLocked.transactionNestingCount == 0 && mLocked.deferredSpriteUpdate) {
michael@0 79 mLocked.deferredSpriteUpdate = false;
michael@0 80 #ifdef HAVE_ANDROID_OS
michael@0 81 mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES));
michael@0 82 #endif
michael@0 83 }
michael@0 84 }
michael@0 85
michael@0 86 void SpriteController::invalidateSpriteLocked(const sp<SpriteImpl>& sprite) {
michael@0 87 bool wasEmpty = mLocked.invalidatedSprites.isEmpty();
michael@0 88 mLocked.invalidatedSprites.push(sprite);
michael@0 89 if (wasEmpty) {
michael@0 90 if (mLocked.transactionNestingCount != 0) {
michael@0 91 mLocked.deferredSpriteUpdate = true;
michael@0 92 } else {
michael@0 93 #ifdef HAVE_ANDROID_OS
michael@0 94 mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES));
michael@0 95 #endif
michael@0 96 }
michael@0 97 }
michael@0 98 }
michael@0 99
michael@0 100 #ifdef HAVE_ANDROID_OS
michael@0 101 void SpriteController::disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl) {
michael@0 102 bool wasEmpty = mLocked.disposedSurfaces.isEmpty();
michael@0 103 mLocked.disposedSurfaces.push(surfaceControl);
michael@0 104 if (wasEmpty) {
michael@0 105 mLooper->sendMessage(mHandler, Message(MSG_DISPOSE_SURFACES));
michael@0 106 }
michael@0 107 }
michael@0 108
michael@0 109 void SpriteController::handleMessage(const Message& message) {
michael@0 110 switch (message.what) {
michael@0 111 case MSG_UPDATE_SPRITES:
michael@0 112 doUpdateSprites();
michael@0 113 break;
michael@0 114 case MSG_DISPOSE_SURFACES:
michael@0 115 doDisposeSurfaces();
michael@0 116 break;
michael@0 117 }
michael@0 118 }
michael@0 119 #endif
michael@0 120
michael@0 121 void SpriteController::doUpdateSprites() {
michael@0 122 // Collect information about sprite updates.
michael@0 123 // Each sprite update record includes a reference to its associated sprite so we can
michael@0 124 // be certain the sprites will not be deleted while this function runs. Sprites
michael@0 125 // may invalidate themselves again during this time but we will handle those changes
michael@0 126 // in the next iteration.
michael@0 127 Vector<SpriteUpdate> updates;
michael@0 128 size_t numSprites;
michael@0 129 { // acquire lock
michael@0 130 AutoMutex _l(mLock);
michael@0 131
michael@0 132 numSprites = mLocked.invalidatedSprites.size();
michael@0 133 for (size_t i = 0; i < numSprites; i++) {
michael@0 134 const sp<SpriteImpl>& sprite = mLocked.invalidatedSprites.itemAt(i);
michael@0 135
michael@0 136 updates.push(SpriteUpdate(sprite, sprite->getStateLocked()));
michael@0 137 sprite->resetDirtyLocked();
michael@0 138 }
michael@0 139 mLocked.invalidatedSprites.clear();
michael@0 140 } // release lock
michael@0 141
michael@0 142 // Create missing surfaces.
michael@0 143 bool surfaceChanged = false;
michael@0 144 for (size_t i = 0; i < numSprites; i++) {
michael@0 145 SpriteUpdate& update = updates.editItemAt(i);
michael@0 146
michael@0 147 #ifdef HAVE_ANDROID_OS
michael@0 148 if (update.state.surfaceControl == NULL && update.state.wantSurfaceVisible()) {
michael@0 149 update.state.surfaceWidth = update.state.icon.bitmap.width();
michael@0 150 update.state.surfaceHeight = update.state.icon.bitmap.height();
michael@0 151 update.state.surfaceDrawn = false;
michael@0 152 update.state.surfaceVisible = false;
michael@0 153 update.state.surfaceControl = obtainSurface(
michael@0 154 update.state.surfaceWidth, update.state.surfaceHeight);
michael@0 155 if (update.state.surfaceControl != NULL) {
michael@0 156 update.surfaceChanged = surfaceChanged = true;
michael@0 157 }
michael@0 158 }
michael@0 159 #endif
michael@0 160 }
michael@0 161
michael@0 162 // Resize sprites if needed, inside a global transaction.
michael@0 163 bool haveGlobalTransaction = false;
michael@0 164 for (size_t i = 0; i < numSprites; i++) {
michael@0 165 SpriteUpdate& update = updates.editItemAt(i);
michael@0 166
michael@0 167 #ifdef HAVE_ANDROID_OS
michael@0 168 if (update.state.surfaceControl != NULL && update.state.wantSurfaceVisible()) {
michael@0 169 int32_t desiredWidth = update.state.icon.bitmap.width();
michael@0 170 int32_t desiredHeight = update.state.icon.bitmap.height();
michael@0 171 if (update.state.surfaceWidth < desiredWidth
michael@0 172 || update.state.surfaceHeight < desiredHeight) {
michael@0 173 if (!haveGlobalTransaction) {
michael@0 174 SurfaceComposerClient::openGlobalTransaction();
michael@0 175 haveGlobalTransaction = true;
michael@0 176 }
michael@0 177
michael@0 178 status_t status = update.state.surfaceControl->setSize(desiredWidth, desiredHeight);
michael@0 179 if (status) {
michael@0 180 ALOGE("Error %d resizing sprite surface from %dx%d to %dx%d",
michael@0 181 status, update.state.surfaceWidth, update.state.surfaceHeight,
michael@0 182 desiredWidth, desiredHeight);
michael@0 183 } else {
michael@0 184 update.state.surfaceWidth = desiredWidth;
michael@0 185 update.state.surfaceHeight = desiredHeight;
michael@0 186 update.state.surfaceDrawn = false;
michael@0 187 update.surfaceChanged = surfaceChanged = true;
michael@0 188
michael@0 189 if (update.state.surfaceVisible) {
michael@0 190 status = update.state.surfaceControl->hide();
michael@0 191 if (status) {
michael@0 192 ALOGE("Error %d hiding sprite surface after resize.", status);
michael@0 193 } else {
michael@0 194 update.state.surfaceVisible = false;
michael@0 195 }
michael@0 196 }
michael@0 197 }
michael@0 198 }
michael@0 199 }
michael@0 200 #endif
michael@0 201 }
michael@0 202 #ifdef HAVE_ANDROID_OS
michael@0 203 if (haveGlobalTransaction) {
michael@0 204 SurfaceComposerClient::closeGlobalTransaction();
michael@0 205 }
michael@0 206 #endif
michael@0 207
michael@0 208 // Redraw sprites if needed.
michael@0 209 for (size_t i = 0; i < numSprites; i++) {
michael@0 210 SpriteUpdate& update = updates.editItemAt(i);
michael@0 211
michael@0 212 if ((update.state.dirty & DIRTY_BITMAP) && update.state.surfaceDrawn) {
michael@0 213 update.state.surfaceDrawn = false;
michael@0 214 update.surfaceChanged = surfaceChanged = true;
michael@0 215 }
michael@0 216
michael@0 217 #ifdef HAVE_ANDROID_OS
michael@0 218 if (update.state.surfaceControl != NULL && !update.state.surfaceDrawn
michael@0 219 && update.state.wantSurfaceVisible()) {
michael@0 220 sp<Surface> surface = update.state.surfaceControl->getSurface();
michael@0 221 ANativeWindow_Buffer outBuffer;
michael@0 222 status_t status = surface->lock(&outBuffer, NULL);
michael@0 223 if (status) {
michael@0 224 ALOGE("Error %d locking sprite surface before drawing.", status);
michael@0 225 } else {
michael@0 226 SkBitmap surfaceBitmap;
michael@0 227 ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
michael@0 228 surfaceBitmap.setConfig(SkBitmap::kARGB_8888_Config,
michael@0 229 outBuffer.width, outBuffer.height, bpr);
michael@0 230 surfaceBitmap.setPixels(outBuffer.bits);
michael@0 231
michael@0 232 SkCanvas surfaceCanvas(surfaceBitmap);
michael@0 233
michael@0 234 SkPaint paint;
michael@0 235 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
michael@0 236 surfaceCanvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint);
michael@0 237
michael@0 238 if (outBuffer.width > uint32_t(update.state.icon.bitmap.width())) {
michael@0 239 paint.setColor(0); // transparent fill color
michael@0 240 surfaceCanvas.drawRectCoords(update.state.icon.bitmap.width(), 0,
michael@0 241 outBuffer.width, update.state.icon.bitmap.height(), paint);
michael@0 242 }
michael@0 243 if (outBuffer.height > uint32_t(update.state.icon.bitmap.height())) {
michael@0 244 paint.setColor(0); // transparent fill color
michael@0 245 surfaceCanvas.drawRectCoords(0, update.state.icon.bitmap.height(),
michael@0 246 outBuffer.width, outBuffer.height, paint);
michael@0 247 }
michael@0 248
michael@0 249 status = surface->unlockAndPost();
michael@0 250 if (status) {
michael@0 251 ALOGE("Error %d unlocking and posting sprite surface after drawing.", status);
michael@0 252 } else {
michael@0 253 update.state.surfaceDrawn = true;
michael@0 254 update.surfaceChanged = surfaceChanged = true;
michael@0 255 }
michael@0 256 }
michael@0 257 }
michael@0 258 #endif
michael@0 259 }
michael@0 260
michael@0 261 // Set sprite surface properties and make them visible.
michael@0 262 bool haveTransaction = false;
michael@0 263 for (size_t i = 0; i < numSprites; i++) {
michael@0 264 SpriteUpdate& update = updates.editItemAt(i);
michael@0 265
michael@0 266 bool wantSurfaceVisibleAndDrawn = update.state.wantSurfaceVisible()
michael@0 267 && update.state.surfaceDrawn;
michael@0 268 bool becomingVisible = wantSurfaceVisibleAndDrawn && !update.state.surfaceVisible;
michael@0 269 bool becomingHidden = !wantSurfaceVisibleAndDrawn && update.state.surfaceVisible;
michael@0 270 #ifdef HAVE_ANDROID_OS
michael@0 271 if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden
michael@0 272 || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA
michael@0 273 | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER
michael@0 274 | DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) {
michael@0 275 status_t status;
michael@0 276 if (!haveTransaction) {
michael@0 277 SurfaceComposerClient::openGlobalTransaction();
michael@0 278 haveTransaction = true;
michael@0 279 }
michael@0 280
michael@0 281 if (wantSurfaceVisibleAndDrawn
michael@0 282 && (becomingVisible || (update.state.dirty & DIRTY_ALPHA))) {
michael@0 283 status = update.state.surfaceControl->setAlpha(update.state.alpha);
michael@0 284 if (status) {
michael@0 285 ALOGE("Error %d setting sprite surface alpha.", status);
michael@0 286 }
michael@0 287 }
michael@0 288
michael@0 289 if (wantSurfaceVisibleAndDrawn
michael@0 290 && (becomingVisible || (update.state.dirty & (DIRTY_POSITION
michael@0 291 | DIRTY_HOTSPOT)))) {
michael@0 292 status = update.state.surfaceControl->setPosition(
michael@0 293 update.state.positionX - update.state.icon.hotSpotX,
michael@0 294 update.state.positionY - update.state.icon.hotSpotY);
michael@0 295 if (status) {
michael@0 296 ALOGE("Error %d setting sprite surface position.", status);
michael@0 297 }
michael@0 298 }
michael@0 299
michael@0 300 if (wantSurfaceVisibleAndDrawn
michael@0 301 && (becomingVisible
michael@0 302 || (update.state.dirty & DIRTY_TRANSFORMATION_MATRIX))) {
michael@0 303 status = update.state.surfaceControl->setMatrix(
michael@0 304 update.state.transformationMatrix.dsdx,
michael@0 305 update.state.transformationMatrix.dtdx,
michael@0 306 update.state.transformationMatrix.dsdy,
michael@0 307 update.state.transformationMatrix.dtdy);
michael@0 308 if (status) {
michael@0 309 ALOGE("Error %d setting sprite surface transformation matrix.", status);
michael@0 310 }
michael@0 311 }
michael@0 312
michael@0 313 int32_t surfaceLayer = mOverlayLayer + update.state.layer;
michael@0 314 if (wantSurfaceVisibleAndDrawn
michael@0 315 && (becomingVisible || (update.state.dirty & DIRTY_LAYER))) {
michael@0 316 status = update.state.surfaceControl->setLayer(surfaceLayer);
michael@0 317 if (status) {
michael@0 318 ALOGE("Error %d setting sprite surface layer.", status);
michael@0 319 }
michael@0 320 }
michael@0 321
michael@0 322 if (becomingVisible) {
michael@0 323 status = update.state.surfaceControl->show();
michael@0 324 if (status) {
michael@0 325 ALOGE("Error %d showing sprite surface.", status);
michael@0 326 } else {
michael@0 327 update.state.surfaceVisible = true;
michael@0 328 update.surfaceChanged = surfaceChanged = true;
michael@0 329 }
michael@0 330 } else if (becomingHidden) {
michael@0 331 status = update.state.surfaceControl->hide();
michael@0 332 if (status) {
michael@0 333 ALOGE("Error %d hiding sprite surface.", status);
michael@0 334 } else {
michael@0 335 update.state.surfaceVisible = false;
michael@0 336 update.surfaceChanged = surfaceChanged = true;
michael@0 337 }
michael@0 338 }
michael@0 339 }
michael@0 340 #endif
michael@0 341 }
michael@0 342
michael@0 343 #ifdef HAVE_ANDROID_OS
michael@0 344 if (haveTransaction) {
michael@0 345 SurfaceComposerClient::closeGlobalTransaction();
michael@0 346 }
michael@0 347 #endif
michael@0 348
michael@0 349 // If any surfaces were changed, write back the new surface properties to the sprites.
michael@0 350 if (surfaceChanged) { // acquire lock
michael@0 351 AutoMutex _l(mLock);
michael@0 352
michael@0 353 for (size_t i = 0; i < numSprites; i++) {
michael@0 354 const SpriteUpdate& update = updates.itemAt(i);
michael@0 355
michael@0 356 #ifdef HAVE_ANDROID_OS
michael@0 357 if (update.surfaceChanged) {
michael@0 358 update.sprite->setSurfaceLocked(update.state.surfaceControl,
michael@0 359 update.state.surfaceWidth, update.state.surfaceHeight,
michael@0 360 update.state.surfaceDrawn, update.state.surfaceVisible);
michael@0 361 }
michael@0 362 #endif
michael@0 363 }
michael@0 364 } // release lock
michael@0 365
michael@0 366 // Clear the sprite update vector outside the lock. It is very important that
michael@0 367 // we do not clear sprite references inside the lock since we could be releasing
michael@0 368 // the last remaining reference to the sprite here which would result in the
michael@0 369 // sprite being deleted and the lock being reacquired by the sprite destructor
michael@0 370 // while already held.
michael@0 371 updates.clear();
michael@0 372 }
michael@0 373
michael@0 374 void SpriteController::doDisposeSurfaces() {
michael@0 375 #ifdef HAVE_ANDROID_OS
michael@0 376 // Collect disposed surfaces.
michael@0 377 Vector<sp<SurfaceControl> > disposedSurfaces;
michael@0 378 { // acquire lock
michael@0 379 AutoMutex _l(mLock);
michael@0 380
michael@0 381 disposedSurfaces = mLocked.disposedSurfaces;
michael@0 382 mLocked.disposedSurfaces.clear();
michael@0 383 } // release lock
michael@0 384
michael@0 385 // Release the last reference to each surface outside of the lock.
michael@0 386 // We don't want the surfaces to be deleted while we are holding our lock.
michael@0 387 disposedSurfaces.clear();
michael@0 388 #endif
michael@0 389 }
michael@0 390
michael@0 391 void SpriteController::ensureSurfaceComposerClient() {
michael@0 392 #ifdef HAVE_ANDROID_OS
michael@0 393 if (mSurfaceComposerClient == NULL) {
michael@0 394 mSurfaceComposerClient = new SurfaceComposerClient();
michael@0 395 }
michael@0 396 #endif
michael@0 397 }
michael@0 398
michael@0 399 #ifdef HAVE_ANDROID_OS
michael@0 400 sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height) {
michael@0 401 ensureSurfaceComposerClient();
michael@0 402
michael@0 403 sp<SurfaceControl> surfaceControl = mSurfaceComposerClient->createSurface(
michael@0 404 String8("Sprite"), width, height, PIXEL_FORMAT_RGBA_8888,
michael@0 405 ISurfaceComposerClient::eHidden);
michael@0 406 if (surfaceControl == NULL || !surfaceControl->isValid()) {
michael@0 407 ALOGE("Error creating sprite surface.");
michael@0 408 return NULL;
michael@0 409 }
michael@0 410 return surfaceControl;
michael@0 411 }
michael@0 412 #endif
michael@0 413
michael@0 414
michael@0 415 // --- SpriteController::SpriteImpl ---
michael@0 416
michael@0 417 SpriteController::SpriteImpl::SpriteImpl(const sp<SpriteController> controller) :
michael@0 418 mController(controller) {
michael@0 419 }
michael@0 420
michael@0 421 SpriteController::SpriteImpl::~SpriteImpl() {
michael@0 422 AutoMutex _m(mController->mLock);
michael@0 423
michael@0 424 #ifdef HAVE_ANDROID_OS
michael@0 425 // Let the controller take care of deleting the last reference to sprite
michael@0 426 // surfaces so that we do not block the caller on an IPC here.
michael@0 427 if (mLocked.state.surfaceControl != NULL) {
michael@0 428 mController->disposeSurfaceLocked(mLocked.state.surfaceControl);
michael@0 429 mLocked.state.surfaceControl.clear();
michael@0 430 }
michael@0 431 #endif
michael@0 432 }
michael@0 433
michael@0 434 void SpriteController::SpriteImpl::setIcon(const SpriteIcon& icon) {
michael@0 435 AutoMutex _l(mController->mLock);
michael@0 436
michael@0 437 #ifdef HAVE_ANDROID_OS
michael@0 438 uint32_t dirty;
michael@0 439 if (icon.isValid()) {
michael@0 440 icon.bitmap.copyTo(&mLocked.state.icon.bitmap, SkBitmap::kARGB_8888_Config);
michael@0 441
michael@0 442 if (!mLocked.state.icon.isValid()
michael@0 443 || mLocked.state.icon.hotSpotX != icon.hotSpotX
michael@0 444 || mLocked.state.icon.hotSpotY != icon.hotSpotY) {
michael@0 445 mLocked.state.icon.hotSpotX = icon.hotSpotX;
michael@0 446 mLocked.state.icon.hotSpotY = icon.hotSpotY;
michael@0 447 dirty = DIRTY_BITMAP | DIRTY_HOTSPOT;
michael@0 448 } else {
michael@0 449 dirty = DIRTY_BITMAP;
michael@0 450 }
michael@0 451 } else if (mLocked.state.icon.isValid()) {
michael@0 452 mLocked.state.icon.bitmap.reset();
michael@0 453 dirty = DIRTY_BITMAP | DIRTY_HOTSPOT;
michael@0 454 } else {
michael@0 455 return; // setting to invalid icon and already invalid so nothing to do
michael@0 456 }
michael@0 457
michael@0 458 invalidateLocked(dirty);
michael@0 459 #endif
michael@0 460 }
michael@0 461
michael@0 462 void SpriteController::SpriteImpl::setVisible(bool visible) {
michael@0 463 AutoMutex _l(mController->mLock);
michael@0 464
michael@0 465 if (mLocked.state.visible != visible) {
michael@0 466 mLocked.state.visible = visible;
michael@0 467 invalidateLocked(DIRTY_VISIBILITY);
michael@0 468 }
michael@0 469 }
michael@0 470
michael@0 471 void SpriteController::SpriteImpl::setPosition(float x, float y) {
michael@0 472 AutoMutex _l(mController->mLock);
michael@0 473
michael@0 474 if (mLocked.state.positionX != x || mLocked.state.positionY != y) {
michael@0 475 mLocked.state.positionX = x;
michael@0 476 mLocked.state.positionY = y;
michael@0 477 invalidateLocked(DIRTY_POSITION);
michael@0 478 }
michael@0 479 }
michael@0 480
michael@0 481 void SpriteController::SpriteImpl::setLayer(int32_t layer) {
michael@0 482 AutoMutex _l(mController->mLock);
michael@0 483
michael@0 484 if (mLocked.state.layer != layer) {
michael@0 485 mLocked.state.layer = layer;
michael@0 486 invalidateLocked(DIRTY_LAYER);
michael@0 487 }
michael@0 488 }
michael@0 489
michael@0 490 void SpriteController::SpriteImpl::setAlpha(float alpha) {
michael@0 491 AutoMutex _l(mController->mLock);
michael@0 492
michael@0 493 if (mLocked.state.alpha != alpha) {
michael@0 494 mLocked.state.alpha = alpha;
michael@0 495 invalidateLocked(DIRTY_ALPHA);
michael@0 496 }
michael@0 497 }
michael@0 498
michael@0 499 void SpriteController::SpriteImpl::setTransformationMatrix(
michael@0 500 const SpriteTransformationMatrix& matrix) {
michael@0 501 AutoMutex _l(mController->mLock);
michael@0 502
michael@0 503 if (mLocked.state.transformationMatrix != matrix) {
michael@0 504 mLocked.state.transformationMatrix = matrix;
michael@0 505 invalidateLocked(DIRTY_TRANSFORMATION_MATRIX);
michael@0 506 }
michael@0 507 }
michael@0 508
michael@0 509 void SpriteController::SpriteImpl::invalidateLocked(uint32_t dirty) {
michael@0 510 bool wasDirty = mLocked.state.dirty;
michael@0 511 mLocked.state.dirty |= dirty;
michael@0 512
michael@0 513 if (!wasDirty) {
michael@0 514 mController->invalidateSpriteLocked(this);
michael@0 515 }
michael@0 516 }
michael@0 517
michael@0 518 } // namespace android

mercurial