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