[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

vangelis at chromium.org vangelis at chromium.org
Wed Dec 22 15:52:08 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 7ad08d0aa444beff395b5fde5fdf1bc737822396
Author: vangelis at chromium.org <vangelis at chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Mon Nov 15 20:25:00 2010 +0000

    2010-11-15  Vangelis Kokkevis  <vangelis at chromium.org>
    
            Reviewed by Kenneth Russell.
    
            [chromium] Fixes layer opacity implementation of composited layers
            https://bugs.webkit.org/show_bug.cgi?id=49233
    
            This introduces a fairly drastic change in how LayerRendererChromium draws
            composited layers. Layers that have non-zero opacity as well as layers that
            clip their descendants (and have non-trivial transforms) are now first
            rendered onto off-screen surfaces (RenderSurfaceChromium's). The compositing
            operation now consists of two distinct phases: First a hierarchical traversal
            of the layer tree to compute the layer transforms, determine what the necessary
            RenderSurfaces are and sort layer that preserve-3d based on their z-value. A second
            pass goes through all the RenderSurfaces discovered by the first pass and updates
            their contents.
            Additional significant side-effects of this change are:
            1. Depth buffer and depth testing is no longer used. Drawing relies on a painter's
               algorithm to render layers with the preserves-3d property from back to front using
               the Z coordinate of their center. This will further be improved in the future with
               the intoduction of a BSP tree to properly deal with intersecting layers.
            2. Compositor no longer uses the stencil buffer to do clipping. Clipping is now performed
               by rendering layer subtrees into an offscreen buffer and setting the appropriate
               scissor and viewport transformation.
    
            Tests: abs-position-inside-opacity.html (for the opacity implementation)
                   and the rest of the compositing layout tests to verify that
                   everything still works.
    
            * WebCore.gypi:
            * platform/graphics/chromium/ContentLayerChromium.cpp:
            (WebCore::ContentLayerChromium::cleanupResources):
            (WebCore::ContentLayerChromium::requiresClippedUpdateRect):
            (WebCore::ContentLayerChromium::calculateClippedUpdateRect):
            (WebCore::ContentLayerChromium::updateContents):
            * platform/graphics/chromium/LayerChromium.cpp:
            (WebCore::LayerChromium::LayerChromium):
            (WebCore::LayerChromium::cleanupResources):
            (WebCore::LayerChromium::createRenderSurface):
            (WebCore::LayerChromium::descendantsDrawContent):
            (WebCore::LayerChromium::descendantsDrawContentRecursive):
            * platform/graphics/chromium/LayerChromium.h:
            (WebCore::LayerChromium::drawTransform):
            (WebCore::LayerChromium::layerRenderer):
            * platform/graphics/chromium/LayerRendererChromium.cpp:
            (WebCore::orthoMatrix):
            (WebCore::isScaleOrTranslation):
            (WebCore::LayerRendererChromium::compareLayerZ):
            (WebCore::LayerRendererChromium::LayerRendererChromium):
            (WebCore::LayerRendererChromium::prepareToDrawLayers):
            (WebCore::LayerRendererChromium::drawLayers):
            (WebCore::LayerRendererChromium::updateLayersRecursive):
            (WebCore::LayerRendererChromium::useRenderSurface):
            (WebCore::LayerRendererChromium::drawLayer):
            (WebCore::LayerRendererChromium::setScissorToRect):
            (WebCore::LayerRendererChromium::setDrawViewportRect):
            (WebCore::LayerRendererChromium::initializeSharedObjects):
            (WebCore::LayerRendererChromium::cleanupSharedObjects):
            * platform/graphics/chromium/LayerRendererChromium.h:
            * platform/graphics/chromium/RenderSurfaceChromium.cpp: Added.
            (WebCore::RenderSurfaceChromium::RenderSurfaceChromium):
            (WebCore::RenderSurfaceChromium::~RenderSurfaceChromium):
            (WebCore::RenderSurfaceChromium::cleanupResources):
            (WebCore::RenderSurfaceChromium::layerRenderer):
            (WebCore::RenderSurfaceChromium::prepareContentsTexture):
            * platform/graphics/chromium/RenderSurfaceChromium.h: Added.
            (WebCore::RenderSurfaceChromium::contentRectCenter):
            (WebCore::RenderSurfaceChromium::contentRect):
            * platform/graphics/chromium/VideoLayerChromium.cpp:
            (WebCore::VideoLayerChromium::cleanupResources):
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@72021 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 4f3fe13..510c085 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,74 @@
+2010-11-15  Vangelis Kokkevis  <vangelis at chromium.org>
+
+        Reviewed by Kenneth Russell.
+
+        [chromium] Fixes layer opacity implementation of composited layers
+        https://bugs.webkit.org/show_bug.cgi?id=49233
+
+        This introduces a fairly drastic change in how LayerRendererChromium draws
+        composited layers. Layers that have non-zero opacity as well as layers that
+        clip their descendants (and have non-trivial transforms) are now first
+        rendered onto off-screen surfaces (RenderSurfaceChromium's). The compositing
+        operation now consists of two distinct phases: First a hierarchical traversal
+        of the layer tree to compute the layer transforms, determine what the necessary
+        RenderSurfaces are and sort layer that preserve-3d based on their z-value. A second
+        pass goes through all the RenderSurfaces discovered by the first pass and updates
+        their contents.
+        Additional significant side-effects of this change are:
+        1. Depth buffer and depth testing is no longer used. Drawing relies on a painter's
+           algorithm to render layers with the preserves-3d property from back to front using
+           the Z coordinate of their center. This will further be improved in the future with
+           the intoduction of a BSP tree to properly deal with intersecting layers.
+        2. Compositor no longer uses the stencil buffer to do clipping. Clipping is now performed
+           by rendering layer subtrees into an offscreen buffer and setting the appropriate
+           scissor and viewport transformation.
+
+        Tests: abs-position-inside-opacity.html (for the opacity implementation)
+               and the rest of the compositing layout tests to verify that
+               everything still works.
+
+        * WebCore.gypi:
+        * platform/graphics/chromium/ContentLayerChromium.cpp:
+        (WebCore::ContentLayerChromium::cleanupResources):
+        (WebCore::ContentLayerChromium::requiresClippedUpdateRect):
+        (WebCore::ContentLayerChromium::calculateClippedUpdateRect):
+        (WebCore::ContentLayerChromium::updateContents):
+        * platform/graphics/chromium/LayerChromium.cpp:
+        (WebCore::LayerChromium::LayerChromium):
+        (WebCore::LayerChromium::cleanupResources):
+        (WebCore::LayerChromium::createRenderSurface):
+        (WebCore::LayerChromium::descendantsDrawContent):
+        (WebCore::LayerChromium::descendantsDrawContentRecursive):
+        * platform/graphics/chromium/LayerChromium.h:
+        (WebCore::LayerChromium::drawTransform):
+        (WebCore::LayerChromium::layerRenderer):
+        * platform/graphics/chromium/LayerRendererChromium.cpp:
+        (WebCore::orthoMatrix):
+        (WebCore::isScaleOrTranslation):
+        (WebCore::LayerRendererChromium::compareLayerZ):
+        (WebCore::LayerRendererChromium::LayerRendererChromium):
+        (WebCore::LayerRendererChromium::prepareToDrawLayers):
+        (WebCore::LayerRendererChromium::drawLayers):
+        (WebCore::LayerRendererChromium::updateLayersRecursive):
+        (WebCore::LayerRendererChromium::useRenderSurface):
+        (WebCore::LayerRendererChromium::drawLayer):
+        (WebCore::LayerRendererChromium::setScissorToRect):
+        (WebCore::LayerRendererChromium::setDrawViewportRect):
+        (WebCore::LayerRendererChromium::initializeSharedObjects):
+        (WebCore::LayerRendererChromium::cleanupSharedObjects):
+        * platform/graphics/chromium/LayerRendererChromium.h:
+        * platform/graphics/chromium/RenderSurfaceChromium.cpp: Added.
+        (WebCore::RenderSurfaceChromium::RenderSurfaceChromium):
+        (WebCore::RenderSurfaceChromium::~RenderSurfaceChromium):
+        (WebCore::RenderSurfaceChromium::cleanupResources):
+        (WebCore::RenderSurfaceChromium::layerRenderer):
+        (WebCore::RenderSurfaceChromium::prepareContentsTexture):
+        * platform/graphics/chromium/RenderSurfaceChromium.h: Added.
+        (WebCore::RenderSurfaceChromium::contentRectCenter):
+        (WebCore::RenderSurfaceChromium::contentRect):
+        * platform/graphics/chromium/VideoLayerChromium.cpp:
+        (WebCore::VideoLayerChromium::cleanupResources):
+
 2010-11-15  Martin Robinson  <mrobinson at igalia.com>
 
         Reviewed by Andreas Kling.
diff --git a/WebCore/WebCore.gypi b/WebCore/WebCore.gypi
index 75455ed..a93dc51 100644
--- a/WebCore/WebCore.gypi
+++ b/WebCore/WebCore.gypi
@@ -2479,6 +2479,8 @@
             'platform/graphics/chromium/PlatformIcon.h',
             'platform/graphics/chromium/PluginLayerChromium.cpp',
             'platform/graphics/chromium/PluginLayerChromium.h',
+            'platform/graphics/chromium/RenderSurfaceChromium.h',
+            'platform/graphics/chromium/RenderSurfaceChromium.cpp',
             'platform/graphics/chromium/SimpleFontDataChromiumWin.cpp',
             'platform/graphics/chromium/SimpleFontDataLinux.cpp',
             'platform/graphics/chromium/TransparencyWin.cpp',
diff --git a/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp b/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp
index 97f5c3f..375a74b 100644
--- a/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp
+++ b/WebCore/platform/graphics/chromium/ContentLayerChromium.cpp
@@ -122,6 +122,7 @@ ContentLayerChromium::~ContentLayerChromium()
 
 void ContentLayerChromium::cleanupResources()
 {
+    LayerChromium::cleanupResources();
     if (layerRenderer()) {
         if (m_contentsTexture) {
             layerRenderer()->deleteLayerTexture(m_contentsTexture);
@@ -133,11 +134,11 @@ 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.
+    // one of the layer's dimensions is larger than 2000 pixels or the size of
+    // surface it's rendering into. 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())
+    return (m_bounds.width() > max(maxLayerSize, m_targetRenderSurface->contentRect().width())
+            || m_bounds.height() > max(maxLayerSize, m_targetRenderSurface->contentRect().height())
             || !layerRenderer()->checkTextureSize(m_bounds));
 }
 
@@ -145,25 +146,26 @@ void ContentLayerChromium::calculateClippedUpdateRect(IntRect& dirtyRect, IntRec
 {
     // 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());
+    // 2) The rectangle to draw this texture in relative to the target render surface, returned in drawRect.
+
+    ASSERT(m_targetRenderSurface);
+    const IntRect clipRect = m_targetRenderSurface->contentRect();
+
+    TransformationMatrix layerOriginTransform = drawTransform();
+    layerOriginTransform.translate3d(-0.5 * m_bounds.width(), -0.5 * m_bounds.height(), 0);
+
+    // For now we apply the large layer treatment only for layers that are either untransformed
+    // or are purely translated. Their matrix is expected to be invertible.
+    ASSERT(layerOriginTransform.isInvertible());
+
+    TransformationMatrix targetToLayerMatrix = layerOriginTransform.inverse();
+    IntRect clipRectInLayerCoords = targetToLayerMatrix.mapRect(clipRect);
+    clipRectInLayerCoords.intersect(IntRect(0, 0, m_bounds.width(), m_bounds.height()));
+
+    dirtyRect = clipRectInLayerCoords;
+
+    // Map back to the target surface coordinate system.
+    drawRect = layerOriginTransform.mapRect(dirtyRect);
 }
 
 void ContentLayerChromium::updateContents()
@@ -197,12 +199,21 @@ void ContentLayerChromium::updateContents()
             m_skipsDraw = true;
             return;
         }
-        if (m_largeLayerDirtyRect == dirtyRect)
-            return;
 
-        m_largeLayerDirtyRect = dirtyRect;
-        requiredTextureSize = dirtyRect.size();
-        updateRect = IntRect(IntPoint(0, 0), dirtyRect.size());
+        // If the portion of the large layer that's visible hasn't changed
+        // then we don't need to update it, _unless_ its contents have changed
+        // in which case we only update the dirty bits.
+        if (m_largeLayerDirtyRect == dirtyRect) {
+            if (!m_dirtyRect.intersects(dirtyRect))
+                return;
+            dirtyRect.intersect(IntRect(m_dirtyRect));
+            updateRect = dirtyRect;
+            requiredTextureSize = m_largeLayerDirtyRect.size();
+        } else {
+            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);
@@ -219,6 +230,9 @@ void ContentLayerChromium::updateContents()
         updateRect = dirtyRect;
     }
 
+    if (dirtyRect.isEmpty())
+        return;
+
 #if PLATFORM(SKIA)
     const SkBitmap* skiaBitmap = 0;
     OwnPtr<skia::PlatformCanvas> canvas;
diff --git a/WebCore/platform/graphics/chromium/LayerChromium.cpp b/WebCore/platform/graphics/chromium/LayerChromium.cpp
index 23e54e5..1f4feaf 100644
--- a/WebCore/platform/graphics/chromium/LayerChromium.cpp
+++ b/WebCore/platform/graphics/chromium/LayerChromium.cpp
@@ -143,6 +143,7 @@ PassRefPtr<LayerChromium> LayerChromium::create(GraphicsLayerChromium* owner)
 LayerChromium::LayerChromium(GraphicsLayerChromium* owner)
     : m_owner(owner)
     , m_contentsDirty(false)
+    , m_targetRenderSurface(0)
     , m_superlayer(0)
     , m_anchorPoint(0.5, 0.5)
     , m_backgroundColor(0, 0, 0, 0)
@@ -158,7 +159,9 @@ LayerChromium::LayerChromium(GraphicsLayerChromium* owner)
     , m_opaque(true)
     , m_geometryFlipped(false)
     , m_needsDisplayOnBoundsChange(false)
+    , m_drawDepth(0)
     , m_layerRenderer(0)
+    , m_renderSurface(0)
 {
 }
 
@@ -172,6 +175,12 @@ LayerChromium::~LayerChromium()
     removeAllSublayers();
 }
 
+void LayerChromium::cleanupResources()
+{
+    if (m_renderSurface)
+        m_renderSurface->cleanupResources();
+}
+
 void LayerChromium::setLayerRenderer(LayerRendererChromium* renderer)
 {
     // If we're changing layer renderers then we need to free up any resources
@@ -184,6 +193,12 @@ void LayerChromium::setLayerRenderer(LayerRendererChromium* renderer)
     m_layerRenderer = renderer;
 }
 
+RenderSurfaceChromium* LayerChromium::createRenderSurface()
+{
+    m_renderSurface = new RenderSurfaceChromium(this);
+    return m_renderSurface.get();
+}
+
 unsigned LayerChromium::createShaderProgram(GraphicsContext3D* context, const char* vertexShaderSource, const char* fragmentShaderSource)
 {
     unsigned vertexShader = loadShader(context, GraphicsContext3D::VERTEX_SHADER, vertexShaderSource);
@@ -463,24 +478,27 @@ const IntRect LayerChromium::getDrawRect() const
     return mappedRect;
 }
 
-// Draws the layer with a single colored shader. This method is used to do
-// quick draws into the stencil buffer.
-void LayerChromium::drawAsMask()
+// Returns true if any of the layer's descendants has drawable content.
+bool LayerChromium::descendantsDrawContent()
 {
-    ASSERT(layerRenderer());
-    const SharedValues* sv = layerRenderer()->layerSharedValues();
-    ASSERT(sv && sv->initialized());
-    layerRenderer()->useShader(sv->borderShaderProgram());
-
-    // We reuse the border shader here as all we need a single colored shader pass.
-    // The color specified here is only for debug puproses as typically when we call this
-    // method, writes to the color channels are disabled.
-    GraphicsContext3D* context = layerRendererContext();
-    GLC(context, context->uniform4f(sv->borderShaderColorLocation(), 0, 1 , 0, 0.7));
+    const Vector<RefPtr<LayerChromium> >& sublayers = getSublayers();
+    for (size_t i = 0; i < sublayers.size(); ++i)
+        if (sublayers[i]->descendantsDrawContentRecursive())
+            return true;
+    return false;
+}
 
-    drawTexturedQuad(context, layerRenderer()->projectionMatrix(), drawTransform(),
-                     bounds().width(), bounds().height(), drawOpacity(),
-                     sv->borderShaderMatrixLocation(), -1);
+// Returns true if either this layer or one of its descendants has drawable content.
+bool LayerChromium::descendantsDrawContentRecursive()
+{
+    if (drawsContent())
+        return true;
+
+    const Vector<RefPtr<LayerChromium> >& sublayers = getSublayers();
+    for (size_t i = 0; i < sublayers.size(); ++i)
+        if (sublayers[i]->descendantsDrawContentRecursive())
+            return true;
+    return false;
 }
 
 // static
diff --git a/WebCore/platform/graphics/chromium/LayerChromium.h b/WebCore/platform/graphics/chromium/LayerChromium.h
index 3956e28..86f3580 100644
--- a/WebCore/platform/graphics/chromium/LayerChromium.h
+++ b/WebCore/platform/graphics/chromium/LayerChromium.h
@@ -38,6 +38,7 @@
 #include "GraphicsContext.h"
 #include "GraphicsLayerChromium.h"
 #include "PlatformString.h"
+#include "RenderSurfaceChromium.h"
 #include "TransformationMatrix.h"
 #include <wtf/OwnPtr.h>
 #include <wtf/PassRefPtr.h>
@@ -139,10 +140,7 @@ public:
     void setGeometryFlipped(bool flipped) { m_geometryFlipped = flipped; setNeedsCommit(); }
     bool geometryFlipped() const { return m_geometryFlipped; }
 
-    void setDrawTransform(const TransformationMatrix& transform) { m_drawTransform = transform; }
     const TransformationMatrix& drawTransform() const { return m_drawTransform; }
-
-    void setDrawOpacity(float opacity) { m_drawOpacity = opacity; }
     float drawOpacity() const { return m_drawOpacity; }
 
     bool preserves3D() { return m_owner && m_owner->preserves3D(); }
@@ -165,8 +163,7 @@ public:
 
     void drawDebugBorder();
 
-    // Draws the layer without a texture. This is used for stencil operations.
-    void drawAsMask();
+    RenderSurfaceChromium* createRenderSurface();
 
     // Stores values that are shared between instances of this class that are
     // associated with the same LayerRendererChromium (and hence the same GL
@@ -198,6 +195,8 @@ public:
 
     static void prepareForDraw(const SharedValues*);
 
+    LayerRendererChromium* layerRenderer() const { return m_layerRenderer.get(); }
+
 protected:
     GraphicsLayerChromium* m_owner;
     LayerChromium(GraphicsLayerChromium* owner);
@@ -205,11 +204,13 @@ protected:
     // This is called to clean up resources being held in the same context as
     // layerRendererContext(). Subclasses should override this method if they
     // hold context-dependent resources such as textures.
-    virtual void cleanupResources() { }
+    virtual void cleanupResources();
 
-    LayerRendererChromium* layerRenderer() const { return m_layerRenderer.get(); }
     GraphicsContext3D* layerRendererContext() const;
 
+    // Returns true if any of the layer's descendants has content to draw.
+    bool descendantsDrawContent();
+
     static void drawTexturedQuad(GraphicsContext3D*, const TransformationMatrix& projectionMatrix, const TransformationMatrix& layerMatrix,
                                  float width, float height, float opacity,
                                  int matrixLocation, int alphaLocation);
@@ -222,6 +223,12 @@ protected:
     FloatRect m_dirtyRect;
     bool m_contentsDirty;
 
+    // Render surface this layer draws into. This is a surface that can belong
+    // either to this layer (if m_targetRenderSurface == m_renderSurface) or
+    // to an ancestor of this layer. The target render surface determines the
+    // coordinate system the layer's transforms are relative to.
+    RenderSurfaceChromium* m_targetRenderSurface;
+
     // All layer shaders share the same attribute locations for the vertex positions
     // and texture coordinates. This allows switching shaders without rebinding attribute
     // arrays.
@@ -244,6 +251,8 @@ private:
     // This should only be called from removeFromSuperlayer.
     void removeSublayer(LayerChromium*);
 
+    bool descendantsDrawContentRecursive();
+
     Vector<RefPtr<LayerChromium> > m_sublayers;
     LayerChromium* m_superlayer;
 
@@ -266,6 +275,10 @@ private:
     bool m_geometryFlipped;
     bool m_needsDisplayOnBoundsChange;
 
+    // The global depth value of the center of the layer. This value is used
+    // to sort layers from back to front.
+    float m_drawDepth;
+
     // Points to the layer renderer that updates and draws this layer.
     RefPtr<LayerRendererChromium> m_layerRenderer;
 
@@ -274,6 +287,18 @@ private:
     TransformationMatrix m_sublayerTransform;
     TransformationMatrix m_drawTransform;
 
+    // The scissor rectangle that should be used when this layer is drawn.
+    // Inherited by the parent layer and further restricted if this layer masks
+    // to bounds.
+    IntRect m_scissorRect;
+
+    // Render surface associated with this layer. The layer and its descendants
+    // will render to this surface.
+    OwnPtr<RenderSurfaceChromium> m_renderSurface;
+
+    // Hierarchical bounding rect containing the layer and its descendants.
+    IntRect m_drawableContentRect;
+
     String m_name;
 };
 
diff --git a/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp b/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp
index 3d692a2..6ba3b54 100644
--- a/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp
+++ b/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp
@@ -48,29 +48,38 @@
 
 namespace WebCore {
 
-static TransformationMatrix orthoMatrix(float left, float right, float bottom, float top, float nearZ, float farZ)
+static TransformationMatrix orthoMatrix(float left, float right, float bottom, float top)
 {
     float deltaX = right - left;
     float deltaY = top - bottom;
-    float deltaZ = farZ - nearZ;
     TransformationMatrix ortho;
-    if (!deltaX || !deltaY || !deltaZ)
+    if (!deltaX || !deltaY)
         return ortho;
     ortho.setM11(2.0f / deltaX);
     ortho.setM41(-(right + left) / deltaX);
     ortho.setM22(2.0f / deltaY);
     ortho.setM42(-(top + bottom) / deltaY);
-    ortho.setM33(-2.0f / deltaZ);
-    ortho.setM43(-(nearZ + farZ) / deltaZ);
+
+    // Z component of vertices is always set to zero as we don't use the depth buffer
+    // while drawing.
+    ortho.setM33(0);
+
     return ortho;
 }
 
-static inline bool compareLayerZ(const LayerChromium* a, const LayerChromium* b)
+// Returns true if the matrix has no rotation, skew or perspective components to it.
+static bool isScaleOrTranslation(const TransformationMatrix& m)
 {
-    const TransformationMatrix& transformA = a->drawTransform();
-    const TransformationMatrix& transformB = b->drawTransform();
+    return !m.m12() && !m.m13() && !m.m14()
+           && !m.m21() && !m.m23() && !m.m24()
+           && !m.m31() && !m.m32() && !m.m43()
+           && m.m44();
+
+}
 
-    return transformA.m43() < transformB.m43();
+bool LayerRendererChromium::compareLayerZ(const LayerChromium* a, const LayerChromium* b)
+{
+    return a->m_drawDepth < b->m_drawDepth;
 }
 
 PassRefPtr<LayerRendererChromium> LayerRendererChromium::create(PassRefPtr<GraphicsContext3D> context)
@@ -89,11 +98,14 @@ LayerRendererChromium::LayerRendererChromium(PassRefPtr<GraphicsContext3D> conte
     : m_rootLayerTextureId(0)
     , m_rootLayerTextureWidth(0)
     , m_rootLayerTextureHeight(0)
-    , m_scrollShaderProgram(0)
+    , m_textureLayerShaderProgram(0)
     , m_rootLayer(0)
     , m_scrollPosition(IntPoint(-1, -1))
     , m_currentShader(0)
+    , m_currentRenderSurface(0)
+    , m_offscreenFramebufferId(0)
     , m_context(context)
+    , m_defaultRenderSurface(0)
 {
     m_hardwareCompositing = initializeSharedObjects();
 }
@@ -181,12 +193,15 @@ void LayerRendererChromium::prepareToDrawLayers(const IntRect& visibleRect, cons
     int visibleRectWidth = visibleRect.width();
     int visibleRectHeight = visibleRect.height();
     if (visibleRectWidth != m_rootLayerTextureWidth || visibleRectHeight != m_rootLayerTextureHeight) {
-        m_rootLayerTextureWidth = visibleRect.width();
-        m_rootLayerTextureHeight = visibleRect.height();
+        m_rootLayerTextureWidth = visibleRectWidth;
+        m_rootLayerTextureHeight = visibleRectHeight;
 
-        m_projectionMatrix = orthoMatrix(0, visibleRectWidth, visibleRectHeight, 0, -1000, 1000);
         GLC(m_context, m_context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, m_rootLayerTextureWidth, m_rootLayerTextureHeight, 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, 0));
 
+        // Reset the current render surface to force an update of the viewport and
+        // projection matrix next time useRenderSurface is called.
+        m_currentRenderSurface = 0;
+
         // The root layer texture was just resized so its contents are not
         // useful for scrolling.
         skipScroll = true;
@@ -201,8 +216,7 @@ void LayerRendererChromium::prepareToDrawLayers(const IntRect& visibleRect, cons
     // FIXME: These calls can be made once, when the compositor context is initialized.
     GLC(m_context, m_context->disable(GraphicsContext3D::DEPTH_TEST));
     GLC(m_context, m_context->disable(GraphicsContext3D::CULL_FACE));
-    GLC(m_context, m_context->depthFunc(GraphicsContext3D::LEQUAL));
-    GLC(m_context, m_context->clearStencil(0));
+
     // Blending disabled by default. Root layer alpha channel on Windows is incorrect when Skia uses ClearType. 
     GLC(m_context, m_context->disable(GraphicsContext3D::BLEND)); 
 
@@ -230,11 +244,11 @@ void LayerRendererChromium::prepareToDrawLayers(const IntRect& visibleRect, cons
             0.5 * visibleRect.height() + scrollDelta.y(), 0);
         scrolledLayerMatrix.scale3d(1, -1, 1);
 
-        useShader(m_scrollShaderProgram);
-        GLC(m_context, m_context->uniform1i(m_scrollShaderSamplerLocation, 0));
+        useShader(m_textureLayerShaderProgram);
+        GLC(m_context, m_context->uniform1i(m_textureLayerShaderSamplerLocation, 0));
         LayerChromium::drawTexturedQuad(m_context.get(), m_projectionMatrix, scrolledLayerMatrix,
                                         visibleRect.width(), visibleRect.height(), 1,
-                                        m_scrollShaderMatrixLocation, -1);
+                                        m_textureLayerShaderMatrixLocation, m_textureLayerShaderAlphaLocation);
 
         GLC(m_context, m_context->copyTexSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, 0, 0, 0, 0, contentRect.width(), contentRect.height()));
     }
@@ -275,8 +289,16 @@ void LayerRendererChromium::drawLayers(const IntRect& visibleRect, const IntRect
 {
     ASSERT(m_hardwareCompositing);
 
+    m_defaultRenderSurface = m_rootLayer->m_renderSurface.get();
+    if (!m_defaultRenderSurface)
+        m_defaultRenderSurface = m_rootLayer->createRenderSurface();
+    m_defaultRenderSurface->m_contentRect = IntRect(0, 0, m_rootLayerTextureWidth, m_rootLayerTextureHeight);
+
+    useRenderSurface(m_defaultRenderSurface);
+
+    // Clear to blue to make it easier to spot unrendered regions.
     m_context->clearColor(0, 0, 1, 1);
-    m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT | GraphicsContext3D::DEPTH_BUFFER_BIT);
+    m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT);
 
     GLC(m_context, m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_rootLayerTextureId));
 
@@ -295,46 +317,54 @@ void LayerRendererChromium::drawLayers(const IntRect& visibleRect, const IntRect
                                     contentLayerValues->shaderMatrixLocation(), contentLayerValues->shaderAlphaLocation());
     GLC(m_context, m_context->colorMask(true, true, true, true));
 
-    // If culling is enabled then we will cull the backface.
-    GLC(m_context, m_context->cullFace(GraphicsContext3D::BACK));
-    // The orthographic projection is setup such that Y starts at zero and
-    // increases going down the page so we need to adjust the winding order of
-    // front facing triangles.
-    GLC(m_context, m_context->frontFace(GraphicsContext3D::CW));
-
-    // The shader used to render layers returns pre-multiplied alpha colors
-    // so we need to send the blending mode appropriately.
-    GLC(m_context, m_context->enable(GraphicsContext3D::BLEND));
-    GLC(m_context, m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA));
-
     // Set the root visible/content rects --- used by subsequent drawLayers calls.
     m_rootVisibleRect = visibleRect;
     m_rootContentRect = contentRect;
 
-    // Traverse the layer tree and update the layer transforms.
-    float opacity = 1;
-    const Vector<RefPtr<LayerChromium> >& sublayers = m_rootLayer->getSublayers();
-    size_t i;
+    // Scissor out the scrollbars to avoid rendering on top of them.
+    IntRect rootScissorRect(contentRect);
+    // The scissorRect should not include the scroll offset.
+    rootScissorRect.move(-m_scrollPosition.x(), -m_scrollPosition.y());
+    m_rootLayer->m_scissorRect = rootScissorRect;
+
+    Vector<LayerChromium*> renderSurfaceLayerList;
+    renderSurfaceLayerList.append(m_rootLayer.get());
+
     TransformationMatrix identityMatrix;
-    for (i = 0; i < sublayers.size(); i++)
-        updateLayersRecursive(sublayers[i].get(), identityMatrix, opacity);
+    m_defaultRenderSurface->m_layerList.clear();
+    updateLayersRecursive(m_rootLayer.get(), identityMatrix, renderSurfaceLayerList, m_defaultRenderSurface->m_layerList);
 
-    // Enable scissoring to avoid rendering composited layers over the scrollbars.
+    // The shader used to render layers returns pre-multiplied alpha colors
+    // so we need to send the blending mode appropriately.
+    GLC(m_context, m_context->enable(GraphicsContext3D::BLEND));
+    GLC(m_context, m_context->blendFunc(GraphicsContext3D::ONE, GraphicsContext3D::ONE_MINUS_SRC_ALPHA));
     GLC(m_context, m_context->enable(GraphicsContext3D::SCISSOR_TEST));
-    IntRect scissorRect(contentRect);
 
-    // The scissorRect should not include the scroll offset.
-    scissorRect.move(-m_scrollPosition.x(), -m_scrollPosition.y());
-    scissorToRect(scissorRect);
-
-    // Clear the stencil buffer to 0.
-    GLC(m_context, m_context->clear(GraphicsContext3D::STENCIL_BUFFER_BIT));
-    // Disable writes to the stencil buffer.
-    GLC(m_context, m_context->stencilMask(0));
+    // Update the contents of the render surfaces. We traverse the array from
+    // back to front to guarantee that nested render surfaces get rendered in the
+    // correct order.
+    for (int surfaceIndex = renderSurfaceLayerList.size() - 1; surfaceIndex >= 0 ; --surfaceIndex) {
+        LayerChromium* renderSurfaceLayer = renderSurfaceLayerList[surfaceIndex];
+        ASSERT(renderSurfaceLayer->m_renderSurface);
+
+        // Render surfaces whose drawable area has zero width or height
+        // will have no layers associated with them and should be skipped.
+        if (!renderSurfaceLayer->m_renderSurface->m_layerList.size())
+            continue;
+
+        useRenderSurface(renderSurfaceLayer->m_renderSurface.get());
+        if (renderSurfaceLayer != m_rootLayer) {
+            GLC(m_context, m_context->disable(GraphicsContext3D::SCISSOR_TEST));
+            GLC(m_context, m_context->clearColor(0, 0, 0, 0));
+            GLC(m_context, m_context->clear(GraphicsContext3D::COLOR_BUFFER_BIT));
+            GLC(m_context, m_context->enable(GraphicsContext3D::SCISSOR_TEST));
+        }
 
-    // Traverse the layer tree one more time to draw the layers.
-    for (size_t i = 0; i < sublayers.size(); i++)
-        drawLayersRecursive(sublayers[i].get());
+        Vector<LayerChromium*>& layerList = renderSurfaceLayer->m_renderSurface->m_layerList;
+        ASSERT(layerList.size());
+        for (unsigned layerIndex = 0; layerIndex < layerList.size(); ++layerIndex)
+            drawLayer(layerList[layerIndex], renderSurfaceLayer->m_renderSurface.get());
+    }
 
     GLC(m_context, m_context->disable(GraphicsContext3D::SCISSOR_TEST));
     GLC(m_context, m_context->disable(GraphicsContext3D::BLEND));
@@ -408,10 +438,12 @@ bool LayerRendererChromium::isLayerVisible(LayerChromium* layer, const Transform
     return mappedRect.intersects(FloatRect(-1, -1, 2, 2));
 }
 
-// Recursively walks the layer tree starting at the given node and updates the 
-// transform and opacity values.
-void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const TransformationMatrix& parentMatrix, float opacity)
+// Recursively walks the layer tree starting at the given node and computes all the
+// necessary transformations, scissor rectangles, render surfaces, etc.
+void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const TransformationMatrix& parentMatrix, Vector<LayerChromium*>& renderSurfaceLayerList, Vector<LayerChromium*>& layerList)
 {
+    layer->setLayerRenderer(this);
+
     // Compute the new matrix transformation that will be applied to this layer and
     // all its sublayers. It's important to remember that the layer's position
     // is the position of the layer's anchor point. Also, the coordinate system used
@@ -438,182 +470,254 @@ void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const Tr
     float centerOffsetX = (0.5 - anchorPoint.x()) * bounds.width();
     float centerOffsetY = (0.5 - anchorPoint.y()) * bounds.height();
 
-    // M = M[p]
-    TransformationMatrix localMatrix = parentMatrix;
-    // M = M[p] * Tr[l]
-    localMatrix.translate3d(position.x(), position.y(), layer->anchorPointZ());
-    // M = M[p] * Tr[l] * M[l]
-    localMatrix.multLeft(layer->transform());
-    // M = M[p] * Tr[l] * M[l] * Tr[c]
-    localMatrix.translate3d(centerOffsetX, centerOffsetY, -layer->anchorPointZ());
+    TransformationMatrix layerLocalTransform;
+    // LT = Tr[l]
+    layerLocalTransform.translate3d(position.x(), position.y(), layer->anchorPointZ());
+    // LT = Tr[l] * M[l]
+    layerLocalTransform.multLeft(layer->transform());
+    // LT = Tr[l] * M[l] * Tr[c]
+    layerLocalTransform.translate3d(centerOffsetX, centerOffsetY, -layer->anchorPointZ());
+
+    TransformationMatrix combinedTransform = parentMatrix;
+    combinedTransform = combinedTransform.multLeft(layerLocalTransform);
+
+    FloatRect layerRect(-0.5 * layer->bounds().width(), -0.5 * layer->bounds().height(), layer->bounds().width(), layer->bounds().height());
+    IntRect transformedLayerRect;
+
+    // The layer and its descendants render on a new RenderSurface if any of
+    // these conditions hold:
+    // 1. The layer clips its descendants and its transform is not a simple translation.
+    // 2. If the layer has opacity != 1 and does not have a preserves-3d transform style.
+    // If a layer preserves-3d then we don't create a RenderSurface for it to avoid flattening
+    // out its children. The opacity value of the children layers is multiplied by the opacity
+    // of their parent.
+    bool useSurfaceForClipping = layer->masksToBounds() && !isScaleOrTranslation(combinedTransform);
+    bool useSurfaceForOpacity = layer->opacity() != 1 && !layer->preserves3D();
+    if ((useSurfaceForClipping || useSurfaceForOpacity) && layer->descendantsDrawContent()) {
+        RenderSurfaceChromium* renderSurface = layer->m_renderSurface.get();
+        if (!renderSurface)
+            renderSurface = layer->createRenderSurface();
+
+        // The origin of the new surface is the upper left corner of the layer.
+        layer->m_drawTransform = TransformationMatrix();
+        layer->m_drawTransform.translate3d(0.5 * bounds.width(), 0.5 * bounds.height(), 0);
+
+        transformedLayerRect = IntRect(0, 0, bounds.width(), bounds.height());
+
+        // Layer's opacity will be applied when drawing the render surface.
+        renderSurface->m_drawOpacity = layer->opacity();
+        if (layer->superlayer()->preserves3D())
+            renderSurface->m_drawOpacity *= layer->superlayer()->m_drawOpacity;
+        layer->m_drawOpacity = 1;
+
+        TransformationMatrix layerOriginTransform = combinedTransform;
+        layerOriginTransform.translate3d(-0.5 * bounds.width(), -0.5 * bounds.height(), 0);
+        renderSurface->m_originTransform = layerOriginTransform;
+        if (layerOriginTransform.isInvertible() && layer->superlayer()) {
+            TransformationMatrix parentToLayer = layerOriginTransform.inverse();
+
+            layer->m_scissorRect = parentToLayer.mapRect(layer->superlayer()->m_scissorRect);
+        } else
+            layer->m_scissorRect = IntRect();
+
+        // The render surface scissor rect is the scissor rect that needs to
+        // be applied before drawing the render surface onto its containing
+        // surface and is therefore expressed in the superlayer's coordinate system.
+        renderSurface->m_scissorRect = layer->superlayer()->m_scissorRect;
+
+        renderSurface->m_layerList.clear();
+
+        renderSurfaceLayerList.append(layer);
+    } else {
+        // DT = M[p] * LT
+        layer->m_drawTransform = combinedTransform;
+        transformedLayerRect = enclosingIntRect(layer->m_drawTransform.mapRect(layerRect));
+
+        layer->m_drawOpacity = layer->opacity();
+
+        if (layer->superlayer()) {
+            if (layer->superlayer()->preserves3D())
+               layer->m_drawOpacity *= layer->superlayer()->m_drawOpacity;
+
+            // Layers inherit the scissor rect from their superlayer.
+            layer->m_scissorRect = layer->superlayer()->m_scissorRect;
 
-    // Calculate the layer's opacity.
-    opacity *= layer->opacity();
+            layer->m_targetRenderSurface = layer->superlayer()->m_targetRenderSurface;
+        }
+
+        if (layer != m_rootLayer)
+            layer->m_renderSurface = 0;
+
+        if (layer->masksToBounds())
+            layer->m_scissorRect.intersect(transformedLayerRect);
+    }
+
+    if (layer->m_renderSurface)
+        layer->m_targetRenderSurface = layer->m_renderSurface.get();
+    else {
+        ASSERT(layer->superlayer());
+        layer->m_targetRenderSurface = layer->superlayer()->m_targetRenderSurface;
+    }
 
-    layer->setDrawTransform(localMatrix);
-    layer->setDrawOpacity(opacity);
+    // m_drawableContentRect is always stored in the coordinate system of the
+    // RenderSurface the layer draws into.
+    if (layer->drawsContent())
+        layer->m_drawableContentRect = transformedLayerRect;
+    else
+        layer->m_drawableContentRect = IntRect();
+
+    TransformationMatrix sublayerMatrix = layer->m_drawTransform;
 
     // Flatten to 2D if the layer doesn't preserve 3D.
     if (!layer->preserves3D()) {
-        localMatrix.setM13(0);
-        localMatrix.setM23(0);
-        localMatrix.setM31(0);
-        localMatrix.setM32(0);
-        localMatrix.setM33(1);
-        localMatrix.setM34(0);
-        localMatrix.setM43(0);
+        sublayerMatrix.setM13(0);
+        sublayerMatrix.setM23(0);
+        sublayerMatrix.setM31(0);
+        sublayerMatrix.setM32(0);
+        sublayerMatrix.setM33(1);
+        sublayerMatrix.setM34(0);
+        sublayerMatrix.setM43(0);
     }
 
     // Apply the sublayer transform at the center of the layer.
-    localMatrix.multLeft(layer->sublayerTransform());
+    sublayerMatrix.multLeft(layer->sublayerTransform());
 
-    // The origin of the sublayers is actually the bottom left corner of the layer
-    // (or top left when looking it it from the browser's pespective) instead of the center.
-    // The matrix passed down to the sublayers is therefore:
+    // The origin of the sublayers is the top left corner of the layer, not the
+    // center. The matrix passed down to the sublayers is therefore:
     // M[s] = M * Tr[-center]
-    localMatrix.translate3d(-bounds.width() * 0.5, -bounds.height() * 0.5, 0);
+    sublayerMatrix.translate3d(-bounds.width() * 0.5, -bounds.height() * 0.5, 0);
+
+    Vector<LayerChromium*>& descendants = (layer->m_renderSurface ? layer->m_renderSurface->m_layerList : layerList);
+    descendants.append(layer);
+    unsigned thisLayerIndex = descendants.size() - 1;
 
     const Vector<RefPtr<LayerChromium> >& sublayers = layer->getSublayers();
-    for (size_t i = 0; i < sublayers.size(); i++)
-        updateLayersRecursive(sublayers[i].get(), localMatrix, opacity);
+    for (size_t i = 0; i < sublayers.size(); ++i) {
+        LayerChromium* sublayer = sublayers[i].get();
+        updateLayersRecursive(sublayer, sublayerMatrix, renderSurfaceLayerList, descendants);
+
+        if (sublayer->m_renderSurface) {
+            RenderSurfaceChromium* sublayerRenderSurface = sublayer->m_renderSurface.get();
+            const IntRect& contentRect = sublayerRenderSurface->m_contentRect;
+            FloatRect sublayerRect(-0.5 * contentRect.width(), -0.5 * contentRect.height(),
+                                   contentRect.width(), contentRect.height());
+            layer->m_drawableContentRect.unite(enclosingIntRect(sublayerRenderSurface->m_drawTransform.mapRect(sublayerRect)));
+            descendants.append(sublayer);
+        } else
+            layer->m_drawableContentRect.unite(sublayer->m_drawableContentRect);
+    }
 
-    layer->setLayerRenderer(this);
-}
+    if (layer->masksToBounds())
+        layer->m_drawableContentRect.intersect(transformedLayerRect);
 
-// Does a quick draw of the given layer into the stencil buffer. If decrement
-// is true then it decrements the current stencil values otherwise it increments them.
-void LayerRendererChromium::drawLayerIntoStencilBuffer(LayerChromium* layer, bool decrement)
-{
-    // Enable writes to the stencil buffer and increment the stencil values
-    // by one for every pixel under the current layer.
-    GLC(m_context, m_context->stencilMask(0xff));
-    GLC(m_context, m_context->stencilFunc(GraphicsContext3D::ALWAYS, 1, 0xff));
-    unsigned stencilOp = (decrement ? GraphicsContext3D::DECR : GraphicsContext3D::INCR);
-    GLC(m_context, m_context->stencilOp(stencilOp, stencilOp, stencilOp));
+    if (layer->m_renderSurface && layer != m_rootLayer) {
+        RenderSurfaceChromium* renderSurface = layer->m_renderSurface.get();
+        renderSurface->m_contentRect = layer->m_drawableContentRect;
+        FloatPoint surfaceCenter = renderSurface->contentRectCenter();
 
-    GLC(m_context, m_context->colorMask(false, false, false, false));
+        // Restrict the RenderSurface size to the portion that's visible.
+        FloatSize centerOffsetDueToClipping;
+        renderSurface->m_contentRect.intersect(layer->m_scissorRect);
+        FloatPoint clippedSurfaceCenter = renderSurface->contentRectCenter();
+        centerOffsetDueToClipping = clippedSurfaceCenter - surfaceCenter;
 
-    layer->drawAsMask();
+        // The RenderSurface backing texture cannot exceed the maximum supported
+        // texture size.
+        renderSurface->m_contentRect.setWidth(std::min(renderSurface->m_contentRect.width(), m_maxTextureSize));
+        renderSurface->m_contentRect.setHeight(std::min(renderSurface->m_contentRect.height(), m_maxTextureSize));
 
-    // Disable writes to the stencil buffer.
-    GLC(m_context, m_context->stencilMask(0));
-    GLC(m_context, m_context->colorMask(true, true, true, true));
+        if (renderSurface->m_contentRect.isEmpty())
+            renderSurface->m_layerList.clear();
+
+        // Since the layer starts a new render surface we need to adjust its
+        // scissor rect to be expressed in the new surface's coordinate system.
+        layer->m_scissorRect = layer->m_drawableContentRect;
+
+        // Adjust the origin of the transform to be the center of the render surface.
+        renderSurface->m_drawTransform = renderSurface->m_originTransform;
+        renderSurface->m_drawTransform.translate3d(surfaceCenter.x() + centerOffsetDueToClipping.width(), surfaceCenter.y() + centerOffsetDueToClipping.height(), 0);
+    }
+
+    // Compute the depth value of the center of the layer which will be used when
+    // sorting the layers for the preserves-3d property.
+    TransformationMatrix& layerDrawMatrix = layer->m_renderSurface ? layer->m_renderSurface->m_drawTransform : layer->m_drawTransform;
+    if (layer->superlayer()) {
+        if (!layer->superlayer()->preserves3D())
+            layer->m_drawDepth = layer->superlayer()->m_drawDepth;
+        else
+            layer->m_drawDepth = layerDrawMatrix.m43();
+    } else
+        layer->m_drawDepth = 0;
+
+    // If preserves-3d then sort all the descendants by the Z coordinate of their
+    // center. If the preserves-3d property is also set on the superlayer then
+    // skip the sorting as the superlayer will sort all the descendants anyway.
+    if (layer->preserves3D() && (!layer->superlayer() || !layer->superlayer()->preserves3D()))
+        std::stable_sort(&descendants.at(thisLayerIndex), descendants.end(), compareLayerZ);
 }
 
-// Recursively walk the layer tree and draw the layers.
-void LayerRendererChromium::drawLayersRecursive(LayerChromium* layer)
+bool LayerRendererChromium::useRenderSurface(RenderSurfaceChromium* renderSurface)
 {
-    static bool depthTestEnabledForSubtree = false;
-    static int currentStencilValue = 0;
+    if (m_currentRenderSurface == renderSurface)
+        return true;
 
-    // Check if the layer falls within the visible bounds of the page.
-    IntRect layerRect = layer->getDrawRect();
-    bool isLayerVisible = m_currentScissorRect.intersects(layerRect);
+    m_currentRenderSurface = renderSurface;
 
-    // Enable depth testing for this layer and all its descendants if preserves3D is set.
-    bool mustClearDepth = false;
-    if (layer->preserves3D()) {
-        if (!depthTestEnabledForSubtree) {
-            GLC(m_context, m_context->enable(GraphicsContext3D::DEPTH_TEST));
-            depthTestEnabledForSubtree = true;
-
-            // Need to clear the depth buffer when we're done rendering this subtree.
-            mustClearDepth = true;
-        }
+    if (renderSurface == m_defaultRenderSurface) {
+        GLC(m_context, m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0));
+        setDrawViewportRect(renderSurface->m_contentRect, true);
+        return true;
     }
 
-    if (isLayerVisible)
-        drawLayer(layer);
-
-    // FIXME: We should check here if the layer has descendants that draw content
-    // before we setup for clipping.
-    IntRect previousScissorRect = m_currentScissorRect;
-    bool mustResetScissorRect = false;
-    bool didStencilDraw = false;
-    if (layer->masksToBounds()) {
-        // If the layer isn't rotated then we can use scissoring otherwise we need
-        // to clip using the stencil buffer.
-        if (layer->drawTransform().isIdentityOrTranslation()) {
-            IntRect currentScissorRect = previousScissorRect;
-            currentScissorRect.intersect(layerRect);
-            if (currentScissorRect != previousScissorRect) {
-                scissorToRect(currentScissorRect);
-                mustResetScissorRect = true;
-            }
-        } else if (currentStencilValue < ((1 << m_numStencilBits) - 1)) {
-            // Clipping using the stencil buffer works as follows: When we encounter
-            // a clipping layer we increment the stencil buffer values for all the pixels
-            // the layer touches. As a result 1's will be stored in the stencil buffer for pixels under
-            // the first clipping layer found in a traversal, 2's for pixels in the intersection
-            // of two nested clipping layers, etc. When the sublayers of a clipping layer are drawn
-            // we turn on stencil testing to render only pixels that have the correct stencil
-            // value (one that matches the value of currentStencilValue). As the recursion unravels,
-            // we decrement the stencil buffer values for each clipping layer. When the entire layer tree
-            // is rendered, the stencil values should be all back to zero. An 8 bit stencil buffer
-            // will allow us up to 255 nested clipping layers which is hopefully enough.
-            if (!currentStencilValue)
-                GLC(m_context, m_context->enable(GraphicsContext3D::STENCIL_TEST));
-
-            drawLayerIntoStencilBuffer(layer, false);
-
-            currentStencilValue++;
-            didStencilDraw = true;
-        }
-    }
-    // Sublayers will render only if the value in the stencil buffer is equal to
-    // currentStencilValue.
-    if (didStencilDraw) {
-        // The sublayers will render only if the stencil test passes.
-        GLC(m_context, m_context->stencilFunc(GraphicsContext3D::EQUAL, currentStencilValue, 0xff));
-    }
+    GLC(m_context, m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_offscreenFramebufferId));
 
-    // If we're using depth testing then we need to sort the children in Z to
-    // get the transparency to work properly.
-    if (depthTestEnabledForSubtree) {
-        const Vector<RefPtr<LayerChromium> >& sublayers = layer->getSublayers();
-        Vector<LayerChromium*> sublayerList;
-        size_t i;
-        for (i = 0; i < sublayers.size(); i++)
-            sublayerList.append(sublayers[i].get());
-
-        // Sort by the z coordinate of the layer center so that layers further away
-        // are drawn first.
-        std::stable_sort(sublayerList.begin(), sublayerList.end(), compareLayerZ);
-
-        for (i = 0; i < sublayerList.size(); i++)
-            drawLayersRecursive(sublayerList[i]);
-    } else {
-        const Vector<RefPtr<LayerChromium> >& sublayers = layer->getSublayers();
-        for (size_t i = 0; i < sublayers.size(); i++)
-            drawLayersRecursive(sublayers[i].get());
-    }
+    renderSurface->prepareContentsTexture();
 
-    if (didStencilDraw) {
-        // Draw into the stencil buffer subtracting 1 for every pixel hit
-        // effectively removing this mask
-        drawLayerIntoStencilBuffer(layer, true);
-        currentStencilValue--;
-        if (!currentStencilValue) {
-            // Disable stencil testing.
-            GLC(m_context, m_context->disable(GraphicsContext3D::STENCIL_TEST));
-            GLC(m_context, m_context->stencilFunc(GraphicsContext3D::ALWAYS, 0, 0xff));
-        }
-    }
+    GLC(m_context, m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0,
+                                                   GraphicsContext3D::TEXTURE_2D, renderSurface->m_contentsTextureId, 0));
 
-    if (mustResetScissorRect) {
-        scissorToRect(previousScissorRect);
+#if !defined ( NDEBUG )
+    if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
+        ASSERT_NOT_REACHED();
+        return false;
     }
+#endif
 
-    if (mustClearDepth) {
-        GLC(m_context, m_context->disable(GraphicsContext3D::DEPTH_TEST));
-        GLC(m_context, m_context->clear(GraphicsContext3D::DEPTH_BUFFER_BIT));
-        depthTestEnabledForSubtree = false;
-    }
+    setDrawViewportRect(renderSurface->m_contentRect, false);
+    return true;
 }
 
-void LayerRendererChromium::drawLayer(LayerChromium* layer)
+void LayerRendererChromium::drawLayer(LayerChromium* layer, RenderSurfaceChromium* targetSurface)
 {
-    IntSize bounds = layer->bounds();
+    if (layer->m_renderSurface && layer->m_renderSurface != targetSurface) {
+        GLC(m_context, m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, layer->m_renderSurface->m_contentsTextureId));
+        useShader(m_textureLayerShaderProgram);
+
+        setScissorToRect(layer->m_renderSurface->m_scissorRect);
+
+        IntRect contentRect = layer->m_renderSurface->m_contentRect;
+        LayerChromium::drawTexturedQuad(m_context.get(), m_projectionMatrix, layer->m_renderSurface->m_drawTransform,
+                                        contentRect.width(), contentRect.height(), layer->m_renderSurface->m_drawOpacity,
+                                        m_textureLayerShaderMatrixLocation, m_textureLayerShaderAlphaLocation);
+        return;
+    }
+
+    if (layer->m_bounds.isEmpty())
+        return;
+
+    setScissorToRect(layer->m_scissorRect);
+
+    // Check if the layer falls within the visible bounds of the page.
+    IntRect layerRect = layer->getDrawRect();
+    bool isLayerVisible = layer->m_scissorRect.intersects(layerRect);
+    if (!isLayerVisible)
+        return;
+
+    // FIXME: Need to take into account the transform of the containing
+    // RenderSurface here, otherwise single-sided layers that draw on
+    // transformed surfaces won't always be culled properly.
+    if (!layer->doubleSided() && layer->m_drawTransform.m33() < 0)
+         return;
 
     if (layer->drawsContent()) {
         // Update the contents of the layer if necessary.
@@ -623,11 +727,6 @@ void LayerRendererChromium::drawLayer(LayerChromium* layer)
             m_context->makeContextCurrent();
         }
 
-        if (layer->doubleSided())
-            m_context->disable(GraphicsContext3D::CULL_FACE);
-        else
-            m_context->enable(GraphicsContext3D::CULL_FACE);
-
         layer->draw();
     }
 
@@ -637,12 +736,19 @@ void LayerRendererChromium::drawLayer(LayerChromium* layer)
 
 // Sets the scissor region to the given rectangle. The coordinate system for the
 // scissorRect has its origin at the top left corner of the current visible rect.
-void LayerRendererChromium::scissorToRect(const IntRect& scissorRect)
+void LayerRendererChromium::setScissorToRect(const IntRect& scissorRect)
 {
-    // Compute the lower left corner of the scissor rect.
-    int bottom = std::max(m_rootVisibleRect.height() - scissorRect.bottom(), 0);
-    GLC(m_context, m_context->scissor(scissorRect.x(), bottom, scissorRect.width(), scissorRect.height()));
-    m_currentScissorRect = scissorRect;
+    // The scissor coordinates must be supplied in viewport space so we need to offset
+    // by the relative position of the top left corner of the current render surface.
+    int scissorX = scissorRect.x() - m_currentRenderSurface->m_contentRect.x();
+    // When rendering to the default render surface we're rendering upside down so the top
+    // of the GL scissor is the bottom of our layer.
+    int scissorY;
+    if (m_currentRenderSurface == m_defaultRenderSurface)
+        scissorY = m_currentRenderSurface->m_contentRect.height() - (scissorRect.bottom() - m_currentRenderSurface->m_contentRect.y());
+    else
+        scissorY = scissorRect.y() - m_currentRenderSurface->m_contentRect.y();
+    GLC(m_context, m_context->scissor(scissorX, scissorY, scissorRect.width(), scissorRect.height()));
 }
 
 bool LayerRendererChromium::makeContextCurrent()
@@ -659,6 +765,20 @@ bool LayerRendererChromium::checkTextureSize(const IntSize& textureSize)
     return true;
 }
 
+// Sets the coordinate range of content that ends being drawn onto the target render surface.
+// The target render surface is assumed to have an origin at 0, 0 and the width and height of
+// of the drawRect.
+void LayerRendererChromium::setDrawViewportRect(const IntRect& drawRect, bool flipY)
+{
+    if (flipY)
+        m_projectionMatrix = orthoMatrix(drawRect.x(), drawRect.right(), drawRect.bottom(), drawRect.y());
+    else
+        m_projectionMatrix = orthoMatrix(drawRect.x(), drawRect.right(), drawRect.y(), drawRect.bottom());
+    GLC(m_context, m_context->viewport(0, 0, drawRect.width(), drawRect.height()));
+}
+
+
+
 void LayerRendererChromium::resizeOnscreenContent(const IntSize& size)
 {
     if (m_context)
@@ -669,10 +789,10 @@ bool LayerRendererChromium::initializeSharedObjects()
 {
     makeContextCurrent();
 
-    // Vertex and fragment shaders for rendering the scrolled root layer quad.
-    // They differ from a regular content layer shader in that they don't swizzle
-    // the colors or take an alpha value.
-    char scrollVertexShaderString[] =
+    // The following program composites layers whose contents are the results of a previous
+    // render operation and therefore doesn't perform any color swizzling. It is used
+    // in scrolling and for compositing offscreen textures.
+    char textureLayerVertexShaderString[] =
         "attribute vec4 a_position;   \n"
         "attribute vec2 a_texCoord;   \n"
         "uniform mat4 matrix;         \n"
@@ -682,27 +802,29 @@ bool LayerRendererChromium::initializeSharedObjects()
         "  gl_Position = matrix * a_position; \n"
         "  v_texCoord = a_texCoord;   \n"
         "}                            \n";
-    char scrollFragmentShaderString[] =
+    char textureLayerFragmentShaderString[] =
         "precision mediump float;                            \n"
         "varying vec2 v_texCoord;                            \n"
         "uniform sampler2D s_texture;                        \n"
+        "uniform float alpha;                                \n"
         "void main()                                         \n"
         "{                                                   \n"
         "  vec4 texColor = texture2D(s_texture, v_texCoord); \n"
-        "  gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w); \n"
+        "  gl_FragColor = vec4(texColor.x, texColor.y, texColor.z, texColor.w) * alpha; \n"
         "}                                                   \n";
 
-    m_scrollShaderProgram = LayerChromium::createShaderProgram(m_context.get(), scrollVertexShaderString, scrollFragmentShaderString);
-    if (!m_scrollShaderProgram) {
+    m_textureLayerShaderProgram = LayerChromium::createShaderProgram(m_context.get(), textureLayerVertexShaderString, textureLayerFragmentShaderString);
+    if (!m_textureLayerShaderProgram) {
         LOG_ERROR("LayerRendererChromium: Failed to create scroll shader program");
         cleanupSharedObjects();
         return false;
     }
 
-    GLC(m_context, m_scrollShaderSamplerLocation = m_context->getUniformLocation(m_scrollShaderProgram, "s_texture"));
-    GLC(m_context, m_scrollShaderMatrixLocation = m_context->getUniformLocation(m_scrollShaderProgram, "matrix"));
-    if (m_scrollShaderSamplerLocation == -1 || m_scrollShaderMatrixLocation == -1) {
-        LOG_ERROR("Failed to initialize scroll shader.");
+    GLC(m_context, m_textureLayerShaderSamplerLocation = m_context->getUniformLocation(m_textureLayerShaderProgram, "s_texture"));
+    GLC(m_context, m_textureLayerShaderMatrixLocation = m_context->getUniformLocation(m_textureLayerShaderProgram, "matrix"));
+    GLC(m_context, m_textureLayerShaderAlphaLocation = m_context->getUniformLocation(m_textureLayerShaderProgram, "alpha"));
+    if (m_textureLayerShaderSamplerLocation == -1 || m_textureLayerShaderMatrixLocation == -1 || m_textureLayerShaderAlphaLocation == -1) {
+        LOG_ERROR("Failed to initialize texture layer shader.");
         cleanupSharedObjects();
         return false;
     }
@@ -723,8 +845,8 @@ bool LayerRendererChromium::initializeSharedObjects()
     // Get the max texture size supported by the system.
     GLC(m_context, m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &m_maxTextureSize));
 
-    // Get the number of bits available in the stencil buffer.
-    GLC(m_context, m_context->getIntegerv(GraphicsContext3D::STENCIL_BITS, &m_numStencilBits));
+    // Create an FBO for doing offscreen rendering.
+    GLC(m_context, m_offscreenFramebufferId = m_context->createFramebuffer());
 
     m_layerSharedValues = adoptPtr(new LayerChromium::SharedValues(m_context.get()));
     m_contentLayerSharedValues = adoptPtr(new ContentLayerChromium::SharedValues(m_context.get()));
@@ -751,15 +873,18 @@ void LayerRendererChromium::cleanupSharedObjects()
     m_videoLayerSharedValues.clear();
     m_pluginLayerSharedValues.clear();
 
-    if (m_scrollShaderProgram) {
-        GLC(m_context, m_context->deleteProgram(m_scrollShaderProgram));
-        m_scrollShaderProgram = 0;
+    if (m_textureLayerShaderProgram) {
+        GLC(m_context, m_context->deleteProgram(m_textureLayerShaderProgram));
+        m_textureLayerShaderProgram = 0;
     }
 
     if (m_rootLayerTextureId) {
         deleteLayerTexture(m_rootLayerTextureId);
         m_rootLayerTextureId = 0;
     }
+
+    if (m_offscreenFramebufferId)
+        GLC(m_context, m_context->deleteFramebuffer(m_offscreenFramebufferId));
 }
 
 } // namespace WebCore
diff --git a/WebCore/platform/graphics/chromium/LayerRendererChromium.h b/WebCore/platform/graphics/chromium/LayerRendererChromium.h
index 52fbe36..531d652 100644
--- a/WebCore/platform/graphics/chromium/LayerRendererChromium.h
+++ b/WebCore/platform/graphics/chromium/LayerRendererChromium.h
@@ -39,6 +39,7 @@
 #include "IntRect.h"
 #include "LayerChromium.h"
 #include "PluginLayerChromium.h"
+#include "RenderSurfaceChromium.h"
 #include "SkBitmap.h"
 #include "VideoLayerChromium.h"
 #include <wtf/HashMap.h>
@@ -94,8 +95,6 @@ public:
     unsigned createLayerTexture();
     void deleteLayerTexture(unsigned);
 
-    IntRect currentScissorRect() const { return m_currentScissorRect; }
-
     static void debugGLCall(GraphicsContext3D*, const char* command, const char* file, int line);
 
     const TransformationMatrix& projectionMatrix() const { return m_projectionMatrix; }
@@ -118,21 +117,22 @@ public:
 
 private:
     explicit LayerRendererChromium(PassRefPtr<GraphicsContext3D> graphicsContext3D);
+    void updateLayersRecursive(LayerChromium* layer, const TransformationMatrix& parentMatrix, Vector<LayerChromium*>& renderSurfaceLayerList, Vector<LayerChromium*>& layerList);
 
-    void updateLayersRecursive(LayerChromium* layer, const TransformationMatrix& parentMatrix, float opacity);
-
-    void drawLayersRecursive(LayerChromium*);
-
-    void drawLayer(LayerChromium*);
+    void drawLayer(LayerChromium*, RenderSurfaceChromium*);
 
     bool isLayerVisible(LayerChromium*, const TransformationMatrix&, const IntRect& visibleRect);
 
-    void drawLayerIntoStencilBuffer(LayerChromium*, bool decrement);
+    void setScissorToRect(const IntRect&);
+
+    void setDrawViewportRect(const IntRect&, bool flipY);
 
-    void scissorToRect(const IntRect&);
+    bool useRenderSurface(RenderSurfaceChromium*);
 
     bool makeContextCurrent();
 
+    static bool compareLayerZ(const LayerChromium*, const LayerChromium*);
+
     bool initializeSharedObjects();
     void cleanupSharedObjects();
 
@@ -140,10 +140,12 @@ private:
     int m_rootLayerTextureWidth;
     int m_rootLayerTextureHeight;
 
-    // Scroll shader uniform locations.
-    unsigned m_scrollShaderProgram;
-    int m_scrollShaderSamplerLocation;
-    int m_scrollShaderMatrixLocation;
+    // Shader uniform locations used by layers whose contents are the results of a
+    // previous rendering operation.
+    unsigned m_textureLayerShaderProgram;
+    int m_textureLayerShaderSamplerLocation;
+    int m_textureLayerShaderMatrixLocation;
+    int m_textureLayerShaderAlphaLocation;
 
     TransformationMatrix m_projectionMatrix;
 
@@ -152,7 +154,10 @@ private:
     IntPoint m_scrollPosition;
     bool m_hardwareCompositing;
 
-    unsigned int m_currentShader;
+    unsigned m_currentShader;
+    RenderSurfaceChromium* m_currentRenderSurface;
+
+    unsigned m_offscreenFramebufferId;
 
 #if PLATFORM(SKIA)
     OwnPtr<skia::PlatformCanvas> m_rootLayerCanvas;
@@ -168,12 +173,10 @@ private:
 
     IntRect m_rootVisibleRect;
     IntRect m_rootContentRect;
-    IntRect m_currentScissorRect;
 
+    // Maximum texture dimensions supported.
     int m_maxTextureSize;
 
-    int m_numStencilBits;
-
     // Store values that are shared between instances of each layer type
     // associated with this instance of the compositor. Since there can be
     // multiple instances of the compositor running in the same renderer process
@@ -185,6 +188,8 @@ private:
     OwnPtr<PluginLayerChromium::SharedValues> m_pluginLayerSharedValues;
 
     RefPtr<GraphicsContext3D> m_context;
+
+    RenderSurfaceChromium* m_defaultRenderSurface;
 };
 
 // Setting DEBUG_GL_CALLS to 1 will call glGetError() after almost every GL
diff --git a/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp b/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp
new file mode 100644
index 0000000..816fd3d
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "RenderSurfaceChromium.h"
+
+#include "GraphicsContext3D.h"
+#include "LayerRendererChromium.h"
+
+namespace WebCore {
+
+RenderSurfaceChromium::RenderSurfaceChromium(LayerChromium* owningLayer)
+    : m_owningLayer(owningLayer)
+    , m_contentsTextureId(0)
+{
+}
+
+RenderSurfaceChromium::~RenderSurfaceChromium()
+{
+    cleanupResources();
+}
+
+void RenderSurfaceChromium::cleanupResources()
+{
+    if (!m_contentsTextureId)
+        return;
+
+    ASSERT(layerRenderer());
+
+    layerRenderer()->deleteLayerTexture(m_contentsTextureId);
+    m_contentsTextureId = 0;
+    m_allocatedTextureSize = IntSize();
+}
+
+LayerRendererChromium* RenderSurfaceChromium::layerRenderer()
+{
+    ASSERT(m_owningLayer);
+    return m_owningLayer->layerRenderer();
+}
+
+void RenderSurfaceChromium::prepareContentsTexture()
+{
+    ASSERT(m_owningLayer);
+
+    if (!m_contentsTextureId) {
+        m_contentsTextureId = layerRenderer()->createLayerTexture();
+        ASSERT(m_contentsTextureId);
+        m_allocatedTextureSize = IntSize();
+    }
+
+    IntSize requiredSize(m_contentRect.width(), m_contentRect.height());
+    if (m_allocatedTextureSize != requiredSize) {
+        GraphicsContext3D* context = m_owningLayer->layerRenderer()->context();
+        GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_contentsTextureId));
+        GLC(context, context->texImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA,
+                                             requiredSize.width(), requiredSize.height(), 0, GraphicsContext3D::RGBA,
+                                             GraphicsContext3D::UNSIGNED_BYTE, 0));
+        m_allocatedTextureSize = requiredSize;
+    }
+}
+
+}
+#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h b/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h
new file mode 100644
index 0000000..1f33527
--- /dev/null
+++ b/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef RenderSurfaceChromium_h
+#define RenderSurfaceChromium_h
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "FloatRect.h"
+#include "IntRect.h"
+#include "TransformationMatrix.h"
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class LayerRendererChromium;
+class LayerChromium;
+
+class RenderSurfaceChromium : public Noncopyable {
+    friend class LayerRendererChromium;
+public:
+    explicit RenderSurfaceChromium(LayerChromium*);
+    ~RenderSurfaceChromium();
+
+    void prepareContentsTexture();
+    void cleanupResources();
+
+    FloatPoint contentRectCenter() const { return FloatRect(m_contentRect).center(); }
+    IntRect contentRect() const { return m_contentRect; }
+
+private:
+    LayerRendererChromium* layerRenderer();
+
+    LayerChromium* m_owningLayer;
+    IntRect m_contentRect;
+    unsigned m_contentsTextureId;
+    float m_drawOpacity;
+    IntSize m_allocatedTextureSize;
+    TransformationMatrix m_drawTransform;
+    TransformationMatrix m_originTransform;
+    IntRect m_scissorRect;
+    Vector<LayerChromium*> m_layerList;
+};
+
+}
+#endif // USE(ACCELERATED_COMPOSITING)
+
+#endif
diff --git a/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp b/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp
index fa6c2c8..feb7ebc 100644
--- a/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp
+++ b/WebCore/platform/graphics/chromium/VideoLayerChromium.cpp
@@ -188,6 +188,7 @@ VideoLayerChromium::~VideoLayerChromium()
 
 void VideoLayerChromium::cleanupResources()
 {
+    LayerChromium::cleanupResources();
     releaseCurrentFrame();
     if (!layerRenderer())
         return;

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list