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