Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1520)

Unified Diff: Source/core/rendering/RenderLayer.cpp

Issue 59613010: Fix propagation of clip-path and border-radius clipping to child layers (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: fix for mac build Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/rendering/RenderLayer.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/rendering/RenderLayer.cpp
diff --git a/Source/core/rendering/RenderLayer.cpp b/Source/core/rendering/RenderLayer.cpp
index 5d5b5c227e0b7e53a8fbd031a0299635c782e065..25469e280e3919d1a8bce2a8ae9ae5e3d449315e 100644
--- a/Source/core/rendering/RenderLayer.cpp
+++ b/Source/core/rendering/RenderLayer.cpp
@@ -110,6 +110,7 @@ RenderLayer::RenderLayer(RenderLayerModelObject* renderer)
, m_hasOutOfFlowPositionedDescendantDirty(true)
, m_hasUnclippedDescendant(false)
, m_isUnclippedDescendant(false)
+ , m_hasComplexClippedAncestor(false)
, m_isRootLayer(renderer->isRenderView())
, m_usedTransparency(false)
, m_childLayerHasBlendMode(false)
@@ -1398,6 +1399,7 @@ void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
child->stackingNode()->dirtyStackingContainerZOrderLists();
}
+ child->updateHasComplexClippedAncestor();
child->updateDescendantDependentFlags();
if (child->m_hasVisibleContent || child->m_hasVisibleDescendant)
setAncestorChainHasVisibleDescendant();
@@ -2014,43 +2016,11 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti
bool rootRelativeBoundsComputed = false;
// Apply clip-path to context.
- bool hasClipPath = false;
- RenderStyle* style = renderer()->style();
- RenderSVGResourceClipper* resourceClipper = 0;
+ bool needsContextRestore = false;
+ Vector<RenderSVGResourceClipper*> resourceClippers;
ClipperContext clipperContext;
- if (renderer()->hasClipPath() && !context->paintingDisabled() && style) {
- ASSERT(style->clipPath());
- if (style->clipPath()->type() == ClipPathOperation::SHAPE) {
- hasClipPath = true;
- context->save();
- ShapeClipPathOperation* clipPath = toShapeClipPathOperation(style->clipPath());
-
- if (!rootRelativeBoundsComputed) {
- rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
- rootRelativeBoundsComputed = true;
- }
-
- context->clipPath(clipPath->path(rootRelativeBounds), clipPath->windRule());
- } else if (style->clipPath()->type() == ClipPathOperation::REFERENCE) {
- ReferenceClipPathOperation* referenceClipPathOperation = toReferenceClipPathOperation(style->clipPath());
- Document& document = renderer()->document();
- // FIXME: It doesn't work with forward or external SVG references (https://bugs.webkit.org/show_bug.cgi?id=90405)
- Element* element = document.getElementById(referenceClipPathOperation->fragment());
- if (element && element->hasTagName(SVGNames::clipPathTag) && element->renderer()) {
- if (!rootRelativeBoundsComputed) {
- rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
- rootRelativeBoundsComputed = true;
- }
-
- resourceClipper = toRenderSVGResourceClipper(toRenderSVGResourceContainer(element->renderer()));
- if (!resourceClipper->applyClippingToContext(renderer(), rootRelativeBounds,
- paintingInfo.paintDirtyRect, context, clipperContext)) {
- // No need to post-apply the clipper if this failed.
- resourceClipper = 0;
- }
- }
- }
- }
+ if (!context->paintingDisabled())
+ applyComplexClip(context, this, &clipperContext, paintingInfo, offsetFromRoot, &needsContextRestore, &rootRelativeBoundsComputed, &rootRelativeBounds, &resourceClippers);
// Blending operations must be performed only with the nearest ancestor stacking context.
// Note that there is no need to create a transparency layer if we're painting the root.
@@ -2185,13 +2155,78 @@ void RenderLayer::paintLayerContents(GraphicsContext* context, const LayerPainti
m_usedTransparency = false;
}
- if (resourceClipper)
- resourceClipper->postApplyStatefulResource(renderer(), context, clipperContext);
+ while (resourceClippers.size()) {
+ resourceClippers.last()->postApplyStatefulResource(renderer(), context, clipperContext);
+ resourceClippers.removeLast();
+ }
- if (hasClipPath)
+ if (needsContextRestore)
context->restore();
}
+void RenderLayer::applyComplexClip(GraphicsContext* context, RenderLayer* currentLayer, ClipperContext* clipperContext, const LayerPaintingInfo& paintingInfo, const LayoutPoint& offsetFromRoot, bool* needsContextRestore, bool* rootRelativeBoundsComputed, IntRect* rootRelativeBounds, Vector<RenderSVGResourceClipper*>* resourceClippers)
+{
+ bool isRecursing = currentLayer != this;
+ if (parent() && parent()->hasComplexClippedAncestor() && (hasCompositedLayerMapping() || isRecursing)) {
+ bool parentRelativeBoundsComputed = false;
+ IntRect parentRootRelativeBounds;
+ LayoutPoint delta;
+ convertToLayerCoords(parent(), delta);
+ LayoutPoint parentOffsetFromRoot = toPoint(offsetFromRoot - delta);
+ AffineTransform savedCTM;
+ if (hasTransform()) {
+ // Apply inverse transform to bring parent layer's clip into currentLayer's frame of reference.
+ // Can't use save/restore because clip must be preserved.
+ savedCTM = context->getCTM();
+ // FIXME: Flattening to an affine transform at each recursion level does not handle cascading
+ // 3D transforms correctly when preserves3D() == true.
+ context->concatCTM(transform()->inverse().toAffineTransform());
+ }
+ parent()->applyComplexClip(context, currentLayer, clipperContext, paintingInfo, parentOffsetFromRoot, needsContextRestore, &parentRelativeBoundsComputed, &parentRootRelativeBounds, resourceClippers);
+ if (hasTransform())
+ context->setCTM(savedCTM);
+ }
+
+ RenderStyle* style = renderer()->style();
+ if (style && inContainingBlockChain(currentLayer, this)) {
+ if (renderer()->hasClipPath()) {
+ ASSERT(style->clipPath());
+ if (style->clipPath()->type() == ClipPathOperation::SHAPE) {
+ if (!*needsContextRestore) {
+ // we have not yet saved the context in the current applyClipPath recursion chain
+ *needsContextRestore = true;
+ context->save();
+ }
+ ShapeClipPathOperation* clipPath = static_cast<ShapeClipPathOperation*>(style->clipPath());
+ if (!*rootRelativeBoundsComputed) {
+ *rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
+ *rootRelativeBoundsComputed = true;
+ }
+ context->clipPath(clipPath->path(*rootRelativeBounds), clipPath->windRule());
+ } else if (style->clipPath()->type() == ClipPathOperation::REFERENCE) {
+ ReferenceClipPathOperation* referenceClipPathOperation = static_cast<ReferenceClipPathOperation*>(style->clipPath());
+ Document& document = renderer()->document();
+ // FIXME: It doesn't work with forward or external SVG references (https://bugs.webkit.org/show_bug.cgi?id=90405)
+ Element* element = document.getElementById(referenceClipPathOperation->fragment());
+ if (element && element->hasTagName(SVGNames::clipPathTag) && element->renderer()) {
+ if (!*rootRelativeBoundsComputed) {
+ *rootRelativeBounds = calculateLayerBounds(paintingInfo.rootLayer, &offsetFromRoot, 0);
+ *rootRelativeBoundsComputed = true;
+ }
+ RenderSVGResourceClipper* resourceClipper = toRenderSVGResourceClipper(toRenderSVGResourceContainer(element->renderer()));
+ if (resourceClipper->applyClippingToContext(renderer(), *rootRelativeBounds, paintingInfo.paintDirtyRect, context, *clipperContext))
+ resourceClippers->append(resourceClipper);
+ }
+ }
+ }
+ if (isRecursing && renderer()->hasOverflowClip() && style->hasBorderRadius()) {
+ // Propagate border radius clipping from ancestors.
+ // The border radius of currentLayer is skipped because it is already taken care of by clipToRect
+ context->clipRoundedRect(style->getRoundedInnerBorderFor(LayoutRect(offsetFromRoot, size())));
+ }
+ }
+}
+
void RenderLayer::paintLayerByApplyingTransform(GraphicsContext* context, const LayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags, const LayoutPoint& translationOffset)
{
// This involves subtracting out the position of the layer in our current coordinate space, but preserving
@@ -3716,6 +3751,9 @@ bool RenderLayer::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect)
if (m_stackingNode->zOrderListsDirty() || m_stackingNode->normalFlowListDirty())
return false;
+ if (hasComplexClippedAncestor())
+ return false;
+
// FIXME: We currently only check the immediate renderer,
// which will miss many cases.
if (renderer()->backgroundIsKnownToBeOpaqueInRect(localRect))
@@ -3896,6 +3934,22 @@ void RenderLayer::updateOutOfFlowPositioned(const RenderStyle* oldStyle)
}
}
+void RenderLayer::updateHasComplexClippedAncestor()
+{
+ bool hasComplexClip = renderer()->hasClipPath()
+ || (renderer()->hasOverflowClip() && renderer()->style()->hasBorderRadius())
+ || (parent() && parent()->hasComplexClippedAncestor());
+
+ if (hasComplexClip == hasComplexClippedAncestor())
+ return;
+
+ setHasComplexClippedAncestor(hasComplexClip);
+
+ for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
+ child->updateHasComplexClippedAncestor();
+ }
+}
+
static bool hasOrHadFilters(const RenderStyle* oldStyle, const RenderStyle* newStyle)
{
ASSERT(newStyle);
@@ -3984,6 +4038,8 @@ void RenderLayer::styleChanged(StyleDifference, const RenderStyle* oldStyle)
bool didPaintWithFilters = false;
+ updateHasComplexClippedAncestor();
+
if (paintsWithFilters())
didPaintWithFilters = true;
updateFilters(oldStyle, renderer()->style());
« no previous file with comments | « Source/core/rendering/RenderLayer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698