diff options
Diffstat (limited to 'Source')
31 files changed, 1420 insertions, 738 deletions
diff --git a/Source/WebCore/Android.mk b/Source/WebCore/Android.mk index a516f48..6542931 100644 --- a/Source/WebCore/Android.mk +++ b/Source/WebCore/Android.mk @@ -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 \ diff --git a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp index 0e6f64f..8358b2a 100644 --- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp @@ -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(); diff --git a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h index 20942ec..c5ce52f 100644 --- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h @@ -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; }; diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp index fa22593..f000532 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp @@ -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(); diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.h b/Source/WebCore/platform/graphics/android/GLWebViewState.h index a1adaf1..5aa030b 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.h +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.h @@ -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 diff --git a/Source/WebCore/platform/graphics/android/ImageTexture.h b/Source/WebCore/platform/graphics/android/ImageTexture.h index 7f35f06..cea79c3 100644 --- a/Source/WebCore/platform/graphics/android/ImageTexture.h +++ b/Source/WebCore/platform/graphics/android/ImageTexture.h @@ -26,7 +26,6 @@ #ifndef ImageTexture_h #define ImageTexture_h -#include "ClassTracker.h" #include "GLUtils.h" #include "SkBitmap.h" #include "SkBitmapRef.h" diff --git a/Source/WebCore/platform/graphics/android/Layer.cpp b/Source/WebCore/platform/graphics/android/Layer.cpp index f650c52..9280461 100644 --- a/Source/WebCore/platform/graphics/android/Layer.cpp +++ b/Source/WebCore/platform/graphics/android/Layer.cpp @@ -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); +} diff --git a/Source/WebCore/platform/graphics/android/Layer.h b/Source/WebCore/platform/graphics/android/Layer.h index 89e101c..5200a3d 100644 --- a/Source/WebCore/platform/graphics/android/Layer.h +++ b/Source/WebCore/platform/graphics/android/Layer.h @@ -17,17 +17,24 @@ #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; }; diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp index 12a11bf..b86be99 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -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(); } } diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.h b/Source/WebCore/platform/graphics/android/LayerAndroid.h index b536b22..ae9dc88 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.h @@ -30,11 +30,9 @@ #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; diff --git a/Source/WebCore/platform/graphics/android/MediaLayer.cpp b/Source/WebCore/platform/graphics/android/MediaLayer.cpp index 0181892..12cfe38 100644 --- a/Source/WebCore/platform/graphics/android/MediaLayer.cpp +++ b/Source/WebCore/platform/graphics/android/MediaLayer.cpp @@ -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() diff --git a/Source/WebCore/platform/graphics/android/MediaLayer.h b/Source/WebCore/platform/graphics/android/MediaLayer.h index ef84abf..b94ec53 100644 --- a/Source/WebCore/platform/graphics/android/MediaLayer.h +++ b/Source/WebCore/platform/graphics/android/MediaLayer.h @@ -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; } diff --git a/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp b/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp index d9a729a..5d06ea3 100644 --- a/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp +++ b/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp @@ -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) diff --git a/Source/WebCore/platform/graphics/android/PaintTileOperation.h b/Source/WebCore/platform/graphics/android/PaintTileOperation.h index 65d20f2..fabc2f7 100644 --- a/Source/WebCore/platform/graphics/android/PaintTileOperation.h +++ b/Source/WebCore/platform/graphics/android/PaintTileOperation.h @@ -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 { diff --git a/Source/WebCore/platform/graphics/android/PaintedSurface.cpp b/Source/WebCore/platform/graphics/android/PaintedSurface.cpp index 939d106..d3c1e15 100644 --- a/Source/WebCore/platform/graphics/android/PaintedSurface.cpp +++ b/Source/WebCore/platform/graphics/android/PaintedSurface.cpp @@ -28,6 +28,7 @@ #include "LayerAndroid.h" +#include "TiledTexture.h" #include "TilesManager.h" #include "SkCanvas.h" #include "SkPicture.h" @@ -57,107 +58,64 @@ 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; diff --git a/Source/WebCore/platform/graphics/android/PaintedSurface.h b/Source/WebCore/platform/graphics/android/PaintedSurface.h index 83b2c9b..b438111 100644 --- a/Source/WebCore/platform/graphics/android/PaintedSurface.h +++ b/Source/WebCore/platform/graphics/android/PaintedSurface.h @@ -32,34 +32,37 @@ #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; diff --git a/Source/WebCore/platform/graphics/android/QueuedOperation.h b/Source/WebCore/platform/graphics/android/QueuedOperation.h index a2e49a7..1a83f65 100644 --- a/Source/WebCore/platform/graphics/android/QueuedOperation.h +++ b/Source/WebCore/platform/graphics/android/QueuedOperation.h @@ -26,10 +26,10 @@ #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 index 0000000..15d7cc3 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/TestExport.h @@ -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 diff --git a/Source/WebCore/platform/graphics/android/TiledPage.cpp b/Source/WebCore/platform/graphics/android/TiledPage.cpp index 3c262d4..e33d39a 100644 --- a/Source/WebCore/platform/graphics/android/TiledPage.cpp +++ b/Source/WebCore/platform/graphics/android/TiledPage.cpp @@ -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) diff --git a/Source/WebCore/platform/graphics/android/TiledPage.h b/Source/WebCore/platform/graphics/android/TiledPage.h index 960f3d5..791e1f6 100644 --- a/Source/WebCore/platform/graphics/android/TiledPage.h +++ b/Source/WebCore/platform/graphics/android/TiledPage.h @@ -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 diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.cpp b/Source/WebCore/platform/graphics/android/TiledTexture.cpp index e1e5ec9..5538e1b 100644 --- a/Source/WebCore/platform/graphics/android/TiledTexture.cpp +++ b/Source/WebCore/platform/graphics/android/TiledTexture.cpp @@ -32,6 +32,7 @@ #include "PaintedSurface.h" #include "PaintTileOperation.h" #include "SkCanvas.h" +#include "SkPicture.h" #include <cutils/log.h> #include <wtf/CurrentTime.h> @@ -54,7 +55,17 @@ 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); diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.h b/Source/WebCore/platform/graphics/android/TiledTexture.h index 5a47cd9..b761880 100644 --- a/Source/WebCore/platform/graphics/android/TiledTexture.h +++ b/Source/WebCore/platform/graphics/android/TiledTexture.h @@ -34,19 +34,18 @@ #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) { diff --git a/Source/WebCore/platform/graphics/android/TilesManager.cpp b/Source/WebCore/platform/graphics/android/TilesManager.cpp index acfe9e7..ca484ce 100644 --- a/Source/WebCore/platform/graphics/android/TilesManager.cpp +++ b/Source/WebCore/platform/graphics/android/TilesManager.cpp @@ -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); } } diff --git a/Source/WebCore/platform/graphics/android/TilesManager.h b/Source/WebCore/platform/graphics/android/TilesManager.h index 8ae9202..cc66f1a 100644 --- a/Source/WebCore/platform/graphics/android/TilesManager.h +++ b/Source/WebCore/platform/graphics/android/TilesManager.h @@ -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 index 0000000..4915f8b --- /dev/null +++ b/Source/WebCore/platform/graphics/android/TreeManager.cpp @@ -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 diff --git a/Source/WebCore/platform/graphics/android/UpdateManager.h b/Source/WebCore/platform/graphics/android/TreeManager.h index 6254184..09b1bd9 100644 --- a/Source/WebCore/platform/graphics/android/UpdateManager.h +++ b/Source/WebCore/platform/graphics/android/TreeManager.h @@ -23,65 +23,59 @@ * 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 index 1c20f1f..0000000 --- a/Source/WebCore/platform/graphics/android/UpdateManager.cpp +++ /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 diff --git a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp index 9576ed1..482d711 100644 --- a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp @@ -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(); } } diff --git a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h index abc1c13..8a064bb 100644 --- a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h @@ -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 index 0000000..c98a9a3 --- /dev/null +++ b/Source/WebCore/tests/Android.mk @@ -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 index 0000000..3837627 --- /dev/null +++ b/Source/WebCore/tests/TreeManager_test.cpp @@ -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 |