OSDN Git Service

Implement partial screen invalidations
authorNicolas Roard <nicolasroard@google.com>
Wed, 16 Mar 2011 01:20:42 +0000 (18:20 -0700)
committerNicolas Roard <nicolasroard@google.com>
Thu, 17 Mar 2011 06:43:46 +0000 (23:43 -0700)
bug:3461349

Change-Id: Id654d176c58027c67be7cb604b87c0ec68984525

WebCore/platform/graphics/android/BaseLayerAndroid.cpp
WebCore/platform/graphics/android/GLWebViewState.cpp
WebCore/platform/graphics/android/GLWebViewState.h
WebCore/platform/graphics/android/LayerAndroid.cpp
WebCore/platform/graphics/android/LayerAndroid.h
WebCore/platform/graphics/android/MediaLayer.cpp
WebCore/platform/graphics/android/MediaLayer.h
WebCore/platform/graphics/android/VideoLayerAndroid.cpp
WebCore/platform/graphics/android/VideoLayerAndroid.h
WebKit/android/nav/WebView.cpp

index 1f969be..4ab0774 100644 (file)
@@ -211,6 +211,7 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, double
     const SkIRect& preZoomBounds = m_glWebViewState->preZoomBounds();
 
     TiledPage* nextTiledPage = m_glWebViewState->backPage();
+    bool needsRedraw = false;
 
     // We are now using an hybrid model -- during scrolling,
     // we will display the current tiledPage even if some tiles are
@@ -225,12 +226,16 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, double
         }
         if (nextTiledPage->ready(preZoomBounds, m_glWebViewState->currentScale())) {
             nextTiledPage->draw(transparency, preZoomBounds);
+            m_glWebViewState->resetFrameworkInval();
             m_glWebViewState->unlockBaseLayerUpdate();
             doSwap = true;
         } else {
             tiledPage->draw(transparency, preZoomBounds);
         }
     } else {
+        if (tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale()))
+           m_glWebViewState->resetFrameworkInval();
+
         // Ask for the tiles and draw -- tiles may be out of date.
         if (!zooming)
            m_glWebViewState->unlockBaseLayerUpdate();
@@ -239,10 +244,9 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, double
         tiledPage->draw(transparency, preZoomBounds);
     }
 
-    bool ret = false;
     if (m_glWebViewState->scaleRequestState() != GLWebViewState::kNoScaleRequest
         || !tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale()))
-      ret = true;
+        needsRedraw = true;
 
     if (doSwap) {
         m_glWebViewState->setCurrentScale(scale);
@@ -250,14 +254,14 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, double
         m_glWebViewState->unlockBaseLayerUpdate();
     }
 
-    return ret;
+    return needsRedraw;
 }
 #endif // USE(ACCELERATED_COMPOSITING)
 
 bool BaseLayerAndroid::drawGL(IntRect& viewRect, SkRect& visibleRect,
                               float scale, SkColor color)
 {
-    bool ret = false;
+    bool needsRedraw = false;
 #if USE(ACCELERATED_COMPOSITING)
     int left = viewRect.x();
     int top = viewRect.y();
@@ -285,11 +289,18 @@ bool BaseLayerAndroid::drawGL(IntRect& viewRect, SkRect& visibleRect,
     shader->resetBlending();
 
     double currentTime = WTF::currentTime();
-    ret = drawBasePictureInGL(visibleRect, scale, currentTime);
+    needsRedraw = drawBasePictureInGL(visibleRect, scale, currentTime);
+    if (!needsRedraw)
+        m_glWebViewState->resetFrameworkInval();
 
     if (countChildren() >= 1) {
         LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(getChild(0));
         TransformationMatrix ident;
+
+        bool animsRunning = compositedRoot->evaluateAnimations();
+        if (animsRunning)
+            needsRedraw = true;
+
         compositedRoot->updateFixedLayersPositions(visibleRect);
         FloatRect clip(0, 0, viewRect.width(), viewRect.height());
         compositedRoot->updateGLPositions(ident, clip, 1);
@@ -331,8 +342,11 @@ bool BaseLayerAndroid::drawGL(IntRect& viewRect, SkRect& visibleRect,
         // repaints if needed
         compositedRoot->createGLTextures();
 
-        if (compositedRoot->drawGL(matrix))
-            ret = true;
+        if (compositedRoot->drawGL(m_glWebViewState, matrix))
+            needsRedraw = true;
+        else if (!animsRunning)
+            m_glWebViewState->resetLayersDirtyArea();
+
     } else {
         TilesManager::instance()->cleanupLayersTextures(0);
     }
@@ -344,7 +358,7 @@ bool BaseLayerAndroid::drawGL(IntRect& viewRect, SkRect& visibleRect,
 #ifdef DEBUG
     ClassTracker::instance()->show();
 #endif
-    return ret;
+    return needsRedraw;
 }
 
 } // namespace WebCore
index 62eab0f..dbbc633 100644 (file)
@@ -71,6 +71,8 @@ GLWebViewState::GLWebViewState(android::Mutex* buttonMutex)
     , m_currentBaseLayer(0)
     , m_currentPictureCounter(0)
     , m_usePageA(true)
+    , m_frameworkInval(0, 0, 0, 0)
+    , m_frameworkLayersInval(0, 0, 0, 0)
     , m_globalButtonMutex(buttonMutex)
     , m_baseLayerUpdate(true)
     , m_backgroundColor(SK_ColorWHITE)
@@ -198,6 +200,13 @@ void GLWebViewState::inval(const IntRect& rect)
             // find which tiles fall within the invalRect and mark them as dirty
             m_tiledPageA->invalidateRect(rect, m_currentPictureCounter);
             m_tiledPageB->invalidateRect(rect, m_currentPictureCounter);
+            if (m_frameworkInval.isEmpty())
+                m_frameworkInval = rect;
+            else
+                m_frameworkInval.unite(rect);
+            XLOG("intermediate invalRect(%d, %d, %d, %d) after unite with rect %d %d %d %d", m_frameworkInval.x(),
+                 m_frameworkInval.y(), m_frameworkInval.right(), m_frameworkInval.bottom(),
+                 rect.x(), rect.y(), rect.right(), rect.bottom());
         }
     } else {
         m_invalidateRegion.op(rect.x(), rect.y(), rect.right(), rect.bottom(), SkRegion::kUnion_Op);
@@ -353,7 +362,32 @@ void GLWebViewState::dumpMeasures()
 }
 #endif // MEASURES_PERF
 
-bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, float scale, SkColor color)
+void GLWebViewState::resetFrameworkInval()
+{
+    m_frameworkInval.setX(0);
+    m_frameworkInval.setY(0);
+    m_frameworkInval.setWidth(0);
+    m_frameworkInval.setHeight(0);
+}
+
+void GLWebViewState::addDirtyArea(const IntRect& rect)
+{
+    if (m_frameworkLayersInval.isEmpty())
+        m_frameworkLayersInval = rect;
+    else
+        m_frameworkLayersInval.unite(rect);
+}
+
+void GLWebViewState::resetLayersDirtyArea()
+{
+    m_frameworkLayersInval.setX(0);
+    m_frameworkLayersInval.setY(0);
+    m_frameworkLayersInval.setWidth(0);
+    m_frameworkLayersInval.setHeight(0);
+}
+
+bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
+                            float scale, SkColor color)
 {
     glFinish();
 
@@ -374,7 +408,26 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, float scale, SkColo
     if (!baseLayer)
         return false;
 
+    XLOG("drawGL, rect(%d, %d, %d, %d), viewport(%.2f, %.2f, %.2f, %.2f)",
+         rect.x(), rect.y(), rect.right(), rect.bottom(),
+         viewport.fLeft, viewport.fTop, viewport.fRight, viewport.fBottom);
+
+    resetLayersDirtyArea();
     bool ret = baseLayer->drawGL(rect, viewport, scale, color);
+    if (ret) {
+        IntRect inval = m_frameworkInval;
+        inval.unite(m_frameworkLayersInval);
+
+        invalRect->setX((- viewport.fLeft + inval.x()) * scale);
+        invalRect->setY((- viewport.fTop + inval.y()) * scale);
+        invalRect->setWidth(inval.width() * scale);
+        invalRect->setHeight(inval.height() * scale);
+
+        XLOG("invalRect(%d, %d, %d, %d)", inval.x(),
+             inval.y(), inval.right(), inval.bottom());
+    } else {
+        resetFrameworkInval();
+    }
 
 #ifdef MEASURES_PERF
     if (m_measurePerfs) {
index e3b33f2..854d8cc 100644 (file)
@@ -213,7 +213,7 @@ public:
         return false;
     }
 
-    bool drawGL(IntRect& rect, SkRect& viewport,
+    bool drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
                 float scale, SkColor color = SK_ColorWHITE);
 
     void setBackgroundColor(SkColor color) { m_backgroundColor = color; }
@@ -223,6 +223,10 @@ public:
     void dumpMeasures();
 #endif
 
+    void resetFrameworkInval();
+    void addDirtyArea(const IntRect& rect);
+    void resetLayersDirtyArea();
+
 private:
     void inval(const IntRect& rect); // caller must hold m_baseLayerLock
     void invalRegion(const SkRegion& region);
@@ -259,6 +263,8 @@ private:
     TiledPage* m_tiledPageA;
     TiledPage* m_tiledPageB;
     IntRect m_lastInval;
+    IntRect m_frameworkInval;
+    IntRect m_frameworkLayersInval;
     android::Mutex* m_globalButtonMutex;
 
     bool m_baseLayerUpdate;
index 839798d..89ce301 100644 (file)
@@ -208,7 +208,7 @@ LayerAndroid::~LayerAndroid()
 
 static int gDebugNbAnims = 0;
 
-bool LayerAndroid::evaluateAnimations() const
+bool LayerAndroid::evaluateAnimations()
 {
     double time = WTF::currentTime();
     gDebugNbAnims = 0;
@@ -224,22 +224,35 @@ bool LayerAndroid::hasAnimations() const
     return !!m_animations.size();
 }
 
-bool LayerAndroid::evaluateAnimations(double time) const
+bool LayerAndroid::evaluateAnimations(double time)
 {
     bool hasRunningAnimations = false;
     for (int i = 0; i < countChildren(); i++) {
         if (getChild(i)->evaluateAnimations(time))
             hasRunningAnimations = true;
     }
+
+    m_hasRunningAnimations = false;
+    int nbAnims = 0;
     KeyframesMap::const_iterator end = m_animations.end();
     for (KeyframesMap::const_iterator it = m_animations.begin(); it != end; ++it) {
         gDebugNbAnims++;
+        nbAnims++;
         LayerAndroid* currentLayer = const_cast<LayerAndroid*>(this);
         if ((it->second)->evaluate(currentLayer, time))
-            hasRunningAnimations = true;
+            m_hasRunningAnimations = true;
     }
 
-    return hasRunningAnimations;
+    return hasRunningAnimations || m_hasRunningAnimations;
+}
+
+void LayerAndroid::addDirtyArea(GLWebViewState* glWebViewState)
+{
+    IntRect rect(0, 0, getWidth(), getHeight());
+    IntRect dirtyArea = drawTransform().mapRect(rect);
+    IntRect clip(m_clippingRect.x(), m_clippingRect.y(), m_clippingRect.width(), m_clippingRect.height());
+    dirtyArea.intersect(clip);
+    glWebViewState->addDirtyArea(dirtyArea);
 }
 
 void LayerAndroid::addAnimation(PassRefPtr<AndroidAnimation> prpAnim)
@@ -894,7 +907,7 @@ static inline bool compareLayerZ(const LayerAndroid* a, const LayerAndroid* b)
     return transformA.m43() < transformB.m43();
 }
 
-bool LayerAndroid::drawGL(SkMatrix& matrix)
+bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
 {
     TilesManager::instance()->shader()->clip(m_clippingRect);
 
@@ -916,15 +929,17 @@ bool LayerAndroid::drawGL(SkMatrix& matrix)
     }
 
     // When the layer is dirty, the UI thread should be notified to redraw.
-    bool askPaint = drawChildrenGL(matrix);
+    bool askPaint = drawChildrenGL(glWebViewState, matrix);
     m_atomicSync.lock();
     askPaint |= m_dirty;
+    if (m_dirty || m_hasRunningAnimations)
+        addDirtyArea(glWebViewState);
     m_atomicSync.unlock();
     return askPaint;
 }
 
 
-bool LayerAndroid::drawChildrenGL(SkMatrix& matrix)
+bool LayerAndroid::drawChildrenGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
 {
     bool askPaint = false;
     int count = this->countChildren();
@@ -937,7 +952,7 @@ bool LayerAndroid::drawChildrenGL(SkMatrix& matrix)
         std::stable_sort(sublayers.begin(), sublayers.end(), compareLayerZ);
         for (int i = 0; i < count; i++) {
             LayerAndroid* layer = sublayers[i];
-            askPaint |= layer->drawGL(matrix);
+            askPaint |= layer->drawGL(glWebViewState, matrix);
         }
     }
 
index 3e00bfa..98a0a15 100644 (file)
@@ -128,8 +128,8 @@ public:
 
     void setScale(float scale);
     float getScale() { return m_scale; }
-    virtual bool drawGL(SkMatrix&);
-    bool drawChildrenGL(SkMatrix&);
+    virtual bool drawGL(GLWebViewState*, SkMatrix&);
+    bool drawChildrenGL(GLWebViewState*, SkMatrix&);
     virtual void paintBitmapGL();
     void updateGLPositions(const TransformationMatrix& parentMatrix,
                            const FloatRect& clip, float opacity);
@@ -182,9 +182,10 @@ public:
     void addAnimation(PassRefPtr<AndroidAnimation> anim);
     void removeAnimationsForProperty(AnimatedPropertyID property);
     void removeAnimationsForKeyframes(const String& name);
-    bool evaluateAnimations() const;
-    bool evaluateAnimations(double time) const;
+    bool evaluateAnimations();
+    bool evaluateAnimations(double time);
     bool hasAnimations() const;
+    void addDirtyArea(GLWebViewState*);
 
     SkPicture* picture() const { return m_recordingPicture; }
 
@@ -325,6 +326,9 @@ private:
     bool m_dirty;
     unsigned int m_pictureUsed;
 
+    // used to signal the framework we need a repaint
+    bool m_hasRunningAnimations;
+
     // painting request sent
     bool m_requestSent;
 
index 6c34585..40a0f11 100644 (file)
@@ -73,7 +73,7 @@ MediaLayer::~MediaLayer()
     m_videoTexture->decStrong(this);
 }
 
-bool MediaLayer::drawGL(SkMatrix& matrix)
+bool MediaLayer::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
 {
     TilesManager::instance()->shader()->clip(drawClip());
 
@@ -112,7 +112,7 @@ bool MediaLayer::drawGL(SkMatrix& matrix)
         m_bufferedTexture->consumerRelease();
     }
 
-    return drawChildrenGL(matrix);
+    return drawChildrenGL(glWebViewState, matrix);
 }
 
 ANativeWindow* MediaLayer::acquireNativeWindowForVideo()
index 203ef93..46789cb 100644 (file)
@@ -36,7 +36,7 @@ public:
     MediaLayer(const MediaLayer& layer);
     virtual ~MediaLayer();
 
-    virtual bool drawGL(SkMatrix&);
+    virtual bool drawGL(GLWebViewState*, SkMatrix&);
     virtual void paintBitmapGL() const { };
     virtual bool needsTexture() { return false; }
 
index 2eced57..697281c 100644 (file)
@@ -101,7 +101,7 @@ GLuint VideoLayerAndroid::createPauseTexture()
     return texture;
 }
 
-bool VideoLayerAndroid::drawGL(SkMatrix& matrix)
+bool VideoLayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
 {
     // Lazy allocated the paused texture.
     if (!m_createdPauseTexture) {
@@ -127,7 +127,7 @@ bool VideoLayerAndroid::drawGL(SkMatrix& matrix)
                                                                rect, m_textureId);
     }
 
-    return drawChildrenGL(matrix);
+    return drawChildrenGL(glWebViewState, matrix);
 }
 
 }
index c2a962e..d291dda 100644 (file)
@@ -48,7 +48,7 @@ public:
     virtual LayerAndroid* copy() const { return new VideoLayerAndroid(*this); }
 
     // The following 3 functions are called in UI thread only.
-    virtual bool drawGL(SkMatrix& matrix);
+    virtual bool drawGL(GLWebViewState*, SkMatrix& matrix);
     void setSurfaceTexture(sp<SurfaceTexture> texture, int textureName, bool updateTexture);
     GLuint createPauseTexture();
 
index 8cc5810..6e85873 100644 (file)
@@ -428,7 +428,7 @@ void drawCursorPostamble()
     }
 }
 
-bool drawGL(WebCore::IntRect& viewRect, float scale, int extras)
+bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, float scale, int extras)
 {
 #if USE(ACCELERATED_COMPOSITING)
     if (!m_baseLayer || inFullScreenMode())
@@ -499,7 +499,7 @@ bool drawGL(WebCore::IntRect& viewRect, float scale, int extras)
 
     SkRect visibleRect;
     calcOurContentVisibleRect(&visibleRect);
-    bool ret = m_glWebViewState->drawGL(viewRect, visibleRect, scale);
+    bool ret = m_glWebViewState->drawGL(viewRect, visibleRect, invalRect, scale);
     if (ret || m_glWebViewState->currentPictureCounter() != pic)
         return true;
 #endif
@@ -1473,7 +1473,7 @@ private: // local state for WebView
 class GLDrawFunctor : Functor {
     public:
     GLDrawFunctor(WebView* _wvInstance,
-            bool(WebView::*_funcPtr)(WebCore::IntRect&, jfloat, jint),
+            bool(WebView::*_funcPtr)(WebCore::IntRect&, WebCore::IntRect*, jfloat, jint),
             WebCore::IntRect _viewRect, float _scale, int _extras) {
         wvInstance = _wvInstance;
         funcPtr = _funcPtr;
@@ -1501,13 +1501,26 @@ class GLDrawFunctor : Functor {
             float dirtyBottom;
         };
 
-        bool retVal = (*wvInstance.*funcPtr)(viewRect, scale, extras);
+        WebCore::IntRect inval;
+        int titlebarHeight = webViewRect.height() - viewRect.height();
+        bool retVal = (*wvInstance.*funcPtr)(viewRect, &inval, scale, extras);
         if (retVal) {
             DrawConstraints* constraints = reinterpret_cast<DrawConstraints*>(data);
-            constraints->dirtyLeft = webViewRect.x();
-            constraints->dirtyTop = webViewRect.y();
-            constraints->dirtyRight = webViewRect.right();
-            constraints->dirtyBottom = webViewRect.bottom();
+            IntRect finalInval;
+            if (inval.isEmpty()) {
+                finalInval = webViewRect;
+                retVal = false;
+            } else {
+                finalInval.setX(webViewRect.x() + inval.x());
+                finalInval.setY(webViewRect.y() + inval.y() + titlebarHeight);
+                finalInval.setWidth(inval.width());
+                finalInval.setHeight(inval.height());
+                finalInval.intersect(webViewRect);
+            }
+            constraints->dirtyLeft = finalInval.x();
+            constraints->dirtyTop = finalInval.y();
+            constraints->dirtyRight = finalInval.right();
+            constraints->dirtyBottom = finalInval.bottom();
         }
         // return 1 if invalidation needed, 0 otherwise
         return retVal ? 1 : 0;
@@ -1520,7 +1533,7 @@ class GLDrawFunctor : Functor {
     }
     private:
     WebView* wvInstance;
-    bool (WebView::*funcPtr)(WebCore::IntRect&, float, int);
+    bool (WebView::*funcPtr)(WebCore::IntRect&, WebCore::IntRect*, float, int);
     WebCore::IntRect viewRect;
     WebCore::IntRect webViewRect;
     jfloat scale;
@@ -1805,13 +1818,14 @@ static bool nativeDrawGL(JNIEnv *env, jobject obj, jobject jrect,
                          jfloat scale, jint extras)
 {
     WebCore::IntRect viewRect = jrect_to_webrect(env, jrect);
-    return GET_NATIVE_VIEW(env, obj)->drawGL(viewRect, scale, extras);
+    WebCore::IntRect invalRect;
+    return GET_NATIVE_VIEW(env, obj)->drawGL(viewRect, &invalRect, scale, extras);
 }
 
 static bool nativeEvaluateLayersAnimations(JNIEnv *env, jobject obj)
 {
 #if USE(ACCELERATED_COMPOSITING)
-    const LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot();
+    LayerAndroid* root = GET_NATIVE_VIEW(env, obj)->compositeRoot();
     if (root)
         return root->evaluateAnimations();
 #endif