summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/graphics/chromium/ContentLayerChromium.cpp')
-rw-r--r--WebCore/platform/graphics/chromium/ContentLayerChromium.cpp129
1 files changed, 92 insertions, 37 deletions
diff --git a/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp b/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp
index 8dda4d6..eba5349 100644
--- a/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp
+++ b/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp
@@ -43,8 +43,6 @@
#include "PlatformContextSkia.h"
#include "skia/ext/platform_canvas.h"
#elif PLATFORM(CG)
-#include "LocalCurrentGraphicsContext.h"
-
#include <CoreGraphics/CGBitmapContext.h>
#endif
@@ -121,6 +119,7 @@ PassRefPtr<ContentLayerChromium> ContentLayerChromium::create(GraphicsLayerChrom
ContentLayerChromium::ContentLayerChromium(GraphicsLayerChromium* owner)
: LayerChromium(owner)
, m_contentsTexture(0)
+ , m_skipsDraw(false)
{
}
@@ -129,16 +128,6 @@ ContentLayerChromium::~ContentLayerChromium()
cleanupResources();
}
-void ContentLayerChromium::setLayerRenderer(LayerRendererChromium* renderer)
-{
- // If we're changing layer renderers then we need to free up any resources
- // allocated by the old renderer.
- if (layerRenderer() && layerRenderer() != renderer)
- cleanupResources();
-
- LayerChromium::setLayerRenderer(renderer);
-}
-
void ContentLayerChromium::cleanupResources()
{
if (layerRenderer()) {
@@ -149,6 +138,42 @@ void ContentLayerChromium::cleanupResources()
}
}
+bool ContentLayerChromium::requiresClippedUpdateRect() const
+{
+ // To avoid allocating excessively large textures, switch into "large layer mode" if
+ // one of the layer's dimensions is larger than 2000 pixels or the current size
+ // of the visible rect. This is a temporary measure until layer tiling is implemented.
+ static const int maxLayerSize = 2000;
+ return (m_bounds.width() > max(maxLayerSize, layerRenderer()->rootLayerContentRect().width())
+ || m_bounds.height() > max(maxLayerSize, layerRenderer()->rootLayerContentRect().height())
+ || !layerRenderer()->checkTextureSize(m_bounds));
+}
+
+void ContentLayerChromium::calculateClippedUpdateRect(IntRect& dirtyRect, IntRect& drawRect) const
+{
+ // For the given layer size and content rect, calculate:
+ // 1) The minimal texture space rectangle to be uploaded, returned in dirtyRect.
+ // 2) The content rect-relative rectangle to draw this texture in, returned in drawRect.
+
+ const IntRect clipRect = layerRenderer()->currentScissorRect();
+ const TransformationMatrix& transform = drawTransform();
+ // The layer's draw transform points to the center of the layer, relative to
+ // the content rect. layerPos is the distance from the top left of the
+ // layer to the top left of the content rect.
+ const IntPoint layerPos(m_bounds.width() / 2 - transform.m41(),
+ m_bounds.height() / 2 - transform.m42());
+ // Transform the contentRect into the space of the layer.
+ IntRect contentRectInLayerSpace(layerPos, clipRect.size());
+
+ // Clip the entire layer against the visible region in the content rect
+ // and use that as the drawable texture, instead of the entire layer.
+ dirtyRect = IntRect(IntPoint(0, 0), m_bounds);
+ dirtyRect.intersect(contentRectInLayerSpace);
+
+ // The draw position is relative to the content rect.
+ drawRect = IntRect(toPoint(dirtyRect.location() - layerPos), dirtyRect.size());
+}
+
void ContentLayerChromium::updateContents()
{
RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client());
@@ -159,29 +184,47 @@ void ContentLayerChromium::updateContents()
ASSERT(layerRenderer());
- // FIXME: Remove this test when tiled layers are implemented.
- m_skipsDraw = false;
- if (!layerRenderer()->checkTextureSize(m_bounds)) {
- m_skipsDraw = true;
- return;
- }
-
void* pixels = 0;
- IntRect dirtyRect(m_dirtyRect);
+ IntRect dirtyRect;
+ IntRect updateRect;
IntSize requiredTextureSize;
IntSize bitmapSize;
- requiredTextureSize = m_bounds;
- IntRect boundsRect(IntPoint(0, 0), m_bounds);
-
- // If the texture needs to be reallocated then we must redraw the entire
- // contents of the layer.
- if (requiredTextureSize != m_allocatedTextureSize)
- dirtyRect = boundsRect;
- else {
- // Clip the dirtyRect to the size of the layer to avoid drawing outside
- // the bounds of the backing texture.
- dirtyRect.intersect(boundsRect);
+ // FIXME: Remove this test when tiled layers are implemented.
+ if (requiresClippedUpdateRect()) {
+ // A layer with 3D transforms could require an arbitrarily large number
+ // of texels to be repainted, so ignore these layers until tiling is
+ // implemented.
+ if (!drawTransform().isIdentityOrTranslation()) {
+ m_skipsDraw = true;
+ return;
+ }
+
+ calculateClippedUpdateRect(dirtyRect, m_largeLayerDrawRect);
+ if (!layerRenderer()->checkTextureSize(m_largeLayerDrawRect.size())) {
+ m_skipsDraw = true;
+ return;
+ }
+ if (m_largeLayerDirtyRect == dirtyRect)
+ return;
+
+ m_largeLayerDirtyRect = dirtyRect;
+ requiredTextureSize = dirtyRect.size();
+ updateRect = IntRect(IntPoint(0, 0), dirtyRect.size());
+ } else {
+ dirtyRect = IntRect(m_dirtyRect);
+ IntRect boundsRect(IntPoint(0, 0), m_bounds);
+ requiredTextureSize = m_bounds;
+ // If the texture needs to be reallocated then we must redraw the entire
+ // contents of the layer.
+ if (requiredTextureSize != m_allocatedTextureSize)
+ dirtyRect = boundsRect;
+ else {
+ // Clip the dirtyRect to the size of the layer to avoid drawing
+ // outside the bounds of the backing texture.
+ dirtyRect.intersect(boundsRect);
+ }
+ updateRect = dirtyRect;
}
#if PLATFORM(SKIA)
@@ -228,7 +271,6 @@ void ContentLayerChromium::updateContents()
CGContextScaleCTM(contextCG.get(), 1, -1);
GraphicsContext graphicsContext(contextCG.get());
- LocalCurrentGraphicsContext scopedNSGraphicsContext(&graphicsContext);
// Translate the graphics context into the coordinate system of the dirty rect.
graphicsContext.translate(-dirtyRect.x(), -dirtyRect.y());
@@ -246,7 +288,7 @@ void ContentLayerChromium::updateContents()
textureId = layerRenderer()->createLayerTexture();
if (pixels)
- updateTextureRect(pixels, bitmapSize, requiredTextureSize, dirtyRect, textureId);
+ updateTextureRect(pixels, bitmapSize, requiredTextureSize, updateRect, textureId);
}
void ContentLayerChromium::updateTextureRect(void* pixels, const IntSize& bitmapSize, const IntSize& requiredTextureSize, const IntRect& updateRect, unsigned textureId)
@@ -272,7 +314,8 @@ void ContentLayerChromium::updateTextureRect(void* pixels, const IntSize& bitmap
}
m_dirtyRect.setSize(FloatSize());
- m_contentsDirty = false;
+ // Large layers always stay dirty, because they need to update when the content rect changes.
+ m_contentsDirty = requiresClippedUpdateRect();
}
void ContentLayerChromium::draw()
@@ -288,9 +331,21 @@ void ContentLayerChromium::draw()
GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_contentsTexture));
layerRenderer()->useShader(sv->contentShaderProgram());
GLC(context, context->uniform1i(sv->shaderSamplerLocation(), 0));
- drawTexturedQuad(context, layerRenderer()->projectionMatrix(), drawTransform(),
- bounds().width(), bounds().height(), drawOpacity(),
- sv->shaderMatrixLocation(), sv->shaderAlphaLocation());
+
+ if (requiresClippedUpdateRect()) {
+ float m43 = drawTransform().m43();
+ TransformationMatrix transform;
+ transform.translate3d(m_largeLayerDrawRect.center().x(), m_largeLayerDrawRect.center().y(), m43);
+ drawTexturedQuad(context, layerRenderer()->projectionMatrix(),
+ transform, m_largeLayerDrawRect.width(),
+ m_largeLayerDrawRect.height(), drawOpacity(),
+ sv->shaderMatrixLocation(), sv->shaderAlphaLocation());
+ } else {
+ drawTexturedQuad(context, layerRenderer()->projectionMatrix(),
+ drawTransform(), m_bounds.width(), m_bounds.height(),
+ drawOpacity(), sv->shaderMatrixLocation(),
+ sv->shaderAlphaLocation());
+ }
}
}