#include <wtf/CurrentTime.h>
#endif // USE(ACCELERATED_COMPOSITING)
-#ifdef DEBUG
-
#include <cutils/log.h>
#include <wtf/text/CString.h>
+#undef XLOGC
+#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "BaseLayerAndroid", __VA_ARGS__)
+
+#ifdef DEBUG
+
#undef XLOG
#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "BaseLayerAndroid", __VA_ARGS__)
#endif // DEBUG
+// TODO: dynamically determine based on DPI
+#define PREFETCH_SCALE_MODIFIER 0.3
+#define PREFETCH_OPACITY 1
+#define PREFETCH_X_DIST 1
+#define PREFETCH_Y_DIST 2
+
namespace WebCore {
using namespace android;
BaseLayerAndroid::BaseLayerAndroid()
#if USE(ACCELERATED_COMPOSITING)
- : m_glWebViewState(0),
- m_color(Color::white)
+ : m_glWebViewState(0)
+ , m_color(Color::white)
+ , m_scrollState(NotScrolling)
#endif
{
#ifdef DEBUG_COUNT
}
#if USE(ACCELERATED_COMPOSITING)
-bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, double currentTime)
+
+void BaseLayerAndroid::prefetchBasePicture(SkRect& viewport, float currentScale,
+ TiledPage* prefetchTiledPage)
{
- if (!m_glWebViewState)
- return false;
+ SkIRect bounds;
+ float prefetchScale = currentScale * PREFETCH_SCALE_MODIFIER;
+
+ float invTileWidth = (prefetchScale)
+ / TilesManager::instance()->tileWidth();
+ float invTileHeight = (prefetchScale)
+ / TilesManager::instance()->tileHeight();
+ bool goingDown = m_glWebViewState->goingDown();
+ bool goingLeft = m_glWebViewState->goingLeft();
+
+
+ XLOG("fetch rect %f %f %f %f, scale %f",
+ viewport.fLeft,
+ viewport.fTop,
+ viewport.fRight,
+ viewport.fBottom,
+ scale);
+
+ bounds.fLeft = static_cast<int>(floorf(viewport.fLeft * invTileWidth)) - PREFETCH_X_DIST;
+ bounds.fTop = static_cast<int>(floorf(viewport.fTop * invTileHeight)) - PREFETCH_Y_DIST;
+ bounds.fRight = static_cast<int>(ceilf(viewport.fRight * invTileWidth)) + PREFETCH_X_DIST;
+ bounds.fBottom = static_cast<int>(ceilf(viewport.fBottom * invTileHeight)) + PREFETCH_Y_DIST;
+
+ XLOG("prefetch rect %d %d %d %d, scale %f, preparing page %p",
+ bounds.fLeft, bounds.fTop,
+ bounds.fRight, bounds.fBottom,
+ scale * PREFETCH_SCALE,
+ prefetchTiledPage);
+
+ prefetchTiledPage->setScale(prefetchScale);
+ prefetchTiledPage->updateTileDirtiness(bounds);
+ prefetchTiledPage->prepare(goingDown, goingLeft, bounds,
+ TiledPage::ExpandedBounds);
+ prefetchTiledPage->swapBuffersIfReady(bounds,
+ prefetchScale,
+ TiledPage::SwapWhateverIsReady);
+ prefetchTiledPage->draw(PREFETCH_OPACITY, bounds);
+}
- bool goingDown = m_previousVisible.fTop - viewport.fTop <= 0;
- bool goingLeft = m_previousVisible.fLeft - viewport.fLeft >= 0;
+bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale,
+ double currentTime, bool* buffersSwappedPtr)
+{
+ ZoomManager* zoomManager = m_glWebViewState->zoomManager();
- m_glWebViewState->setViewport(viewport, scale);
+ bool goingDown = m_glWebViewState->goingDown();
+ bool goingLeft = m_glWebViewState->goingLeft();
const SkIRect& viewportTileBounds = m_glWebViewState->viewportTileBounds();
XLOG("drawBasePicture, TX: %d, TY: %d scale %.2f", viewportTileBounds.fLeft,
viewportTileBounds.fTop, scale);
- if (scale == m_glWebViewState->currentScale()
- || m_glWebViewState->preZoomBounds().isEmpty())
- m_glWebViewState->setPreZoomBounds(viewportTileBounds);
-
- bool prepareNextTiledPage = false;
- // 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,
- // so that we do not slow down zooming unnecessarily.
- if ((m_glWebViewState->currentScale() != scale && (m_glWebViewState->scaleRequestState() == GLWebViewState::kNoScaleRequest || m_glWebViewState->futureScale() != scale))
- || m_glWebViewState->scaleRequestState() == GLWebViewState::kWillScheduleRequest) {
-
- // schedule the new request
- m_glWebViewState->scheduleUpdate(currentTime, viewportTileBounds, scale);
-
- // If it's a new request, we will have to prepare the page.
- if (m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale)
- prepareNextTiledPage = true;
- }
-
- // If the viewport has changed since we scheduled the request, we also need to prepare.
- if ((m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale || m_glWebViewState->scaleRequestState() == GLWebViewState::kReceivedNewScale)
- && m_glWebViewState->futureViewport() != viewportTileBounds)
- prepareNextTiledPage = true;
-
- bool zooming = false;
- if (m_glWebViewState->scaleRequestState() != GLWebViewState::kNoScaleRequest) {
- prepareNextTiledPage = true;
- zooming = true;
- }
+ // Query the resulting state from the zoom manager
+ bool prepareNextTiledPage = zoomManager->needPrepareNextTiledPage();
// Display the current page
TiledPage* tiledPage = m_glWebViewState->frontPage();
- tiledPage->setScale(m_glWebViewState->currentScale());
+ TiledPage* nextTiledPage = m_glWebViewState->backPage();
+ tiledPage->setScale(zoomManager->currentScale());
- // Let's prepare the page if needed
+ // Let's prepare the page if needed so that it will start painting
if (prepareNextTiledPage) {
- TiledPage* nextTiledPage = m_glWebViewState->backPage();
nextTiledPage->setScale(scale);
m_glWebViewState->setFutureViewport(viewportTileBounds);
m_glWebViewState->lockBaseLayerUpdate();
- nextTiledPage->prepare(goingDown, goingLeft, viewportTileBounds);
+
+ // ignore dirtiness return value since while zooming we repaint regardless
+ nextTiledPage->updateTileDirtiness(viewportTileBounds);
+
+ nextTiledPage->prepare(goingDown, goingLeft, viewportTileBounds,
+ TiledPage::VisibleBounds);
// Cancel pending paints for the foreground page
TilesManager::instance()->removePaintOperationsForPage(tiledPage, false);
}
- float transparency = 1;
- bool doSwap = false;
-
// If we fired a request, let's check if it's ready to use
- if (m_glWebViewState->scaleRequestState() == GLWebViewState::kRequestNewScale) {
- TiledPage* nextTiledPage = m_glWebViewState->backPage();
- if (nextTiledPage->ready(viewportTileBounds, m_glWebViewState->futureScale()))
- m_glWebViewState->setScaleRequestState(GLWebViewState::kReceivedNewScale);
+ if (zoomManager->didFireRequest()) {
+ if (nextTiledPage->swapBuffersIfReady(viewportTileBounds,
+ zoomManager->futureScale(),
+ TiledPage::SwapWholePage))
+ zoomManager->setReceivedRequest(); // transition to received request state
}
+ float transparency = 1;
+ bool doZoomPageSwap = false;
+
// If the page is ready, display it. We do a short transition between
// the two pages (current one and future one with the new scale factor)
- if (m_glWebViewState->scaleRequestState() == GLWebViewState::kReceivedNewScale) {
- TiledPage* nextTiledPage = m_glWebViewState->backPage();
- double transitionTime = (scale < m_glWebViewState->currentScale()) ?
- m_glWebViewState->zoomOutTransitionTime(currentTime) :
- m_glWebViewState->zoomInTransitionTime(currentTime);
-
- float newTilesTransparency = 1;
- if (scale < m_glWebViewState->currentScale())
- newTilesTransparency = 1 - m_glWebViewState->zoomOutTransparency(currentTime);
- else
- transparency = m_glWebViewState->zoomInTransparency(currentTime);
+ if (zoomManager->didReceivedRequest()) {
+ float nextTiledPageTransparency = 1;
+ zoomManager->processTransition(currentTime, scale, &doZoomPageSwap,
+ &nextTiledPageTransparency, &transparency);
+ nextTiledPage->draw(nextTiledPageTransparency, viewportTileBounds);
+ }
- nextTiledPage->draw(newTilesTransparency, viewportTileBounds);
+ const SkIRect& preZoomBounds = m_glWebViewState->preZoomBounds();
- // The transition between the two pages is finished, swap them
- if (currentTime > transitionTime) {
- m_glWebViewState->resetTransitionTime();
- doSwap = true;
+ // 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();
+
+ // prefetch in the nextTiledPage if unused by zooming (even if not scrolling
+ // since we want the tiles to be ready before they're needed)
+ bool usePrefetchPage = !zooming;
+ nextTiledPage->setIsPrefetchPage(usePrefetchPage);
+ if (usePrefetchPage)
+ prefetchBasePicture(viewport, scale, nextTiledPage);
+
+ // 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 buffersSwapped = false;
+ if (!zooming) {
+ TiledPage::SwapMethod swapMethod;
+ if (scrolling)
+ swapMethod = TiledPage::SwapWhateverIsReady;
+ else
+ swapMethod = TiledPage::SwapWholePage;
+
+ buffersSwapped = tiledPage->swapBuffersIfReady(preZoomBounds,
+ zoomManager->currentScale(),
+ swapMethod);
+
+ if (buffersSwappedPtr && buffersSwapped)
+ *buffersSwappedPtr = true;
+ if (buffersSwapped) {
+ if (m_scrollState == ScrollingFinishPaint) {
+ m_scrollState = NotScrolling;
+ scrolling = false;
+ }
}
}
- const SkIRect& preZoomBounds = m_glWebViewState->preZoomBounds();
+ if (doZoomPageSwap) {
+ zoomManager->setCurrentScale(scale);
+ m_glWebViewState->swapPages();
+ if (buffersSwappedPtr)
+ *buffersSwappedPtr = true;
+ }
- TiledPage* nextTiledPage = m_glWebViewState->backPage();
- bool needsRedraw = false;
- // We are now using an hybrid model -- during scrolling,
- // we will display the current tiledPage even if some tiles are
- // out of date. When standing still on the other hand, we wait until
- // the back page is ready before swapping the pages, ensuring that the
- // displayed content is in sync.
- if (!doSwap && !zooming && !m_glWebViewState->moving()) {
- if (!tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale())) {
- m_glWebViewState->lockBaseLayerUpdate();
- nextTiledPage->setScale(m_glWebViewState->currentScale());
- nextTiledPage->prepare(goingDown, goingLeft, preZoomBounds);
- }
- if (nextTiledPage->ready(preZoomBounds, m_glWebViewState->currentScale())) {
- nextTiledPage->draw(transparency, preZoomBounds);
- m_glWebViewState->resetFrameworkInval();
- m_glWebViewState->unlockBaseLayerUpdate();
- doSwap = true;
- } else {
- tiledPage->draw(transparency, preZoomBounds);
- }
- } else {
- if (tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale()))
- m_glWebViewState->resetFrameworkInval();
+ bool needsRedraw = scrolling || zooming || !buffersSwapped;
- // Ask for the tiles and draw -- tiles may be out of date.
- if (!zooming)
- m_glWebViewState->unlockBaseLayerUpdate();
+ // if we don't expect to redraw, unlock the invals
+ if (!needsRedraw)
+ m_glWebViewState->unlockBaseLayerUpdate();
- if (!prepareNextTiledPage)
- tiledPage->prepare(goingDown, goingLeft, preZoomBounds);
- tiledPage->draw(transparency, preZoomBounds);
+ // 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);
}
- if (m_glWebViewState->scaleRequestState() != GLWebViewState::kNoScaleRequest
- || !tiledPage->ready(preZoomBounds, m_glWebViewState->currentScale()))
- needsRedraw = true;
+ XLOG("scrolling %d, zooming %d, buffersSwapped %d, needsRedraw %d",
+ scrolling, zooming, buffersSwapped, needsRedraw);
- if (doSwap) {
- m_glWebViewState->setCurrentScale(scale);
- m_glWebViewState->swapPages();
- m_glWebViewState->unlockBaseLayerUpdate();
- }
+ tiledPage->draw(transparency, preZoomBounds);
- m_glWebViewState->paintExtras();
return needsRedraw;
}
#endif // USE(ACCELERATED_COMPOSITING)
-bool BaseLayerAndroid::drawGL(LayerAndroid* compositedRoot,
- IntRect& viewRect, SkRect& visibleRect,
- IntRect& webViewRect, int titleBarHeight,
- IntRect& screenClip, float scale, SkColor color)
+bool BaseLayerAndroid::drawGL(double currentTime, LayerAndroid* compositedRoot,
+ IntRect& viewRect, SkRect& visibleRect, float scale,
+ bool* buffersSwappedPtr)
{
bool needsRedraw = false;
#if USE(ACCELERATED_COMPOSITING)
- int left = viewRect.x();
- int top = viewRect.y();
- int width = viewRect.width();
- int height = viewRect.height();
- XLOG("drawBasePicture drawGL() viewRect: %d, %d, %d, %d - %.2f",
- left, top, width, height, scale);
-
- m_glWebViewState->setBackgroundColor(color);
- if (TilesManager::instance()->invertedScreen()) {
- float color = 1.0 - ((((float) m_color.red() / 255.0) +
- ((float) m_color.green() / 255.0) +
- ((float) m_color.blue() / 255.0)) / 3.0);
- glClearColor(color, color, color, 1);
- } else {
- glClearColor((float)m_color.red() / 255.0,
- (float)m_color.green() / 255.0,
- (float)m_color.blue() / 255.0, 1);
- }
- glClear(GL_COLOR_BUFFER_BIT);
- glViewport(left, top, width, height);
- ShaderProgram* shader = TilesManager::instance()->shader();
- if (shader->program() == -1) {
- XLOG("Reinit shader");
- shader->init();
- }
- glUseProgram(shader->program());
- glUniform1i(shader->textureSampler(), 0);
- shader->setViewRect(viewRect);
- shader->setViewport(visibleRect);
- shader->setWebViewRect(webViewRect);
- shader->setTitleBarHeight(titleBarHeight);
- shader->setScreenClip(screenClip);
- shader->resetBlending();
-
- double currentTime = WTF::currentTime();
- needsRedraw = drawBasePictureInGL(visibleRect, scale, currentTime);
- bool goingDown = m_previousVisible.fTop - visibleRect.fTop <= 0;
- bool goingLeft = m_previousVisible.fLeft - visibleRect.fLeft >= 0;
- m_glWebViewState->setDirection(goingDown, goingLeft);
+ needsRedraw = drawBasePictureInGL(visibleRect, scale, currentTime,
+ buffersSwappedPtr);
+
if (!needsRedraw)
m_glWebViewState->resetFrameworkInval();
compositedRoot->updateFixedLayersPositions(visibleRect);
FloatRect clip(0, 0, viewRect.width(), viewRect.height());
- compositedRoot->updateGLPositions(ident, clip, 1);
+ compositedRoot->updateGLPositionsAndScale(
+ ident, clip, 1, m_glWebViewState->zoomManager()->layersScale());
SkMatrix matrix;
- matrix.setTranslate(left, top);
-
- // Get the current scale; if we are zooming, we don't change the scale
- // factor immediately (see BaseLayerAndroid::drawBasePictureInGL()), but
- // we change the scaleRequestState. When the state is kReceivedNewScale
- // we can use the future scale instead of the current scale to request
- // new textures. After a transition time, the scaleRequestState will be
- // reset and the current scale will be set to the future scale.
- float scale = m_glWebViewState->currentScale();
- if (m_glWebViewState->scaleRequestState() == GLWebViewState::kReceivedNewScale) {
- scale = m_glWebViewState->futureScale();
- }
- compositedRoot->setScale(scale);
+ matrix.setTranslate(viewRect.x(), viewRect.y());
#ifdef DEBUG
compositedRoot->showLayer(0);
// Clean up GL textures for video layer.
TilesManager::instance()->videoLayerManager()->deleteUnusedTextures();
+ compositedRoot->prepare(m_glWebViewState);
if (compositedRoot->drawGL(m_glWebViewState, matrix))
needsRedraw = true;
else if (!animsRunning)
m_glWebViewState->resetLayersDirtyArea();
}
+ m_glWebViewState->paintExtras();
- glBindBuffer(GL_ARRAY_BUFFER, 0);
m_previousVisible = visibleRect;
#endif // USE(ACCELERATED_COMPOSITING)