OSDN Git Service

synchronize animation starts with webkit
authorChris Craik <ccraik@google.com>
Tue, 29 Nov 2011 21:39:24 +0000 (13:39 -0800)
committerChris Craik <ccraik@google.com>
Wed, 30 Nov 2011 00:04:54 +0000 (16:04 -0800)
bug:5239801

this better supports animations not synchronous with webkit

Relies on the frameworks/base CL: https://android-git.corp.google.com/g/#/c/152533/

Change-Id: Ia79a475065b3891db8fc4014559062ab1ac95ebe

13 files changed:
Source/WebCore/platform/graphics/android/AndroidAnimation.cpp
Source/WebCore/platform/graphics/android/AndroidAnimation.h
Source/WebCore/platform/graphics/android/GLWebViewState.cpp
Source/WebCore/platform/graphics/android/GLWebViewState.h
Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp
Source/WebCore/platform/graphics/android/LayerAndroid.cpp
Source/WebCore/platform/graphics/android/LayerAndroid.h
Source/WebCore/platform/graphics/android/TreeManager.cpp
Source/WebCore/platform/graphics/android/TreeManager.h
Source/WebCore/rendering/RenderLayerCompositor.cpp
Source/WebKit/android/jni/WebViewCore.cpp
Source/WebKit/android/jni/WebViewCore.h
Source/WebKit/android/nav/WebView.cpp

index 5601269..245d2f1 100644 (file)
@@ -49,6 +49,8 @@
 
 namespace WebCore {
 
+static int gUniqueId;
+
 static long gDebugAndroidAnimationInstances;
 
 long AndroidAnimation::instancesCount()
@@ -69,12 +71,11 @@ AndroidAnimation::AndroidAnimation(AnimatedPropertyID type,
     , m_timingFunction(animation->timingFunction())
     , m_type(type)
     , m_operations(operations)
+    , m_uniqueId(++gUniqueId)
+    , m_hasFinished(false)
 {
     ASSERT(m_timingFunction);
 
-    if (!static_cast<int>(beginTime)) // time not set
-        m_beginTime = WTF::currentTime();
-
     gDebugAndroidAnimationInstances++;
 }
 
@@ -89,6 +90,8 @@ AndroidAnimation::AndroidAnimation(AndroidAnimation* anim)
     , m_name(anim->name())
     , m_type(anim->m_type)
     , m_operations(anim->m_operations)
+    , m_uniqueId(anim->m_uniqueId)
+    , m_hasFinished(anim->m_hasFinished)
 {
     gDebugAndroidAnimationInstances++;
 }
@@ -98,20 +101,24 @@ AndroidAnimation::~AndroidAnimation()
     gDebugAndroidAnimationInstances--;
 }
 
-double AndroidAnimation::elapsedTime(double time)
+void AndroidAnimation::suggestBeginTime(double time)
 {
-    if (m_beginTime <= 0.000001) // overflow or not correctly set
+    if (m_beginTime <= 0.000001) // overflow or not yet set
         m_beginTime = time;
+}
 
-    m_elapsedTime = time - m_beginTime;
+double AndroidAnimation::elapsedTime(double time)
+{
+    suggestBeginTime(time);
+    double elapsedTime = time - m_beginTime;
 
     if (m_duration <= 0)
       m_duration = 0.000001;
 
-    if (m_elapsedTime < 0) // animation not yet started.
+    if (elapsedTime < 0) // animation not yet started.
         return 0;
 
-    return m_elapsedTime;
+    return elapsedTime;
 }
 
 bool AndroidAnimation::checkIterationsAndProgress(double time, float* finalProgress)
@@ -127,6 +134,13 @@ bool AndroidAnimation::checkIterationsAndProgress(double time, float* finalProgr
     // If not infinite, return false if we are done
     if (m_iterationCount > 0 && progress > dur) {
         *finalProgress = 1.0;
+        if (!m_hasFinished) {
+            // first time past duration, continue with progress 1.0 so the
+            // element's final position lines up with it's last keyframe
+            m_hasFinished = true;
+            return true;
+        }
+
         return false;
     }
 
@@ -195,7 +209,7 @@ bool AndroidAnimation::evaluate(LayerAndroid* layer, double time)
         return true;
     }
 
-    if (progress >= 1) {
+    if (progress > 1) {
         if (!m_fillsForwards)
             return false;
         progress = 1;
index 16a63e8..52cef4e 100644 (file)
@@ -43,6 +43,7 @@ public:
 
     virtual ~AndroidAnimation();
     virtual PassRefPtr<AndroidAnimation> copy() = 0;
+    void suggestBeginTime(double time);
     double elapsedTime(double time);
     void pickValues(double progress, int* start, int* end);
     bool checkIterationsAndProgress(double time, float* finalProgress);
@@ -56,11 +57,12 @@ public:
     AnimatedPropertyID type() { return m_type; }
     bool fillsBackwards() { return m_fillsBackwards; }
     bool fillsForwards() { return m_fillsForwards; }
+    int uniqueId() { return m_uniqueId; }
 
+    double beginTime() { return m_beginTime; }
 
 protected:
     double m_beginTime;
-    double m_elapsedTime;
     double m_duration;
     bool m_fillsBackwards;
     bool m_fillsForwards;
@@ -70,6 +72,8 @@ protected:
     String m_name;
     AnimatedPropertyID m_type;
     KeyframeValueList* m_operations;
+    int m_uniqueId;
+    bool m_hasFinished;
 };
 
 class AndroidOpacityAnimation : public AndroidAnimation {
index a33c3d0..5227a8f 100644 (file)
@@ -84,9 +84,9 @@ GLWebViewState::GLWebViewState()
     , m_goingLeft(false)
     , m_expandedTileBoundsX(0)
     , m_expandedTileBoundsY(0)
+    , m_highEndGfx(false)
     , m_scale(1)
     , m_layersRenderingMode(kAllTextures)
-    , m_highEndGfx(false)
 {
     m_viewport.setEmpty();
     m_futureViewportTileBounds.setEmpty();
@@ -431,7 +431,8 @@ void GLWebViewState::fullInval()
 
 bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
                             IntRect& webViewRect, int titleBarHeight,
-                            IntRect& clip, float scale, bool* buffersSwappedPtr)
+                            IntRect& clip, float scale,
+                            bool* treesSwappedPtr, bool* newTreeHasAnimPtr)
 {
     m_scale = scale;
     TilesManager::instance()->getProfiler()->nextFrame(viewport.fLeft,
@@ -488,7 +489,8 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
     bool fastSwap = isScrolling() || m_layersRenderingMode == kSingleSurfaceRendering;
     ret |= m_treeManager.drawGL(currentTime, rect, viewport,
                                 scale, fastSwap,
-                                buffersSwappedPtr, &nbTexturesNeeded);
+                                treesSwappedPtr, newTreeHasAnimPtr,
+                                &nbTexturesNeeded);
     if (!ret)
         resetFrameworkInval();
 
index 2a6c8df..cffd28f 100644 (file)
@@ -214,7 +214,8 @@ public:
 
     bool drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
                 IntRect& webViewRect, int titleBarHeight,
-                IntRect& clip, float scale, bool* buffersSwappedPtr);
+                IntRect& clip, float scale,
+                bool* treesSwappedPtr, bool* newTreeHasAnimPtr);
 
 #ifdef MEASURES_PERF
     void dumpMeasures();
index 3e062f8..741b9e4 100644 (file)
@@ -331,6 +331,9 @@ void GraphicsLayerAndroid::setSize(const FloatSize& size)
 
 void GraphicsLayerAndroid::setBackfaceVisibility(bool b)
 {
+    if (b == m_backfaceVisibility)
+        return;
+
     GraphicsLayer::setBackfaceVisibility(b);
     m_contentLayer->setBackfaceVisibility(b);
     askForSync();
@@ -397,7 +400,7 @@ void GraphicsLayerAndroid::setDrawsContent(bool drawsContent)
 
 void GraphicsLayerAndroid::setBackgroundColor(const Color& color)
 {
-    if (color == m_backgroundColor)
+    if (color == m_backgroundColor && m_backgroundColorSet)
         return;
     LOG("(%x) setBackgroundColor", this);
     GraphicsLayer::setBackgroundColor(color);
@@ -409,6 +412,9 @@ void GraphicsLayerAndroid::setBackgroundColor(const Color& color)
 
 void GraphicsLayerAndroid::clearBackgroundColor()
 {
+    if (!m_backgroundColorSet)
+        return;
+
     LOG("(%x) clearBackgroundColor", this);
     GraphicsLayer::clearBackgroundColor();
     askForSync();
index 859973a..86991d5 100644 (file)
@@ -879,6 +879,12 @@ void LayerAndroid::setIsDrawing(bool isDrawing)
         m_texture->setDrawingLayer(isDrawing ? this : 0);
         m_texture->clearPaintingLayer();
     }
+
+    // tell auto-initializing animations to start now
+    KeyframesMap::const_iterator localBegin = m_animations.begin();
+    KeyframesMap::const_iterator localEnd = m_animations.end();
+    for (KeyframesMap::const_iterator localIt = localBegin; localIt != localEnd; ++localIt)
+        (localIt->second)->suggestBeginTime(WTF::currentTime());
 }
 
 void LayerAndroid::setIsPainting(Layer* drawingTree)
@@ -889,7 +895,34 @@ void LayerAndroid::setIsPainting(Layer* drawingTree)
     for (int i = 0; i < count; i++)
         this->getChild(i)->setIsPainting(drawingTree);
 
-    obtainTextureForPainting(static_cast<LayerAndroid*>(drawingTree));
+
+    LayerAndroid* drawingLayer = 0;
+    if (drawingTree)
+        drawingLayer = static_cast<LayerAndroid*>(drawingTree)->findById(uniqueId());
+
+    copyAnimationStartTimes(drawingLayer);
+    obtainTextureForPainting(drawingLayer);
+}
+
+void LayerAndroid::copyAnimationStartTimes(LayerAndroid* oldLayer)
+{
+    if (!oldLayer)
+        return;
+
+    // copy animation start times, if applicable
+    KeyframesMap::const_iterator localBegin = m_animations.begin();
+    KeyframesMap::const_iterator localEnd = m_animations.end();
+    for (KeyframesMap::const_iterator localIt = localBegin; localIt != localEnd; ++localIt) {
+        KeyframesMap::const_iterator oldBegin = oldLayer->m_animations.begin();
+        KeyframesMap::const_iterator oldEnd = oldLayer->m_animations.end();
+        for (KeyframesMap::const_iterator oldIt = oldBegin; oldIt != oldEnd; ++oldIt) {
+            if ((localIt->second)->uniqueId() == (oldIt->second)->uniqueId()) {
+                // animations are identical, try to copy start time of the old
+                // one, which will have been initialized some time in the past
+                (localIt->second)->suggestBeginTime((oldIt->second)->beginTime());
+            }
+        }
+    }
 }
 
 void LayerAndroid::mergeInvalsInto(Layer* replacementTree)
@@ -960,7 +993,7 @@ bool LayerAndroid::updateWithLayer(LayerAndroid* layer)
     return false;
 }
 
-void LayerAndroid::obtainTextureForPainting(LayerAndroid* drawingTree)
+void LayerAndroid::obtainTextureForPainting(LayerAndroid* drawingLayer)
 {
     if (!needsTexture())
         return;
@@ -976,12 +1009,9 @@ void LayerAndroid::obtainTextureForPainting(LayerAndroid* drawingTree)
             m_texture = 0;
         }
     } else {
-        if (drawingTree) {
-            LayerAndroid* drawingLayer = drawingTree->findById(uniqueId());
-            if (drawingLayer) {
-                // if a previous tree had the same layer, paint with that painted surface
-                m_texture = drawingLayer->m_texture;
-            }
+        if (drawingLayer) {
+            // if a previous tree had the same layer, paint with that painted surface
+            m_texture = drawingLayer->m_texture;
         }
 
         if (!m_texture)
index ae9dc88..8b82b27 100644 (file)
@@ -290,7 +290,7 @@ public:
     friend void android::cleanupImageRefs(LayerAndroid* layer);
 
     PaintedSurface* texture() { return m_texture; }
-    void obtainTextureForPainting(LayerAndroid* drawingTree);
+    void obtainTextureForPainting(LayerAndroid* drawingLayer);
 
     // Update layers using another tree. Only works for basic properties
     // such as the position, the transform. Return true if anything more
@@ -323,6 +323,7 @@ private:
     friend class CachedLayer::Debug; // debugging access only
 #endif
 
+    void copyAnimationStartTimes(LayerAndroid* oldLayer);
     void findInner(FindState&) const;
     bool prepareContext(bool force = false);
     void clipInner(SkTDArray<SkRect>* region, const SkRect& local) const;
index 5fd3b7c..fe55df8 100644 (file)
@@ -132,6 +132,10 @@ void TreeManager::clearTrees()
 // or start painting it if we aren't
 void TreeManager::updateWithTree(Layer* newTree, bool brandNew)
 {
+    XLOG("updateWithTree - %p, has children %d, has animations %d",
+         newTree, newTree && newTree->countChildren(),
+         newTree && newTree->countChildren()
+             ? static_cast<LayerAndroid*>(newTree->getChild(0))->hasAnimations() : 0);
 
     // can't have a queued tree unless have a painting tree too
     ASSERT(m_paintingTree || !m_queuedTree);
@@ -143,10 +147,6 @@ void TreeManager::updateWithTree(Layer* newTree, bool brandNew)
     if (!newTree || brandNew) {
         clearTrees();
         if (brandNew) {
-            m_animationOffset = 0;
-            m_isAnimating = false;
-            m_lastFrameTime = WTF::currentTime();
-
             m_paintingTree = newTree;
             m_paintingTree->setIsPainting(m_drawingTree);
         }
@@ -159,6 +159,11 @@ void TreeManager::updateWithTree(Layer* newTree, bool brandNew)
             // have a queued tree, copy over invals so the regions are
             // eventually repainted
             m_queuedTree->mergeInvalsInto(newTree);
+
+            XLOG("DISCARDING tree - %p, has children %d, has animations %d",
+                 newTree, newTree && newTree->countChildren(),
+                 newTree && newTree->countChildren()
+                     ? static_cast<LayerAndroid*>(newTree->getChild(0))->hasAnimations() : 0);
         }
         SkSafeUnref(m_queuedTree);
         m_queuedTree = newTree;
@@ -172,7 +177,7 @@ void TreeManager::updateWithTree(Layer* newTree, bool brandNew)
 
 bool TreeManager::drawGL(double currentTime, IntRect& viewRect,
                          SkRect& visibleRect, float scale,
-                         bool enterFastSwapMode, bool* buffersSwappedPtr,
+                         bool enterFastSwapMode, bool* treesSwappedPtr, bool* newTreeHasAnimPtr,
                          TexturesResult* texturesResultPtr)
 {
     m_fastSwapMode |= enterFastSwapMode;
@@ -185,17 +190,20 @@ bool TreeManager::drawGL(double currentTime, IntRect& viewRect,
     if (m_paintingTree) {
         ret |= m_paintingTree->prepare(currentTime, viewRect,
                                        visibleRect, scale);
+        LayerAndroid* laTree = 0;
 
         if (m_paintingTree->countChildren()) {
-            LayerAndroid* laTree = static_cast<LayerAndroid*>(m_paintingTree->getChild(0));
+            laTree = static_cast<LayerAndroid*>(m_paintingTree->getChild(0));
             laTree->computeTexturesAmount(texturesResultPtr);
         }
         if (/*!m_fastSwapMode && */ m_paintingTree->isReady()) {
             XLOG("have painting tree %p ready, swapping!", m_paintingTree);
             didTreeSwap = true;
             swap();
-            if (buffersSwappedPtr)
-                *buffersSwappedPtr = true;
+            if (treesSwappedPtr)
+                *treesSwappedPtr = true;
+            if (laTree && newTreeHasAnimPtr)
+                *newTreeHasAnimPtr = laTree->hasAnimations();
         }
     } else if (m_drawingTree) {
         XLOG("preparing drawing tree %p", m_drawingTree);
@@ -207,17 +215,11 @@ bool TreeManager::drawGL(double currentTime, IntRect& viewRect,
         }
     }
 
-    if (!m_isAnimating) {
-        m_animationOffset += currentTime - m_lastFrameTime;
-#ifdef ANIM_DEBUG
-        XLOGC("adding to %f", m_animationOffset);
-#endif
-    }
 
     if (m_drawingTree) {
         bool drawingReady = didTreeSwap || m_drawingTree->isReady();
 
-        if (drawingReady || m_fastSwapMode)
+        if (didTreeSwap || m_fastSwapMode || (drawingReady && !m_paintingTree))
             m_drawingTree->swapTiles();
 
         if (drawingReady) {
@@ -229,18 +231,8 @@ bool TreeManager::drawGL(double currentTime, IntRect& viewRect,
         }
 
         if (m_drawingTree->countChildren()) {
-#ifdef ANIM_DEBUG
-            XLOGC("drawing tree %p with animation time offset of %f, locked %d",
-                  m_drawingTree, m_animationOffset, m_isAnimating);
-#endif
             LayerAndroid* laTree = static_cast<LayerAndroid*>(m_drawingTree->getChild(0));
-            m_isAnimating = laTree->evaluateAnimations(currentTime - m_animationOffset);
-            if (!m_isAnimating)
-                m_animationOffset = 0;
-            ret |= m_isAnimating;
-        } else if (!m_paintingTree) {
-            m_animationOffset = 0;
-            m_isAnimating = false;
+            ret |= laTree->evaluateAnimations(currentTime);
         }
         XLOG("drawing tree %p", m_drawingTree);
         ret |= m_drawingTree->drawGL(viewRect, visibleRect, scale);
@@ -250,8 +242,6 @@ bool TreeManager::drawGL(double currentTime, IntRect& viewRect,
         m_paintingTree->state()->drawBackground(defaultBackground);
     }
 
-    m_lastFrameTime = currentTime;
-
     if (m_paintingTree) {
         XLOG("still have painting tree %p", m_paintingTree);
         return true;
index 09b1bd9..d2e10c8 100644 (file)
@@ -48,7 +48,7 @@ public:
 
     bool drawGL(double currentTime, IntRect& viewRect,
                 SkRect& visibleRect, float scale,
-                bool enterFastSwapMode, bool* buffersSwappedPtr,
+                bool enterFastSwapMode, bool* treesSwappedPtr, bool* newTreeHasAnimPtr,
                 TexturesResult* texturesResultPtr);
 
     void drawCanvas(SkCanvas* canvas, bool drawLayers);
@@ -70,10 +70,6 @@ private:
     Layer* m_queuedTree;
 
     bool m_fastSwapMode;
-
-    double m_animationOffset;
-    double m_lastFrameTime;
-    bool m_isAnimating;
 };
 
 } // namespace WebCore
index 85c57a6..06fa0f6 100644 (file)
@@ -1578,7 +1578,12 @@ bool RenderLayerCompositor::requiresCompositingForAnimation(RenderObject* render
         return false;
 
     if (AnimationController* animController = renderer->animation()) {
+#if PLATFORM(ANDROID)
+        // android renders an opacity animation much faster if it's composited
+        return (animController->isRunningAnimationOnRenderer(renderer, CSSPropertyOpacity))
+#else
         return (animController->isRunningAnimationOnRenderer(renderer, CSSPropertyOpacity) && inCompositingMode())
+#endif
             || animController->isRunningAnimationOnRenderer(renderer, CSSPropertyWebkitTransform);
     }
     return false;
index 6cc15d7..839c352 100644 (file)
@@ -885,13 +885,23 @@ bool WebViewCore::updateLayers(LayerAndroid* layers)
     ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
     GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
     if (root) {
-        root->notifyClientAnimationStarted();
         LayerAndroid* updatedLayer = root->contentLayer();
         return layers->updateWithTree(updatedLayer);
     }
     return true;
 }
 
+void WebViewCore::notifyAnimationStarted()
+{
+    // We notify webkit that the animations have begun
+    // TODO: handle case where not all have begun
+    ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
+    GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
+    if (root)
+        root->notifyClientAnimationStarted();
+
+}
+
 BaseLayerAndroid* WebViewCore::createBaseLayer(SkRegion* region)
 {
     BaseLayerAndroid* base = new BaseLayerAndroid();
@@ -920,7 +930,6 @@ BaseLayerAndroid* WebViewCore::createBaseLayer(SkRegion* region)
     ChromeClientAndroid* chromeC = static_cast<ChromeClientAndroid*>(m_mainFrame->page()->chrome()->client());
     GraphicsLayerAndroid* root = static_cast<GraphicsLayerAndroid*>(chromeC->layersSync());
     if (root) {
-        root->notifyClientAnimationStarted();
         LayerAndroid* copyLayer = new LayerAndroid(*root->contentLayer());
         base->addChild(copyLayer);
         copyLayer->unref();
@@ -4104,9 +4113,9 @@ void WebViewCore::addVisitedLink(const UChar* string, int length)
         m_groupForVisitedLinks->addVisitedLink(string, length);
 }
 
-static bool UpdateLayers(JNIEnv *env, jobject obj, jint jbaseLayer)
+static bool UpdateLayers(JNIEnv *env, jobject obj, jint nativeClass, jint jbaseLayer)
 {
-    WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+    WebViewCore* viewImpl = (WebViewCore*) nativeClass;
     BaseLayerAndroid* baseLayer = (BaseLayerAndroid*)  jbaseLayer;
     if (baseLayer) {
         LayerAndroid* root = static_cast<LayerAndroid*>(baseLayer->getChild(0));
@@ -4116,6 +4125,12 @@ static bool UpdateLayers(JNIEnv *env, jobject obj, jint jbaseLayer)
     return true;
 }
 
+static void NotifyAnimationStarted(JNIEnv *env, jobject obj, jint nativeClass)
+{
+    WebViewCore* viewImpl = (WebViewCore*) nativeClass;
+    viewImpl->notifyAnimationStarted();
+}
+
 static jint RecordContent(JNIEnv *env, jobject obj, jobject region, jobject pt)
 {
 #ifdef ANDROID_INSTRUMENT
@@ -4695,8 +4710,10 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = {
         (void*) UpdateFrameCache },
     { "nativeGetContentMinPrefWidth", "()I",
         (void*) GetContentMinPrefWidth },
-    { "nativeUpdateLayers", "(I)Z",
+    { "nativeUpdateLayers", "(II)Z",
         (void*) UpdateLayers },
+    { "nativeNotifyAnimationStarted", "(I)V",
+        (void*) NotifyAnimationStarted },
     { "nativeRecordContent", "(Landroid/graphics/Region;Landroid/graphics/Point;)I",
         (void*) RecordContent },
     { "setViewportSettingsFromNative", "()V",
index acde590..a05c3ea 100644 (file)
@@ -529,6 +529,7 @@ namespace android {
         // as we are calling layersSync().
         BaseLayerAndroid* createBaseLayer(SkRegion*);
         bool updateLayers(LayerAndroid*);
+        void notifyAnimationStarted();
 
         int textWrapWidth() const { return m_textWrapWidth; }
         float scale() const { return m_scale; }
index 13346b3..18c4d4b 100644 (file)
@@ -172,7 +172,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir,
     m_javaGlue.m_viewInvalidateRect = GetJMethod(env, clazz, "viewInvalidate", "(IIII)V");
     m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz,
         "viewInvalidateDelayed", "(JIIII)V");
-    m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "()V");
+    m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "(Z)V");
     m_javaGlue.m_inFullScreenMode = GetJMethod(env, clazz, "inFullScreenMode", "()Z");
     m_javaGlue.m_getTextHandleScale = GetJMethod(env, clazz, "getTextHandleScale", "()F");
     env->DeleteLocalRef(clazz);
@@ -505,17 +505,18 @@ bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect,
     // once the correct scale is set
     if (!m_visibleRect.hasValidCoordinates())
         return false;
-    bool pagesSwapped = false;
+    bool treesSwapped = false;
+    bool newTreeHasAnim = false;
     bool ret = m_glWebViewState->drawGL(viewRect, m_visibleRect, invalRect,
                                         webViewRect, titleBarHeight, clip, scale,
-                                        &pagesSwapped);
-    if (m_pageSwapCallbackRegistered && pagesSwapped) {
+                                        &treesSwapped, &newTreeHasAnim);
+    if (treesSwapped && (m_pageSwapCallbackRegistered || newTreeHasAnim)) {
         m_pageSwapCallbackRegistered = false;
         LOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
         JNIEnv* env = JSC::Bindings::getJNIEnv();
         AutoJObject javaObject = m_javaGlue.object(env);
         if (javaObject.get()) {
-            env->CallVoidMethod(javaObject.get(), m_javaGlue.m_pageSwapCallback);
+            env->CallVoidMethod(javaObject.get(), m_javaGlue.m_pageSwapCallback, newTreeHasAnim);
             checkException(env);
         }
     }