android::Mutex::Autolock lock(m_drawLock);
#endif
m_content.set(src);
+ setSize(src.width(), src.height());
}
void BaseLayerAndroid::drawCanvas(SkCanvas* canvas)
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,
// Check if the page is ready...
if (m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale
- && nextTiledPage->ready(firstTileX, firstTileY)) {
+ && nextTiledPage->ready(viewportTileBounds)) {
m_glWebViewState->setScaleRequestState(GLWebViewState::kReceivedNewScale);
}
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) {
}
} 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)
, 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)
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
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);
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; }
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;
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;
}
}
-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++) {
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);
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,
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;
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;
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;
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*);
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;