summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/graphics/android/rendering/Surface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/platform/graphics/android/rendering/Surface.cpp')
-rw-r--r--Source/WebCore/platform/graphics/android/rendering/Surface.cpp157
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