OSDN Git Service

Track all tiles in the viewport instead of only the upper left tile.
authorDerek Sollenberger <djsollen@google.com>
Thu, 11 Nov 2010 20:22:47 +0000 (15:22 -0500)
committerDerek Sollenberger <djsollen@google.com>
Fri, 12 Nov 2010 16:32:31 +0000 (11:32 -0500)
We currently store only the coordinates of the upper left tile and
leave it to the caller to compute the actual number of tiles in the
viewport. This CL computes that information upfront and then passes
a rect containing the tiles in the viewport to the necessary parties.

This also allows us to intelligently prepare tiles that are currently
off-screen but given the user's scroll direction will be on-screen
shortly.

bug: 3190926

Change-Id: I50a5922ed8bc7e8fd8e4cacd4986a9f275cd37b0

WebCore/platform/graphics/android/BaseLayerAndroid.cpp
WebCore/platform/graphics/android/GLWebViewState.cpp
WebCore/platform/graphics/android/GLWebViewState.h
WebCore/platform/graphics/android/TiledPage.cpp
WebCore/platform/graphics/android/TiledPage.h

index c7420c8..9e090a6 100644 (file)
@@ -92,6 +92,7 @@ void BaseLayerAndroid::setContent(const PictureSet& src)
     android::Mutex::Autolock lock(m_drawLock);
 #endif
     m_content.set(src);
+    setSize(src.width(), src.height());
 }
 
 void BaseLayerAndroid::drawCanvas(SkCanvas* canvas)
@@ -117,14 +118,12 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale)
 
     m_glWebViewState->setViewport(viewport, scale);
 
-    int firstTileX = m_glWebViewState->firstTileX();
-    int firstTileY = m_glWebViewState->firstTileY();
+    const SkIRect& viewportTileBounds = m_glWebViewState->viewportTileBounds();
+    XLOG("drawBasePicture, TX: %d, TY: %d scale %.2f", viewportTileBounds.fLeft,
+            viewportTileBounds.fTop, scale);
 
-    XLOG("drawBasePicture, TX: %d, TY: %d scale %.2f", firstTileX, firstTileY, scale);
-    if (scale == m_glWebViewState->currentScale()) {
-        m_glWebViewState->setOriginalTilesPosX(firstTileX);
-        m_glWebViewState->setOriginalTilesPosY(firstTileY);
-    }
+    if (scale == m_glWebViewState->currentScale())
+        m_glWebViewState->setPreZoomBounds(viewportTileBounds);
 
     // If we have a different scale than the current one, we have to
     // decide what to do. The current behaviour is to delay an update,
@@ -148,7 +147,7 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale)
 
         // Check if the page is ready...
         if (m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale
-            && nextTiledPage->ready(firstTileX, firstTileY)) {
+            && nextTiledPage->ready(viewportTileBounds)) {
             m_glWebViewState->setScaleRequestState(GLWebViewState::kReceivedNewScale);
         }
 
@@ -162,8 +161,7 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale)
             if (scale < m_glWebViewState->currentScale())
                 newTilesTransparency = 1 - transparency;
 
-            nextTiledPage->draw(newTilesTransparency, viewport,
-                                firstTileX, firstTileY);
+            nextTiledPage->draw(newTilesTransparency, viewport, viewportTileBounds);
 
             // The transition between the two pages is finished, swap them
             if (currentTime > transitionTime) {
@@ -173,21 +171,20 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale)
             }
         } else {
             // If the page is not ready, schedule it if needed.
-            nextTiledPage->prepare(goingDown, goingLeft, firstTileX, firstTileY);
+            nextTiledPage->prepare(goingDown, goingLeft, viewportTileBounds);
         }
     }
 
     // Display the current page
     TiledPage* tiledPage = m_glWebViewState->frontPage();
     tiledPage->setScale(m_glWebViewState->currentScale());
-    int originalTX = m_glWebViewState->originalTilesPosX();
-    int originalTY = m_glWebViewState->originalTilesPosY();
-    tiledPage->prepare(goingDown, goingLeft, originalTX, originalTY);
-    tiledPage->draw(transparency, viewport, originalTX, originalTY);
+    const SkIRect& preZoomBounds = m_glWebViewState->preZoomBounds();
+    tiledPage->prepare(goingDown, goingLeft, preZoomBounds);
+    tiledPage->draw(transparency, viewport, preZoomBounds);
 
     bool ret = false;
     if (m_glWebViewState->scaleRequestState() != GLWebViewState::kNoScaleRequest
-        || !tiledPage->ready(originalTX, originalTY))
+        || !tiledPage->ready(preZoomBounds))
       ret = true;
 
     if (doSwap)
index 617690c..bcb5cbf 100644 (file)
@@ -69,12 +69,6 @@ GLWebViewState::GLWebViewState()
     , m_futureScale(1)
     , m_updateTime(-1)
     , m_transitionTime(-1)
-    , m_originalTilesPosX(0)
-    , m_originalTilesPosY(0)
-    , m_nbTilesWidth(0)
-    , m_nbTilesHeight(0)
-    , m_firstTileX(0)
-    , m_firstTileY(0)
     , m_baseLayer(0)
     , m_currentPictureCounter(0)
     , m_usePageA(true)
@@ -211,24 +205,35 @@ void GLWebViewState::swapPages()
     m_scaleRequestState = kNoScaleRequest;
 }
 
+int GLWebViewState::baseContentWidth()
+{
+    return m_baseLayer ? m_baseLayer->getWidth() : 0;
+
+}
+int GLWebViewState::baseContentHeight()
+{
+    return m_baseLayer ? m_baseLayer->getHeight() : 0;
+}
+
 void GLWebViewState::setViewport(SkRect& viewport, float scale)
 {
     if (m_viewport == viewport)
         return;
 
     m_viewport = viewport;
-    float fnbw = m_viewport.width() * scale / TilesManager::tileWidth();
-    int nbw = static_cast<int>(ceilf(fnbw));
-    float fnbh = m_viewport.height() * scale / TilesManager::tileHeight();
-    int nbh = static_cast<int>(ceilf(fnbh));
-    m_nbTilesWidth = nbw + 1;
-    m_nbTilesHeight = nbh + 1;
     XLOG("New VIEWPORT %.2f - %.2f %.2f - %.2f (w: %2.f h: %.2f scale: %.2f), nbw: %d nbh: %d",
          m_viewport.fLeft, m_viewport.fTop, m_viewport.fRight, m_viewport.fBottom,
          m_viewport.width(), m_viewport.height(), scale,
          m_nbTilesWidth, m_nbTilesHeight);
-    m_firstTileX = static_cast<int>(m_viewport.fLeft * scale / TilesManager::tileWidth());
-    m_firstTileY = static_cast<int>(m_viewport.fTop * scale / TilesManager::tileHeight());
+
+    const float invTileContentWidth = scale / TilesManager::tileWidth();
+    const float invTileContentHeight = scale / TilesManager::tileHeight();
+
+    m_viewportTileBounds.set(
+            static_cast<int>(floorf(viewport.fLeft * invTileContentWidth)),
+            static_cast<int>(floorf(viewport.fTop * invTileContentHeight)),
+            static_cast<int>(ceilf(viewport.fRight * invTileContentWidth)),
+            static_cast<int>(ceilf(viewport.fBottom * invTileContentHeight)));
 }
 
 } // namespace WebCore
index 3eaabb3..526061e 100644 (file)
@@ -165,10 +165,6 @@ public:
     double transitionTime(double currentTime);
     float transparency(double currentTime);
     void resetTransitionTime() { m_transitionTime = -1; }
-    int originalTilesPosX() const { return m_originalTilesPosX; }
-    void setOriginalTilesPosX(int pos) { m_originalTilesPosX = pos; }
-    int originalTilesPosY() const { return m_originalTilesPosY; }
-    void setOriginalTilesPosY(int pos) { m_originalTilesPosY = pos; }
 
     unsigned int paintBaseLayerContent(SkCanvas* canvas);
     void setBaseLayer(BaseLayerAndroid* layer, IntRect& rect);
@@ -181,14 +177,17 @@ public:
     TiledPage* backPage();
     void swapPages();
 
-    void setViewport(SkRect& viewport, float scale);
+    // dimensions of the current base layer
+    int baseContentWidth();
+    int baseContentHeight();
 
-    // returns the number of tiles needed to cover the viewport
-    int nbTilesWidth() const { return m_nbTilesWidth; }
-    int nbTilesHeight() const { return m_nbTilesHeight; }
+    void setViewport(SkRect& viewport, float scale);
 
-    int firstTileX() const { return m_firstTileX; }
-    int firstTileY() const { return m_firstTileY; }
+    // a rect containing the coordinates of all tiles in the current viewport
+    const SkIRect& viewportTileBounds() const { return m_viewportTileBounds; }
+    // a rect containing the viewportTileBounds before there was a scale change
+    const SkIRect& preZoomBounds() const { return m_preZoomBounds; }
+    void setPreZoomBounds(const SkIRect& bounds) { m_preZoomBounds = bounds; }
 
     unsigned int currentPictureCounter() const { return m_currentPictureCounter; }
 
@@ -210,14 +209,10 @@ private:
     float m_futureScale;
     double m_updateTime;
     double m_transitionTime;
-    int m_originalTilesPosX;
-    int m_originalTilesPosY;
     android::Mutex m_tiledPageLock;
     SkRect m_viewport;
-    int m_nbTilesWidth;
-    int m_nbTilesHeight;
-    int m_firstTileX;
-    int m_firstTileY;
+    SkIRect m_viewportTileBounds;
+    SkIRect m_preZoomBounds;
     android::Mutex m_baseLayerLock;
     BaseLayerAndroid* m_baseLayer;
     unsigned int m_currentPictureCounter;
index eb500ac..295c849 100644 (file)
@@ -130,13 +130,13 @@ void TiledPage::prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y
     for (int i = 0; i < tilesInRow; i++) {
         int x = firstTileX;
 
-        // If we are goingLeft, we want to schedule the tiles
-        // starting from the left (and to the right if not)
+        // If we are goingLeft, we want to schedule the tiles starting from the
+        // right (and to the left if not). This is because tiles are appended to
+        // the list and the texture uploader goes through the set front to back.
         if (goingLeft)
-          x += i;
+            x += (tilesInRow - 1) - i;
         else
-          x += (tilesInRow - 1) - i;
-
+            x += i;
 
         BaseTile* currentTile = 0;
         BaseTile* availableTile = 0;
@@ -165,13 +165,16 @@ void TiledPage::prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y
     }
 }
 
-void TiledPage::updateTileState(int firstTileX, int firstTileY)
+void TiledPage::updateTileState(const SkIRect& tileBounds)
 {
-    if (!m_glWebViewState)
+    if (!m_glWebViewState || tileBounds.isEmpty())
         return;
 
-    const int nbTilesWidth = m_glWebViewState->nbTilesWidth();
-    const int nbTilesHeight = m_glWebViewState->nbTilesHeight();
+    const int nbTilesWidth = tileBounds.width();
+    const int nbTilesHeight = tileBounds.height();
+
+    const int lastTileX = tileBounds.fRight - 1;
+    const int lastTileY = tileBounds.fBottom - 1;
 
     for (int x = 0; x < m_baseTileSize; x++) {
 
@@ -189,15 +192,15 @@ void TiledPage::updateTileState(int firstTileX, int firstTileY)
         int dx = 0;
         int dy = 0;
 
-        if (firstTileX > tile.x())
-            dx = firstTileX - tile.x();
-        else if (firstTileX + (nbTilesWidth - 1) < tile.x())
-            dx = tile.x() - firstTileX - (nbTilesWidth - 1);
+        if (tileBounds.fLeft > tile.x())
+            dx = tileBounds.fLeft - tile.x();
+        else if (lastTileX < tile.x())
+            dx = tile.x() - lastTileX;
 
-        if (firstTileY > tile.y())
-            dy = firstTileY - tile.y();
-        else if (firstTileY + (nbTilesHeight - 1) < tile.y())
-            dy = tile.y() - firstTileY - (nbTilesHeight - 1);
+        if (tileBounds.fTop > tile.y())
+            dy = tileBounds.fTop - tile.y();
+        else if (lastTileY < tile.y())
+            dy = tile.y() - lastTileY;
 
         int d = std::max(dx, dy);
 
@@ -210,27 +213,60 @@ void TiledPage::updateTileState(int firstTileX, int firstTileY)
     m_invalRegion.setEmpty();
 }
 
-void TiledPage::prepare(bool goingDown, bool goingLeft, int firstTileX, int firstTileY)
+void TiledPage::prepare(bool goingDown, bool goingLeft, const SkIRect& tileBounds)
 {
     if (!m_glWebViewState)
         return;
 
     // update the tiles distance from the viewport
-    updateTileState(firstTileX, firstTileY);
+    updateTileState(tileBounds);
+
+    int firstTileX = tileBounds.fLeft;
+    int firstTileY = tileBounds.fTop;
+    int nbTilesWidth = tileBounds.width();
+    int nbTilesHeight = tileBounds.height();
 
-    int nbTilesWidth = m_glWebViewState->nbTilesWidth();
-    int nbTilesHeight = m_glWebViewState->nbTilesHeight();
+    const int lastTileX = tileBounds.fRight - 1;
+    const int lastTileY = tileBounds.fBottom - 1;
+
+    const int baseContentHeight = m_glWebViewState->baseContentHeight();
+    const int baseContentWidth = m_glWebViewState->baseContentWidth();
 
     TileSet* highResSet = new TileSet(this, nbTilesHeight, nbTilesWidth);
 
-    // We chose to display tiles depending on the scroll direction:
+    // PREPARE OFF-SCREEN TILES FOR SMOOTHER SCROLLING
+    // if you are going down and you are not already at the bottom of the page
+    // go ahead and prepare the tiles just off-screen beneath the viewport.
+    if (goingDown && baseContentHeight > lastTileY * TilesManager::tileHeight())
+        nbTilesHeight++;
+    // if you are going up and you are not already at the top of the page go
+    // ahead and prepare the tiles just off-screen above the viewport.
+    else if (!goingDown && firstTileY > 0) {
+        firstTileY--;
+        nbTilesHeight++;
+    }
+    // if you are going right and you are not already at the edge of the page go
+    // ahead and prepare the tiles just off-screen to the right of the viewport.
+    if (!goingLeft && baseContentWidth > lastTileX * TilesManager::tileWidth())
+        nbTilesWidth++;
+    // if you are going left and you are not already at the edge of the page go
+    // ahead and prepare the tiles just off-screen to the left of the viewport.
+    else if (goingLeft && firstTileX > 0) {
+        firstTileX--;
+        nbTilesWidth++;
+    }
+
+
+    // We chose to prepare tiles depending on the scroll direction. Tiles are
+    // appended to the list and the texture uploader goes through the list front
+    // to back. So we append tiles in reverse order because the last additions
+    // to the are processed first.
     if (goingDown) {
         for (int i = 0; i < nbTilesHeight; i++)
-            prepareRow(goingLeft, nbTilesWidth, firstTileX, firstTileY + i, highResSet);
+            prepareRow(goingLeft, nbTilesWidth, firstTileX, lastTileY - i, highResSet);
     } else {
-        int startingTileY = firstTileY + (nbTilesHeight - 1);
         for (int i = 0; i < nbTilesHeight; i++)
-            prepareRow(goingLeft, nbTilesWidth, firstTileX, startingTileY - i, highResSet);
+            prepareRow(goingLeft, nbTilesWidth, firstTileX, firstTileY + i, highResSet);
     }
 
     // schedulePaintForTileSet will take ownership of the highResSet here,
@@ -238,18 +274,13 @@ void TiledPage::prepare(bool goingDown, bool goingLeft, int firstTileX, int firs
     TilesManager::instance()->schedulePaintForTileSet(highResSet);
 }
 
-bool TiledPage::ready(int firstTileX, int firstTileY)
+bool TiledPage::ready(const SkIRect& tileBounds)
 {
     if (!m_glWebViewState)
         return false;
 
-    int nbTilesWidth = m_glWebViewState->nbTilesWidth();
-    int nbTilesHeight = m_glWebViewState->nbTilesHeight();
-
-    for (int i = 0; i < nbTilesHeight; i++) {
-        for (int j = 0; j < nbTilesWidth; j++) {
-            int x = j + firstTileX;
-            int y = i + firstTileY;
+    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;
@@ -258,7 +289,7 @@ bool TiledPage::ready(int firstTileX, int firstTileY)
     return true;
 }
 
-void TiledPage::draw(float transparency, SkRect& viewport, int firstTileX, int firstTileY)
+void TiledPage::draw(float transparency, SkRect& viewport, const SkIRect& tileBounds)
 {
     if (!m_glWebViewState)
         return;
@@ -266,16 +297,10 @@ void TiledPage::draw(float transparency, SkRect& viewport, int firstTileX, int f
     const float tileWidth = TilesManager::tileWidth() * m_invScale;
     const float tileHeight = TilesManager::tileHeight() * m_invScale;
 
-    SkIRect viewportTilesRect;
-    viewportTilesRect.fLeft = firstTileX;
-    viewportTilesRect.fTop = firstTileY;
-    viewportTilesRect.fRight = firstTileY + m_glWebViewState->nbTilesWidth() + 1;
-    viewportTilesRect.fBottom = firstTileY + m_glWebViewState->nbTilesHeight() + 1;
-
     XLOG("WE DRAW %x (%.2f) with transparency %.2f", this, scale(), transparency);
     for (int j = 0; j < m_baseTileSize; j++) {
         BaseTile& tile = m_baseTiles[j];
-        if(viewportTilesRect.contains(tile.x(), tile.y())) {
+        if(tileBounds.contains(tile.x(), tile.y())) {
 
             SkRect rect;
             rect.fLeft = tile.x() * tileWidth;
index 1edf5b4..fa310bf 100644 (file)
@@ -60,11 +60,11 @@ public:
     TiledPage* sibling();
 
     // prepare the page for display on the screen
-    void prepare(bool goingDown, bool goingLeft, int firstTileX, int firstTileY);
+    void prepare(bool goingDown, bool goingLeft, const SkIRect& tileBounds);
     // check to see if the page is ready for display
-    bool ready(int firstTileX, int firstTileY);
+    bool ready(const SkIRect& tileBounds);
     // draw the page on the screen
-    void draw(float transparency, SkRect& viewport, int firstTileX, int firstTileY);
+    void draw(float transparency, SkRect& viewport, const SkIRect& tileBounds);
 
     // used by individual tiles to generate the bitmap for their tile
     unsigned int paintBaseLayerContent(SkCanvas*);
@@ -77,7 +77,7 @@ public:
     void invalidateRect(const IntRect& invalRect, const unsigned int pictureCount);
 
 private:
-    void updateTileState(int firstTileX, int firstTileY);
+    void updateTileState(const SkIRect& tileBounds);
     void prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y, TileSet* set);
 
     BaseTile* getBaseTile(int x, int y) const;