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
BaseRenderNodeAnimator(float finalValue)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
~BaseRenderNodeAnimator()48 BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
49 }
50
checkMutable()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
setInterpolator(Interpolator * interpolator)57 void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) {
58 checkMutable();
59 mInterpolator.reset(interpolator);
60 }
61
setStartValue(float value)62 void BaseRenderNodeAnimator::setStartValue(float value) {
63 checkMutable();
64 doSetStartValue(value);
65 }
66
doSetStartValue(float value)67 void BaseRenderNodeAnimator::doSetStartValue(float value) {
68 mFromValue = value;
69 mDeltaValue = (mFinalValue - mFromValue);
70 mHasStartValue = true;
71 }
72
setDuration(nsecs_t duration)73 void BaseRenderNodeAnimator::setDuration(nsecs_t duration) {
74 checkMutable();
75 mDuration = duration;
76 }
77
setStartDelay(nsecs_t startDelay)78 void BaseRenderNodeAnimator::setStartDelay(nsecs_t startDelay) {
79 checkMutable();
80 mStartDelay = startDelay;
81 }
82
attach(RenderNode * target)83 void BaseRenderNodeAnimator::attach(RenderNode* target) {
84 mTarget = target;
85 onAttached();
86 }
87
pushStaging(AnimationContext & context)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
transitionToRunning(AnimationContext & context)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
animate(AnimationContext & context)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
forceEndNow(AnimationContext & context)163 void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) {
164 if (mPlayState < FINISHED) {
165 mPlayState = FINISHED;
166 callOnFinishedListener(context);
167 }
168 }
169
callOnFinishedListener(AnimationContext & context)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
RenderPropertyAnimator(RenderProperty property,float finalValue)202 RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue)
203 : BaseRenderNodeAnimator(finalValue)
204 , mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {
205 }
206
onAttached()207 void RenderPropertyAnimator::onAttached() {
208 if (!mHasStartValue
209 && mTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
210 setStartValue((mTarget->stagingProperties().*mPropertyAccess->getter)());
211 }
212 }
213
onStagingPlayStateChanged()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
dirtyMask()224 uint32_t RenderPropertyAnimator::dirtyMask() {
225 return mPropertyAccess->dirtyMask;
226 }
227
getValue(RenderNode * target) const228 float RenderPropertyAnimator::getValue(RenderNode* target) const {
229 return (target->properties().*mPropertyAccess->getter)();
230 }
231
setValue(RenderNode * target,float value)232 void RenderPropertyAnimator::setValue(RenderNode* target, float value) {
233 (target->animatorProperties().*mPropertyAccess->setter)(value);
234 }
235
236 /************************************************************
237 * CanvasPropertyPrimitiveAnimator
238 ************************************************************/
239
CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive * property,float finalValue)240 CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(
241 CanvasPropertyPrimitive* property, float finalValue)
242 : BaseRenderNodeAnimator(finalValue)
243 , mProperty(property) {
244 }
245
getValue(RenderNode * target) const246 float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const {
247 return mProperty->value;
248 }
249
setValue(RenderNode * target,float value)250 void CanvasPropertyPrimitiveAnimator::setValue(RenderNode* target, float value) {
251 mProperty->value = value;
252 }
253
dirtyMask()254 uint32_t CanvasPropertyPrimitiveAnimator::dirtyMask() {
255 return RenderNode::DISPLAY_LIST;
256 }
257
258 /************************************************************
259 * CanvasPropertySkPaintAnimator
260 ************************************************************/
261
CanvasPropertyPaintAnimator(CanvasPropertyPaint * property,PaintField field,float finalValue)262 CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(
263 CanvasPropertyPaint* property, PaintField field, float finalValue)
264 : BaseRenderNodeAnimator(finalValue)
265 , mProperty(property)
266 , mField(field) {
267 }
268
getValue(RenderNode * target) const269 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
to_uint8(float value)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
setValue(RenderNode * target,float value)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
dirtyMask()297 uint32_t CanvasPropertyPaintAnimator::dirtyMask() {
298 return RenderNode::DISPLAY_LIST;
299 }
300
RevealAnimator(int centerX,int centerY,float startValue,float finalValue)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
getValue(RenderNode * target) const309 float RevealAnimator::getValue(RenderNode* target) const {
310 return target->properties().getRevealClip().getRadius();
311 }
312
setValue(RenderNode * target,float value)313 void RevealAnimator::setValue(RenderNode* target, float value) {
314 target->animatorProperties().mutableRevealClip().set(true,
315 mCenterX, mCenterY, value);
316 }
317
dirtyMask()318 uint32_t RevealAnimator::dirtyMask() {
319 return RenderNode::GENERIC;
320 }
321
322 } /* namespace uirenderer */
323 } /* namespace android */
324