OSDN Git Service

synchronous layer updates, and animation deferral during paint
authorChris Craik <ccraik@google.com>
Tue, 15 Nov 2011 19:28:34 +0000 (11:28 -0800)
committerChris Craik <ccraik@google.com>
Thu, 17 Nov 2011 00:19:16 +0000 (16:19 -0800)
bug:5522081
bug:5239801
bug:5297563

Change-Id: I600f66999e093f720a8ea97ef3e15d3d1d297a8f

31 files changed:
Source/WebCore/Android.mk
Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp
Source/WebCore/platform/graphics/android/BaseLayerAndroid.h
Source/WebCore/platform/graphics/android/GLWebViewState.cpp
Source/WebCore/platform/graphics/android/GLWebViewState.h
Source/WebCore/platform/graphics/android/ImageTexture.h
Source/WebCore/platform/graphics/android/Layer.cpp
Source/WebCore/platform/graphics/android/Layer.h
Source/WebCore/platform/graphics/android/LayerAndroid.cpp
Source/WebCore/platform/graphics/android/LayerAndroid.h
Source/WebCore/platform/graphics/android/MediaLayer.cpp
Source/WebCore/platform/graphics/android/MediaLayer.h
Source/WebCore/platform/graphics/android/PaintTileOperation.cpp
Source/WebCore/platform/graphics/android/PaintTileOperation.h
Source/WebCore/platform/graphics/android/PaintedSurface.cpp
Source/WebCore/platform/graphics/android/PaintedSurface.h
Source/WebCore/platform/graphics/android/QueuedOperation.h
Source/WebCore/platform/graphics/android/TestExport.h [new file with mode: 0644]
Source/WebCore/platform/graphics/android/TiledPage.cpp
Source/WebCore/platform/graphics/android/TiledPage.h
Source/WebCore/platform/graphics/android/TiledTexture.cpp
Source/WebCore/platform/graphics/android/TiledTexture.h
Source/WebCore/platform/graphics/android/TilesManager.cpp
Source/WebCore/platform/graphics/android/TilesManager.h
Source/WebCore/platform/graphics/android/TreeManager.cpp [new file with mode: 0644]
Source/WebCore/platform/graphics/android/TreeManager.h [moved from Source/WebCore/platform/graphics/android/UpdateManager.h with 51% similarity]
Source/WebCore/platform/graphics/android/UpdateManager.cpp [deleted file]
Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp
Source/WebCore/platform/graphics/android/VideoLayerAndroid.h
Source/WebCore/tests/Android.mk [new file with mode: 0644]
Source/WebCore/tests/TreeManager_test.cpp [new file with mode: 0644]

index a516f48..6542931 100644 (file)
@@ -680,7 +680,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \
        platform/graphics/android/TiledPage.cpp \
        platform/graphics/android/TiledTexture.cpp \
        platform/graphics/android/TransferQueue.cpp \
-       platform/graphics/android/UpdateManager.cpp \
+       platform/graphics/android/TreeManager.cpp \
        platform/graphics/android/VerticalTextMap.cpp \
        platform/graphics/android/VideoLayerAndroid.cpp \
        platform/graphics/android/VideoLayerManager.cpp \
index 0e6f64f..8358b2a 100644 (file)
@@ -66,8 +66,7 @@ using namespace android;
 
 BaseLayerAndroid::BaseLayerAndroid()
 #if USE(ACCELERATED_COMPOSITING)
-    : m_glWebViewState(0)
-    , m_color(Color::white)
+    : m_color(Color::white)
     , m_scrollState(NotScrolling)
 #endif
 {
@@ -123,8 +122,8 @@ void BaseLayerAndroid::prefetchBasePicture(SkRect& viewport, float currentScale,
         / TilesManager::instance()->tileWidth();
     float invTileHeight = (prefetchScale)
         / TilesManager::instance()->tileHeight();
-    bool goingDown = m_glWebViewState->goingDown();
-    bool goingLeft = m_glWebViewState->goingLeft();
+    bool goingDown = m_state->goingDown();
+    bool goingLeft = m_state->goingLeft();
 
 
     XLOG("fetch rect %f %f %f %f, scale %f",
@@ -150,21 +149,82 @@ void BaseLayerAndroid::prefetchBasePicture(SkRect& viewport, float currentScale,
     prefetchTiledPage->prepare(goingDown, goingLeft, bounds,
                                TiledPage::ExpandedBounds);
     prefetchTiledPage->swapBuffersIfReady(bounds,
-                                          prefetchScale,
-                                          TiledPage::SwapWhateverIsReady);
+                                          prefetchScale);
     if (draw)
-        prefetchTiledPage->draw(PREFETCH_OPACITY, bounds);
+        prefetchTiledPage->prepareForDrawGL(PREFETCH_OPACITY, bounds);
 }
 
-bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale,
-                                           double currentTime, bool* buffersSwappedPtr)
+bool BaseLayerAndroid::isReady()
 {
-    ZoomManager* zoomManager = m_glWebViewState->zoomManager();
+    ZoomManager* zoomManager = m_state->zoomManager();
+    if (ZoomManager::kNoScaleRequest != zoomManager->scaleRequestState()) {
+        XLOG("base layer not ready, still zooming");
+        return false; // still zooming
+    }
+
+    if (!m_state->frontPage()->isReady(m_state->preZoomBounds())) {
+        XLOG("base layer not ready, front page not done painting");
+        return false;
+    }
+
+    LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(getChild(0));
+    if (compositedRoot) {
+        XLOG("base layer is ready, how about children?");
+        return compositedRoot->isReady();
+    }
+
+    return true;
+}
+
+void BaseLayerAndroid::swapTiles()
+{
+    if (countChildren())
+        getChild(0)->swapTiles(); // TODO: move to parent impl
+
+    m_state->frontPage()->swapBuffersIfReady(m_state->preZoomBounds(),
+                                             m_state->zoomManager()->currentScale());
+
+    m_state->backPage()->swapBuffersIfReady(m_state->preZoomBounds(),
+                                            m_state->zoomManager()->currentScale());
+}
+
+void BaseLayerAndroid::setIsDrawing(bool isDrawing)
+{
+    if (countChildren())
+        getChild(0)->setIsDrawing(isDrawing); // TODO: move to parent impl
+}
+
+void BaseLayerAndroid::setIsPainting(Layer* drawingTree)
+{
+    XLOG("BLA %p painting, dirty %d", this, isDirty());
+    if (drawingTree)
+        drawingTree = drawingTree->getChild(0);
+
+    if (countChildren())
+        getChild(0)->setIsPainting(drawingTree); // TODO: move to parent impl
+
+    m_state->invalRegion(m_dirtyRegion);
+    m_dirtyRegion.setEmpty();
+}
+
+void BaseLayerAndroid::mergeInvalsInto(Layer* replacementTree)
+{
+    XLOG("merging invals (empty=%d) from BLA %p to %p", m_dirtyRegion.isEmpty(), this, replacementTree);
+    if (countChildren() && replacementTree->countChildren())
+        getChild(0)->mergeInvalsInto(replacementTree->getChild(0));
 
-    bool goingDown = m_glWebViewState->goingDown();
-    bool goingLeft = m_glWebViewState->goingLeft();
+    replacementTree->markAsDirty(m_dirtyRegion);
+}
+
+bool BaseLayerAndroid::prepareBasePictureInGL(SkRect& viewport, float scale,
+                                              double currentTime)
+{
+    ZoomManager* zoomManager = m_state->zoomManager();
+
+    bool goingDown = m_state->goingDown();
+    bool goingLeft = m_state->goingLeft();
 
-    const SkIRect& viewportTileBounds = m_glWebViewState->viewportTileBounds();
+    const SkIRect& viewportTileBounds = m_state->viewportTileBounds();
     XLOG("drawBasePicture, TX: %d, TY: %d scale %.2f", viewportTileBounds.fLeft,
             viewportTileBounds.fTop, scale);
 
@@ -172,15 +232,14 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale,
     bool prepareNextTiledPage = zoomManager->needPrepareNextTiledPage();
 
     // Display the current page
-    TiledPage* tiledPage = m_glWebViewState->frontPage();
-    TiledPage* nextTiledPage = m_glWebViewState->backPage();
+    TiledPage* tiledPage = m_state->frontPage();
+    TiledPage* nextTiledPage = m_state->backPage();
     tiledPage->setScale(zoomManager->currentScale());
 
     // Let's prepare the page if needed so that it will start painting
     if (prepareNextTiledPage) {
         nextTiledPage->setScale(scale);
-        m_glWebViewState->setFutureViewport(viewportTileBounds);
-        m_glWebViewState->lockBaseLayerUpdate();
+        m_state->setFutureViewport(viewportTileBounds);
 
         // ignore dirtiness return value since while zooming we repaint regardless
         nextTiledPage->updateTileDirtiness(viewportTileBounds);
@@ -194,8 +253,7 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale,
     // If we fired a request, let's check if it's ready to use
     if (zoomManager->didFireRequest()) {
         if (nextTiledPage->swapBuffersIfReady(viewportTileBounds,
-                                              zoomManager->futureScale(),
-                                              TiledPage::SwapWholePage))
+                                              zoomManager->futureScale()))
             zoomManager->setReceivedRequest(); // transition to received request state
     }
 
@@ -208,74 +266,31 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale,
         float nextTiledPageTransparency = 1;
         zoomManager->processTransition(currentTime, scale, &doZoomPageSwap,
                                        &nextTiledPageTransparency, &transparency);
-        nextTiledPage->draw(nextTiledPageTransparency, viewportTileBounds);
+        nextTiledPage->prepareForDrawGL(nextTiledPageTransparency, viewportTileBounds);
     }
 
-    const SkIRect& preZoomBounds = m_glWebViewState->preZoomBounds();
+    const SkIRect& preZoomBounds = m_state->preZoomBounds();
 
-    // update scrolling state machine by querying glwebviewstate - note that the
-    // NotScrolling state is only set below
-    if (m_glWebViewState->isScrolling())
-        m_scrollState = Scrolling;
-    else if (m_scrollState == Scrolling)
-        m_scrollState = ScrollingFinishPaint;
-
-    bool scrolling = m_scrollState != NotScrolling;
     bool zooming = ZoomManager::kNoScaleRequest != zoomManager->scaleRequestState();
 
-    // When we aren't zooming, we should TRY and swap tile buffers if they're
-    // ready. When scrolling, we swap whatever's ready. Otherwise, buffer until
-    // the entire page is ready and then swap.
-    bool tilesFinished = false;
-    if (!zooming) {
-        TiledPage::SwapMethod swapMethod;
-        if (scrolling)
-            swapMethod = TiledPage::SwapWhateverIsReady;
-        else
-            swapMethod = TiledPage::SwapWholePage;
-
-        tilesFinished = tiledPage->swapBuffersIfReady(preZoomBounds,
-                                                       zoomManager->currentScale(),
-                                                       swapMethod);
-
-        if (buffersSwappedPtr && tilesFinished)
-            *buffersSwappedPtr = true;
-        if (tilesFinished) {
-            if (m_scrollState == ScrollingFinishPaint) {
-                m_scrollState = NotScrolling;
-                scrolling = false;
-            }
-        }
-    }
-
     if (doZoomPageSwap) {
         zoomManager->setCurrentScale(scale);
-        m_glWebViewState->swapPages();
-        if (buffersSwappedPtr)
-            *buffersSwappedPtr = true;
+        m_state->swapPages();
     }
 
-
-    bool needsRedraw = scrolling || zooming || !tilesFinished;
-
-    // if we don't expect to redraw, unlock the invals
-    if (!needsRedraw)
-        m_glWebViewState->unlockBaseLayerUpdate();
+    bool needsRedraw = zooming;
 
     // if applied invals mark tiles dirty, need to redraw
     needsRedraw |= tiledPage->updateTileDirtiness(preZoomBounds);
 
-    if (needsRedraw) {
-        // lock and paint what's needed unless we're zooming, since the new
-        // tiles won't be relevant soon anyway
-        m_glWebViewState->lockBaseLayerUpdate();
-        if (!zooming)
-            tiledPage->prepare(goingDown, goingLeft, preZoomBounds,
-                               TiledPage::ExpandedBounds);
-    }
+    // paint what's needed unless we're zooming, since the new tiles won't
+    // be relevant soon anyway
+    if (!zooming)
+        tiledPage->prepare(goingDown, goingLeft, preZoomBounds,
+                           TiledPage::ExpandedBounds);
 
-    XLOG("scrolling %d, zooming %d, tilesFinished %d, needsRedraw %d",
-         scrolling, zooming, tilesFinished, needsRedraw);
+    XLOG("scrolling %d, zooming %d, needsRedraw %d",
+         scrolling, zooming, needsRedraw);
 
     // prefetch in the nextTiledPage if unused by zooming (even if not scrolling
     // since we want the tiles to be ready before they're needed)
@@ -288,39 +303,75 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale,
         prefetchBasePicture(viewport, scale, nextTiledPage, drawPrefetchPage);
     }
 
-    tiledPage->draw(transparency, preZoomBounds);
+    tiledPage->prepareForDrawGL(transparency, preZoomBounds);
 
     return needsRedraw;
 }
+
+void BaseLayerAndroid::drawBasePictureInGL()
+{
+    m_state->backPage()->drawGL();
+    m_state->frontPage()->drawGL();
+}
+
 #endif // USE(ACCELERATED_COMPOSITING)
 
-bool BaseLayerAndroid::drawGL(double currentTime, LayerAndroid* compositedRoot,
-                              IntRect& viewRect, SkRect& visibleRect, float scale,
-                              bool* buffersSwappedPtr)
+void BaseLayerAndroid::updateLayerPositions(SkRect& visibleRect)
 {
-    bool needsRedraw = false;
-#if USE(ACCELERATED_COMPOSITING)
+    LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(getChild(0));
+    TransformationMatrix ident;
+    compositedRoot->updateFixedLayersPositions(visibleRect);
+    FloatRect clip(0, 0, content()->width(), content()->height());
+    compositedRoot->updateGLPositionsAndScale(
+        ident, clip, 1, m_state->zoomManager()->layersScale());
+
+#ifdef DEBUG
+    compositedRoot->showLayer(0);
+    XLOG("We have %d layers, %d textured",
+         compositedRoot->nbLayers(),
+         compositedRoot->nbTexturedLayers());
+#endif
+}
 
-    needsRedraw = drawBasePictureInGL(visibleRect, scale, currentTime,
-                                      buffersSwappedPtr);
+bool BaseLayerAndroid::prepare(double currentTime, IntRect& viewRect,
+                               SkRect& visibleRect, float scale)
+{
+    XLOG("preparing BLA %p", this);
 
-    if (!needsRedraw)
-        m_glWebViewState->resetFrameworkInval();
+    // base layer is simply drawn in prepare, since there is always a base layer it doesn't matter
+    bool needsRedraw = prepareBasePictureInGL(visibleRect, scale, currentTime);
 
+    LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(getChild(0));
     if (compositedRoot) {
-        SkMatrix matrix;
-        matrix.setTranslate(viewRect.x(), viewRect.y());
+        updateLayerPositions(visibleRect);
 
-#ifdef DEBUG
-        compositedRoot->showLayer(0);
-        XLOG("We have %d layers, %d textured",
-              compositedRoot->nbLayers(),
-              compositedRoot->nbTexturedLayers());
-#endif
+        XLOG("preparing BLA %p, root %p", this, compositedRoot);
+        compositedRoot->prepare();
+    }
+
+    return needsRedraw;
+}
+
+bool BaseLayerAndroid::drawGL(IntRect& viewRect, SkRect& visibleRect,
+                              float scale)
+{
+    XLOG("drawing BLA %p", this);
+
+    // TODO: consider moving drawBackground outside of prepare (into tree manager)
+    m_state->drawBackground(m_color);
+    drawBasePictureInGL();
+
+    bool needsRedraw = false;
+
+#if USE(ACCELERATED_COMPOSITING)
+
+    LayerAndroid* compositedRoot = static_cast<LayerAndroid*>(getChild(0));
+    if (compositedRoot) {
+        updateLayerPositions(visibleRect);
         // For now, we render layers only if the rendering mode
         // is kAllTextures or kClippedTextures
-        if (m_glWebViewState->layersRenderingMode() < GLWebViewState::kScrollableAndFixedLayers
-            && compositedRoot->drawGL(m_glWebViewState, matrix)) {
+        if (m_state->layersRenderingMode() < GLWebViewState::kScrollableAndFixedLayers
+            && compositedRoot->drawGL()) {
             if (TilesManager::instance()->layerTexturesRemain()) {
                 // only try redrawing for layers if layer textures remain,
                 // otherwise we'll repaint without getting anything done
@@ -329,8 +380,6 @@ bool BaseLayerAndroid::drawGL(double currentTime, LayerAndroid* compositedRoot,
         }
     }
 
-    m_previousVisible = visibleRect;
-
 #endif // USE(ACCELERATED_COMPOSITING)
 #ifdef DEBUG
     ClassTracker::instance()->show();
index 20942ec..c5ce52f 100644 (file)
@@ -48,7 +48,6 @@ public:
     virtual ~BaseLayerAndroid();
 
 #if USE(ACCELERATED_COMPOSITING)
-    void setGLWebViewState(GLWebViewState* infos) { m_glWebViewState = infos; }
     void setBackgroundColor(Color& color) { m_color = color; }
     Color getBackgroundColor() { return m_color; }
 #endif
@@ -60,21 +59,29 @@ public:
     // we are running in different threads.
     virtual bool drawCanvas(SkCanvas* canvas);
 
-    bool drawGL(double currentTime, LayerAndroid* compositedRoot, IntRect& rect,
-                SkRect& viewport, float scale, bool* buffersSwappedPtr);
+    void updateLayerPositions(SkRect& visibleRect);
+    bool prepare(double currentTime, IntRect& viewRect,
+                 SkRect& visibleRect, float scale);
+    bool drawGL(IntRect& viewRect, SkRect& visibleRect, float scale);
+
+    // rendering asset management
+    void swapTiles();
+    void setIsDrawing(bool isDrawing);
+    void setIsPainting(Layer* drawingTree);
+    void mergeInvalsInto(Layer* replacementTree);
+    bool isReady();
+
 private:
 #if USE(ACCELERATED_COMPOSITING)
     void prefetchBasePicture(SkRect& viewport, float currentScale,
                              TiledPage* prefetchTiledPage, bool draw);
-    bool drawBasePictureInGL(SkRect& viewport, float scale, double currentTime,
-                             bool* buffersSwappedPtr);
+    bool prepareBasePictureInGL(SkRect& viewport, float scale, double currentTime);
+    void drawBasePictureInGL();
 
-    GLWebViewState* m_glWebViewState;
     android::Mutex m_drawLock;
     Color m_color;
 #endif
     android::PictureSet m_content;
-    SkRect m_previousVisible;
 
     ScrollState m_scrollState;
 };
index fa22593..f000532 100644 (file)
@@ -37,6 +37,7 @@
 #include "SkPath.h"
 #include "TilesManager.h"
 #include "TilesTracker.h"
+#include "TreeManager.h"
 #include <wtf/CurrentTime.h>
 
 #include <pthread.h>
@@ -74,15 +75,10 @@ using namespace android;
 
 GLWebViewState::GLWebViewState()
     : m_zoomManager(this)
-    , m_paintingBaseLayer(0)
-    , m_currentBaseLayer(0)
-    , m_currentBaseLayerRoot(0)
     , m_currentPictureCounter(0)
     , m_usePageA(true)
     , m_frameworkInval(0, 0, 0, 0)
     , m_frameworkLayersInval(0, 0, 0, 0)
-    , m_baseLayerUpdate(true)
-    , m_backgroundColor(SK_ColorWHITE)
     , m_isScrolling(false)
     , m_goingDown(true)
     , m_goingLeft(false)
@@ -111,10 +107,6 @@ GLWebViewState::GLWebViewState()
 
 GLWebViewState::~GLWebViewState()
 {
-    // Unref the existing tree/PaintedSurfaces
-    if (m_currentBaseLayerRoot)
-        TilesManager::instance()->swapLayersTextures(m_currentBaseLayerRoot, 0);
-
     // Take care of the transfer queue such that Tex Gen thread will not stuck
     TilesManager::instance()->unregisterGLWebViewState(this);
 
@@ -126,12 +118,6 @@ GLWebViewState::~GLWebViewState()
     // will remove any pending operations, and wait if one is underway).
     delete m_tiledPageA;
     delete m_tiledPageB;
-    SkSafeUnref(m_paintingBaseLayer);
-    SkSafeUnref(m_currentBaseLayer);
-    SkSafeUnref(m_currentBaseLayerRoot);
-    m_paintingBaseLayer = 0;
-    m_currentBaseLayer = 0;
-    m_currentBaseLayerRoot = 0;
 #ifdef DEBUG_COUNT
     ClassTracker::instance()->decrement("GLWebViewState");
 #endif
@@ -141,49 +127,19 @@ GLWebViewState::~GLWebViewState()
 void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval,
                                   bool showVisualIndicator, bool isPictureAfterFirstLayout)
 {
-    android::Mutex::Autolock lock(m_baseLayerLock);
     if (!layer || isPictureAfterFirstLayout) {
+        // TODO: move this into TreeManager
         m_tiledPageA->discardTextures();
         m_tiledPageB->discardTextures();
     }
-    if (isPictureAfterFirstLayout) {
-        m_baseLayerUpdate = true;
-        m_invalidateRegion.setEmpty();
-    }
-
-    SkSafeRef(layer);
-    SkSafeUnref(m_currentBaseLayer);
-    m_currentBaseLayer = layer;
-
-    // copy content from old composited root to new
-    LayerAndroid* oldRoot = m_currentBaseLayerRoot;
     if (layer) {
-        layer->setGLWebViewState(this);
-        m_currentBaseLayerRoot = static_cast<LayerAndroid*>(layer->getChild(0));
-        SkSafeRef(m_currentBaseLayerRoot);
-    } else {
-        m_currentBaseLayerRoot = 0;
-    }
-    if (oldRoot != m_currentBaseLayerRoot)
-        TilesManager::instance()->swapLayersTextures(oldRoot, m_currentBaseLayerRoot);
-    SkSafeUnref(oldRoot);
-
-    // We only update the base layer if we are not currently
-    // waiting for a tiledPage to be painted
-    if (m_baseLayerUpdate) {
-        SkSafeRef(layer);
-        SkSafeUnref(m_paintingBaseLayer);
-        m_paintingBaseLayer = layer;
+        XLOG("new base layer %p, (inval region empty %d) with child %p", layer, inval.isEmpty(), layer->getChild(0));
+        layer->setState(this);
+        layer->markAsDirty(inval); // TODO: set in webview.cpp
     }
+    m_treeManager.updateWithTree(layer, isPictureAfterFirstLayout);
     m_glExtras.setDrawExtra(0);
 
-    // TODO: do the union of both layers tree to compute
-    // the minimum inval instead of doing a fullInval()
-    if (m_layersRenderingMode == kSingleSurfaceRendering)
-        fullInval();
-    else
-        invalRegion(inval);
-
 #ifdef MEASURES_PERF
     if (m_measurePerfs && !showVisualIndicator)
         dumpMeasures();
@@ -203,6 +159,12 @@ void GLWebViewState::scrolledLayer(ScrollableLayerAndroid*)
 
 void GLWebViewState::invalRegion(const SkRegion& region)
 {
+    if (m_layersRenderingMode == kSingleSurfaceRendering) {
+        // TODO: do the union of both layers tree to compute
+        //the minimum inval instead of doing a fullInval()
+        fullInval();
+        return;
+    }
     SkRegion::Iterator iterator(region);
     while (!iterator.done()) {
         SkIRect r = iterator.rect();
@@ -212,59 +174,27 @@ void GLWebViewState::invalRegion(const SkRegion& region)
     }
 }
 
-void GLWebViewState::unlockBaseLayerUpdate() {
-    if (m_baseLayerUpdate)
-        return;
-
-    m_baseLayerUpdate = true;
-    android::Mutex::Autolock lock(m_baseLayerLock);
-    SkSafeRef(m_currentBaseLayer);
-    SkSafeUnref(m_paintingBaseLayer);
-    m_paintingBaseLayer = m_currentBaseLayer;
-
-    invalRegion(m_invalidateRegion);
-    m_invalidateRegion.setEmpty();
-}
-
 void GLWebViewState::inval(const IntRect& rect)
 {
-    if (m_baseLayerUpdate) {
-        // base layer isn't locked, so go ahead and issue the inval to both tiled pages
-        m_currentPictureCounter++;
-        if (!rect.isEmpty()) {
-            // 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.width(), m_frameworkInval.height(),
-                 rect.x(), rect.y(), rect.width(), rect.height());
-        }
-    } else {
-        // base layer is locked, so defer invalidation until unlockBaseLayerUpdate()
-        m_invalidateRegion.op(rect.x(), rect.y(), rect.maxX(), rect.maxY(), SkRegion::kUnion_Op);
+    m_currentPictureCounter++;
+    if (!rect.isEmpty()) {
+        // 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.width(), m_frameworkInval.height(),
+             rect.x(), rect.y(), rect.width(), rect.height());
     }
     TilesManager::instance()->getProfiler()->nextInval(rect, zoomManager()->currentScale());
 }
 
 unsigned int GLWebViewState::paintBaseLayerContent(SkCanvas* canvas)
 {
-    m_baseLayerLock.lock();
-    BaseLayerAndroid* base = m_paintingBaseLayer;
-    SkSafeRef(base);
-    m_baseLayerLock.unlock();
-    if (base) {
-        base->drawCanvas(canvas);
-        if (m_layersRenderingMode == kSingleSurfaceRendering) {
-            LayerAndroid* rootLayer = static_cast<LayerAndroid*>(base->getChild(0));
-            if (rootLayer)
-                rootLayer->drawCanvas(canvas);
-        }
-    }
-    SkSafeUnref(base);
+    m_treeManager.drawCanvas(canvas, m_layersRenderingMode == kSingleSurfaceRendering);
     return m_currentPictureCounter;
 }
 
@@ -296,11 +226,11 @@ void GLWebViewState::swapPages()
 
 int GLWebViewState::baseContentWidth()
 {
-    return m_paintingBaseLayer ? m_paintingBaseLayer->content()->width() : 0;
+    return m_treeManager.baseContentWidth();
 }
 int GLWebViewState::baseContentHeight()
 {
-    return m_paintingBaseLayer ? m_paintingBaseLayer->content()->height() : 0;
+    return m_treeManager.baseContentHeight();
 }
 
 void GLWebViewState::setViewport(SkRect& viewport, float scale)
@@ -381,27 +311,29 @@ void GLWebViewState::resetLayersDirtyArea()
     m_frameworkLayersInval.setHeight(0);
 }
 
-double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect,
-                                  IntRect& webViewRect, int titleBarHeight,
-                                  IntRect& screenClip, float scale)
+void GLWebViewState::drawBackground(Color& backgroundColor)
 {
-    int left = viewRect.x();
-    int top = viewRect.y();
-    int width = viewRect.width();
-    int height = viewRect.height();
-
     if (TilesManager::instance()->invertedScreen()) {
-        float color = 1.0 - ((((float) m_backgroundColor.red() / 255.0) +
-                      ((float) m_backgroundColor.green() / 255.0) +
-                      ((float) m_backgroundColor.blue() / 255.0)) / 3.0);
+        float color = 1.0 - ((((float) backgroundColor.red() / 255.0) +
+                      ((float) backgroundColor.green() / 255.0) +
+                      ((float) backgroundColor.blue() / 255.0)) / 3.0);
         glClearColor(color, color, color, 1);
     } else {
-        glClearColor((float)m_backgroundColor.red() / 255.0,
-                     (float)m_backgroundColor.green() / 255.0,
-                     (float)m_backgroundColor.blue() / 255.0, 1);
+        glClearColor((float)backgroundColor.red() / 255.0,
+                     (float)backgroundColor.green() / 255.0,
+                     (float)backgroundColor.blue() / 255.0, 1);
     }
     glClear(GL_COLOR_BUFFER_BIT);
+}
 
+double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect,
+                                    IntRect& webViewRect, int titleBarHeight,
+                                    IntRect& screenClip, float scale)
+{
+    int left = viewRect.x();
+    int top = viewRect.y();
+    int width = viewRect.width();
+    int height = viewRect.height();
     glViewport(left, top, width, height);
 
     ShaderProgram* shader = TilesManager::instance()->shader();
@@ -503,13 +435,6 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
     TilesManager::instance()->getTilesTracker()->clear();
 #endif
 
-    m_baseLayerLock.lock();
-    BaseLayerAndroid* baseLayer = m_paintingBaseLayer;
-    SkSafeRef(baseLayer);
-    m_baseLayerLock.unlock();
-    if (!baseLayer)
-         return false;
-
     float viewWidth = (viewport.fRight - viewport.fLeft) * TILE_PREFETCH_RATIO;
     float viewHeight = (viewport.fBottom - viewport.fTop) * TILE_PREFETCH_RATIO;
     bool useMinimalMemory = TilesManager::instance()->useMinimalMemory();
@@ -524,17 +449,8 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
 
     resetLayersDirtyArea();
 
-    LayerAndroid* compositedRoot = m_currentBaseLayerRoot;
-    LayerAndroid* paintingBaseLayerRoot = 0;
-    if (baseLayer && baseLayer->countChildren() >= 1)
-        paintingBaseLayerRoot = static_cast<LayerAndroid*>(baseLayer->getChild(0));
-
     // when adding or removing layers, use the the paintingBaseLayer's tree so
     // that content that moves to the base layer from a layer is synchronized
-    bool paintingHasLayers = (paintingBaseLayerRoot == 0);
-    bool currentHasLayers = (m_currentBaseLayerRoot == 0);
-    if (paintingHasLayers != currentHasLayers)
-        compositedRoot = paintingBaseLayerRoot;
 
     if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING)
         XLOGC("WARNING, scale seems corrupted before update: %e", scale);
@@ -555,45 +471,19 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
     // gather the textures we can use
     TilesManager::instance()->gatherLayerTextures();
 
-    // set up zoom manager, shaders, etc.
-    m_backgroundColor = baseLayer->getBackgroundColor();
     double currentTime = setupDrawing(rect, viewport, webViewRect, titleBarHeight, clip, scale);
 
-    if (compositedRoot)
-        compositedRoot->setState(this);
 
-    bool animsRunning = false;
     TexturesResult nbTexturesNeeded;
-    if (compositedRoot) {
-        TransformationMatrix ident;
-        animsRunning = compositedRoot->evaluateAnimations();
-        bool hasFixedElements = compositedRoot->updateFixedLayersPositions(viewport);
-        if (m_layersRenderingMode == kSingleSurfaceRendering) {
-            // If we are in single surface rendering, we may have to fully
-            // invalidate if we have fixed elements or if we have CSS
-            // animations.
-            // TODO: compute the minimum invals
-            if (animsRunning || hasFixedElements)
-                fullInval();
-        }
-
-        // TODO: get the base document area for the original clip
-        FloatRect clip(0, 0, 1E6, 1E6);
-        compositedRoot->updateGLPositionsAndScale(ident, clip, 1, zoomManager()->layersScale());
-        compositedRoot->prepare(this);
-
-        ret |= animsRunning;
+    bool fastSwap = isScrolling() || m_layersRenderingMode == kSingleSurfaceRendering;
+    ret |= m_treeManager.drawGL(currentTime, rect, viewport,
+                                scale, fastSwap,
+                                buffersSwappedPtr, &nbTexturesNeeded);
+    if (!ret)
+        resetFrameworkInval();
 
-        compositedRoot->computeTexturesAmount(&nbTexturesNeeded);
-    }
     ret |= setLayersRenderingMode(nbTexturesNeeded);
 
-    // Clean up GL textures for video layer.
-    TilesManager::instance()->videoLayerManager()->deleteUnusedTextures();
-
-    ret |= baseLayer->drawGL(currentTime, compositedRoot, rect,
-                                 viewport, scale, buffersSwappedPtr);
-
     FloatRect extrasclip(0, 0, rect.width(), rect.height());
     TilesManager::instance()->shader()->clip(extrasclip);
 
@@ -601,6 +491,8 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
 
     glBindBuffer(GL_ARRAY_BUFFER, 0);
 
+    // Clean up GL textures for video layer.
+    TilesManager::instance()->videoLayerManager()->deleteUnusedTextures();
     ret |= TilesManager::instance()->invertedScreenSwitch();
 
     if (ret) {
@@ -656,7 +548,6 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
     }
 #endif
 
-    SkSafeUnref(baseLayer);
 #ifdef DEBUG
     TilesManager::instance()->getTilesTracker()->showTrackTextures();
     ImagesManager::instance()->showImages();
index a1adaf1..5aa030b 100644 (file)
@@ -36,6 +36,7 @@
 #include "SkRect.h"
 #include "SkRegion.h"
 #include "TiledPage.h"
+#include "TreeManager.h"
 #include "ZoomManager.h"
 #include <utils/threads.h>
 
@@ -200,15 +201,13 @@ public:
 
     unsigned int currentPictureCounter() const { return m_currentPictureCounter; }
 
-    void lockBaseLayerUpdate() { m_baseLayerUpdate = false; }
-    void unlockBaseLayerUpdate();
-
     void setIsScrolling(bool isScrolling) { m_isScrolling = isScrolling; }
     bool isScrolling() { return m_isScrolling; }
 
-    double setupDrawing(IntRect& rect, SkRect& viewport, IntRect& webViewRect,
-                int titleBarHeight, IntRect& screenClip,
-                float scale);
+    void drawBackground(Color& backgroundColor);
+    double setupDrawing(IntRect& viewRect, SkRect& visibleRect,
+                        IntRect& webViewRect, int titleBarHeight,
+                        IntRect& screenClip, float scale);
 
     bool setLayersRenderingMode(TexturesResult&);
     void fullInval();
@@ -249,20 +248,17 @@ public:
     LayersRenderingMode layersRenderingMode() { return m_layersRenderingMode; }
     void scrolledLayer(ScrollableLayerAndroid*);
 
-private:
-    void inval(const IntRect& rect); // caller must hold m_baseLayerLock
     void invalRegion(const SkRegion& region);
 
+private:
+    void inval(const IntRect& rect);
+
     ZoomManager m_zoomManager;
     android::Mutex m_tiledPageLock;
     SkRect m_viewport;
     SkIRect m_viewportTileBounds;
     SkIRect m_futureViewportTileBounds;
     SkIRect m_preZoomBounds;
-    android::Mutex m_baseLayerLock;
-    BaseLayerAndroid* m_paintingBaseLayer;
-    BaseLayerAndroid* m_currentBaseLayer;
-    LayerAndroid* m_currentBaseLayerRoot;
 
     unsigned int m_currentPictureCounter;
     bool m_usePageA;
@@ -272,11 +268,6 @@ private:
     IntRect m_frameworkInval;
     IntRect m_frameworkLayersInval;
 
-    bool m_baseLayerUpdate;
-    SkRegion m_invalidateRegion;
-
-    Color m_backgroundColor;
-
 #ifdef MEASURES_PERF
     unsigned int m_totalTimeCounter;
     int m_timeCounter;
@@ -295,6 +286,7 @@ private:
     float m_scale;
 
     LayersRenderingMode m_layersRenderingMode;
+    TreeManager m_treeManager;
 };
 
 } // namespace WebCore
index 7f35f06..cea79c3 100644 (file)
@@ -26,7 +26,6 @@
 #ifndef ImageTexture_h
 #define ImageTexture_h
 
-#include "ClassTracker.h"
 #include "GLUtils.h"
 #include "SkBitmap.h"
 #include "SkBitmapRef.h"
index f650c52..9280461 100644 (file)
@@ -23,6 +23,7 @@ Layer::Layer() {
     m_shouldInheritFromRootTransform = false;
 
     m_hasOverflowChildren = false;
+    m_state = 0;
 
 #ifdef DEBUG_TRACK_NEW_DELETE
     gLayerAllocCount += 1;
@@ -42,6 +43,7 @@ Layer::Layer(const Layer& src) : INHERITED() {
     m_shouldInheritFromRootTransform = src.m_shouldInheritFromRootTransform;
 
     m_hasOverflowChildren = src.m_hasOverflowChildren;
+    m_state = 0;
 
 #ifdef DEBUG_TRACK_NEW_DELETE
     gLayerAllocCount += 1;
@@ -225,3 +227,10 @@ bool Layer::isAncestor(const Layer* possibleAncestor) const {
     }
     return false;
 }
+
+void Layer::setState(WebCore::GLWebViewState* state) {
+    m_state = state;
+    int count = countChildren();
+    for (int i = 0; i < count; i++)
+        m_children[i]->setState(state);
+}
index 89e101c..5200a3d 100644 (file)
 #ifndef Layer_DEFINED
 #define Layer_DEFINED
 
+#include "TestExport.h"
 #include "SkRefCnt.h"
 #include "SkTDArray.h"
 #include "SkColor.h"
 #include "SkMatrix.h"
 #include "SkPoint.h"
 #include "SkRect.h"
+#include "SkRegion.h"
 #include "SkSize.h"
 
+namespace WebCore {
+class IntRect;
+class GLWebViewState;
+};
+
 class SkCanvas;
 
-class Layer : public SkRefCnt {
+class TEST_EXPORT Layer : public SkRefCnt {
 
 public:
     Layer();
@@ -56,7 +63,42 @@ public:
     void setMatrix(const SkMatrix& matrix) { m_matrix = matrix; }
     void setChildrenMatrix(const SkMatrix& matrix) { m_childrenMatrix = matrix; }
 
-    // children
+// rendering asset management
+
+    // tell rendering assets to update their tile content with most recent painted data
+    virtual void swapTiles() {}
+
+    // tell rendering assets to use this layer tree for drawing
+    virtual void setIsDrawing(bool isDrawing) {}
+
+    // take rendering assets from drawing tree, or create if they don't exist
+    virtual void setIsPainting(Layer* drawingTree) {}
+
+    // if a similar layer exists in the replacement tree, add invals to it
+    virtual void mergeInvalsInto(Layer* replacementTree) {}
+
+    void markAsDirty(const SkRegion& invalRegion) {
+        m_dirtyRegion.op(invalRegion, SkRegion::kUnion_Op);
+    }
+
+    bool isDirty() {
+        return !m_dirtyRegion.isEmpty();
+    }
+
+// drawing
+
+    virtual bool isReady() { return false; }
+
+    // TODO: clean out several of these, leave them in GLWebViewState
+
+    virtual bool prepare(double currentTime, WebCore::IntRect& viewRect,
+                         SkRect& visibleRect, float scale) { return 0; }
+    virtual bool drawGL(WebCore::IntRect& viewRect,
+                        SkRect& visibleRect, float scale) { return 0; }
+    WebCore::GLWebViewState* state() { return m_state; }
+    void setState(WebCore::GLWebViewState* state);
+
+// children
 
     /** Return the number of layers in our child list.
      */
@@ -153,6 +195,11 @@ protected:
 
     SkTDArray<Layer*> m_children;
 
+    // invalidation region
+    SkRegion m_dirtyRegion;
+
+    WebCore::GLWebViewState* m_state;
+
     typedef SkRefCnt INHERITED;
 };
 
index 12a11bf..b86be99 100644 (file)
@@ -152,18 +152,15 @@ LayerAndroid::LayerAndroid(RenderLayer* owner) : Layer(),
     m_imageRef(0),
     m_imageTexture(0),
     m_pictureUsed(0),
-    m_requestSent(false),
     m_scale(1),
     m_lastComputeTextureSize(0),
     m_owningLayer(owner),
     m_type(LayerAndroid::WebCoreLayer),
-    m_state(0),
     m_hasText(true)
 {
     m_backgroundColor = 0;
 
     m_preserves3D = false;
-    m_dirty = false;
     m_iframeOffset.set(0,0);
     m_dirtyRegion.setEmpty();
 #ifdef DEBUG_COUNT
@@ -178,10 +175,8 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer),
     m_uniqueId(layer.m_uniqueId),
     m_texture(0),
     m_imageTexture(0),
-    m_requestSent(false),
     m_owningLayer(layer.m_owningLayer),
     m_type(LayerAndroid::UILayer),
-    m_state(0),
     m_hasText(true)
 {
     m_isFixed = layer.m_isFixed;
@@ -211,7 +206,6 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer),
     m_anchorPointZ = layer.m_anchorPointZ;
     m_drawTransform = layer.m_drawTransform;
     m_childrenTransform = layer.m_childrenTransform;
-    m_dirty = layer.m_dirty;
     m_pictureUsed = layer.m_pictureUsed;
     m_dirtyRegion = layer.m_dirtyRegion;
     m_scale = layer.m_scale;
@@ -256,20 +250,17 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : Layer(),
     m_isFixed(false),
     m_isIframe(false),
     m_recordingPicture(picture),
-    m_uniqueId(-1),
+    m_uniqueId(++gUniqueId),
     m_texture(0),
     m_imageRef(0),
     m_imageTexture(0),
-    m_requestSent(false),
     m_scale(1),
     m_lastComputeTextureSize(0),
     m_owningLayer(0),
     m_type(LayerAndroid::NavCacheLayer),
-    m_state(0),
     m_hasText(true)
 {
     m_backgroundColor = 0;
-    m_dirty = false;
     SkSafeRef(m_recordingPicture);
     m_iframeOffset.set(0,0);
     m_dirtyRegion.setEmpty();
@@ -335,7 +326,7 @@ bool LayerAndroid::evaluateAnimations(double time)
     return hasRunningAnimations || m_hasRunningAnimations;
 }
 
-void LayerAndroid::addDirtyArea(GLWebViewState* glWebViewState)
+void LayerAndroid::addDirtyArea()
 {
     IntSize layerSize(getSize().width(), getSize().height());
 
@@ -345,7 +336,7 @@ void LayerAndroid::addDirtyArea(GLWebViewState* glWebViewState)
 
     area.intersect(clip);
     IntRect dirtyArea(area.x(), area.y(), area.width(), area.height());
-    glWebViewState->addDirtyArea(dirtyArea);
+    m_state->addDirtyArea(dirtyArea);
 }
 
 void LayerAndroid::addAnimation(PassRefPtr<AndroidAnimation> prpAnim)
@@ -820,6 +811,9 @@ int LayerAndroid::nbTexturedLayers()
 
 void LayerAndroid::computeTexturesAmount(TexturesResult* result)
 {
+    if (!result)
+        return;
+
     int count = this->countChildren();
     for (int i = 0; i < count; i++)
         this->getChild(i)->computeTexturesAmount(result);
@@ -864,33 +858,63 @@ void LayerAndroid::showLayer(int indent)
         this->getChild(i)->showLayer(indent + 1);
 }
 
-// We go through our tree, and if we have layer in the new
-// tree that is similar, we transfer our texture to it.
-// Otherwise, we remove ourselves from the texture so
-// that TilesManager::swapLayersTextures() have a chance
-// at deallocating the textures (PaintedSurfaces)
-void LayerAndroid::assignTextureTo(LayerAndroid* newTree)
+void LayerAndroid::swapTiles()
 {
     int count = this->countChildren();
     for (int i = 0; i < count; i++)
-        this->getChild(i)->assignTextureTo(newTree);
+        this->getChild(i)->swapTiles();
 
-    if (newTree) {
-        LayerAndroid* newLayer = newTree->findById(uniqueId());
-        if (newLayer == this)
-            return;
-        if (newLayer && m_texture) {
-            m_texture->replaceLayer(newLayer);
-            newLayer->m_texture = m_texture;
-            m_texture = 0;
-        }
-        if (!newLayer && m_texture) {
-            m_texture->removeLayer(this);
-            m_texture = 0;
-        }
+    if (m_texture)
+        m_texture->swapTiles();
+}
+
+void LayerAndroid::setIsDrawing(bool isDrawing)
+{
+    int count = this->countChildren();
+    for (int i = 0; i < count; i++)
+        this->getChild(i)->setIsDrawing(isDrawing);
+
+    if (m_texture) {
+        m_texture->setDrawingLayer(isDrawing ? this : 0);
+        m_texture->clearPaintingLayer();
     }
 }
 
+void LayerAndroid::setIsPainting(Layer* drawingTree)
+{
+    XLOG("setting layer %p as painting, needs texture %d, drawing tree %p",
+         this, needsTexture(), drawingTree);
+    int count = this->countChildren();
+    for (int i = 0; i < count; i++)
+        this->getChild(i)->setIsPainting(drawingTree);
+
+    obtainTextureForPainting(static_cast<LayerAndroid*>(drawingTree));
+}
+
+void LayerAndroid::mergeInvalsInto(Layer* replacementTree)
+{
+    int count = this->countChildren();
+    for (int i = 0; i < count; i++)
+        this->getChild(i)->mergeInvalsInto(replacementTree);
+
+    LayerAndroid* replacementLayer = static_cast<LayerAndroid*>(replacementTree)->findById(uniqueId());
+    if (replacementLayer)
+        replacementLayer->markAsDirty(m_dirtyRegion);
+}
+
+bool LayerAndroid::isReady()
+{
+    int count = countChildren();
+    for (int i = 0; i < count; i++)
+        if (!getChild(i)->isReady())
+            return false;
+
+    if (m_texture)
+        return m_texture->isReady();
+    // TODO: image, check if uploaded?
+    return true;
+}
+
 bool LayerAndroid::updateWithTree(LayerAndroid* newTree)
 {
 // Disable fast update for now
@@ -935,12 +959,8 @@ bool LayerAndroid::updateWithLayer(LayerAndroid* layer)
     return false;
 }
 
-void LayerAndroid::createTexture()
+void LayerAndroid::obtainTextureForPainting(LayerAndroid* drawingTree)
 {
-    int count = this->countChildren();
-    for (int i = 0; i < count; i++)
-        this->getChild(i)->createTexture();
-
     if (!needsTexture())
         return;
 
@@ -950,29 +970,34 @@ void LayerAndroid::createTexture()
             m_dirtyRegion.setEmpty();
         }
         if (m_texture) {
-            m_texture->removeLayer(this);
+            m_texture->setDrawingLayer(0);
+            m_texture->clearPaintingLayer();
             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 (!m_texture)
-            m_texture = new PaintedSurface(this);
+            m_texture = new PaintedSurface();
 
         // pass the invalidated regions to the PaintedSurface
-        m_texture->markAsDirty(m_dirtyRegion);
+        m_texture->setPaintingLayer(this, m_dirtyRegion);
         m_dirtyRegion.setEmpty();
     }
 }
 
+
 static inline bool compareLayerZ(const LayerAndroid* a, const LayerAndroid* b)
 {
     return a->zValue() > b->zValue();
 }
 
-void LayerAndroid::markAsDirty(const SkRegion& dirtyArea)
-{
-    m_dirtyRegion.op(dirtyArea, SkRegion::kUnion_Op);
-}
-
 // We call this in WebViewCore, when copying the tree of layers.
 // As we construct a new tree that will be passed on the UI,
 // we mark the webkit-side tree as having no more dirty region
@@ -986,18 +1011,9 @@ void LayerAndroid::clearDirtyRegion()
     m_dirtyRegion.setEmpty();
 }
 
-void LayerAndroid::setState(GLWebViewState* state)
-{
-    int count = this->countChildren();
-    for (int i = 0; i < count; i++)
-        this->getChild(i)->setState(state);
-
-    m_state = state;
-}
-
-void LayerAndroid::prepare(GLWebViewState* glWebViewState)
+void LayerAndroid::prepare()
 {
-    m_state = glWebViewState;
+    XLOG("LA %p preparing, m_texture %p", this, m_texture);
 
     int count = this->countChildren();
     if (count > 0) {
@@ -1010,11 +1026,11 @@ void LayerAndroid::prepare(GLWebViewState* glWebViewState)
 
         // iterate in reverse so top layers get textures first
         for (int i = count-1; i >= 0; i--)
-            sublayers[i]->prepare(glWebViewState);
+            sublayers[i]->prepare();
     }
 
     if (m_texture)
-        m_texture->prepare(glWebViewState);
+        m_texture->prepare(m_state);
 
     if (m_imageTexture)
         m_imageTexture->prepareGL();
@@ -1082,15 +1098,14 @@ bool LayerAndroid::drawCanvas(SkCanvas* canvas)
     // When the layer is dirty, the UI thread should be notified to redraw.
     askScreenUpdate |= drawChildrenCanvas(canvas);
     m_atomicSync.lock();
-    askScreenUpdate |= m_dirty;
     if (askScreenUpdate || m_hasRunningAnimations || m_drawTransform.hasPerspective())
-        addDirtyArea(m_state);
+        addDirtyArea();
 
     m_atomicSync.unlock();
     return askScreenUpdate;
 }
 
-bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
+bool LayerAndroid::drawGL()
 {
     FloatRect clippingRect = TilesManager::instance()->shader()->rectInScreenCoord(m_clippingRect);
     TilesManager::instance()->shader()->clip(clippingRect);
@@ -1106,11 +1121,10 @@ bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
         m_imageTexture->drawGL(this);
 
     // When the layer is dirty, the UI thread should be notified to redraw.
-    askScreenUpdate |= drawChildrenGL(glWebViewState, matrix);
+    askScreenUpdate |= drawChildrenGL();
     m_atomicSync.lock();
-    askScreenUpdate |= m_dirty;
     if (askScreenUpdate || m_hasRunningAnimations || m_drawTransform.hasPerspective())
-        addDirtyArea(glWebViewState);
+        addDirtyArea();
 
     m_atomicSync.unlock();
     return askScreenUpdate;
@@ -1136,7 +1150,7 @@ bool LayerAndroid::drawChildrenCanvas(SkCanvas* canvas)
     return askScreenUpdate;
 }
 
-bool LayerAndroid::drawChildrenGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
+bool LayerAndroid::drawChildrenGL()
 {
     bool askScreenUpdate = false;
     int count = this->countChildren();
@@ -1149,7 +1163,7 @@ bool LayerAndroid::drawChildrenGL(GLWebViewState* glWebViewState, SkMatrix& matr
         std::stable_sort(sublayers.begin(), sublayers.end(), compareLayerZ);
         for (int i = 0; i < count; i++) {
             LayerAndroid* layer = sublayers[i];
-            askScreenUpdate |= layer->drawGL(glWebViewState, matrix);
+            askScreenUpdate |= layer->drawGL();
         }
     }
 
index b536b22..ae9dc88 100644 (file)
 #include "SkColor.h"
 #include "SkRegion.h"
 #include "SkStream.h"
-#include "TextureOwner.h"
 #include "TransformationMatrix.h"
 
 #include <wtf/HashMap.h>
-#include <wtf/text/StringHash.h>
 
 #ifndef BZERO_DEFINED
 #define BZERO_DEFINED
@@ -94,6 +92,7 @@ namespace WebCore {
 
 class AndroidAnimation;
 class BaseTileTexture;
+class GLWebViewState;
 class LayerAndroidFindState;
 class RenderLayer;
 class TiledPage;
@@ -114,7 +113,7 @@ public:
     int full;
 };
 
-class LayerAndroid : public Layer {
+class TEST_EXPORT LayerAndroid : public Layer {
 public:
     enum LayerType { UndefinedLayer, WebCoreLayer, UILayer, NavCacheLayer };
 
@@ -124,7 +123,6 @@ public:
     virtual ~LayerAndroid();
 
     virtual TiledPage* page() { return 0; }
-    virtual GLWebViewState* state() { return m_state; }
 
     void setBackfaceVisibility(bool value) { m_backfaceVisibility = value; }
     void setTransform(const TransformationMatrix& matrix) { m_transform = matrix; }
@@ -146,22 +144,20 @@ public:
     // Debug helper methods
     int nbLayers();
     int nbTexturedLayers();
-    void showLayer(int indent);
+    void showLayer(int indent = 0);
 
     void computeTexturesAmount(TexturesResult*);
 
     float getScale() { return m_scale; }
 
-    void setState(GLWebViewState*);
-
     // draw layer and its children via Z, pre-order traversal
-    virtual bool drawGL(GLWebViewState*, SkMatrix&);
-    bool drawChildrenGL(GLWebViewState*, SkMatrix&);
+    virtual bool drawGL();
+    bool drawChildrenGL();
     virtual bool drawCanvas(SkCanvas*);
     bool drawChildrenCanvas(SkCanvas*);
 
     // prepare layer and its children via reverse-Z, post-order traversal
-    void prepare(GLWebViewState*);
+    void prepare();
 
     void updateGLPositionsAndScale(const TransformationMatrix& parentMatrix,
                                    const FloatRect& clip, float opacity, float scale);
@@ -219,7 +215,7 @@ public:
     bool evaluateAnimations();
     bool evaluateAnimations(double time);
     bool hasAnimations() const;
-    void addDirtyArea(GLWebViewState*);
+    void addDirtyArea();
 
     SkPicture* picture() const { return m_recordingPicture; }
 
@@ -276,9 +272,7 @@ public:
     void needsRepaint() { m_pictureUsed++; }
     unsigned int pictureUsed() { return m_pictureUsed; }
 
-    void markAsDirty(const SkRegion& dirtyArea);
     void clearDirtyRegion();
-    const SkRegion& dirtyRegion() { return m_dirtyRegion; }
 
     void contentDraw(SkCanvas*);
 
@@ -296,8 +290,7 @@ public:
     friend void android::cleanupImageRefs(LayerAndroid* layer);
 
     PaintedSurface* texture() { return m_texture; }
-    void assignTextureTo(LayerAndroid* newTree);
-    void createTexture();
+    void obtainTextureForPainting(LayerAndroid* drawingTree);
 
     // Update layers using another tree. Only works for basic properties
     // such as the position, the transform. Return true if anything more
@@ -312,6 +305,13 @@ public:
     bool hasText() { return m_hasText; }
     void checkTextPresence();
 
+// rendering asset management
+    void swapTiles();
+    void setIsDrawing(bool isDrawing);
+    void setIsPainting(Layer* drawingTree);
+    void mergeInvalsInto(Layer* replacementTree);
+    bool isReady();
+
 protected:
     virtual void onDraw(SkCanvas*, SkScalar opacity);
 
@@ -389,19 +389,11 @@ private:
     SkBitmapRef* m_imageRef;
     ImageTexture* m_imageTexture;
 
-    // used to signal that the tile is out-of-date and needs to be redrawn
-    bool m_dirty;
     unsigned int m_pictureUsed;
 
-    // dirty regions
-    SkRegion m_dirtyRegion;
-
     // used to signal the framework we need a repaint
     bool m_hasRunningAnimations;
 
-    // painting request sent
-    bool m_requestSent;
-
     float m_scale;
 
     // We try to not always compute the texture size, as this is quite heavy
@@ -416,7 +408,6 @@ private:
     RenderLayer* m_owningLayer;
 
     int m_type;
-    GLWebViewState* m_state;
 
     bool m_hasText;
 
index 0181892..12cfe38 100644 (file)
@@ -66,7 +66,7 @@ MediaLayer::~MediaLayer()
     m_mediaTexture->decStrong(this);
 }
 
-bool MediaLayer::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
+bool MediaLayer::drawGL()
 {
     FloatRect clippingRect = TilesManager::instance()->shader()->rectInScreenCoord(drawClip());
     TilesManager::instance()->shader()->clip(clippingRect);
@@ -93,7 +93,7 @@ bool MediaLayer::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
     // draw any content or video if present
     m_mediaTexture->draw(m, m_drawTransform, mediaBounds);
 
-    return drawChildrenGL(glWebViewState, matrix);
+    return drawChildrenGL();
 }
 
 ANativeWindow* MediaLayer::acquireNativeWindowForContent()
index ef84abf..b94ec53 100644 (file)
@@ -36,7 +36,7 @@ public:
     MediaLayer(const MediaLayer& layer);
     virtual ~MediaLayer();
 
-    virtual bool drawGL(GLWebViewState*, SkMatrix&);
+    virtual bool drawGL();
     virtual void paintBitmapGL() const { };
     virtual bool needsTexture() { return false; }
 
index d9a729a..5d06ea3 100644 (file)
@@ -34,14 +34,10 @@ PaintTileOperation::PaintTileOperation(BaseTile* tile, PaintedSurface* surface)
     : QueuedOperation(QueuedOperation::PaintTile, tile->page())
     , m_tile(tile)
     , m_surface(surface)
-    , m_layer(0)
 {
     if (m_tile)
         m_tile->setRepaintPending(true);
-    if (m_surface)
-        m_layer = surface->layer();
     SkSafeRef(m_surface);
-    SkSafeRef(m_layer);
 }
 
 PaintTileOperation::~PaintTileOperation()
@@ -51,7 +47,6 @@ PaintTileOperation::~PaintTileOperation()
         m_tile = 0;
     }
     SkSafeUnref(m_surface);
-    SkSafeUnref(m_layer);
 }
 
 bool PaintTileOperation::operator==(const QueuedOperation* operation)
@@ -99,7 +94,6 @@ int PaintTileOperation::priority()
     // for base tiles, prioritize based on position
     if (!m_tile->isLayerTile()) {
         bool goingDown = m_tile->page()->scrollingDown();
-        SkIRect *rect = m_tile->page()->expandedTileBounds();
         priority += m_tile->x();
 
         if (goingDown)
index 65d20f2..fabc2f7 100644 (file)
@@ -26,6 +26,7 @@
 #ifndef PaintTileSetOperation_h
 #define PaintTileSetOperation_h
 
+#include "BaseTile.h"
 #include "QueuedOperation.h"
 
 namespace WebCore {
@@ -47,7 +48,6 @@ public:
 private:
     BaseTile* m_tile;
     PaintedSurface* m_surface;
-    LayerAndroid* m_layer;
 };
 
 class ScaleFilter : public OperationFilter {
index 939d106..d3c1e15 100644 (file)
@@ -28,6 +28,7 @@
 
 
 #include "LayerAndroid.h"
+#include "TiledTexture.h"
 #include "TilesManager.h"
 #include "SkCanvas.h"
 #include "SkPicture.h"
 
 namespace WebCore {
 
-PaintedSurface::PaintedSurface(LayerAndroid* layer)
-    : m_layer(layer)
+PaintedSurface::PaintedSurface()
+    : m_drawingLayer(0)
+    , m_paintingLayer(0)
     , m_tiledTexture(0)
     , m_scale(0)
     , m_pictureUsed(0)
 {
     TilesManager::instance()->addPaintedSurface(this);
-    SkSafeRef(m_layer);
 #ifdef DEBUG_COUNT
     ClassTracker::instance()->increment("PaintedSurface");
 #endif
     m_tiledTexture = new DualTiledTexture(this);
-    if (layer && layer->picture())
-        m_updateManager.updatePicture(layer->picture());
 }
 
 PaintedSurface::~PaintedSurface()
 {
-    XLOG("dtor of %x m_layer: %x", this, m_layer);
-    android::Mutex::Autolock lock(m_layerLock);
-    SkSafeUnref(m_layer);
 #ifdef DEBUG_COUNT
     ClassTracker::instance()->decrement("PaintedSurface");
 #endif
     delete m_tiledTexture;
 }
 
-void PaintedSurface::removeLayer()
-{
-    android::Mutex::Autolock lock(m_layerLock);
-    if (m_layer)
-        m_layer->removeTexture(this);
-    SkSafeUnref(m_layer);
-    m_layer = 0;
-}
-
-void PaintedSurface::removeLayer(LayerAndroid* layer)
-{
-    android::Mutex::Autolock lock(m_layerLock);
-    if (m_layer != layer)
-        return;
-    SkSafeUnref(m_layer);
-    m_layer = 0;
-}
-
-void PaintedSurface::replaceLayer(LayerAndroid* layer)
-{
-    android::Mutex::Autolock lock(m_layerLock);
-    if (!layer)
-        return;
-
-    if (m_layer && layer->uniqueId() != m_layer->uniqueId())
-        return;
-
-    SkSafeRef(layer);
-    SkSafeUnref(m_layer);
-    m_layer = layer;
-    if (layer && layer->picture())
-        m_updateManager.updatePicture(layer->picture());
-}
-
 void PaintedSurface::prepare(GLWebViewState* state)
 {
-    if (!m_layer)
-        return;
+    XLOG("PS %p has PL %p, DL %p", this, m_paintingLayer, m_drawingLayer);
+    LayerAndroid* paintingLayer = m_paintingLayer;
+    if (!paintingLayer)
+        paintingLayer = m_drawingLayer;
 
-    if (!m_layer->needsTexture())
+    if (!paintingLayer)
         return;
 
     bool startFastSwap = false;
     if (state->isScrolling()) {
         // when scrolling, block updates and swap tiles as soon as they're ready
         startFastSwap = true;
-    } else {
-        // when not, push updates down to TiledTexture in every prepare
-        m_updateManager.swap();
-        m_tiledTexture->update(m_updateManager.getPaintingInval(),
-                               m_updateManager.getPaintingPicture());
-        m_updateManager.clearPaintingInval();
     }
 
     XLOG("prepare layer %d %x at scale %.2f",
-         m_layer->uniqueId(), m_layer,
-         m_layer->getScale());
+         paintingLayer->uniqueId(), paintingLayer,
+         paintingLayer->getScale());
 
-    IntRect visibleArea = computeVisibleArea(m_layer);
+    IntRect visibleArea = computeVisibleArea(paintingLayer);
 
     m_scale = state->scale();
 
     // If we do not have text, we may as well limit ourselves to
     // a scale factor of one... this saves up textures.
-    if (m_scale > 1 && !m_layer->hasText())
+    if (m_scale > 1 && !paintingLayer->hasText())
         m_scale = 1;
 
-    m_tiledTexture->prepare(state, m_scale, m_pictureUsed != m_layer->pictureUsed(),
+    m_tiledTexture->prepare(state, m_scale, m_pictureUsed != paintingLayer->pictureUsed(),
                             startFastSwap, visibleArea);
 }
 
 bool PaintedSurface::draw()
 {
-    if (!m_layer || !m_layer->needsTexture())
+    if (!m_drawingLayer || !m_drawingLayer->needsTexture())
         return false;
 
     bool askRedraw = false;
@@ -167,22 +125,38 @@ bool PaintedSurface::draw()
     return askRedraw;
 }
 
-void PaintedSurface::markAsDirty(const SkRegion& dirtyArea)
+void PaintedSurface::setPaintingLayer(LayerAndroid* layer, const SkRegion& dirtyArea)
+{
+    m_paintingLayer = layer;
+    if (m_tiledTexture)
+        m_tiledTexture->update(dirtyArea, layer->picture());
+}
+
+bool PaintedSurface::isReady()
+{
+    if (m_tiledTexture)
+        return m_tiledTexture->isReady();
+    return false;
+}
+
+void PaintedSurface::swapTiles()
 {
-    m_updateManager.updateInval(dirtyArea);
+    if (m_tiledTexture)
+        m_tiledTexture->swapTiles();
 }
 
 float PaintedSurface::opacity() {
-    if (m_layer)
-        return m_layer->drawOpacity();
+    if (m_drawingLayer)
+        return m_drawingLayer->drawOpacity();
     return 1.0;
 }
 
 const TransformationMatrix* PaintedSurface::transform() {
-    if (!m_layer)
+    // used exclusively for drawing, so only use m_drawingLayer
+    if (!m_drawingLayer)
         return 0;
 
-    return m_layer->drawTransform();
+    return m_drawingLayer->drawTransform();
 }
 
 void PaintedSurface::computeTexturesAmount(TexturesResult* result)
@@ -190,11 +164,14 @@ void PaintedSurface::computeTexturesAmount(TexturesResult* result)
     if (!m_tiledTexture)
         return;
 
-    if (!m_layer)
+    // for now, always done on drawinglayer
+    LayerAndroid* layer = m_drawingLayer;
+
+    if (!layer)
         return;
 
-    IntRect unclippedArea = m_layer->unclippedArea();
-    IntRect clippedVisibleArea = m_layer->visibleArea();
+    IntRect unclippedArea = layer->unclippedArea();
+    IntRect clippedVisibleArea = layer->visibleArea();
     // get two numbers here:
     // - textures needed for a clipped area
     // - textures needed for an un-clipped area
@@ -202,19 +179,19 @@ void PaintedSurface::computeTexturesAmount(TexturesResult* result)
     int nbTexturesClipped = m_tiledTexture->nbTextures(clippedVisibleArea, m_scale);
 
     // Set kFixedLayers level
-    if (m_layer->isFixed())
+    if (layer->isFixed())
         result->fixed += nbTexturesClipped;
 
     // Set kScrollableAndFixedLayers level
-    if (m_layer->contentIsScrollable()
-        || m_layer->isFixed())
+    if (layer->contentIsScrollable()
+        || layer->isFixed())
         result->scrollable += nbTexturesClipped;
 
     // Set kClippedTextures level
     result->clipped += nbTexturesClipped;
 
     // Set kAllTextures level
-    if (m_layer->contentIsScrollable())
+    if (layer->contentIsScrollable())
         result->full += nbTexturesClipped;
     else
         result->full += nbTexturesUnclipped;
index 83b2c9b..b438111 100644 (file)
 #include "LayerAndroid.h"
 #include "SkRefCnt.h"
 #include "TextureOwner.h"
-#include "TiledTexture.h"
 #include "TilesManager.h"
 #include "TilePainter.h"
 #include "TransformationMatrix.h"
-#include "UpdateManager.h"
 
 class SkCanvas;
 class SkRegion;
 
 namespace WebCore {
 
-class UpdateManager;
+class DualTiledTexture;
 
 class PaintedSurface : public SkRefCnt {
 public:
-    PaintedSurface(LayerAndroid* layer);
+    PaintedSurface();
     virtual ~PaintedSurface();
 
     // PaintedSurface methods
 
-    LayerAndroid* layer() { return m_layer; }
     void prepare(GLWebViewState*);
     bool draw();
-    void markAsDirty(const SkRegion& dirtyArea);
     bool paint(SkCanvas*);
-    void removeLayer();
-    void removeLayer(LayerAndroid* layer);
-    void replaceLayer(LayerAndroid* layer);
+
+    void setDrawingLayer(LayerAndroid* layer) { m_drawingLayer = layer; }
+    LayerAndroid* drawingLayer() { return m_drawingLayer; }
+
+    void setPaintingLayer(LayerAndroid* layer, const SkRegion& dirtyArea);
+    void clearPaintingLayer() { m_paintingLayer = 0; }
+    LayerAndroid* paintingLayer() { return m_paintingLayer; }
+
+    void swapTiles();
+    bool isReady();
 
     bool owns(BaseTileTexture* texture);
 
@@ -75,9 +78,8 @@ public:
     unsigned int pictureUsed() { return m_pictureUsed; }
 
 private:
-    UpdateManager m_updateManager;
-
-    LayerAndroid* m_layer;
+    LayerAndroid* m_drawingLayer;
+    LayerAndroid* m_paintingLayer;
     DualTiledTexture* m_tiledTexture;
 
     float m_scale;
index a2e49a7..1a83f65 100644 (file)
 #ifndef QueuedOperation_h
 #define QueuedOperation_h
 
-#include "TiledPage.h"
-
 namespace WebCore {
 
+class TiledPage;
+
 class QueuedOperation {
 public:
     enum OperationType { Undefined, PaintTile, PaintLayer, DeleteTexture };
diff --git a/Source/WebCore/platform/graphics/android/TestExport.h b/Source/WebCore/platform/graphics/android/TestExport.h
new file mode 100644 (file)
index 0000000..15d7cc3
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TestExport_h
+#define TestExport_h
+
+// classes used outside of the .so, in tests, are declared with this attribute
+#define TEST_EXPORT __attribute__((visibility("default")))
+
+#endif // #define TestExport_h
index 3c262d4..e33d39a 100644 (file)
@@ -68,6 +68,7 @@ TiledPage::TiledPage(int id, GLWebViewState* state)
     , m_latestPictureInval(0)
     , m_prepare(false)
     , m_isPrefetchPage(false)
+    , m_willDraw(false)
 {
     m_baseTiles = new BaseTile[TilesManager::getMaxTextureAllocation() + 1];
 #ifdef DEBUG_COUNT
@@ -271,11 +272,6 @@ void TiledPage::prepare(bool goingDown, bool goingLeft, const SkIRect& tileBound
     lastTileX = std::min(lastTileX, static_cast<int>(ceilf(maxWidthTiles)) - 1);
     lastTileY = std::min(lastTileY, static_cast<int>(ceilf(maxHeightTiles)) - 1);
 
-    m_expandedTileBounds.fLeft = firstTileX;
-    m_expandedTileBounds.fTop = firstTileY;
-    m_expandedTileBounds.fRight = lastTileX;
-    m_expandedTileBounds.fBottom = lastTileY;
-
     // check against corrupted scale values giving bad height/width (use float to avoid overflow)
     float numTiles = static_cast<float>(nbTilesHeight) * static_cast<float>(nbTilesWidth);
     if (numTiles > TilesManager::getMaxTextureAllocation() || nbTilesHeight < 1 || nbTilesWidth < 1)
@@ -303,7 +299,22 @@ bool TiledPage::hasMissingContent(const SkIRect& tileBounds)
     return neededTiles > 0;
 }
 
-bool TiledPage::swapBuffersIfReady(const SkIRect& tileBounds, float scale, SwapMethod swap)
+bool TiledPage::isReady(const SkIRect& tileBounds)
+{
+    int neededTiles = tileBounds.width() * tileBounds.height();
+    XLOG("tiled page %p needs %d ready tiles", this, neededTiles);
+    for (int j = 0; j < m_baseTileSize; j++) {
+        BaseTile& tile = m_baseTiles[j];
+        if (tileBounds.contains(tile.x(), tile.y())) {
+            if (tile.isTileReady())
+                neededTiles--;
+        }
+    }
+    XLOG("tiled page %p still needs %d ready tiles", this, neededTiles);
+    return neededTiles == 0;
+}
+
+bool TiledPage::swapBuffersIfReady(const SkIRect& tileBounds, float scale)
 {
     if (!m_glWebViewState)
         return false;
@@ -316,21 +327,11 @@ bool TiledPage::swapBuffersIfReady(const SkIRect& tileBounds, float scale, SwapM
 
     int swaps = 0;
     bool fullSwap = true;
-    if (swap == SwapWholePage) {
-        for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) {
-            for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) {
-                BaseTile* t = getBaseTile(x, y);
-                if (!t || !t->isTileReady())
-                    return false;
-            }
-        }
-    } else { // SwapWhateveryIsReady
-        for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) {
-            for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) {
-                BaseTile* t = getBaseTile(x, y);
-                if (!t || !t->isTileReady())
-                    fullSwap = false;
-            }
+    for (int x = tileBounds.fLeft; x < tileBounds.fRight; x++) {
+        for (int y = tileBounds.fTop; y < tileBounds.fBottom; y++) {
+            BaseTile* t = getBaseTile(x, y);
+            if (!t || !t->isTileReady())
+                fullSwap = false;
         }
     }
 
@@ -341,15 +342,20 @@ bool TiledPage::swapBuffersIfReady(const SkIRect& tileBounds, float scale, SwapM
             swaps++;
     }
 
-    XLOG("%p %s swapped %d textures, returning true",
-         this, (swap == SwapWholePage) ? "whole page" : "greedy swap", swaps);
+    XLOG("%p greedy swapped %d textures, returning true", this, swaps);
     return fullSwap;
 }
 
+void TiledPage::prepareForDrawGL(float transparency, const SkIRect& tileBounds)
+{
+    m_willDraw = true;
+    m_transparency = transparency;
+    m_tileBounds = tileBounds;
+}
 
-void TiledPage::draw(float transparency, const SkIRect& tileBounds)
+void TiledPage::drawGL()
 {
-    if (!m_glWebViewState)
+    if (!m_glWebViewState || m_transparency == 0 || !m_willDraw)
         return;
 
     const float tileWidth = TilesManager::tileWidth() * m_invScale;
@@ -357,7 +363,7 @@ void TiledPage::draw(float transparency, const SkIRect& tileBounds)
 
     for (int j = 0; j < m_baseTileSize; j++) {
         BaseTile& tile = m_baseTiles[j];
-        bool tileInView = tileBounds.contains(tile.x(), tile.y());
+        bool tileInView = m_tileBounds.contains(tile.x(), tile.y());
         if (tileInView) {
             SkRect rect;
             rect.fLeft = tile.x() * tileWidth;
@@ -365,11 +371,12 @@ void TiledPage::draw(float transparency, const SkIRect& tileBounds)
             rect.fRight = rect.fLeft + tileWidth;
             rect.fBottom = rect.fTop + tileHeight;
 
-            tile.draw(transparency, rect, m_scale);
+            tile.draw(m_transparency, rect, m_scale);
         }
 
         TilesManager::instance()->getProfiler()->nextTile(tile, m_invScale, tileInView);
     }
+    m_willDraw = false; // don't redraw until re-prepared
 }
 
 bool TiledPage::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed)
index 960f3d5..791e1f6 100644 (file)
@@ -55,10 +55,6 @@ public:
         ExpandedBounds = 0,
         VisibleBounds = 1
     };
-    enum SwapMethod {
-        SwapWhateverIsReady = 0,
-        SwapWholePage = 1
-    };
 
     TiledPage(int id, GLWebViewState* state);
     ~TiledPage();
@@ -76,10 +72,14 @@ public:
     // returns true if the page can't draw the entire region (may still be stale)
     bool hasMissingContent(const SkIRect& tileBounds);
 
+    bool isReady(const SkIRect& tileBounds);
+
     // swap 'buffers' by swapping each modified texture
-    bool swapBuffersIfReady(const SkIRect& tileBounds, float scale, SwapMethod swap);
+    bool swapBuffersIfReady(const SkIRect& tileBounds, float scale);
+    // save the transparency and bounds to be drawn in drawGL()
+    void prepareForDrawGL(float transparency, const SkIRect& tileBounds);
     // draw the page on the screen
-    void draw(float transparency, const SkIRect& tileBounds);
+    void drawGL();
 
     // TilePainter implementation
     // used by individual tiles to generate the bitmap for their tile
@@ -97,7 +97,6 @@ public:
     void discardTextures();
     void updateBaseTileSize();
     bool scrollingDown() { return m_scrollingDown; }
-    SkIRect* expandedTileBounds() { return &m_expandedTileBounds; }
     bool isPrefetchPage() { return m_isPrefetchPage; }
     void setIsPrefetchPage(bool isPrefetch) { m_isPrefetchPage = isPrefetch; }
 
@@ -128,8 +127,12 @@ private:
     unsigned int m_latestPictureInval;
     bool m_prepare;
     bool m_scrollingDown;
-    SkIRect m_expandedTileBounds;
     bool m_isPrefetchPage;
+
+    // info saved in prepare, used in drawGL()
+    bool m_willDraw;
+    SkIRect m_tileBounds;
+    float m_transparency;
 };
 
 } // namespace WebCore
index e1e5ec9..5538e1b 100644 (file)
@@ -32,6 +32,7 @@
 #include "PaintedSurface.h"
 #include "PaintTileOperation.h"
 #include "SkCanvas.h"
+#include "SkPicture.h"
 
 #include <cutils/log.h>
 #include <wtf/CurrentTime.h>
 
 namespace WebCore {
 
-bool TiledTexture::ready() {
+TiledTexture::~TiledTexture()
+{
+    SkSafeUnref(m_paintingPicture);
+#ifdef DEBUG_COUNT
+    ClassTracker::instance()->decrement("TiledTexture");
+#endif
+    removeTiles();
+}
+
+bool TiledTexture::ready()
+{
     bool tilesAllReady = true;
     bool tilesVisible = false;
     for (unsigned int i = 0; i < m_tiles.size(); i++) {
@@ -71,10 +82,23 @@ bool TiledTexture::ready() {
     // in order to unblock the zooming process.
     // FIXME: have a better system -- maybe keeping the last scale factor
     // able to fully render everything
+    XLOG("TT %p, ready %d, visible %d, texturesRemain %d",
+         this, tilesAllReady, tilesVisible,
+         TilesManager::instance()->layerTexturesRemain());
+
     return !TilesManager::instance()->layerTexturesRemain()
             || !tilesVisible || tilesAllReady;
 }
 
+void TiledTexture::swapTiles()
+{
+    int swaps = 0;
+    for (unsigned int i = 0; i < m_tiles.size(); i++)
+        if (m_tiles[i]->swapTexturesIfNeeded())
+            swaps++;
+    XLOG("TT %p swapping, swaps = %d", this, swaps);
+}
+
 IntRect TiledTexture::computeTilesArea(IntRect& visibleArea, float scale)
 {
     IntRect computedArea;
@@ -83,6 +107,8 @@ IntRect TiledTexture::computeTilesArea(IntRect& visibleArea, float scale)
                  ceilf(visibleArea.width() * scale),
                  ceilf(visibleArea.height() * scale));
 
+    XLOG("TT %p prepare, scale %f, area %d x %d", this, scale, area.width(), area.height());
+
     if (area.width() == 0 && area.height() == 0) {
         computedArea.setWidth(0);
         computedArea.setHeight(0);
@@ -102,15 +128,13 @@ IntRect TiledTexture::computeTilesArea(IntRect& visibleArea, float scale)
 }
 
 void TiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
-                           bool startFastSwap, IntRect& area)
+                           bool startFastSwap, IntRect& visibleArea)
 {
     if (!m_surface)
         return;
 
-    if (!m_surface->layer())
-        return;
-
-    m_area = computeTilesArea(area, scale);
+    // first, how many tiles do we need
+    m_area = computeTilesArea(visibleArea, scale);
     if (m_area.isEmpty())
         return;
 
@@ -130,31 +154,6 @@ void TiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
 
     m_scale = scale;
 
-    // unlock if tiles all ready
-    bool tilesAllReady = ready();
-
-    // startFastSwap=true will swap all ready tiles each
-    // frame until all visible tiles are up to date
-    if (tilesAllReady)
-        m_swapWhateverIsReady = false;
-    else if (startFastSwap)
-        m_swapWhateverIsReady = true;
-
-    // swap as appropriate
-    for (unsigned int i = 0; i < m_tiles.size(); i++) {
-        BaseTile* tile = m_tiles[i];
-        if (tilesAllReady || m_swapWhateverIsReady)
-            tile->swapTexturesIfNeeded();
-    }
-
-    if (tilesAllReady) {
-        m_updateManager.swap();
-        m_dirtyRegion.op(m_updateManager.getPaintingInval(), SkRegion::kUnion_Op);
-        XLOG("TT %p swapping, now painting with picture %p"
-             this, m_updateManager.getPaintingPicture());
-        m_updateManager.clearPaintingInval();
-    }
-
     // apply dirty region to affected tiles
     if (!m_dirtyRegion.isEmpty()) {
         for (unsigned int i = 0; i < m_tiles.size(); i++) {
@@ -179,12 +178,14 @@ void TiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
 
 void TiledTexture::update(const SkRegion& invalRegion, SkPicture* picture)
 {
-    XLOG("TT %p, update manager %p updated with picture %p, region empty %d",
-          this, &m_updateManager, picture, invalRegion.isEmpty());
-    // attempt to update inval and picture. these may be deferred below instead
-    // of used immediately.
-    m_updateManager.updateInval(invalRegion);
-    m_updateManager.updatePicture(picture);
+    XLOG("TT %p update, current region empty %d, new empty %d, painting picture %p",
+          this, m_dirtyRegion.isEmpty(), invalRegion.isEmpty(), picture);
+    m_dirtyRegion.op(invalRegion, SkRegion::kUnion_Op);
+
+    android::Mutex::Autolock lock(m_paintingPictureSync);
+    SkSafeRef(picture);
+    SkSafeUnref(m_paintingPicture);
+    m_paintingPicture = picture;
 }
 
 void TiledTexture::prepareTile(bool repaint, int x, int y)
@@ -195,7 +196,7 @@ void TiledTexture::prepareTile(bool repaint, int x, int y)
         m_tiles.append(tile);
     }
 
-    XLOG("preparing tile %p, painter is this %p", tile, this);
+    XLOG("preparing tile %p at %d, %d, painter is this %p", tile, x, y, this);
     tile->setContents(this, x, y, m_scale);
 
     // TODO: move below (which is largely the same for layers / tiled page) into
@@ -203,8 +204,8 @@ void TiledTexture::prepareTile(bool repaint, int x, int y)
 
     if (tile->isDirty() || !tile->frontTexture())
         tile->reserveTexture();
-    LayerAndroid* layer = m_surface->layer();
-    if (tile->backTexture() && tile->isDirty() && !tile->isRepaintPending() && layer) {
+    bool hasPicture = m_paintingPicture != 0; // safely read on UI thread, since only UI thread writes
+    if (tile->backTexture() && tile->isDirty() && !tile->isRepaintPending() && hasPicture) {
         PaintTileOperation *operation = new PaintTileOperation(tile, m_surface);
         TilesManager::instance()->scheduleOperation(operation);
     }
@@ -228,6 +229,8 @@ int TiledTexture::nbTextures(IntRect& area, float scale)
 
 bool TiledTexture::draw()
 {
+    XLOG("TT %p draw", this);
+
 #ifdef DEBUG
     TilesManager::instance()->getTilesTracker()->trackLayer();
 #endif
@@ -254,7 +257,7 @@ bool TiledTexture::draw()
             rect.fTop = tile->y() * tileHeight;
             rect.fRight = rect.fLeft + tileWidth;
             rect.fBottom = rect.fTop + tileHeight;
-            XLOG(" - [%d], { painter %x vs %x }, tile %x %d,%d at scale %.2f vs %.2f [ready: %d] dirty: %d",
+            XLOG("- [%d], { painter %x vs %x }, tile %x %d,%d at scale %.2f vs %.2f [ready: %d] dirty: %d",
                  i, this, tile->painter(), tile, tile->x(), tile->y(),
                  tile->scale(), m_scale, tile->isTileReady(), tile->isDirty());
             tile->draw(m_surface->opacity(), rect, m_scale);
@@ -270,7 +273,23 @@ bool TiledTexture::draw()
 
 bool TiledTexture::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed)
 {
-    return m_updateManager.paint(tile, canvas, pictureUsed);
+    m_paintingPictureSync.lock();
+    SkPicture* picture = m_paintingPicture;
+    SkSafeRef(picture);
+    m_paintingPictureSync.unlock();
+
+    if (!picture) {
+        XLOG("TT %p COULDNT PAINT, NO PICTURE", this);
+        return false;
+    }
+
+    XLOG("TT %p painting with picture %p", this, picture);
+
+    canvas->drawPicture(*picture);
+
+    SkSafeUnref(picture);
+
+    return true;
 }
 
 const TransformationMatrix* TiledTexture::transform()
@@ -335,8 +354,8 @@ void DualTiledTexture::prepare(GLWebViewState* state, float scale, bool repaint,
         m_zooming = true;
     }
 
-    XLOG("\n*** %x Drawing with scale %.2f, futureScale: %.2f, zooming: %d",
-          this, scale, m_futureScale, m_zooming);
+    XLOG("Preparing DTT %p with scale %.2f, m_scale %.2f, futureScale: %.2f, zooming: %d",
+          this, scale, m_scale, m_futureScale, m_zooming);
 
     if (m_scale > 0)
         m_frontTexture->prepare(state, m_scale, repaint, startFastSwap, m_preZoomVisibleArea);
@@ -373,6 +392,12 @@ void DualTiledTexture::update(const SkRegion& dirtyArea, SkPicture* picture)
     m_frontTexture->update(dirtyArea, picture);
 }
 
+void DualTiledTexture::swapTiles()
+{
+    m_backTexture->swapTiles();
+    m_frontTexture->swapTiles();
+}
+
 bool DualTiledTexture::owns(BaseTileTexture* texture)
 {
     bool owns = m_textureA->owns(texture);
index 5a47cd9..b761880 100644 (file)
 #include "SkRegion.h"
 #include "TextureOwner.h"
 #include "TilePainter.h"
-#include "UpdateManager.h"
 
 class SkCanvas;
 
 namespace WebCore {
 
-class UpdateManager;
 class PaintedSurface;
 
 class TiledTexture : public TilePainter {
 public:
     TiledTexture(PaintedSurface* surface)
-        : m_surface(surface)
+        : m_paintingPicture(0)
+        , m_surface(surface)
         , m_prevTileX(0)
         , m_prevTileY(0)
         , m_scale(1)
@@ -57,18 +56,14 @@ public:
         ClassTracker::instance()->increment("TiledTexture");
 #endif
     }
-    virtual ~TiledTexture()
-    {
-#ifdef DEBUG_COUNT
-        ClassTracker::instance()->decrement("TiledTexture");
-#endif
-        removeTiles();
-    };
+
+    virtual ~TiledTexture();
 
     IntRect computeTilesArea(IntRect& visibleArea, float scale);
 
     void prepare(GLWebViewState* state, float scale, bool repaint,
                  bool startFastSwap, IntRect& visibleArea);
+    void swapTiles();
     bool draw();
 
     void prepareTile(bool repaint, int x, int y);
@@ -94,7 +89,11 @@ public:
 private:
     bool tileIsVisible(BaseTile* tile);
 
-    UpdateManager m_updateManager;
+    // protect m_paintingPicture
+    //    update() on UI thread modifies
+    //    paint() on texture gen thread reads
+    android::Mutex m_paintingPictureSync;
+    SkPicture* m_paintingPicture;
 
     PaintedSurface* m_surface;
     Vector<BaseTile*> m_tiles;
@@ -117,10 +116,15 @@ public:
     ~DualTiledTexture();
     void prepare(GLWebViewState* state, float scale, bool repaint,
                  bool startFastSwap, IntRect& area);
+    void swapTiles();
     void swap();
     bool draw();
     void update(const SkRegion& dirtyArea, SkPicture* picture);
     bool owns(BaseTileTexture* texture);
+    bool isReady()
+    {
+        return !m_zooming && m_frontTexture->ready();
+    }
 
     int nbTextures(IntRect& area, float scale)
     {
index acfe9e7..ca484ce 100644 (file)
@@ -208,21 +208,6 @@ void TilesManager::printTextures()
 #endif // DEBUG
 }
 
-void TilesManager::swapLayersTextures(LayerAndroid* oldTree, LayerAndroid* newTree)
-{
-    if (oldTree)
-        oldTree->assignTextureTo(newTree);
-
-    if (newTree)
-        newTree->createTexture();
-
-    GLWebViewState* oldState = 0;
-    if (oldTree && !newTree)
-        oldState = oldTree->state();
-
-    paintedSurfacesCleanup(oldState);
-}
-
 void TilesManager::addPaintedSurface(PaintedSurface* surface)
 {
     m_paintedSurfaces.append(surface);
@@ -412,13 +397,24 @@ void TilesManager::paintedSurfacesCleanup(GLWebViewState* state)
     WTF::Vector<PaintedSurface*> collect;
     for (unsigned int i = 0; i < m_paintedSurfaces.size(); i++) {
         PaintedSurface* surface = m_paintedSurfaces[i];
-        if (!surface->layer() || (state && surface->layer()->state() == state))
+
+        Layer* drawing = surface->drawingLayer();
+        Layer* painting = surface->paintingLayer();
+
+        XLOG("considering PS %p, drawing %p, painting %p", surface, drawing, painting);
+
+        bool drawingMatchesState = state && drawing && (drawing->state() == state);
+        bool paintingMatchesState = state && painting && (painting->state() == state);
+
+        if ((!painting && !drawing) || drawingMatchesState || paintingMatchesState) {
+            XLOG("trying to remove PS %p, painting %p, drawing %p, DMS %d, PMS %d",
+                 surface, painting, drawing, drawingMatchesState, paintingMatchesState);
             collect.append(surface);
+        }
     }
     for (unsigned int i = 0; i < collect.size(); i++) {
         PaintedSurface* surface = collect[i];
         m_paintedSurfaces.remove(m_paintedSurfaces.find(surface));
-        surface->removeLayer();
         SkSafeUnref(surface);
     }
 }
index 8ae9202..cc66f1a 100644 (file)
@@ -110,7 +110,7 @@ public:
     static float tileHeight();
     static float layerTileWidth();
     static float layerTileHeight();
-    void paintedSurfacesCleanup(GLWebViewState* state);
+    void paintedSurfacesCleanup(GLWebViewState* state = 0);
     void unregisterGLWebViewState(GLWebViewState* state);
 
     void allocateTiles();
@@ -190,6 +190,11 @@ public:
         return m_drawGLCount;
     }
 
+    int getPaintedSurfaceCount()
+    {
+        return m_paintedSurfaces.size();
+    }
+
 private:
     TilesManager();
 
diff --git a/Source/WebCore/platform/graphics/android/TreeManager.cpp b/Source/WebCore/platform/graphics/android/TreeManager.cpp
new file mode 100644 (file)
index 0000000..4915f8b
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TreeManager.h"
+
+#include "Layer.h"
+#include "BaseLayerAndroid.h"
+#include "TilesManager.h"
+
+#include <cutils/log.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/text/CString.h>
+
+#undef XLOGC
+#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "TreeManager", __VA_ARGS__)
+
+#ifdef DEBUG
+
+#undef XLOG
+#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "TreeManager", __VA_ARGS__)
+
+#else
+
+#undef XLOG
+#define XLOG(...)
+
+#endif // DEBUG
+
+namespace WebCore {
+
+TreeManager::TreeManager()
+    : m_drawingTree(0)
+    , m_paintingTree(0)
+    , m_queuedTree(0)
+    , m_fastSwapMode(false)
+{
+}
+
+TreeManager::~TreeManager()
+{
+    clearTrees();
+}
+
+// the painting tree has finished painting:
+//   discard the drawing tree
+//   swap the painting tree in place of the drawing tree
+//   and start painting the queued tree
+void TreeManager::swap()
+{
+    // swap can't be called unless painting just finished
+    ASSERT(m_paintingTree);
+
+    android::Mutex::Autolock lock(m_paintSwapLock);
+
+    XLOG("SWAPPING, D %p, P %p, Q %p", m_drawingTree, m_paintingTree, m_queuedTree);
+
+    // if we have a drawing tree, discard it since the painting tree is done
+    if (m_drawingTree) {
+        XLOG("destroying drawing tree %p", m_drawingTree);
+        m_drawingTree->setIsDrawing(false);
+        SkSafeUnref(m_drawingTree);
+    }
+
+    // painting tree becomes the drawing tree
+    XLOG("drawing tree %p", m_paintingTree);
+    m_paintingTree->setIsDrawing(true);
+
+    if (m_queuedTree) {
+        // start painting with the queued tree
+        XLOG("now painting tree %p", m_queuedTree);
+        m_queuedTree->setIsPainting(m_paintingTree);
+    }
+    m_drawingTree = m_paintingTree;
+    m_paintingTree = m_queuedTree;
+    m_queuedTree = 0;
+
+    TilesManager::instance()->paintedSurfacesCleanup();
+
+    XLOG("SWAPPING COMPLETE, D %p, P %p, Q %p", m_drawingTree, m_paintingTree, m_queuedTree);
+}
+
+// clear all of the content in the three trees held by the tree manager
+void TreeManager::clearTrees()
+{
+    // remove painted surfaces from any tree in this view, and set trees as no
+    // longer drawing, to clear ptrs from surfaces to layers
+    GLWebViewState* oldState = 0;
+    if (m_drawingTree) {
+        oldState = m_drawingTree->state();
+        m_drawingTree->setIsDrawing(false);
+    }
+    if (m_paintingTree) {
+        oldState = m_paintingTree->state();
+        m_paintingTree->setIsDrawing(false);
+    }
+
+    XLOG("TreeManager %p removing PS from state %p", this, oldState);
+    TilesManager::instance()->paintedSurfacesCleanup(oldState);
+
+    SkSafeUnref(m_drawingTree);
+    m_drawingTree = 0;
+    SkSafeUnref(m_paintingTree);
+    m_paintingTree = 0;
+    SkSafeUnref(m_queuedTree);
+    m_queuedTree = 0;
+}
+
+// a new layer tree has arrived, queue it if we're painting something already,
+// or start painting it if we aren't
+void TreeManager::updateWithTree(Layer* newTree, bool brandNew)
+{
+
+    // can't have a queued tree unless have a painting tree too
+    ASSERT(m_paintingTree || !m_queuedTree);
+
+    SkSafeRef(newTree);
+
+    android::Mutex::Autolock lock(m_paintSwapLock);
+
+    if (!newTree || brandNew) {
+        clearTrees();
+        if (brandNew) {
+            m_animationOffset = 0;
+            m_isAnimating = false;
+            m_lastFrameTime = WTF::currentTime();
+
+            m_paintingTree = newTree;
+            m_paintingTree->setIsPainting(m_drawingTree);
+        }
+        return;
+    }
+
+    if (m_queuedTree || m_paintingTree) {
+        // currently painting, so defer this new tree
+        if (m_queuedTree) {
+            // have a queued tree, copy over invals so the regions are
+            // eventually repainted
+            m_queuedTree->mergeInvalsInto(newTree);
+        }
+        SkSafeUnref(m_queuedTree);
+        m_queuedTree = newTree;
+        return;
+    }
+
+    // don't have painting tree, paint this one!
+    m_paintingTree = newTree;
+    m_paintingTree->setIsPainting(m_drawingTree);
+}
+
+bool TreeManager::drawGL(double currentTime, IntRect& viewRect,
+                         SkRect& visibleRect, float scale,
+                         bool enterFastSwapMode, bool* buffersSwappedPtr,
+                         TexturesResult* texturesResultPtr)
+{
+    m_fastSwapMode |= enterFastSwapMode;
+
+    XLOG("drawGL, D %p, P %p, Q %p, fastSwap %d",
+         m_drawingTree, m_paintingTree, m_queuedTree, m_fastSwapMode);
+
+    bool ret = false;
+    bool didTreeSwap = false;
+    if (m_paintingTree) {
+        ret |= m_paintingTree->prepare(currentTime, viewRect,
+                                       visibleRect, scale);
+
+        if (/*!m_fastSwapMode && */ m_paintingTree->isReady()) {
+            XLOG("have painting tree %p ready, swapping!", m_paintingTree);
+            didTreeSwap = true;
+            swap();
+            if (buffersSwappedPtr)
+                *buffersSwappedPtr = true;
+        }
+    } else if (m_drawingTree) {
+        XLOG("preparing drawing tree %p", m_drawingTree);
+        ret |= m_drawingTree->prepare(currentTime, viewRect,
+                                      visibleRect, scale);
+    }
+
+    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 (didTreeSwap || m_fastSwapMode)
+            m_drawingTree->swapTiles();
+
+        if (drawingReady) {
+            // exit fast swap mode, as content is up to date
+            m_fastSwapMode = false;
+        } else {
+            // drawing isn't ready, must redraw
+            ret = true;
+        }
+
+        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));
+            laTree->computeTexturesAmount(texturesResultPtr);
+            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;
+        }
+        XLOG("drawing tree %p", m_drawingTree);
+        ret |= m_drawingTree->drawGL(viewRect, visibleRect, scale);
+    } else if (m_paintingTree && m_paintingTree->state()) {
+        // Dont have a drawing tree, draw white background
+        Color defaultBackground = Color::white;
+        m_paintingTree->state()->drawBackground(defaultBackground);
+    }
+
+    m_lastFrameTime = currentTime;
+
+    if (m_paintingTree) {
+        XLOG("still have painting tree %p", m_paintingTree);
+        return true;
+    }
+
+    return ret;
+}
+
+int TreeManager::getTotalPaintedSurfaceCount()
+{
+    return TilesManager::instance()->getPaintedSurfaceCount();
+}
+
+// draw for base tile - called on TextureGeneration thread
+void TreeManager::drawCanvas(SkCanvas* canvas, bool drawLayers)
+{
+    BaseLayerAndroid* paintingTree = 0;
+    m_paintSwapLock.lock();
+    if (m_paintingTree)
+        paintingTree = static_cast<BaseLayerAndroid*>(m_paintingTree);
+    else
+        paintingTree = static_cast<BaseLayerAndroid*>(m_drawingTree);
+    SkSafeRef(paintingTree);
+    m_paintSwapLock.unlock();
+
+    if (!paintingTree)
+        return;
+
+
+    paintingTree->drawCanvas(canvas);
+
+    if (drawLayers && paintingTree->countChildren()) {
+        // draw the layers onto the canvas as well
+        Layer* layers = paintingTree->getChild(0);
+        static_cast<LayerAndroid*>(layers)->drawCanvas(canvas);
+    }
+
+    SkSafeUnref(paintingTree);
+}
+
+int TreeManager::baseContentWidth()
+{
+    if (m_paintingTree) {
+        return static_cast<BaseLayerAndroid*>(m_paintingTree)->content()->width();
+    } else if (m_drawingTree) {
+        return static_cast<BaseLayerAndroid*>(m_drawingTree)->content()->width();
+    }
+    return 0;
+}
+
+int TreeManager::baseContentHeight()
+{
+    if (m_paintingTree) {
+        return static_cast<BaseLayerAndroid*>(m_paintingTree)->content()->height();
+    } else if (m_drawingTree) {
+        return static_cast<BaseLayerAndroid*>(m_drawingTree)->content()->height();
+    }
+    return 0;
+}
+
+} // namespace WebCore
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef UpdateManager_h
-#define UpdateManager_h
+#ifndef TreeManager_h
+#define TreeManager_h
 
+#include "TestExport.h"
+#include <utils/threads.h>
+
+class Layer;
+class SkRect;
 class SkCanvas;
-class SkRegion;
 
 namespace WebCore {
 
-class BaseTile;
-
-// UpdateManager Architecture
+class IntRect;
+class TexturesResult;
 
-// The UpdateManager is used to defer updates and invalidations to a layer,
-// so that the layer can finish painting one version completely without being
-// interrupted by new invals/content
-
-class UpdateManager {
+class TEST_EXPORT TreeManager {
 public:
-    UpdateManager();
-
-    ~UpdateManager();
+    TreeManager();
 
-    // swap deferred members in place of painting members
-    void swap();
-
-    void updateInval(const SkRegion& invalRegion);
+    ~TreeManager();
 
-    void updatePicture(SkPicture* picture);
+    void updateWithTree(Layer* tree, bool brandNew);
 
-    bool paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed);
+    bool drawGL(double currentTime, IntRect& viewRect,
+                SkRect& visibleRect, float scale,
+                bool enterFastSwapMode, bool* buffersSwappedPtr,
+                TexturesResult* texturesResultPtr);
 
-    void clearPaintingInval();
+    void drawCanvas(SkCanvas* canvas, bool drawLayers);
 
-    const SkRegion& getPaintingInval() {
-        return m_paintingInval;
-    }
+    // used in debugging (to avoid exporting TilesManager symbols)
+    static int getTotalPaintedSurfaceCount();
 
-    SkPicture* getPaintingPicture() {
-        // NOTE: only modified on UI thread, so UI thread access doesn't need mutex
-        return m_paintingPicture;
-    }
+    int baseContentWidth();
+    int baseContentHeight();
 
 private:
-    // protect m_paintingPicture
-    //    swap() on UI thread modifies
-    //    paint() on texture gen thread reads
-    android::Mutex m_paintingPictureSync;
-    SkPicture* m_paintingPicture;
+    void swap();
+    void clearTrees();
+
+    android::Mutex m_paintSwapLock;
 
-    // inval region to be redrawn with the current paintingPicture
-    SkRegion m_paintingInval;
+    Layer* m_drawingTree;
+    Layer* m_paintingTree;
+    Layer* m_queuedTree;
 
-    // most recently received picture, moved into painting on swap()
-    SkPicture* m_deferredPicture;
+    bool m_fastSwapMode;
 
-    // all invals since last swap(), merged with painting inval on swap()
-    SkRegion m_deferredInval;
+    double m_animationOffset;
+    double m_lastFrameTime;
+    bool m_isAnimating;
 };
 
 } // namespace WebCore
 
-#endif //#define UpdateManager_h
+#endif //#define TreeManager_h
diff --git a/Source/WebCore/platform/graphics/android/UpdateManager.cpp b/Source/WebCore/platform/graphics/android/UpdateManager.cpp
deleted file mode 100644 (file)
index 1c20f1f..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2011, The Android Open Source Project
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "PaintedSurface.h"
-
-#include "LayerAndroid.h"
-#include "TilesManager.h"
-#include "SkCanvas.h"
-#include "SkPicture.h"
-
-#include <cutils/log.h>
-#include <wtf/CurrentTime.h>
-#include <wtf/text/CString.h>
-
-#undef XLOGC
-#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "UpdateManager", __VA_ARGS__)
-
-#ifdef DEBUG
-
-#undef XLOG
-#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "UpdateManager", __VA_ARGS__)
-
-#else
-
-#undef XLOG
-#define XLOG(...)
-
-#endif // DEBUG
-
-namespace WebCore {
-
-UpdateManager::UpdateManager()
-    : m_paintingPicture(0)
-    , m_deferredPicture(0)
-{
-}
-
-UpdateManager::~UpdateManager()
-{
-    SkSafeUnref(m_paintingPicture);
-    SkSafeUnref(m_deferredPicture);
-}
-
-void UpdateManager::swap()
-{
-    m_paintingInval.op(m_deferredInval, SkRegion::kUnion_Op);
-    m_deferredInval.setEmpty();
-
-    android::Mutex::Autolock lock(m_paintingPictureSync);
-    if (m_deferredPicture) {
-        XLOG("unlock of updatemanager %p, was painting %p, now painting %p",
-             this, m_paintingPicture, m_deferredPicture);
-        SkSafeUnref(m_paintingPicture);
-        m_paintingPicture = m_deferredPicture;
-        m_deferredPicture = 0;
-    }
-}
-
-void UpdateManager::updateInval(const SkRegion& invalRegion)
-{
-    m_deferredInval.op(invalRegion, SkRegion::kUnion_Op);
-}
-
-void UpdateManager::updatePicture(SkPicture* picture)
-{
-    SkSafeRef(picture);
-    SkSafeUnref(m_deferredPicture);
-    m_deferredPicture = picture;
-}
-
-bool UpdateManager::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed)
-{
-    m_paintingPictureSync.lock();
-    SkPicture* picture = m_paintingPicture;
-    SkSafeRef(picture);
-    m_paintingPictureSync.unlock();
-
-    XLOG("UpdateManager %p painting with picture %p", this, picture);
-
-    if (!picture)
-        return false;
-
-    canvas->drawPicture(*picture);
-
-    // TODO: visualization layer diagonals
-
-    SkSafeUnref(picture);
-    return true;
-}
-
-
-void UpdateManager::clearPaintingInval()
-{
-    m_paintingInval.setEmpty();
-}
-
-} // namespace WebCore
index 9576ed1..482d711 100644 (file)
@@ -142,7 +142,7 @@ GLuint VideoLayerAndroid::createBackgroundTexture()
     return texture;
 }
 
-bool VideoLayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
+bool VideoLayerAndroid::drawGL()
 {
     // Lazily allocated the textures.
     if (!m_createdTexture) {
@@ -224,7 +224,7 @@ bool VideoLayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
         }
     }
 
-    return drawChildrenGL(glWebViewState, matrix);
+    return drawChildrenGL();
 }
 
 }
index abc1c13..8a064bb 100644 (file)
@@ -56,7 +56,7 @@ public:
     virtual LayerAndroid* copy() const { return new VideoLayerAndroid(*this); }
 
     // The following 3 functions are called in UI thread only.
-    virtual bool drawGL(GLWebViewState*, SkMatrix& matrix);
+    virtual bool drawGL();
     void setSurfaceTexture(sp<SurfaceTexture> texture, int textureName, PlayerState playerState);
     GLuint createBackgroundTexture();
     GLuint createSpinnerOuterTexture();
diff --git a/Source/WebCore/tests/Android.mk b/Source/WebCore/tests/Android.mk
new file mode 100644 (file)
index 0000000..c98a9a3
--- /dev/null
@@ -0,0 +1,49 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# Build the unit tests.
+test_src_files := \
+    TreeManager_test.cpp
+
+shared_libraries := \
+    libcutils \
+    libwebcore \
+    libskia \
+    libstlport
+
+static_libraries := \
+    libgtest \
+    libgtest_main
+
+c_includes := \
+    bionic \
+    bionic/libstdc++/include \
+    external/gtest/include \
+    external/stlport/stlport \
+    external/skia/include/core \
+    external/icu4c/common \
+    $(LOCAL_PATH)/../../JavaScriptCore \
+    $(LOCAL_PATH)/../../JavaScriptCore/wtf \
+    $(LOCAL_PATH)/.. \
+    $(LOCAL_PATH)/../platform/graphics \
+    $(LOCAL_PATH)/../platform/graphics/transforms \
+    $(LOCAL_PATH)/../platform/graphics/android
+
+    # external/webkit/Source/WebCore/platform/graphics/android
+
+module_tags := eng tests
+
+$(foreach file,$(test_src_files), \
+    $(eval include $(CLEAR_VARS)) \
+    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+    $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
+    $(eval LOCAL_C_INCLUDES := $(c_includes)) \
+    $(eval LOCAL_SRC_FILES := $(file)) \
+    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+    $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
+    $(eval include $(BUILD_EXECUTABLE)) \
+)
+
+# Build the manual test programs.
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/Source/WebCore/tests/TreeManager_test.cpp b/Source/WebCore/tests/TreeManager_test.cpp
new file mode 100644 (file)
index 0000000..3837627
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <gtest/gtest.h>
+
+#include "SkRefCnt.h"
+#include "TransformationMatrix.h"
+#include "IntRect.h"
+#include "Layer.h"
+#include "LayerAndroid.h"
+#include "TreeManager.h"
+#include "SkPicture.h"
+
+#include <cutils/log.h>
+#include <wtf/text/CString.h>
+#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "TreeManager_test", __VA_ARGS__)
+
+namespace WebCore {
+
+// Used for testing simple cases for tree painting, drawing, swapping
+class TestLayer : public Layer {
+public:
+    TestLayer()
+        : m_isDrawing(false)
+        , m_isPainting(false)
+        , m_isDonePainting(false)
+        , m_drawCount(0)
+    {}
+
+    bool m_isDrawing;
+    bool m_isPainting;
+    bool m_isDonePainting;
+    double m_drawCount;
+
+    bool drawGL(WebCore::IntRect& viewRect, SkRect& visibleRect, float scale) {
+        m_drawCount++;
+        return false;
+    }
+
+    bool isReady() {
+        return m_isDonePainting;
+    }
+
+    void setIsDrawing(bool isDrawing) {
+        m_isDrawing = isDrawing;
+        if (isDrawing)
+            m_isPainting = false;
+    }
+
+    void setIsPainting(Layer* drawingTree) {
+        m_isPainting = true;
+        m_isDonePainting = false;
+        setIsDrawing(false);
+    }
+};
+
+// Used for testing complex trees, and painted surfaces
+class TestLayerAndroid : public LayerAndroid {
+public:
+    TestLayerAndroid(SkPicture* picture) : LayerAndroid(picture)
+        , m_isDonePainting(false)
+        , m_drawCount(0)
+    {}
+
+    TestLayerAndroid(const TestLayerAndroid& testLayer) : LayerAndroid(testLayer)
+        , m_isDonePainting(testLayer.m_isDonePainting)
+        , m_drawCount(testLayer.m_drawCount)
+    {
+        XLOGC("copying TLA %p as %p", &testLayer, this);
+    }
+
+    bool m_isDonePainting;
+    double m_drawCount;
+
+    bool drawGL(WebCore::IntRect& viewRect, SkRect& visibleRect, float scale) {
+        m_drawCount++;
+        return false;
+    }
+
+    bool isReady() {
+        return m_isDonePainting;
+    }
+
+    LayerAndroid* copy() const { return new TestLayerAndroid(*this); }
+};
+
+class TreeManagerTest : public testing::Test {
+protected:
+    IntRect m_iRect;
+    SkRect m_sRect;
+    double m_scale;
+
+    void allocLayerWithPicture(bool useTestLayer, LayerAndroid** layerHandle, SkPicture** pictureHandle) {
+        SkPicture* p = new SkPicture();
+        p->beginRecording(16,16, 0);
+        p->endRecording();
+
+        LayerAndroid* l;
+        if (useTestLayer)
+            l = new TestLayerAndroid(p);
+        else
+            l = new LayerAndroid(p);
+        l->setSize(16, 16);
+        SkSafeUnref(p); // layer takes sole ownership of picture
+
+        if (layerHandle)
+            *layerHandle = l;
+        if (pictureHandle)
+            *pictureHandle = p;
+    }
+
+    bool drawGL(TreeManager& manager, bool* swappedPtr) {
+        // call draw gl here in one place, so that when its parameters change,
+        // the tests only have to be updated in one place
+        return manager.drawGL(0, m_iRect, m_sRect, m_scale, false, swappedPtr, 0);
+    }
+
+    virtual void SetUp() {
+        m_iRect = IntRect(0, 0, 1, 1);
+        m_sRect = SkRect::MakeWH(1, 1);
+        m_scale = 1.0;
+    }
+    virtual void TearDown() { }
+};
+
+TEST_F(TreeManagerTest, EmptyTree_DoesntRedraw) {
+    TreeManager manager;
+
+    drawGL(manager, false);
+}
+
+TEST_F(TreeManagerTest, OneLayerTree_SingleTree_SwapCheck) {
+    TreeManager manager;
+    TestLayer layer;
+
+    // initialize with tree, should be painting
+    manager.updateWithTree(&layer, true);
+
+    ASSERT_TRUE(layer.m_isPainting);
+    ASSERT_FALSE(layer.m_isDrawing);
+
+    // should not call swap, and return true since content isn't done
+    for (int i = 1; i < 6; i++) {
+        bool swapped = false;
+        ASSERT_TRUE(drawGL(manager, &swapped));
+        ASSERT_FALSE(swapped);
+        ASSERT_EQ(layer.m_drawCount, 0);
+    }
+
+    layer.m_isDonePainting = true;
+
+    // swap content, should return false since no new picture
+    bool swapped = false;
+    ASSERT_FALSE(drawGL(manager, &swapped));
+    ASSERT_TRUE(swapped);
+    ASSERT_EQ(layer.m_drawCount, 1); // verify layer drawn
+}
+
+TEST_F(TreeManagerTest, OneLayerTree_SingleTree_RefCountCorrectly) {
+    TreeManager manager;
+    TestLayer* layer = new TestLayer();
+    ASSERT_EQ(layer->getRefCnt(), 1);
+
+    // initialize with tree, should be painting
+    manager.updateWithTree(layer, true);
+    ASSERT_EQ(layer->getRefCnt(), 2);
+
+    layer->m_isDonePainting = true;
+    ASSERT_FALSE(drawGL(manager, 0));
+
+    // should be drawing
+    ASSERT_EQ(layer->getRefCnt(), 2);
+
+    manager.updateWithTree(0, false);
+
+    // layer should be removed
+    ASSERT_EQ(layer->getRefCnt(), 1);
+    SkSafeUnref(layer);
+}
+
+TEST_F(TreeManagerTest, OneLayerTree_TwoTreeFlush_PaintDrawRefCheck) {
+    TreeManager manager;
+    TestLayer* firstLayer = new TestLayer();
+    TestLayer* secondLayer = new TestLayer();
+    ASSERT_EQ(firstLayer->getRefCnt(), 1);
+    ASSERT_EQ(secondLayer->getRefCnt(), 1);
+
+    ///// ENQUEUE 2 TREES
+
+    // first starts painting
+    manager.updateWithTree(firstLayer, true);
+    ASSERT_TRUE(firstLayer->m_isPainting);
+    ASSERT_FALSE(firstLayer->m_isDrawing);
+
+    // second is queued
+    manager.updateWithTree(secondLayer, false);
+    ASSERT_FALSE(secondLayer->m_isPainting);
+    ASSERT_FALSE(secondLayer->m_isDrawing);
+
+    // nothing changes
+    ASSERT_TRUE(drawGL(manager, 0));
+
+    ////////// FIRST FINISHES PAINTING, SWAP THE TREES
+
+    firstLayer->m_isDonePainting = true;
+    bool swapped = false;
+    ASSERT_TRUE(drawGL(manager, &swapped));
+    ASSERT_TRUE(swapped);
+
+    // first is drawing
+    ASSERT_EQ(firstLayer->m_drawCount, 1);
+    ASSERT_FALSE(firstLayer->m_isPainting);
+    ASSERT_TRUE(firstLayer->m_isDrawing);
+    ASSERT_EQ(firstLayer->getRefCnt(), 2);
+
+    // second is painting (and hasn't drawn)
+    ASSERT_EQ(secondLayer->m_drawCount, 0);
+    ASSERT_TRUE(secondLayer->m_isPainting);
+    ASSERT_FALSE(secondLayer->m_isDrawing);
+    ASSERT_EQ(secondLayer->getRefCnt(), 2);
+
+    ////////// SECOND FINISHES PAINTING, SWAP AGAIN
+
+    secondLayer->m_isDonePainting = true;
+
+    // draw again, swap, first should be deleted
+    swapped = false;
+    ASSERT_FALSE(drawGL(manager, &swapped)); // no painting layer
+    ASSERT_TRUE(swapped);
+
+    // first layer gone!
+    ASSERT_EQ(firstLayer->getRefCnt(), 1);
+    SkSafeUnref(firstLayer);
+
+    // second is drawing
+    ASSERT_EQ(secondLayer->m_drawCount, 1);
+    ASSERT_FALSE(secondLayer->m_isPainting);
+    ASSERT_TRUE(secondLayer->m_isDrawing);
+    ASSERT_EQ(secondLayer->getRefCnt(), 2);
+
+     ////////// INSERT NULL, BOTH TREES NOW REMOVED
+
+    // insert null tree, which should deref secondLayer immediately
+    manager.updateWithTree(0, false);
+    ASSERT_EQ(secondLayer->getRefCnt(), 1);
+    SkSafeUnref(secondLayer);
+
+    // nothing to draw or swap
+    swapped = false;
+    ASSERT_FALSE(drawGL(manager, &swapped));
+    ASSERT_FALSE(swapped);
+}
+
+TEST_F(TreeManagerTest, LayerAndroidTree_PictureRefCount) {
+    RenderLayer* renderLayer = 0;
+    LayerAndroid* l;
+    SkPicture* p;
+    allocLayerWithPicture(false, &l, &p);
+    ASSERT_TRUE(l->needsTexture());
+    SkSafeRef(p); // ref picture locally so it exists after layer (so we can see
+                  // layer derefs it)
+
+    ASSERT_EQ(l->getRefCnt(), 1);
+    ASSERT_EQ(p->getRefCnt(), 2);
+    SkSafeUnref(l);
+
+    ASSERT_EQ(p->getRefCnt(), 1);
+    SkSafeUnref(p);
+}
+
+TEST_F(TreeManagerTest, LayerAndroidTree_PaintTreeWithPictures) {
+    XLOGC("STARTING PAINT TEST");
+
+    TreeManager manager;
+    RenderLayer* renderLayer = 0;
+    LayerAndroid root(renderLayer);
+    LayerAndroid* noPaintChild = new LayerAndroid(renderLayer);
+    root.addChild(noPaintChild);
+
+    root.showLayer(0);
+
+    ASSERT_EQ(noPaintChild->getRefCnt(), 2);
+
+
+    LayerAndroid* copy = new LayerAndroid(root);
+    copy->showLayer(0);
+    manager.updateWithTree(copy, true);
+
+
+    // no painting layer, should swap immediately
+    bool swapped = false;
+    ASSERT_FALSE(drawGL(manager, &swapped));
+    ASSERT_TRUE(swapped);
+
+
+     ////////// add 2 painting layers, push new tree copy into tree manager
+
+    LayerAndroid* paintChildA;
+    allocLayerWithPicture(true, &paintChildA, 0);
+    noPaintChild->addChild(paintChildA);
+    ASSERT_TRUE(paintChildA->needsTexture());
+
+    LayerAndroid* paintChildB;
+    allocLayerWithPicture(true, &paintChildB, 0);
+    noPaintChild->addChild(paintChildB);
+    ASSERT_TRUE(paintChildB->needsTexture());
+
+    LayerAndroid* copy1 = new LayerAndroid(root);
+    copy1->showLayer(0);
+    manager.updateWithTree(copy1, false);
+
+    swapped = false;
+    ASSERT_TRUE(drawGL(manager, &swapped));
+    ASSERT_FALSE(swapped); // painting layers not ready
+
+    ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 2);
+
+    ////////// remove painting layer, add new painting layer, push new tree copy into tree manager
+
+    LayerAndroid* paintChildC;
+    allocLayerWithPicture(true, &paintChildC, 0);
+    noPaintChild->addChild(paintChildC);
+    ASSERT_TRUE(paintChildC->needsTexture());
+
+    paintChildB->detachFromParent();
+    ASSERT_EQ(paintChildB->getRefCnt(), 1);
+    SkSafeUnref(paintChildB);
+
+    LayerAndroid* copy2 = new LayerAndroid(root);
+    copy2->showLayer(0);
+    manager.updateWithTree(copy2, false);
+
+    swapped = false;
+    ASSERT_TRUE(drawGL(manager, &swapped));
+    ASSERT_FALSE(swapped); // painting layers not ready
+
+
+    ////////// swap layers
+
+    static_cast<TestLayerAndroid*>(copy1->getChild(0)->getChild(0))->m_isDonePainting = true;
+    static_cast<TestLayerAndroid*>(copy1->getChild(0)->getChild(1))->m_isDonePainting = true;
+
+    XLOGC("painting should be %p, queued %p", copy1, copy2);
+    swapped = false;
+    ASSERT_TRUE(drawGL(manager, &swapped));
+    ASSERT_TRUE(swapped); // paint complete, new layer tree to paint
+    XLOGC("drawing should be %p, painting %p", copy1, copy2);
+
+
+    ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 3);
+
+
+    ////////// swap layers again
+
+    static_cast<TestLayerAndroid*>(copy2->getChild(0)->getChild(0))->m_isDonePainting = true;
+    static_cast<TestLayerAndroid*>(copy2->getChild(0)->getChild(1))->m_isDonePainting = true;
+
+    swapped = false;
+    ASSERT_FALSE(drawGL(manager, &swapped));
+    ASSERT_TRUE(swapped); // paint complete, no new layer tree to paint
+
+    ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 2);
+
+    ////////// remove all painting layers
+
+    paintChildA->detachFromParent();
+    SkSafeUnref(paintChildA);
+    paintChildC->detachFromParent();
+    SkSafeUnref(paintChildC);
+
+
+    copy = new LayerAndroid(root);
+    copy->showLayer(0);
+    manager.updateWithTree(copy, false);
+
+    swapped = false;
+    ASSERT_FALSE(drawGL(manager, &swapped));
+    ASSERT_TRUE(swapped); // paint complete, no new layer tree to paint
+
+    ASSERT_EQ(TreeManager::getTotalPaintedSurfaceCount(), 0);
+}
+
+} // namespace WebCore