[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
+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.
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)
{
primaryLayer()->setAnchorPoint(FloatPoint(m_anchorPoint.x(), m_anchorPoint.y()));
primaryLayer()->setAnchorPointZ(m_anchorPoint.z());
+
updateLayerPosition();
}
virtual void setContentsOpaque(bool);
virtual void setBackfaceVisibility(bool);
+ virtual void setReplicatedByLayer(GraphicsLayer*);
+
virtual void setOpacity(float);
virtual void setNeedsDisplay();
, m_drawDepth(0)
, m_layerRenderer(0)
, m_renderSurface(0)
+ , m_replicaLayer(0)
{
}
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;
// Hierarchical bounding rect containing the layer and its descendants.
IntRect m_drawableContentRect;
+ // Replica layer used for reflections.
+ LayerChromium* m_replicaLayer;
+
String m_name;
};
// 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();
} 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
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);
// 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.
// 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
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()) {
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());
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();
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);
}
}
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).
private:
LayerRendererChromium* layerRenderer();
+ void drawSurface(LayerChromium* maskLayer, const TransformationMatrix& drawTransform);
LayerChromium* m_owningLayer;
LayerChromium* m_maskLayer;
OwnPtr<LayerTexture> m_contentsTexture;
float m_drawOpacity;
TransformationMatrix m_drawTransform;
+ TransformationMatrix m_replicaDrawTransform;
TransformationMatrix m_originTransform;
IntRect m_scissorRect;
Vector<LayerChromium*> m_layerList;