OSDN Git Service

Prefetch browser content with tiled page
[android-x86/external-webkit.git] / Source / WebCore / platform / graphics / android / BaseLayerAndroid.cpp
index 014fa40..1aefd86 100644 (file)
 #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
@@ -112,202 +122,193 @@ void BaseLayerAndroid::drawCanvas(SkCanvas* canvas)
 }
 
 #if USE(ACCELERATED_COMPOSITING)
-bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale,
-                                           double currentTime, bool* pagesSwapped)
+
+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();
-        if (pagesSwapped)
-            *pagesSwapped = true;
-    }
+    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,
-                              bool* pagesSwapped, 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,
-                                      pagesSwapped);
-    bool goingDown = m_previousVisible.fTop - visibleRect.fTop <= 0;
-    bool goingLeft = m_previousVisible.fLeft - visibleRect.fLeft >= 0;
-    m_glWebViewState->setDirection(goingDown, goingLeft);
+                                      buffersSwappedPtr);
+
     if (!needsRedraw)
         m_glWebViewState->resetFrameworkInval();
 
@@ -320,21 +321,10 @@ bool BaseLayerAndroid::drawGL(LayerAndroid* compositedRoot,
 
         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);
@@ -346,14 +336,15 @@ bool BaseLayerAndroid::drawGL(LayerAndroid* compositedRoot,
         // 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)