OSDN Git Service

Re-enable animations on the UI thread
authorNicolas Roard <nicolasroard@google.com>
Tue, 18 Oct 2011 20:07:37 +0000 (13:07 -0700)
committerNicolas Roard <nicolasroard@google.com>
Tue, 18 Oct 2011 20:11:38 +0000 (13:11 -0700)
Using webkit to compute animations is still slow in some cases.

When animating large elements, we seems to sometimes bogs the GPU,
which then makes the UI takes longer to render a frame. This in turn
slow the rate at which we can call into webkit (to update the position
of the animated layers), which results in perceived stuttering.

We previously had an implementation of CSS animations that could run
fully on the UI thread, without having to call back into webkit.
We turned it off because there was still some glitches, and calling
into webkit seemed to work well enough -- but as we can see, even
if that's the case in general, edge cases still benefit from running
the animations outside of webkit.

The CL fixes the remaining glitches we had (mostly, it was the
non support of fillMode) and re-enable our CSS animations implementation.

bug:5297559

Change-Id: I1f00bc060a76c9dfd55bd6d8ae85d5d6da68ddb5

Source/WebCore/platform/graphics/android/AndroidAnimation.cpp
Source/WebCore/platform/graphics/android/AndroidAnimation.h
Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp
Source/WebCore/platform/graphics/android/LayerAndroid.cpp

index 2939cf0..5601269 100644 (file)
 #include "UnitBezier.h"
 
 #include <wtf/CurrentTime.h>
-
-#ifdef DEBUG
-
 #include <cutils/log.h>
 #include <wtf/text/CString.h>
 
+#undef XLOGC
+#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "AndroidAnimation", __VA_ARGS__)
+
+#ifdef DEBUG
+
 #undef XLOG
 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "AndroidAnimation", __VA_ARGS__)
 
@@ -60,13 +62,13 @@ AndroidAnimation::AndroidAnimation(AnimatedPropertyID type,
                                    double beginTime)
     : m_beginTime(beginTime)
     , m_duration(animation->duration())
-    , m_finished(false)
+    , m_fillsBackwards(animation->fillsBackwards())
+    , m_fillsForwards(animation->fillsForwards())
     , m_iterationCount(animation->iterationCount())
     , m_direction(animation->direction())
     , m_timingFunction(animation->timingFunction())
     , m_type(type)
     , m_operations(operations)
-    , m_originalLayer(0)
 {
     ASSERT(m_timingFunction);
 
@@ -79,14 +81,14 @@ AndroidAnimation::AndroidAnimation(AnimatedPropertyID type,
 AndroidAnimation::AndroidAnimation(AndroidAnimation* anim)
     : m_beginTime(anim->m_beginTime)
     , m_duration(anim->m_duration)
-    , m_finished(anim->m_finished)
+    , m_fillsBackwards(anim->m_fillsBackwards)
+    , m_fillsForwards(anim->m_fillsForwards)
     , m_iterationCount(anim->m_iterationCount)
     , m_direction(anim->m_direction)
     , m_timingFunction(anim->m_timingFunction)
     , m_name(anim->name())
     , m_type(anim->m_type)
     , m_operations(anim->m_operations)
-    , m_originalLayer(0)
 {
     gDebugAndroidAnimationInstances++;
 }
@@ -176,6 +178,37 @@ double AndroidAnimation::applyTimingFunction(float from, float to, double progre
     return fractionalTime;
 }
 
+bool AndroidAnimation::evaluate(LayerAndroid* layer, double time)
+{
+    float progress;
+    if (!checkIterationsAndProgress(time, &progress)
+        && !(m_fillsBackwards || m_fillsForwards))
+        return false;
+
+    if (progress < 0) {
+        // The animation hasn't started yet
+        if (m_fillsBackwards) {
+            // in this case we want to apply the initial keyframe to the layer
+            applyForProgress(layer, 0);
+        }
+        // we still want to be evaluated until we get progress > 0
+        return true;
+    }
+
+    if (progress >= 1) {
+        if (!m_fillsForwards)
+            return false;
+        progress = 1;
+    }
+
+    if (!m_operations->size())
+        return false;
+
+    applyForProgress(layer, progress);
+
+    return true;
+}
+
 PassRefPtr<AndroidOpacityAnimation> AndroidOpacityAnimation::create(
                                                 const Animation* animation,
                                                 KeyframeValueList* operations,
@@ -224,26 +257,9 @@ void AndroidAnimation::pickValues(double progress, int* start, int* end)
         *end = foundAt;
 }
 
-bool AndroidOpacityAnimation::evaluate(LayerAndroid* layer, double time)
+void AndroidOpacityAnimation::applyForProgress(LayerAndroid* layer, float progress)
 {
-    float progress;
-    if (!checkIterationsAndProgress(time, &progress))
-        return false;
-
-    if (progress < 0) // we still want to be evaluated until we get progress > 0
-        return true;
-
-    if (progress >= 1) {
-        m_finished = true;
-        if (layer != m_originalLayer)
-            return false;
-    }
-
-    if (!m_originalLayer)
-        m_originalLayer = layer;
-
     // First, we need to get the from and to values
-
     int from, to;
     pickValues(progress, &from, &to);
     FloatAnimationValue* fromValue = (FloatAnimationValue*) m_operations->at(from);
@@ -260,13 +276,11 @@ bool AndroidOpacityAnimation::evaluate(LayerAndroid* layer, double time)
     const TimingFunction* timingFunction = fromValue->timingFunction();
     progress = applyTimingFunction(fromValue->keyTime(), toValue->keyTime(),
                                    progress, timingFunction);
-    float value = fromValue->value() + ((toValue->value() - fromValue->value()) * progress);
 
-    layer->setOpacity(value);
 
-    XLOG("AndroidOpacityAnimation::evaluate(%p, %p, %.2f) value=%.6f", this, layer, time, value);
+    float value = fromValue->value() + ((toValue->value() - fromValue->value()) * progress);
 
-    return true;
+    layer->setOpacity(value);
 }
 
 PassRefPtr<AndroidTransformAnimation> AndroidTransformAnimation::create(
@@ -294,39 +308,12 @@ PassRefPtr<AndroidAnimation> AndroidTransformAnimation::copy()
     return adoptRef(new AndroidTransformAnimation(this));
 }
 
-bool AndroidTransformAnimation::evaluate(LayerAndroid* layer, double time)
+void AndroidTransformAnimation::applyForProgress(LayerAndroid* layer, float progress)
 {
-    float progress;
-    bool ret = true;
-    if (!checkIterationsAndProgress(time, &progress)) {
-        m_finished = true;
-        ret = false;
-    }
-
-    if (progress < 0) // we still want to be evaluated until we get progress > 0
-        return true;
-
-    if (progress >= 1) {
-        m_finished = true;
-        if (layer != m_originalLayer)
-            return false;
-    }
-
-    if (!m_originalLayer)
-        m_originalLayer = layer;
-
-    IntSize size(layer->getSize().width(), layer->getSize().height());
-    TransformationMatrix matrix;
-    XLOG("Evaluate transforms animations, %d operations, progress %.2f for layer %d (%d, %d)"
-         , m_operations->size(), progress, layer->uniqueId(), size.width(), size.height());
-
-    if (!m_operations->size())
-        return false;
-
     // First, we need to get the from and to values
-
     int from, to;
     pickValues(progress, &from, &to);
+
     TransformAnimationValue* fromValue = (TransformAnimationValue*) m_operations->at(from);
     TransformAnimationValue* toValue = (TransformAnimationValue*) m_operations->at(to);
 
@@ -364,6 +351,7 @@ bool AndroidTransformAnimation::evaluate(LayerAndroid* layer, double time)
         }
     }
 
+    IntSize size(layer->getSize().width(), layer->getSize().height());
     if (valid) {
         for (size_t i = 0; i < toValue->value()->size(); ++i)
             toValue->value()->operations()[i]->blend(fromValue->value()->at(i),
@@ -379,8 +367,6 @@ bool AndroidTransformAnimation::evaluate(LayerAndroid* layer, double time)
 
     // Set the final transform on the layer
     layer->setTransform(transformMatrix);
-
-    return ret;
 }
 
 } // namespace WebCore
index 68caeb9..16a63e8 100644 (file)
@@ -48,25 +48,28 @@ public:
     bool checkIterationsAndProgress(double time, float* finalProgress);
     double applyTimingFunction(float from, float to, double progress,
                                const TimingFunction* timingFunction);
-    virtual bool evaluate(LayerAndroid* layer, double time) = 0;
+    bool evaluate(LayerAndroid* layer, double time);
+    virtual void applyForProgress(LayerAndroid* layer, float progress) = 0;
     static long instancesCount();
     void setName(const String& name) { m_name = name; }
     String name() { return m_name; }
     AnimatedPropertyID type() { return m_type; }
-    bool finished() { return m_finished; }
+    bool fillsBackwards() { return m_fillsBackwards; }
+    bool fillsForwards() { return m_fillsForwards; }
+
 
 protected:
     double m_beginTime;
     double m_elapsedTime;
     double m_duration;
-    bool m_finished;
+    bool m_fillsBackwards;
+    bool m_fillsForwards;
     int m_iterationCount;
     int m_direction;
     RefPtr<TimingFunction> m_timingFunction;
     String m_name;
     AnimatedPropertyID m_type;
     KeyframeValueList* m_operations;
-    LayerAndroid* m_originalLayer;
 };
 
 class AndroidOpacityAnimation : public AndroidAnimation {
@@ -80,7 +83,7 @@ public:
     AndroidOpacityAnimation(AndroidOpacityAnimation* anim);
     virtual PassRefPtr<AndroidAnimation> copy();
 
-    virtual bool evaluate(LayerAndroid* layer, double time);
+    virtual void applyForProgress(LayerAndroid* layer, float progress);
 };
 
 class AndroidTransformAnimation : public AndroidAnimation {
@@ -96,7 +99,7 @@ public:
     AndroidTransformAnimation(AndroidTransformAnimation* anim);
     virtual PassRefPtr<AndroidAnimation> copy();
 
-    virtual bool evaluate(LayerAndroid* layer, double time);
+    virtual void applyForProgress(LayerAndroid* layer, float progress);
 };
 
 } // namespace WebCore
index 89f96d8..6cb9288 100644 (file)
@@ -692,13 +692,6 @@ bool GraphicsLayerAndroid::addAnimation(const KeyframeValueList& valueList,
                                         const String& keyframesName,
                                         double beginTime)
 {
-    // For now, let webkit deals with the animations -- the current UI-side
-    // animation code has some annoying bugs, and we improved communication
-    // between webkit and UI enough that performance-wise it's not so much
-    // a problem to let webkit do everything.
-    // TODO: re-enable UI-side animations
-    return false;
-
     if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2)
         return false;
 
index 4a0e2bb..d4a1225 100644 (file)
@@ -227,9 +227,7 @@ bool LayerAndroid::evaluateAnimations(double time)
         gDebugNbAnims++;
         nbAnims++;
         LayerAndroid* currentLayer = const_cast<LayerAndroid*>(this);
-        if (!(it->second)->finished() &&
-            (it->second)->evaluate(currentLayer, time))
-            m_hasRunningAnimations = true;
+        m_hasRunningAnimations |= (it->second)->evaluate(currentLayer, time);
     }
 
     return hasRunningAnimations || m_hasRunningAnimations;