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