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
27namespace android {
28namespace uirenderer {
29
30/************************************************************
31 *  BaseRenderNodeAnimator
32 ************************************************************/
33
34BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue)
35        : mTarget(nullptr)
36        , mStagingTarget(nullptr)
37        , mFinalValue(finalValue)
38        , mDeltaValue(0)
39        , mFromValue(0)
40        , mStagingPlayState(PlayState::NotStarted)
41        , mPlayState(PlayState::NotStarted)
42        , mHasStartValue(false)
43        , mStartTime(0)
44        , mDuration(300)
45        , mStartDelay(0)
46        , mMayRunAsync(true)
47        , mPlayTime(0) {
48}
49
50BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
51}
52
53void BaseRenderNodeAnimator::checkMutable() {
54    // Should be impossible to hit as the Java-side also has guards for this
55    LOG_ALWAYS_FATAL_IF(mStagingPlayState != PlayState::NotStarted,
56            "Animator has already been started!");
57}
58
59void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) {
60    checkMutable();
61    mInterpolator.reset(interpolator);
62}
63
64void BaseRenderNodeAnimator::setStartValue(float value) {
65    checkMutable();
66    doSetStartValue(value);
67}
68
69void BaseRenderNodeAnimator::doSetStartValue(float value) {
70    mFromValue = value;
71    mDeltaValue = (mFinalValue - mFromValue);
72    mHasStartValue = true;
73}
74
75void BaseRenderNodeAnimator::setDuration(nsecs_t duration) {
76    checkMutable();
77    mDuration = duration;
78}
79
80void BaseRenderNodeAnimator::setStartDelay(nsecs_t startDelay) {
81    checkMutable();
82    mStartDelay = startDelay;
83}
84
85void BaseRenderNodeAnimator::attach(RenderNode* target) {
86    mStagingTarget = target;
87    onAttached();
88}
89
90void BaseRenderNodeAnimator::start() {
91    mStagingPlayState = PlayState::Running;
92    mStagingRequests.push_back(Request::Start);
93    onStagingPlayStateChanged();
94}
95
96void BaseRenderNodeAnimator::cancel() {
97    mStagingPlayState = PlayState::Finished;
98    mStagingRequests.push_back(Request::Cancel);
99    onStagingPlayStateChanged();
100}
101
102void BaseRenderNodeAnimator::reset() {
103    mStagingPlayState = PlayState::Finished;
104    mStagingRequests.push_back(Request::Reset);
105    onStagingPlayStateChanged();
106}
107
108void BaseRenderNodeAnimator::reverse() {
109    mStagingPlayState = PlayState::Reversing;
110    mStagingRequests.push_back(Request::Reverse);
111    onStagingPlayStateChanged();
112}
113
114void BaseRenderNodeAnimator::end() {
115    mStagingPlayState = PlayState::Finished;
116    mStagingRequests.push_back(Request::End);
117    onStagingPlayStateChanged();
118}
119
120void BaseRenderNodeAnimator::resolveStagingRequest(Request request) {
121    switch (request) {
122    case Request::Start:
123        mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ?
124                        mPlayTime : 0;
125        mPlayState = PlayState::Running;
126        break;
127    case Request::Reverse:
128        mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ?
129                        mPlayTime : mDuration;
130        mPlayState = PlayState::Reversing;
131        break;
132    case Request::Reset:
133        mPlayTime = 0;
134        mPlayState = PlayState::Finished;
135        break;
136    case Request::Cancel:
137        mPlayState = PlayState::Finished;
138        break;
139    case Request::End:
140        mPlayTime = mPlayState == PlayState::Reversing ? 0 : mDuration;
141        mPlayState = PlayState::Finished;
142        break;
143    default:
144        LOG_ALWAYS_FATAL("Invalid staging request: %d", static_cast<int>(request));
145    };
146}
147
148void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) {
149    if (mStagingTarget) {
150        RenderNode* oldTarget = mTarget;
151        mTarget = mStagingTarget;
152        mStagingTarget = nullptr;
153        if (oldTarget && oldTarget != mTarget) {
154            oldTarget->onAnimatorTargetChanged(this);
155        }
156    }
157
158    if (!mHasStartValue) {
159        doSetStartValue(getValue(mTarget));
160    }
161
162    if (!mStagingRequests.empty()) {
163        // No interpolator was set, use the default
164        if (mPlayState == PlayState::NotStarted && !mInterpolator) {
165            mInterpolator.reset(Interpolator::createDefaultInterpolator());
166        }
167        // Keep track of the play state and play time before they are changed when
168        // staging requests are resolved.
169        nsecs_t currentPlayTime = mPlayTime;
170        PlayState prevFramePlayState = mPlayState;
171
172        // Resolve staging requests one by one.
173        for (Request request : mStagingRequests) {
174            resolveStagingRequest(request);
175        }
176        mStagingRequests.clear();
177
178        if (mStagingPlayState == PlayState::Finished) {
179            // Set the staging play time and end the animation
180            updatePlayTime(mPlayTime);
181            callOnFinishedListener(context);
182        } else if (mStagingPlayState == PlayState::Running
183                || mStagingPlayState == PlayState::Reversing) {
184            bool changed = currentPlayTime != mPlayTime || prevFramePlayState != mStagingPlayState;
185            if (prevFramePlayState != mStagingPlayState) {
186                transitionToRunning(context);
187            }
188            if (changed) {
189                // Now we need to seek to the stagingPlayTime (i.e. the animation progress that was
190                // requested from UI thread). It is achieved by modifying mStartTime, such that
191                // current time - mStartTime = stagingPlayTime (or mDuration -stagingPlayTime in the
192                // case of reversing)
193                nsecs_t currentFrameTime = context.frameTimeMs();
194                if (mPlayState == PlayState::Reversing) {
195                    // Reverse is not supported for animations with a start delay, so here we
196                    // assume no start delay.
197                    mStartTime = currentFrameTime  - (mDuration - mPlayTime);
198                } else {
199                    // Animation should play forward
200                    if (mPlayTime == 0) {
201                        // If the request is to start from the beginning, include start delay.
202                        mStartTime = currentFrameTime + mStartDelay;
203                    } else {
204                        // If the request is to seek to a non-zero play time, then we skip start
205                        // delay.
206                        mStartTime = currentFrameTime - mPlayTime;
207                    }
208                }
209            }
210        }
211    }
212    onPushStaging();
213}
214
215void BaseRenderNodeAnimator::transitionToRunning(AnimationContext& context) {
216    nsecs_t frameTimeMs = context.frameTimeMs();
217    LOG_ALWAYS_FATAL_IF(frameTimeMs <= 0, "%" PRId64 " isn't a real frame time!", frameTimeMs);
218    if (mStartDelay < 0 || mStartDelay > 50000) {
219        ALOGW("Your start delay is strange and confusing: %" PRId64, mStartDelay);
220    }
221    mStartTime = frameTimeMs + mStartDelay;
222    if (mStartTime < 0) {
223        ALOGW("Ended up with a really weird start time of %" PRId64
224                " with frame time %" PRId64 " and start delay %" PRId64,
225                mStartTime, frameTimeMs, mStartDelay);
226        // Set to 0 so that the animate() basically instantly finishes
227        mStartTime = 0;
228    }
229    if (mDuration < 0) {
230        ALOGW("Your duration is strange and confusing: %" PRId64, mDuration);
231    }
232}
233
234bool BaseRenderNodeAnimator::animate(AnimationContext& context) {
235    if (mPlayState < PlayState::Running) {
236        return false;
237    }
238    if (mPlayState == PlayState::Finished) {
239        return true;
240    }
241
242    // This should be set before setValue() so animators can query this time when setValue
243    // is called.
244    nsecs_t currentPlayTime = context.frameTimeMs() - mStartTime;
245    bool finished = updatePlayTime(currentPlayTime);
246    if (finished && mPlayState != PlayState::Finished) {
247        mPlayState = PlayState::Finished;
248        callOnFinishedListener(context);
249    }
250    return finished;
251}
252
253bool BaseRenderNodeAnimator::updatePlayTime(nsecs_t playTime) {
254    mPlayTime = mPlayState == PlayState::Reversing ? mDuration - playTime : playTime;
255    onPlayTimeChanged(mPlayTime);
256    // If BaseRenderNodeAnimator is handling the delay (not typical), then
257    // because the staging properties reflect the final value, we always need
258    // to call setValue even if the animation isn't yet running or is still
259    // being delayed as we need to override the staging value
260    if (playTime < 0) {
261        setValue(mTarget, mFromValue);
262        return false;
263    }
264
265    float fraction = 1.0f;
266    if ((mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) && mDuration > 0) {
267        fraction = mPlayTime / (float) mDuration;
268    }
269    fraction = MathUtils::clamp(fraction, 0.0f, 1.0f);
270
271    fraction = mInterpolator->interpolate(fraction);
272    setValue(mTarget, mFromValue + (mDeltaValue * fraction));
273
274    return playTime >= mDuration;
275}
276
277void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) {
278    if (mPlayState < PlayState::Finished) {
279        mPlayState = PlayState::Finished;
280        callOnFinishedListener(context);
281    }
282}
283
284void BaseRenderNodeAnimator::callOnFinishedListener(AnimationContext& context) {
285    if (mListener.get()) {
286        context.callOnFinished(this, mListener.get());
287    }
288}
289
290/************************************************************
291 *  RenderPropertyAnimator
292 ************************************************************/
293
294struct RenderPropertyAnimator::PropertyAccessors {
295   RenderNode::DirtyPropertyMask dirtyMask;
296   GetFloatProperty getter;
297   SetFloatProperty setter;
298};
299
300// Maps RenderProperty enum to accessors
301const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = {
302    {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationX, &RenderProperties::setTranslationX },
303    {RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY, &RenderProperties::setTranslationY },
304    {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ },
305    {RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX },
306    {RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY },
307    {RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation },
308    {RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX },
309    {RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY },
310    {RenderNode::X, &RenderProperties::getX, &RenderProperties::setX },
311    {RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY },
312    {RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ },
313    {RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha },
314};
315
316RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue)
317        : BaseRenderNodeAnimator(finalValue)
318        , mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {
319}
320
321void RenderPropertyAnimator::onAttached() {
322    if (!mHasStartValue
323            && mStagingTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
324        setStartValue((mStagingTarget->stagingProperties().*mPropertyAccess->getter)());
325    }
326}
327
328void RenderPropertyAnimator::onStagingPlayStateChanged() {
329    if (mStagingPlayState == PlayState::Running) {
330        if (mStagingTarget) {
331            (mStagingTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
332        } else {
333            // In the case of start delay where stagingTarget has been sync'ed over and null'ed
334            // we delay the properties update to push staging.
335            mShouldUpdateStagingProperties = true;
336        }
337    } else if (mStagingPlayState == PlayState::Finished) {
338        // We're being canceled, so make sure that whatever values the UI thread
339        // is observing for us is pushed over
340        mShouldSyncPropertyFields = true;
341    }
342}
343
344void RenderPropertyAnimator::onPushStaging() {
345    if (mShouldUpdateStagingProperties) {
346        (mTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
347        mShouldUpdateStagingProperties = false;
348    }
349
350    if (mShouldSyncPropertyFields) {
351        mTarget->setPropertyFieldsDirty(dirtyMask());
352        mShouldSyncPropertyFields = false;
353    }
354}
355
356uint32_t RenderPropertyAnimator::dirtyMask() {
357    return mPropertyAccess->dirtyMask;
358}
359
360float RenderPropertyAnimator::getValue(RenderNode* target) const {
361    return (target->properties().*mPropertyAccess->getter)();
362}
363
364void RenderPropertyAnimator::setValue(RenderNode* target, float value) {
365    (target->animatorProperties().*mPropertyAccess->setter)(value);
366}
367
368/************************************************************
369 *  CanvasPropertyPrimitiveAnimator
370 ************************************************************/
371
372CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(
373                CanvasPropertyPrimitive* property, float finalValue)
374        : BaseRenderNodeAnimator(finalValue)
375        , mProperty(property) {
376}
377
378float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const {
379    return mProperty->value;
380}
381
382void CanvasPropertyPrimitiveAnimator::setValue(RenderNode* target, float value) {
383    mProperty->value = value;
384}
385
386uint32_t CanvasPropertyPrimitiveAnimator::dirtyMask() {
387    return RenderNode::DISPLAY_LIST;
388}
389
390/************************************************************
391 *  CanvasPropertySkPaintAnimator
392 ************************************************************/
393
394CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(
395                CanvasPropertyPaint* property, PaintField field, float finalValue)
396        : BaseRenderNodeAnimator(finalValue)
397        , mProperty(property)
398        , mField(field) {
399}
400
401float CanvasPropertyPaintAnimator::getValue(RenderNode* target) const {
402    switch (mField) {
403    case STROKE_WIDTH:
404        return mProperty->value.getStrokeWidth();
405    case ALPHA:
406        return mProperty->value.getAlpha();
407    }
408    LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
409    return -1;
410}
411
412static uint8_t to_uint8(float value) {
413    int c = (int) (value + .5f);
414    return static_cast<uint8_t>( c < 0 ? 0 : c > 255 ? 255 : c );
415}
416
417void CanvasPropertyPaintAnimator::setValue(RenderNode* target, float value) {
418    switch (mField) {
419    case STROKE_WIDTH:
420        mProperty->value.setStrokeWidth(value);
421        return;
422    case ALPHA:
423        mProperty->value.setAlpha(to_uint8(value));
424        return;
425    }
426    LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
427}
428
429uint32_t CanvasPropertyPaintAnimator::dirtyMask() {
430    return RenderNode::DISPLAY_LIST;
431}
432
433RevealAnimator::RevealAnimator(int centerX, int centerY,
434        float startValue, float finalValue)
435        : BaseRenderNodeAnimator(finalValue)
436        , mCenterX(centerX)
437        , mCenterY(centerY) {
438    setStartValue(startValue);
439}
440
441float RevealAnimator::getValue(RenderNode* target) const {
442    return target->properties().getRevealClip().getRadius();
443}
444
445void RevealAnimator::setValue(RenderNode* target, float value) {
446    target->animatorProperties().mutableRevealClip().set(true,
447            mCenterX, mCenterY, value);
448}
449
450uint32_t RevealAnimator::dirtyMask() {
451    return RenderNode::GENERIC;
452}
453
454} /* namespace uirenderer */
455} /* namespace android */
456