| 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());
|
|
|