Animator.cpp revision 2dc236b2bae13b9a0ed9b3f7320502aecd7983b3
1/* 2 * Copyright (C) 2014 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#include "Animator.h" 18 19#include <inttypes.h> 20#include <set> 21 22#include "AnimationContext.h" 23#include "Interpolator.h" 24#include "RenderNode.h" 25#include "RenderProperties.h" 26 27namespace android { 28namespace uirenderer { 29 30/************************************************************ 31 * BaseRenderNodeAnimator 32 ************************************************************/ 33 34BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue) 35 : mTarget(NULL) 36 , mFinalValue(finalValue) 37 , mDeltaValue(0) 38 , mFromValue(0) 39 , mInterpolator(0) 40 , mStagingPlayState(NOT_STARTED) 41 , mPlayState(NOT_STARTED) 42 , mHasStartValue(false) 43 , mStartTime(0) 44 , mDuration(300) 45 , mStartDelay(0) 46 , mMayRunAsync(true) { 47} 48 49BaseRenderNodeAnimator::~BaseRenderNodeAnimator() { 50 delete mInterpolator; 51} 52 53void BaseRenderNodeAnimator::checkMutable() { 54 // Should be impossible to hit as the Java-side also has guards for this 55 LOG_ALWAYS_FATAL_IF(mStagingPlayState != NOT_STARTED, 56 "Animator has already been started!"); 57} 58 59void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) { 60 checkMutable(); 61 delete mInterpolator; 62 mInterpolator = interpolator; 63} 64 65void BaseRenderNodeAnimator::setStartValue(float value) { 66 checkMutable(); 67 doSetStartValue(value); 68} 69 70void BaseRenderNodeAnimator::doSetStartValue(float value) { 71 mFromValue = value; 72 mDeltaValue = (mFinalValue - mFromValue); 73 mHasStartValue = true; 74} 75 76void BaseRenderNodeAnimator::setDuration(nsecs_t duration) { 77 checkMutable(); 78 mDuration = duration; 79} 80 81void BaseRenderNodeAnimator::setStartDelay(nsecs_t startDelay) { 82 checkMutable(); 83 mStartDelay = startDelay; 84} 85 86void BaseRenderNodeAnimator::attach(RenderNode* target) { 87 mTarget = target; 88 onAttached(); 89} 90 91void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) { 92 if (!mHasStartValue) { 93 doSetStartValue(getValue(mTarget)); 94 } 95 if (mStagingPlayState > mPlayState) { 96 mPlayState = mStagingPlayState; 97 // Oh boy, we're starting! Man the battle stations! 98 if (mPlayState == RUNNING) { 99 transitionToRunning(context); 100 } else if (mPlayState == FINISHED) { 101 callOnFinishedListener(context); 102 } 103 } 104} 105 106void BaseRenderNodeAnimator::transitionToRunning(AnimationContext& context) { 107 nsecs_t frameTimeMs = context.frameTimeMs(); 108 LOG_ALWAYS_FATAL_IF(frameTimeMs <= 0, "%" PRId64 " isn't a real frame time!", frameTimeMs); 109 if (mStartDelay < 0 || mStartDelay > 50000) { 110 ALOGW("Your start delay is strange and confusing: %" PRId64, mStartDelay); 111 } 112 mStartTime = frameTimeMs + mStartDelay; 113 if (mStartTime < 0) { 114 ALOGW("Ended up with a really weird start time of %" PRId64 115 " with frame time %" PRId64 " and start delay %" PRId64, 116 mStartTime, frameTimeMs, mStartDelay); 117 // Set to 0 so that the animate() basically instantly finishes 118 mStartTime = 0; 119 } 120 // No interpolator was set, use the default 121 if (!mInterpolator) { 122 mInterpolator = Interpolator::createDefaultInterpolator(); 123 } 124 if (mDuration < 0 || mDuration > 50000) { 125 ALOGW("Your duration is strange and confusing: %" PRId64, mDuration); 126 } 127} 128 129bool BaseRenderNodeAnimator::animate(AnimationContext& context) { 130 if (mPlayState < RUNNING) { 131 return false; 132 } 133 if (mPlayState == FINISHED) { 134 return true; 135 } 136 137 // If BaseRenderNodeAnimator is handling the delay (not typical), then 138 // because the staging properties reflect the final value, we always need 139 // to call setValue even if the animation isn't yet running or is still 140 // being delayed as we need to override the staging value 141 if (mStartTime > context.frameTimeMs()) { 142 setValue(mTarget, mFromValue); 143 return false; 144 } 145 146 float fraction = 1.0f; 147 if (mPlayState == RUNNING && mDuration > 0) { 148 fraction = (float)(context.frameTimeMs() - mStartTime) / mDuration; 149 } 150 if (fraction >= 1.0f) { 151 fraction = 1.0f; 152 mPlayState = FINISHED; 153 } 154 155 fraction = mInterpolator->interpolate(fraction); 156 setValue(mTarget, mFromValue + (mDeltaValue * fraction)); 157 158 if (mPlayState == FINISHED) { 159 callOnFinishedListener(context); 160 return true; 161 } 162 163 return false; 164} 165 166void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) { 167 if (mPlayState < FINISHED) { 168 mPlayState = FINISHED; 169 callOnFinishedListener(context); 170 } 171} 172 173void BaseRenderNodeAnimator::callOnFinishedListener(AnimationContext& context) { 174 if (mListener.get()) { 175 context.callOnFinished(this, mListener.get()); 176 } 177} 178 179/************************************************************ 180 * RenderPropertyAnimator 181 ************************************************************/ 182 183struct RenderPropertyAnimator::PropertyAccessors { 184 RenderNode::DirtyPropertyMask dirtyMask; 185 GetFloatProperty getter; 186 SetFloatProperty setter; 187}; 188 189// Maps RenderProperty enum to accessors 190const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = { 191 {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationX, &RenderProperties::setTranslationX }, 192 {RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY, &RenderProperties::setTranslationY }, 193 {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ }, 194 {RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX }, 195 {RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY }, 196 {RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation }, 197 {RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX }, 198 {RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY }, 199 {RenderNode::X, &RenderProperties::getX, &RenderProperties::setX }, 200 {RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY }, 201 {RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ }, 202 {RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha }, 203}; 204 205RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue) 206 : BaseRenderNodeAnimator(finalValue) 207 , mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) { 208} 209 210void RenderPropertyAnimator::onAttached() { 211 if (!mHasStartValue 212 && mTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) { 213 setStartValue((mTarget->stagingProperties().*mPropertyAccess->getter)()); 214 } 215} 216 217void RenderPropertyAnimator::onStagingPlayStateChanged() { 218 if (mStagingPlayState == RUNNING) { 219 (mTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue()); 220 } else if (mStagingPlayState == FINISHED) { 221 // We're being canceled, so make sure that whatever values the UI thread 222 // is observing for us is pushed over 223 mTarget->setPropertyFieldsDirty(dirtyMask()); 224 } 225} 226 227uint32_t RenderPropertyAnimator::dirtyMask() { 228 return mPropertyAccess->dirtyMask; 229} 230 231float RenderPropertyAnimator::getValue(RenderNode* target) const { 232 return (target->properties().*mPropertyAccess->getter)(); 233} 234 235void RenderPropertyAnimator::setValue(RenderNode* target, float value) { 236 (target->animatorProperties().*mPropertyAccess->setter)(value); 237} 238 239/************************************************************ 240 * CanvasPropertyPrimitiveAnimator 241 ************************************************************/ 242 243CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator( 244 CanvasPropertyPrimitive* property, float finalValue) 245 : BaseRenderNodeAnimator(finalValue) 246 , mProperty(property) { 247} 248 249float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const { 250 return mProperty->value; 251} 252 253void CanvasPropertyPrimitiveAnimator::setValue(RenderNode* target, float value) { 254 mProperty->value = value; 255} 256 257uint32_t CanvasPropertyPrimitiveAnimator::dirtyMask() { 258 return RenderNode::DISPLAY_LIST; 259} 260 261/************************************************************ 262 * CanvasPropertySkPaintAnimator 263 ************************************************************/ 264 265CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator( 266 CanvasPropertyPaint* property, PaintField field, float finalValue) 267 : BaseRenderNodeAnimator(finalValue) 268 , mProperty(property) 269 , mField(field) { 270} 271 272float CanvasPropertyPaintAnimator::getValue(RenderNode* target) const { 273 switch (mField) { 274 case STROKE_WIDTH: 275 return mProperty->value.getStrokeWidth(); 276 case ALPHA: 277 return mProperty->value.getAlpha(); 278 } 279 LOG_ALWAYS_FATAL("Unknown field %d", (int) mField); 280 return -1; 281} 282 283static uint8_t to_uint8(float value) { 284 int c = (int) (value + .5f); 285 return static_cast<uint8_t>( c < 0 ? 0 : c > 255 ? 255 : c ); 286} 287 288void CanvasPropertyPaintAnimator::setValue(RenderNode* target, float value) { 289 switch (mField) { 290 case STROKE_WIDTH: 291 mProperty->value.setStrokeWidth(value); 292 return; 293 case ALPHA: 294 mProperty->value.setAlpha(to_uint8(value)); 295 return; 296 } 297 LOG_ALWAYS_FATAL("Unknown field %d", (int) mField); 298} 299 300uint32_t CanvasPropertyPaintAnimator::dirtyMask() { 301 return RenderNode::DISPLAY_LIST; 302} 303 304RevealAnimator::RevealAnimator(int centerX, int centerY, 305 float startValue, float finalValue) 306 : BaseRenderNodeAnimator(finalValue) 307 , mCenterX(centerX) 308 , mCenterY(centerY) { 309 setStartValue(startValue); 310} 311 312float RevealAnimator::getValue(RenderNode* target) const { 313 return target->properties().getRevealClip().getRadius(); 314} 315 316void RevealAnimator::setValue(RenderNode* target, float value) { 317 target->animatorProperties().mutableRevealClip().set(true, 318 mCenterX, mCenterY, value); 319} 320 321uint32_t RevealAnimator::dirtyMask() { 322 return RenderNode::GENERIC; 323} 324 325} /* namespace uirenderer */ 326} /* namespace android */ 327