diff options
Diffstat (limited to 'Source/WebCore/platform/graphics/android/rendering/Surface.cpp')
-rw-r--r-- | Source/WebCore/platform/graphics/android/rendering/Surface.cpp | 157 |
1 files changed, 123 insertions, 34 deletions
diff --git a/Source/WebCore/platform/graphics/android/rendering/Surface.cpp b/Source/WebCore/platform/graphics/android/rendering/Surface.cpp index 13c7d27..2617bae 100644 --- a/Source/WebCore/platform/graphics/android/rendering/Surface.cpp +++ b/Source/WebCore/platform/graphics/android/rendering/Surface.cpp @@ -33,15 +33,19 @@ #include "BaseLayerAndroid.h" #include "ClassTracker.h" #include "LayerAndroid.h" +#include "LayerContent.h" #include "GLWebViewState.h" +#include "PrerenderedInval.h" #include "SkCanvas.h" #include "SurfaceBacking.h" +#include "Tile.h" +#include "TileTexture.h" #include "TilesManager.h" #include <wtf/text/CString.h> // Surfaces with an area larger than 2048*2048 should never be unclipped -#define MAX_UNCLIPPED_AREA 4194304 +#define MAX_FULL_CONTENT_AREA 4194304 namespace WebCore { @@ -127,48 +131,48 @@ void Surface::addLayer(LayerAndroid* layer, const TransformationMatrix& transfor m_hasText |= layer->hasText(); // calculate area size for comparison later - IntRect rect = layer->unclippedArea(); + IntRect rect = layer->fullContentArea(); SkPoint pos = layer->getPosition(); rect.setLocation(IntPoint(pos.fX, pos.fY)); if (layer->needsTexture()) { - if (m_unclippedArea.isEmpty()) { + if (m_fullContentArea.isEmpty()) { m_drawTransform = transform; m_drawTransform.translate3d(-pos.fX, -pos.fY, 0); - m_unclippedArea = rect; + m_fullContentArea = rect; } else - m_unclippedArea.unite(rect); + m_fullContentArea.unite(rect); ALOGV("Surf %p adding LA %p, size %d, %d %dx%d, now Surf size %d,%d %dx%d", this, layer, rect.x(), rect.y(), rect.width(), rect.height(), - m_unclippedArea.x(), m_unclippedArea.y(), - m_unclippedArea.width(), m_unclippedArea.height()); + m_fullContentArea.x(), m_fullContentArea.y(), + m_fullContentArea.width(), m_fullContentArea.height()); } if (isBase()) m_background = static_cast<BaseLayerAndroid*>(layer)->getBackgroundColor(); } -IntRect Surface::visibleArea() +IntRect Surface::visibleContentArea() { if (singleLayer()) - return getFirstLayer()->visibleArea(); + return getFirstLayer()->visibleContentArea(); - IntRect rect = m_unclippedArea; + IntRect rect = m_fullContentArea; - // clip with the viewport in documents coordinate - IntRect documentViewport(TilesManager::instance()->shader()->documentViewport()); - rect.intersect(documentViewport); + // clip with the viewport in content coordinate + IntRect contentViewport(TilesManager::instance()->shader()->contentViewport()); + rect.intersect(contentViewport); // TODO: handle recursive layer clip return rect; } -IntRect Surface::unclippedArea() +IntRect Surface::fullContentArea() { if (singleLayer()) - return getFirstLayer()->unclippedArea(); - return m_unclippedArea; + return getFirstLayer()->fullContentArea(); + return m_fullContentArea; } bool Surface::useAggressiveRendering() @@ -181,17 +185,17 @@ bool Surface::useAggressiveRendering() || !m_background.hasAlpha()); } -void Surface::prepareGL(bool layerTilesDisabled) +void Surface::prepareGL(bool layerTilesDisabled, bool updateWithBlit) { bool tilesDisabled = layerTilesDisabled && !isBase(); if (!m_surfaceBacking) { ALOGV("prepareGL on Surf %p, no SurfBack, needsTexture? %d", this, m_surfaceBacking, needsTexture()); - if (!needsTexture()) + if (needsTexture() || (isBase() && layerTilesDisabled)) + m_surfaceBacking = new SurfaceBacking(isBase()); + else return; - - m_surfaceBacking = new SurfaceBacking(isBase()); } if (tilesDisabled) { @@ -199,7 +203,7 @@ void Surface::prepareGL(bool layerTilesDisabled) } else { bool allowZoom = hasText(); // only allow for scale > 1 if painting vectors IntRect prepareArea = computePrepareArea(); - IntRect fullArea = unclippedArea(); + IntRect fullArea = fullContentArea(); ALOGV("prepareGL on Surf %p with SurfBack %p, %d layers, first layer %s (%d) " "prepareArea(%d, %d - %d x %d) fullArea(%d, %d - %d x %d)", @@ -210,8 +214,13 @@ void Surface::prepareGL(bool layerTilesDisabled) fullArea.x(), fullArea.y(), fullArea.width(), fullArea.height()); m_surfaceBacking->prepareGL(getFirstLayer()->state(), allowZoom, - prepareArea, fullArea, - this, useAggressiveRendering()); + prepareArea, fullArea, + this, useAggressiveRendering(), updateWithBlit); + } + for (size_t i = 0; i < m_layers.size(); i++) { + LayerContent* content = m_layers[i]->content(); + if (content) + content->clearPrerenders(); } } @@ -228,7 +237,7 @@ bool Surface::drawGL(bool layerTilesDisabled) if (!isBaseLayer) { // TODO: why are clipping regions wrong for base layer? FloatRect drawClip = getFirstLayer()->drawClip(); - FloatRect clippingRect = TilesManager::instance()->shader()->rectInScreenCoord(drawClip); + FloatRect clippingRect = TilesManager::instance()->shader()->rectInInvViewCoord(drawClip); TilesManager::instance()->shader()->clip(clippingRect); } @@ -237,7 +246,7 @@ bool Surface::drawGL(bool layerTilesDisabled) ALOGV("drawGL on Surf %p with SurfBack %p, first layer %s (%d)", this, m_surfaceBacking, getFirstLayer()->subclassName().ascii().data(), getFirstLayer()->uniqueId()); - IntRect drawArea = visibleArea(); + IntRect drawArea = visibleContentArea(); m_surfaceBacking->drawGL(drawArea, opacity(), drawTransform(), useAggressiveRendering(), background()); } @@ -273,21 +282,41 @@ bool Surface::isMissingContent() return m_surfaceBacking->isMissingContent(); } -IntRect Surface::computePrepareArea() { +bool Surface::canUpdateWithBlit() +{ + // If we don't have a texture, we have nothing to update and thus can take + // the fast path + if (!needsTexture()) + return true; + // If we have a surface backing that isn't ready, we can't update with a blit + // If it is ready, then check to see if it is dirty. We can only call isDirty() + // if isReady() returns true + if (!m_surfaceBacking) + return false; + if (!m_surfaceBacking->isReady()) + return false; + if (!m_surfaceBacking->isDirty()) + return true; + if (!singleLayer()) + return false; + return getFirstLayer()->canUpdateWithBlit(); +} + +IntRect Surface::computePrepareArea() +{ IntRect area; if (!getFirstLayer()->contentIsScrollable() && !isBase() && getFirstLayer()->state()->layersRenderingMode() == GLWebViewState::kAllTextures) { - area = unclippedArea(); + area = fullContentArea(); double total = ((double) area.width()) * ((double) area.height()); - if (total > MAX_UNCLIPPED_AREA) - area = visibleArea(); - } else { - area = visibleArea(); - } + if (total > MAX_FULL_CONTENT_AREA) + area = visibleContentArea(); + } else + area = visibleContentArea(); return area; } @@ -320,8 +349,10 @@ bool Surface::paint(SkCanvas* canvas) // In single surface mode, draw layer content onto the base layer if (isBase() && getFirstLayer()->countChildren() - && getFirstLayer()->state()->layersRenderingMode() > GLWebViewState::kClippedTextures) - getFirstLayer()->getChild(0)->drawCanvas(canvas, true, Layer::FlattenedLayers); + && getFirstLayer()->state()->layersRenderingMode() > GLWebViewState::kClippedTextures) { + for (unsigned int i = 0; i < getFirstLayer()->countChildren(); i++) + getFirstLayer()->getChild(i)->drawCanvas(canvas, true, Layer::FlattenedLayers); + } } else { SkAutoCanvasRestore acr(canvas, true); SkMatrix matrix; @@ -355,6 +386,64 @@ Color* Surface::background() return &m_background; } +bool Surface::blitFromContents(Tile* tile) +{ + if (!singleLayer() || !tile || !getFirstLayer() || !getFirstLayer()->content()) + return false; + + LayerContent* content = getFirstLayer()->content(); + // Extract the dirty rect from the region. Note that this is *NOT* constrained + // to this tile + IntRect dirtyRect = tile->dirtyArea().getBounds(); + IntRect tileRect = IntRect(tile->x() * TilesManager::tileWidth(), + tile->y() * TilesManager::tileHeight(), + TilesManager::tileWidth(), + TilesManager::tileHeight()); + FloatRect tileRectInDoc = tileRect; + tileRectInDoc.scale(1 / tile->scale()); + dirtyRect.intersect(enclosingIntRect(tileRectInDoc)); + PrerenderedInval* prerenderedInval = content->prerenderForRect(dirtyRect); + if (!prerenderedInval || prerenderedInval->bitmap.isNull()) + return false; + SkBitmap sourceBitmap = prerenderedInval->bitmap; + // Calculate the screen rect that is dirty, then intersect it with the + // tile's screen rect so that we end up with the pixels we need to blit + FloatRect screenDirty = dirtyRect; + screenDirty.scale(tile->scale()); + IntRect enclosingScreenDirty = enclosingIntRect(screenDirty); + enclosingScreenDirty.intersect(tileRect); + if (enclosingScreenDirty.isEmpty()) + return false; + // Make sure the screen area we want to blit is contained by the + // prerendered screen area + if (!prerenderedInval->screenArea.contains(enclosingScreenDirty)) { + ALOGD("prerendered->screenArea " INT_RECT_FORMAT " doesn't contain " + "enclosingScreenDirty " INT_RECT_FORMAT, + INT_RECT_ARGS(prerenderedInval->screenArea), + INT_RECT_ARGS(enclosingScreenDirty)); + return false; + } + IntPoint origin = prerenderedInval->screenArea.location(); + SkBitmap subset; + subset.setConfig(sourceBitmap.config(), enclosingScreenDirty.width(), + enclosingScreenDirty.height()); + subset.allocPixels(); + + int topOffset = enclosingScreenDirty.y() - prerenderedInval->screenArea.y(); + int leftOffset = enclosingScreenDirty.x() - prerenderedInval->screenArea.x(); + if (!GLUtils::deepCopyBitmapSubset(sourceBitmap, subset, leftOffset, topOffset)) + return false; + // Now upload + SkIRect textureInval = SkIRect::MakeXYWH(enclosingScreenDirty.x() - tileRect.x(), + enclosingScreenDirty.y() - tileRect.y(), + enclosingScreenDirty.width(), + enclosingScreenDirty.height()); + GLUtils::updateTextureWithBitmap(tile->frontTexture()->m_ownTextureId, + subset, textureInval); + tile->onBlitUpdate(); + return true; +} + const TransformationMatrix* Surface::drawTransform() { // single layer surfaces query the layer's draw transform, while multi-layer |