2011-02-02 Vangelis Kokkevis <vangelis@chromium.org>
authorvangelis@chromium.org <vangelis@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 2 Feb 2011 23:08:21 +0000 (23:08 +0000)
committervangelis@chromium.org <vangelis@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 2 Feb 2011 23:08:21 +0000 (23:08 +0000)
        [chromium] Adding support for reflections to the accelerated
        compositing path.
        https://bugs.webkit.org/show_bug.cgi?id=53179

        All layout tests in compositing/reflections generate correct
        results with the exception of:
        1. nested-reflection-anchor-point.html : There appears to be
           some issue with the layer transform math that I haven't been
           able to track down yet.
        2. reflection-opacity.html : The current implementation applies
           opacity before doing the reflection which makes this test
           produce incorrect results.  This will affect reflected layers
           with opacity that overlap their original layer.  FIXME comment
           added in the code.

        Tests: Covered by existing layout tests in compositing/reflections.
               Please see above for exceptions.

        * platform/graphics/chromium/GraphicsLayerChromium.cpp:
        (WebCore::GraphicsLayerChromium::setReplicatedByLayer):
        (WebCore::GraphicsLayerChromium::updateAnchorPoint):
        * platform/graphics/chromium/GraphicsLayerChromium.h:
        * platform/graphics/chromium/LayerChromium.cpp:
        (WebCore::LayerChromium::LayerChromium):
        * platform/graphics/chromium/LayerChromium.h:
        (WebCore::LayerChromium::setReplicaLayer):
        (WebCore::LayerChromium::replicaLayer):
        * platform/graphics/chromium/LayerRendererChromium.cpp:
        (WebCore::LayerRendererChromium::updateLayersRecursive):
        (WebCore::LayerRendererChromium::drawLayer):
        * platform/graphics/chromium/RenderSurfaceChromium.cpp:
        (WebCore::RenderSurfaceChromium::drawableContentRect):
        (WebCore::RenderSurfaceChromium::drawSurface):
        (WebCore::RenderSurfaceChromium::draw):
        * platform/graphics/chromium/RenderSurfaceChromium.h:
        (WebCore::RenderSurfaceChromium::drawTransform):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@77425 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.cpp
Source/WebCore/platform/graphics/chromium/GraphicsLayerChromium.h
Source/WebCore/platform/graphics/chromium/LayerChromium.cpp
Source/WebCore/platform/graphics/chromium/LayerChromium.h
Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp
Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.cpp
Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h

index fb10a894601cb52e8d9341ed3fa863e143cee138..5d315e6c79d88ea413f5550a8ddee70f2bcaf466 100644 (file)
@@ -1,3 +1,42 @@
+2011-02-02  Vangelis Kokkevis  <vangelis@chromium.org>
+
+        [chromium] Adding support for reflections to the accelerated
+        compositing path.
+        https://bugs.webkit.org/show_bug.cgi?id=53179
+
+        All layout tests in compositing/reflections generate correct
+        results with the exception of:
+        1. nested-reflection-anchor-point.html : There appears to be
+           some issue with the layer transform math that I haven't been
+           able to track down yet.
+        2. reflection-opacity.html : The current implementation applies
+           opacity before doing the reflection which makes this test
+           produce incorrect results.  This will affect reflected layers
+           with opacity that overlap their original layer.  FIXME comment
+           added in the code.
+
+        Tests: Covered by existing layout tests in compositing/reflections.
+               Please see above for exceptions.
+
+        * platform/graphics/chromium/GraphicsLayerChromium.cpp:
+        (WebCore::GraphicsLayerChromium::setReplicatedByLayer):
+        (WebCore::GraphicsLayerChromium::updateAnchorPoint):
+        * platform/graphics/chromium/GraphicsLayerChromium.h:
+        * platform/graphics/chromium/LayerChromium.cpp:
+        (WebCore::LayerChromium::LayerChromium):
+        * platform/graphics/chromium/LayerChromium.h:
+        (WebCore::LayerChromium::setReplicaLayer):
+        (WebCore::LayerChromium::replicaLayer):
+        * platform/graphics/chromium/LayerRendererChromium.cpp:
+        (WebCore::LayerRendererChromium::updateLayersRecursive):
+        (WebCore::LayerRendererChromium::drawLayer):
+        * platform/graphics/chromium/RenderSurfaceChromium.cpp:
+        (WebCore::RenderSurfaceChromium::drawableContentRect):
+        (WebCore::RenderSurfaceChromium::drawSurface):
+        (WebCore::RenderSurfaceChromium::draw):
+        * platform/graphics/chromium/RenderSurfaceChromium.h:
+        (WebCore::RenderSurfaceChromium::drawTransform):
+
 2011-02-02  Xiyuan Xia  <xiyuan@chromium.org>
 
         Reviewed by Tony Chang.
index e6f1c9b28062bbc8465046d914747e0a43101f41..488230c95d25c9ae64f57d3d9af0bc5ef9868035 100644 (file)
@@ -294,6 +294,15 @@ void GraphicsLayerChromium::setOpacity(float opacity)
     primaryLayer()->setOpacity(opacity);
 }
 
+void GraphicsLayerChromium::setReplicatedByLayer(GraphicsLayer* layer)
+{
+    GraphicsLayerChromium* layerChromium = static_cast<GraphicsLayerChromium*>(layer);
+    GraphicsLayer::setReplicatedByLayer(layer);
+    LayerChromium* replicaLayer = layerChromium ? layerChromium->primaryLayer() : 0;
+    primaryLayer()->setReplicaLayer(replicaLayer);
+}
+
+
 void GraphicsLayerChromium::setContentsNeedsDisplay()
 {
     if (m_contentsLayer)
@@ -505,6 +514,7 @@ void GraphicsLayerChromium::updateAnchorPoint()
 {
     primaryLayer()->setAnchorPoint(FloatPoint(m_anchorPoint.x(), m_anchorPoint.y()));
     primaryLayer()->setAnchorPointZ(m_anchorPoint.z());
+
     updateLayerPosition();
 }
 
index f39dc0fbe4f4d8ead81bd0418b317ec0a4c78a29..92c61feb2be08a1fed6c11f9055f435d7ebc0265 100644 (file)
@@ -75,6 +75,8 @@ public:
     virtual void setContentsOpaque(bool);
     virtual void setBackfaceVisibility(bool);
 
+    virtual void setReplicatedByLayer(GraphicsLayer*);
+
     virtual void setOpacity(float);
 
     virtual void setNeedsDisplay();
index 8385b7e864b9fbe992ab448fe06bd2b649bfa036..8d01d9bd9aa49e61c96a9eccb766dcb101e36ee3 100644 (file)
@@ -163,6 +163,7 @@ LayerChromium::LayerChromium(GraphicsLayerChromium* owner)
     , m_drawDepth(0)
     , m_layerRenderer(0)
     , m_renderSurface(0)
+    , m_replicaLayer(0)
 {
 }
 
index 579ca7a0018e85a91c2f0d5be7afe63512fd1f29..5c7e2b142177ccf692aaa4c36a2e28f0c6df1c86 100644 (file)
@@ -155,6 +155,9 @@ public:
 
     void setOwner(GraphicsLayerChromium* owner) { m_owner = owner; }
 
+    void setReplicaLayer(LayerChromium* layer) { m_replicaLayer = layer; }
+    LayerChromium* replicaLayer() { return m_replicaLayer; }
+
     // Returns the rect containtaining this layer in the current view's coordinate system.
     const IntRect getDrawRect() const;
 
@@ -305,6 +308,9 @@ private:
     // Hierarchical bounding rect containing the layer and its descendants.
     IntRect m_drawableContentRect;
 
+    // Replica layer used for reflections.
+    LayerChromium* m_replicaLayer;
+
     String m_name;
 };
 
index 3f7353c7fa6121b69476f9b087f30217ec4803fe..0b4d7b1756db4402e2db2b4113ef0e3db4f3d28f 100644 (file)
@@ -452,14 +452,17 @@ void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const Tr
     // 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.
+    // 3. The layer uses a mask
+    // 4. The layer has a replica (used for reflections)
     // 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();
     bool useSurfaceForMasking = layer->maskLayer();
+    bool useSurfaceForReflection = layer->replicaLayer();
     if (((useSurfaceForClipping || useSurfaceForOpacity) && layer->descendantsDrawContent())
-        || useSurfaceForMasking) {
+        || useSurfaceForMasking || useSurfaceForReflection) {
         RenderSurfaceChromium* renderSurface = layer->m_renderSurface.get();
         if (!renderSurface)
             renderSurface = layer->createRenderSurface();
@@ -500,6 +503,11 @@ void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const Tr
         } else
             renderSurface->m_maskLayer = 0;
 
+        if (layer->replicaLayer() && layer->replicaLayer()->maskLayer()) {
+            layer->replicaLayer()->maskLayer()->setLayerRenderer(this);
+            layer->replicaLayer()->maskLayer()->m_targetRenderSurface = renderSurface;
+        }
+
         renderSurfaceLayerList.append(layer);
     } else {
         // DT = M[p] * LT
@@ -571,10 +579,7 @@ void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const Tr
 
         if (sublayer->m_renderSurface) {
             RenderSurfaceChromium* sublayerRenderSurface = sublayer->m_renderSurface.get();
-            const IntRect& contentRect = sublayerRenderSurface->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)));
+            layer->m_drawableContentRect.unite(enclosingIntRect(sublayerRenderSurface->drawableContentRect()));
             descendants.append(sublayer);
         } else
             layer->m_drawableContentRect.unite(sublayer->m_drawableContentRect);
@@ -590,9 +595,13 @@ void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const Tr
 
         // 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;
+        // Don't clip if the layer is reflected as the reflection shouldn't be
+        // clipped.
+        if (!layer->replicaLayer()) {
+            renderSurface->m_contentRect.intersect(layer->m_scissorRect);
+            FloatPoint clippedSurfaceCenter = renderSurface->contentRectCenter();
+            centerOffsetDueToClipping = clippedSurfaceCenter - surfaceCenter;
+        }
 
         // The RenderSurface backing texture cannot exceed the maximum supported
         // texture size.
@@ -609,6 +618,15 @@ void LayerRendererChromium::updateLayersRecursive(LayerChromium* layer, const Tr
         // 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 transformation matrix used to draw the replica of the render
+        // surface.
+        if (layer->replicaLayer()) {
+            renderSurface->m_replicaDrawTransform = renderSurface->m_originTransform;
+            renderSurface->m_replicaDrawTransform.translate3d(layer->replicaLayer()->position().x(), layer->replicaLayer()->position().y(), 0);
+            renderSurface->m_replicaDrawTransform.multiply(layer->replicaLayer()->transform());
+            renderSurface->m_replicaDrawTransform.translate3d(surfaceCenter.x() - anchorPoint.x() * bounds.width(), surfaceCenter.y() - anchorPoint.y() * bounds.height(), 0);
+        }
     }
 
     // Compute the depth value of the center of the layer which will be used when
@@ -695,10 +713,9 @@ void LayerRendererChromium::drawLayer(LayerChromium* layer, RenderSurfaceChromiu
     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)
+    // FIXME: Need to take into account the commulative render surface transforms all the way from
+    //        the default render surface in order to determine visibility.
+    if (!layer->doubleSided() && layer->m_renderSurface->drawTransform().multiply(layer->m_drawTransform).m33() < 0)
          return;
 
     if (layer->drawsContent()) {
index a3b660f577e80b57aa7279158c22bb6adae1ed16..b3ce9d7237168c9547014d2ca534d32e98c0f30c 100644 (file)
@@ -148,6 +148,17 @@ LayerRendererChromium* RenderSurfaceChromium::layerRenderer()
     return m_owningLayer->layerRenderer();
 }
 
+FloatRect RenderSurfaceChromium::drawableContentRect() const
+{
+    FloatRect localContentRect(-0.5 * m_contentRect.width(), -0.5 * m_contentRect.height(),
+                               m_contentRect.width(), m_contentRect.height());
+    FloatRect drawableContentRect = m_drawTransform.mapRect(localContentRect);
+    if (m_owningLayer->replicaLayer())
+        drawableContentRect.unite(m_replicaDrawTransform.mapRect(localContentRect));
+
+    return drawableContentRect;
+}
+
 bool RenderSurfaceChromium::prepareContentsTexture()
 {
     IntSize requiredSize(m_contentRect.size());
@@ -168,26 +179,24 @@ bool RenderSurfaceChromium::prepareContentsTexture()
     return true;
 }
 
-void RenderSurfaceChromium::draw()
+void RenderSurfaceChromium::drawSurface(LayerChromium* maskLayer, const TransformationMatrix& drawTransform)
 {
-    if (m_skipsDraw || !m_contentsTexture)
-        return;
-
     GraphicsContext3D* context3D = layerRenderer()->context();
+
     int shaderMatrixLocation = -1;
     int shaderAlphaLocation = -1;
     const RenderSurfaceChromium::SharedValues* sv = layerRenderer()->renderSurfaceSharedValues();
     ASSERT(sv && sv->initialized());
     bool useMask = false;
-    if (m_maskLayer && m_maskLayer->drawsContent()) {
-        m_maskLayer->updateContentsIfDirty();
-        if (!m_maskLayer->bounds().isEmpty()) {
+    if (maskLayer && maskLayer->drawsContent()) {
+        maskLayer->updateContentsIfDirty();
+        if (!maskLayer->bounds().isEmpty()) {
             context3D->makeContextCurrent();
             layerRenderer()->useShader(sv->maskShaderProgram());
             GLC(context3D, context3D->activeTexture(GraphicsContext3D::TEXTURE0));
             m_contentsTexture->bindTexture();
             GLC(context3D, context3D->activeTexture(GraphicsContext3D::TEXTURE1));
-            m_maskLayer->bindContentsTexture();
+            maskLayer->bindContentsTexture();
             GLC(context3D, context3D->activeTexture(GraphicsContext3D::TEXTURE0));
             shaderMatrixLocation = sv->maskShaderMatrixLocation();
             shaderAlphaLocation = sv->maskShaderAlphaLocation();
@@ -201,16 +210,38 @@ void RenderSurfaceChromium::draw()
         shaderMatrixLocation = sv->shaderMatrixLocation();
         shaderAlphaLocation = sv->shaderAlphaLocation();
     }
+    
+    LayerChromium::drawTexturedQuad(layerRenderer()->context(), layerRenderer()->projectionMatrix(), drawTransform,
+                                        m_contentRect.width(), m_contentRect.height(), m_drawOpacity,
+                                        shaderMatrixLocation, shaderAlphaLocation);
+
+    m_contentsTexture->unreserve();
+
+    if (maskLayer)
+        maskLayer->unreserveContentsTexture();
+}
+
+void RenderSurfaceChromium::draw()
+{
+    if (m_skipsDraw || !m_contentsTexture)
+        return;
+    // FIXME: By using the same RenderSurface for both the content and its reflection,
+    // it's currently not possible to apply a separate mask to the reflection layer
+    // or correctly handle opacity in reflections (opacity must be applied after drawing
+    // both the layer and its reflection). The solution is to introduce yet another RenderSurface
+    // to draw the layer and its reflection in. For now we only apply a separate reflection
+    // mask if the contents don't have a mask of their own.
+    LayerChromium* replicaMaskLayer = m_maskLayer;
+    if (!m_maskLayer && m_owningLayer->replicaLayer())
+        replicaMaskLayer = m_owningLayer->replicaLayer()->maskLayer();
 
     layerRenderer()->setScissorToRect(m_scissorRect);
 
-    LayerChromium::drawTexturedQuad(layerRenderer()->context(), layerRenderer()->projectionMatrix(), m_drawTransform,
-                                    m_contentRect.width(), m_contentRect.height(), m_drawOpacity,
-                                    shaderMatrixLocation, shaderAlphaLocation);
+    // Reflection draws before the layer.
+    if (m_owningLayer->replicaLayer()) 
+        drawSurface(replicaMaskLayer, m_replicaDrawTransform);
 
-    m_contentsTexture->unreserve();
-    if (m_maskLayer)
-        m_maskLayer->unreserveContentsTexture();
+    drawSurface(m_maskLayer, m_drawTransform);
 }
 
 }
index 42ab593ff8cedf2bfd6521079826fa61ff1a8e07..b1f6a5cec81f0acd33c988c877354d7cb2728776 100644 (file)
@@ -55,6 +55,11 @@ public:
     FloatPoint contentRectCenter() const { return FloatRect(m_contentRect).center(); }
     IntRect contentRect() const { return m_contentRect; }
 
+    // Returns the rect that encloses the RenderSurface including any reflection.
+    FloatRect drawableContentRect() const;
+
+    TransformationMatrix drawTransform() const { return m_drawTransform; }
+
     // Stores values that are shared between instances of this class that are
     // associated with the same LayerRendererChromium (and hence the same GL
     // context).
@@ -91,6 +96,7 @@ public:
 
 private:
     LayerRendererChromium* layerRenderer();
+    void drawSurface(LayerChromium* maskLayer, const TransformationMatrix& drawTransform);
 
     LayerChromium* m_owningLayer;
     LayerChromium* m_maskLayer;
@@ -100,6 +106,7 @@ private:
     OwnPtr<LayerTexture> m_contentsTexture;
     float m_drawOpacity;
     TransformationMatrix m_drawTransform;
+    TransformationMatrix m_replicaDrawTransform;
     TransformationMatrix m_originTransform;
     IntRect m_scissorRect;
     Vector<LayerChromium*> m_layerList;