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