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