X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=Source%2FWebCore%2Fplatform%2Fgraphics%2Fandroid%2FTiledTexture.cpp;h=91d689701585c70af1aca0f9b1a84f11b67abf83;hb=60082004bd7975748f8b0bee91645de245f1ea94;hp=c1fb4d1153b43280ea133b20d3b5221a2956a2cc;hpb=cbc4e72fe1d9522411cacae1f71b443229865e7b;p=android-x86%2Fexternal-webkit.git diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.cpp b/Source/WebCore/platform/graphics/android/TiledTexture.cpp index c1fb4d115..91d689701 100644 --- a/Source/WebCore/platform/graphics/android/TiledTexture.cpp +++ b/Source/WebCore/platform/graphics/android/TiledTexture.cpp @@ -32,13 +32,17 @@ #include "PaintedSurface.h" #include "PaintTileOperation.h" #include "SkCanvas.h" - -#ifdef DEBUG +#include "SkPicture.h" #include #include #include +#undef XLOGC +#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "TiledTexture", __VA_ARGS__) + +#ifdef DEBUG + #undef XLOG #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "TiledTexture", __VA_ARGS__) @@ -51,46 +55,92 @@ namespace WebCore { -void TiledTexture::prepare(GLWebViewState* state, bool repaint) +TiledTexture::~TiledTexture() { - if (!m_surface) - return; - - if (!m_surface->layer()) - return; - - // first, how many tiles do we need - IntRect visibleArea = m_surface->visibleArea(); - IntRect area(visibleArea.x() * m_surface->scale(), - visibleArea.y() * m_surface->scale(), - ceilf(visibleArea.width() * m_surface->scale()), - ceilf(visibleArea.height() * m_surface->scale())); + 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++) { BaseTile* tile = m_tiles[i]; - if (!m_dirtyRegion.isEmpty()) - tile->markAsDirty(1, m_dirtyRegion); + if (tile->isTileVisible(m_area)) { + tilesVisible = true; + if (!tile->isTileReady()) { + tilesAllReady = false; + break; + } + } } - m_dirtyRegion.setEmpty(); + // For now, if no textures are available, consider ourselves as 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; + IntRect area(visibleArea.x() * scale, + visibleArea.y() * 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) { - m_area.setWidth(0); - m_area.setHeight(0); - return; + computedArea.setWidth(0); + computedArea.setHeight(0); + return computedArea; } int tileWidth = TilesManager::instance()->layerTileWidth(); int tileHeight = TilesManager::instance()->layerTileHeight(); - m_area.setX(area.x() / tileWidth); - m_area.setY(area.y() / tileHeight); + computedArea.setX(area.x() / tileWidth); + computedArea.setY(area.y() / tileHeight); float right = (area.x() + area.width()) / (float) tileWidth; float bottom = (area.y() + area.height()) / (float) tileHeight; - m_area.setWidth(ceilf(right) - m_area.x()); - m_area.setHeight(ceilf(bottom) - m_area.y()); + computedArea.setWidth(ceilf(right) - computedArea.x()); + computedArea.setHeight(ceilf(bottom) - computedArea.y()); + return computedArea; +} + +void TiledTexture::prepare(GLWebViewState* state, float scale, bool repaint, + bool startFastSwap, IntRect& visibleArea) +{ + if (!m_surface) + return; + + // first, how many tiles do we need + m_area = computeTilesArea(visibleArea, scale); + if (m_area.isEmpty()) + return; - XLOG("for TiledTexture %x, we have a visible area of %d, %d - %d x %d, corresponding to %d, %d x - %d x %d tiles", - this, + XLOG("for TiledTexture %p, we prepare with scale %.2f, have a visible area of " + " %d, %d - %d x %d, corresponding to %d, %d x - %d x %d tiles", + this, scale, visibleArea.x(), visibleArea.y(), visibleArea.width(), visibleArea.height(), m_area.x(), m_area.y(), @@ -99,10 +149,19 @@ void TiledTexture::prepare(GLWebViewState* state, bool repaint) bool goingDown = m_prevTileY < m_area.y(); m_prevTileY = m_area.y(); - if (m_surface->scale() != m_prevScale) - TilesManager::instance()->removeOperationsForFilter(new ScaleFilter(m_surface->scale())); + if (scale != m_scale) + TilesManager::instance()->removeOperationsForFilter(new ScaleFilter(this, scale)); + + m_scale = scale; - m_prevScale = m_surface->scale(); + // apply dirty region to affected tiles + if (!m_dirtyRegion.isEmpty()) { + for (unsigned int i = 0; i < m_tiles.size(); i++) { + // TODO: don't mark all tiles dirty + m_tiles[i]->markAsDirty(1, m_dirtyRegion); + } + } + m_dirtyRegion.setEmpty(); for (int i = 0; i < m_area.width(); i++) { if (goingDown) { @@ -117,9 +176,16 @@ void TiledTexture::prepare(GLWebViewState* state, bool repaint) } } -void TiledTexture::markAsDirty(const SkRegion& dirtyArea) +void TiledTexture::update(const SkRegion& invalRegion, SkPicture* picture) { - m_dirtyRegion.op(dirtyArea, SkRegion::kUnion_Op); + 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) @@ -130,15 +196,16 @@ void TiledTexture::prepareTile(bool repaint, int x, int y) m_tiles.append(tile); } - tile->setContents(this, x, y, m_surface->scale()); + 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 // prepare() function 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); } @@ -154,78 +221,80 @@ BaseTile* TiledTexture::getTile(int x, int y) return 0; } +int TiledTexture::nbTextures(IntRect& area, float scale) +{ + IntRect computedTilesArea = computeTilesArea(area, scale); + return computedTilesArea.width() * computedTilesArea.height(); +} + bool TiledTexture::draw() { + XLOG("TT %p draw", this); + #ifdef DEBUG TilesManager::instance()->getTilesTracker()->trackLayer(); #endif - bool askRedraw = false; if (m_area.width() == 0 || m_area.height() == 0) - return askRedraw; + return false; #ifdef DEBUG TilesManager::instance()->getTilesTracker()->trackVisibleLayer(); #endif - float m_invScale = 1 / m_surface->scale(); + float m_invScale = 1 / m_scale; const float tileWidth = TilesManager::layerTileWidth() * m_invScale; const float tileHeight = TilesManager::layerTileHeight() * m_invScale; - XLOG("draw tile %x, tiles %d", this, m_tiles.size()); - for (unsigned int i = 0; i x() >= m_area.x() - && tile->x() < m_area.x() + m_area.width() - && tile->y() >= m_area.y() - && tile->y() < m_area.y() + m_area.height()) { + + if (tile->isTileVisible(m_area)) { + askRedraw |= !tile->isTileReady(); SkRect rect; rect.fLeft = tile->x() * tileWidth; 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 [ready: %d] dirty: %d", - i, this, tile->painter(), tile, tile->x(), tile->y(), tile->scale(), tile->isTileReady(), tile->isDirty()); - askRedraw |= !tile->isTileReady(); - tile->swapTexturesIfNeeded(); - tile->draw(m_surface->opacity(), rect, m_surface->scale()); + 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); #ifdef DEBUG TilesManager::instance()->getTilesTracker()->track(tile->isTileReady(), tile->backTexture()); #endif } } + + // need to redraw if some visible tile wasn't ready return askRedraw; } bool TiledTexture::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed) { - if (!m_surface) + 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("painting scheduled tile(%x : %d, %d, %.2f, %x) for %x", - tile, tile->x(), tile->y(), tile->scale(), tile->painter(), this); - return m_surface->paint(tile, canvas, pictureUsed); -} + XLOG("TT %p painting with picture %p", this, picture); -void TiledTexture::paintExtra(SkCanvas* canvas) -{ - m_surface->paintExtra(canvas); -} + canvas->drawPicture(*picture); -const TransformationMatrix* TiledTexture::transform() -{ - return m_surface->transform(); -} + SkSafeUnref(picture); -void TiledTexture::beginPaint() -{ - if (m_surface) - m_surface->beginPaint(); + return true; } -void TiledTexture::endPaint() +const TransformationMatrix* TiledTexture::transform() { - if (m_surface) - m_surface->endPaint(); + return m_surface->transform(); } void TiledTexture::removeTiles() @@ -233,6 +302,13 @@ void TiledTexture::removeTiles() for (unsigned int i = 0; i < m_tiles.size(); i++) { delete m_tiles[i]; } + m_tiles.clear(); +} + +void TiledTexture::discardTextures() +{ + for (unsigned int i = 0; i < m_tiles.size(); i++) + m_tiles[i]->discardTextures(); } bool TiledTexture::owns(BaseTileTexture* texture) @@ -247,4 +323,87 @@ bool TiledTexture::owns(BaseTileTexture* texture) return false; } +DualTiledTexture::DualTiledTexture(PaintedSurface* surface) +{ + m_textureA = new TiledTexture(surface); + m_textureB = new TiledTexture(surface); + m_frontTexture = m_textureA; + m_backTexture = m_textureB; + m_scale = -1; + m_futureScale = -1; + m_zooming = false; +} + +DualTiledTexture::~DualTiledTexture() +{ + delete m_textureA; + delete m_textureB; +} + +void DualTiledTexture::prepare(GLWebViewState* state, float scale, bool repaint, + bool startFastSwap, IntRect& visibleArea) +{ + // If we are zooming, we will use the previously used area, to prevent the + // frontTexture to try to allocate more tiles than what it has already + if (!m_zooming) + m_preZoomVisibleArea = visibleArea; + + if (m_futureScale != scale) { + m_futureScale = scale; + m_zoomUpdateTime = WTF::currentTime() + DualTiledTexture::s_zoomUpdateDelay; + m_zooming = true; + } + + 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); + + // If we had a scheduled update + if (m_zooming && m_zoomUpdateTime < WTF::currentTime()) { + m_backTexture->prepare(state, m_futureScale, repaint, startFastSwap, visibleArea); + if (m_backTexture->ready()) { + m_backTexture->swapTiles(); + swap(); + m_zooming = false; + } + } +} + +void DualTiledTexture::swap() +{ + m_frontTexture = m_frontTexture == m_textureA ? m_textureB : m_textureA; + m_backTexture = m_backTexture == m_textureA ? m_textureB : m_textureA; + m_scale = m_futureScale; + m_backTexture->discardTextures(); +} + +bool DualTiledTexture::draw() +{ + bool needsRepaint = m_frontTexture->draw(); + needsRepaint |= m_zooming; + needsRepaint |= (m_scale <= 0); + return needsRepaint; +} + +void DualTiledTexture::update(const SkRegion& dirtyArea, SkPicture* picture) +{ + m_backTexture->update(dirtyArea, 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); + owns |= m_textureB->owns(texture); + return owns; +} + } // namespace WebCore