diff options
31 files changed, 343 insertions, 51 deletions
diff --git a/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-as-formatting-context-expected.txt b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-as-formatting-context-expected.txt new file mode 100644 index 0000000..7ef22e9 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-as-formatting-context-expected.txt @@ -0,0 +1 @@ +PASS diff --git a/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-as-formatting-context.html b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-as-formatting-context.html new file mode 100644 index 0000000..128a79b --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-as-formatting-context.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<style> +div { + height: 100px; + width: 100%; +} +.container { + contain: paint; + border: 1px solid black; +} +.overhangingContainer { + height: 10px; +} +.overhangingFloat { + float: left; +} +</style> +<body> +<div class="overhangingContainer"><div class="overhangingFloat"></div></div> +<div class="container" data-offset-y=108></div> +<script src="../../../resources/check-layout.js"></script> +<script> +checkLayout(".container"); +</script>
\ No newline at end of file diff --git a/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-absolute-position-expected.html b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-absolute-position-expected.html new file mode 100644 index 0000000..b880446 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-absolute-position-expected.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<style> +div { + width: 100px; + height: 100px; + background-color: green; +} +</style> +<body> +<div></div>
\ No newline at end of file diff --git a/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-absolute-position.html b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-absolute-position.html new file mode 100644 index 0000000..bac8d56 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-absolute-position.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<style> +div { + width: 100px; + height: 50px; +} +.container { + contain: paint; + background-color: green; +} +.absolute { + position: absolute; + top: 0px; + left: 100px; + background-color: red; +} +.inline { + display: inline-block; +} +</style> +<body> +<div class="container"><div class="absolute"></div></div> +<div class="container inline"><div class="absolute"></div></div>
\ No newline at end of file diff --git a/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-box-shadow-expected.html b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-box-shadow-expected.html new file mode 100644 index 0000000..b880446 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-box-shadow-expected.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<style> +div { + width: 100px; + height: 100px; + background-color: green; +} +</style> +<body> +<div></div>
\ No newline at end of file diff --git a/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-box-shadow.html b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-box-shadow.html new file mode 100644 index 0000000..ffa0f31 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-box-shadow.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<style> +div { + width: 100px; + height: 100px; +} +#container { + contain: paint; +} +#child { + background-color: green; + -webkit-box-shadow: 0 0 100px 100px red; +} +</style> +<body> +<div id="container"><div id="child"></div></div>
\ No newline at end of file diff --git a/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-fixed-position-expected.html b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-fixed-position-expected.html new file mode 100644 index 0000000..b880446 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-fixed-position-expected.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<style> +div { + width: 100px; + height: 100px; + background-color: green; +} +</style> +<body> +<div></div>
\ No newline at end of file diff --git a/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-fixed-position.html b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-fixed-position.html new file mode 100644 index 0000000..f028d8c --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-fixed-position.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<style> +div { + width: 100px; + height: 50px; +} +.container { + contain: paint; + background-color: green; +} +.fixed { + position: fixed; + top: 0px; + left: 100px; + background-color: red; +} +.inline { + display: inline-block; +} +</style> +<body> +<div class="container"><div class="fixed"></div></div> +<div class="container inline"><div class="fixed"></div></div>
\ No newline at end of file diff --git a/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-transformed-descendant-expected.html b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-transformed-descendant-expected.html new file mode 100644 index 0000000..b880446 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-transformed-descendant-expected.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<style> +div { + width: 100px; + height: 100px; + background-color: green; +} +</style> +<body> +<div></div>
\ No newline at end of file diff --git a/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-transformed-descendant.html b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-transformed-descendant.html new file mode 100644 index 0000000..d11d1821 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/containment/paint-containment-with-transformed-descendant.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<style> +div { + width: 100px; + height: 50px; +} +.container { + contain: paint; + background-color: green; +} +.transform { + background-color: red; + top: 100px; + transform: translateZ(0) scaleY(2) translateX(100px); +} +.inline { + display: inline-block; +} +</style> +<body> +<div class="container"><div class="transform"></div></div> +<div class="container inline"><div class="transform"></div></div>
\ No newline at end of file diff --git a/third_party/WebKit/LayoutTests/hittesting/paint-containment-hittest-expected.txt b/third_party/WebKit/LayoutTests/hittesting/paint-containment-hittest-expected.txt new file mode 100644 index 0000000..7282117 --- /dev/null +++ b/third_party/WebKit/LayoutTests/hittesting/paint-containment-hittest-expected.txt @@ -0,0 +1,12 @@ +Hit testing should respect clips established by contain: paint. + +PASS successfullyParsed is true + +TEST COMPLETE +PASS document.elementFromPoint(centerX, centerY).id is 'containTransform' +PASS document.elementFromPoint(centerX, centerY).id is 'containAbsolute' +PASS document.elementFromPoint(centerX, centerY).id is 'containFixed' +PASS document.elementFromPoint(centerX, centerY).id is 'body' +PASS document.elementFromPoint(centerX, centerY).id is 'body' +PASS document.elementFromPoint(centerX, centerY).id is 'body' + diff --git a/third_party/WebKit/LayoutTests/hittesting/paint-containment-hittest.html b/third_party/WebKit/LayoutTests/hittesting/paint-containment-hittest.html new file mode 100644 index 0000000..24f7bd1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/hittesting/paint-containment-hittest.html @@ -0,0 +1,63 @@ +<!DOCTYPE html> +<script src="../resources/js-test.js"></script> +<script> +var centerX; +var centerY; +function hitTestCenterOfElement(elementID, expectedID) +{ + var element = document.getElementById(elementID); + var rect = element.getBoundingClientRect(); + centerX = rect.left + (rect.width / 2); + centerY = rect.top + (rect.height / 2); + shouldBe("document.elementFromPoint(centerX, centerY).id", "'" + expectedID + "'"); +} + +function test() { + hitTestCenterOfElement("containTransform", "containTransform"); + hitTestCenterOfElement("containAbsolute", "containAbsolute"); + hitTestCenterOfElement("containFixed", "containFixed"); + + hitTestCenterOfElement("transform", "body"); + hitTestCenterOfElement("absolute", "body"); + hitTestCenterOfElement("fixed", "body"); +} +</script> +<style> +div { + width: 100px; + height: 100px; + background-color: green; +} +div > div { + background-color: red; +} +.paintContainment { + contain: paint; + margin: 10px; +} +#transform { + transform: translateZ(0) translateX(100px); +} +#absolute { + position: absolute; + top: 0px; + left: 100px; +} +#fixed { + position: fixed; + top: 0px; + left: 100px; +} +</style> +<body onload="test()" id="body"> + <p>Hit testing should respect clips established by contain: paint.</p> +<div id="containTransform" class="paintContainment"> + <div id="transform"></div> +</div> +<div id="containAbsolute" class="paintContainment"> + <div id="absolute"></div> +</div> +<div id="containFixed" class="paintContainment"> + <div id="fixed"></div> +</div> +<pre id="console"></pre> diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi index a9098c0..f623675e 100644 --- a/third_party/WebKit/Source/core/core.gypi +++ b/third_party/WebKit/Source/core/core.gypi @@ -3930,6 +3930,7 @@ 'layout/MultiColumnFragmentainerGroupTest.cpp', 'layout/OverflowModelTest.cpp', 'layout/PaginationTest.cpp', + 'layout/PaintContainmentTest.cpp', 'layout/compositing/CompositedLayerMappingTest.cpp', 'layout/shapes/BoxShapeTest.cpp', 'loader/FrameFetchContextTest.cpp', diff --git a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp index a3ca171..4f41f9a 100644 --- a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp +++ b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp @@ -2711,7 +2711,7 @@ PassRefPtrWillBeRawPtr<CSSValue> ComputedStyleCSSValueMapping::get(CSSPropertyID list->append(cssValuePool().createIdentifierValue(CSSValueStyle)); if (style.contain() & ContainsLayout) list->append(cssValuePool().createIdentifierValue(CSSValueLayout)); - if (style.contain() & ContainsPaint) + if (style.containsPaint()) list->append(cssValuePool().createIdentifierValue(CSSValuePaint)); ASSERT(list->length()); return list.release(); diff --git a/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp b/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp index 9d584a4..e129549 100644 --- a/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp +++ b/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp @@ -203,7 +203,8 @@ void StyleAdjuster::adjustComputedStyle(ComputedStyle& style, const ComputedStyl || style.hasIsolation() || style.position() == FixedPosition || isInTopLayer(element, style) - || hasWillChangeThatCreatesStackingContext(style))) + || hasWillChangeThatCreatesStackingContext(style) + || style.containsPaint())) style.setZIndex(0); if (doesNotInheritTextDecoration(style, element)) diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp index 3e18330..ecc2c5f 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp @@ -1007,7 +1007,7 @@ bool LayoutBlock::createsNewFormattingContext() const { return isInlineBlockOrInlineTable() || isFloatingOrOutOfFlowPositioned() || hasOverflowClip() || isFlexItemIncludingDeprecated() || style()->specifiesColumns() || isLayoutFlowThread() || isTableCell() || isTableCaption() || isFieldset() || isWritingModeRoot() - || isDocumentElement() || isColumnSpanAll() || isGridItem(); + || isDocumentElement() || isColumnSpanAll() || isGridItem() || style()->containsPaint(); } void LayoutBlock::updateBlockChildDirtyBitsBeforeLayout(bool relayoutChildren, LayoutBox& child) diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp index 31f903a..f8986d1 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp @@ -4058,7 +4058,7 @@ static bool shouldBeConsideredAsReplaced(Node* node) bool LayoutBox::avoidsFloats() const { - return isAtomicInlineLevel() || shouldBeConsideredAsReplaced(node()) || hasOverflowClip() || isHR() || isLegend() || isWritingModeRoot() || isFlexItemIncludingDeprecated(); + return isAtomicInlineLevel() || shouldBeConsideredAsReplaced(node()) || hasOverflowClip() || isHR() || isLegend() || isWritingModeRoot() || isFlexItemIncludingDeprecated() || style()->containsPaint(); } bool LayoutBox::hasNonCompositedScrollbars() const diff --git a/third_party/WebKit/Source/core/layout/LayoutInline.cpp b/third_party/WebKit/Source/core/layout/LayoutInline.cpp index 4fe1686..38409e2 100644 --- a/third_party/WebKit/Source/core/layout/LayoutInline.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutInline.cpp @@ -1142,6 +1142,12 @@ LayoutSize LayoutInline::offsetFromContainer(const LayoutObject* container, cons return offset; } +PaintLayerType LayoutInline::layerTypeRequired() const +{ + return isInFlowPositioned() || createsGroup() || hasClipPath() || style()->shouldCompositeForCurrentAnimations() + || style()->hasCompositorProxy() || style()->containsPaint() ? NormalPaintLayer : NoPaintLayer; +} + void LayoutInline::mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const { if (paintInvalidationContainer == this) diff --git a/third_party/WebKit/Source/core/layout/LayoutInline.h b/third_party/WebKit/Source/core/layout/LayoutInline.h index 2987d26..354505c 100644 --- a/third_party/WebKit/Source/core/layout/LayoutInline.h +++ b/third_party/WebKit/Source/core/layout/LayoutInline.h @@ -228,7 +228,7 @@ private: bool nodeAtPoint(HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) final; - PaintLayerType layerTypeRequired() const override { return isInFlowPositioned() || createsGroup() || hasClipPath() || style()->shouldCompositeForCurrentAnimations() || style()->hasCompositorProxy() ? NormalPaintLayer : NoPaintLayer; } + PaintLayerType layerTypeRequired() const override; LayoutUnit offsetLeft() const final; LayoutUnit offsetTop() const final; diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h index a45e243..9dc0b50 100644 --- a/third_party/WebKit/Source/core/layout/LayoutObject.h +++ b/third_party/WebKit/Source/core/layout/LayoutObject.h @@ -698,7 +698,7 @@ public: bool hasClip() const { return isOutOfFlowPositioned() && !style()->hasAutoClip(); } bool hasOverflowClip() const { return m_bitfields.hasOverflowClip(); } - bool hasClipOrOverflowClip() const { return hasClip() || hasOverflowClip(); } + bool hasClipRelatedProperty() const { return hasClip() || hasOverflowClip() || style()->containsPaint(); } bool hasTransformRelatedProperty() const { return m_bitfields.hasTransformRelatedProperty(); } bool hasMask() const { return style() && style()->hasMask(); } @@ -930,7 +930,7 @@ public: bool canContainFixedPositionObjects() const { - return isLayoutView() || (hasTransformRelatedProperty() && isLayoutBlock()) || isSVGForeignObject(); + return isLayoutView() || (hasTransformRelatedProperty() && isLayoutBlock()) || isSVGForeignObject() || style()->containsPaint(); } // Convert the given local point to absolute coordinates diff --git a/third_party/WebKit/Source/core/layout/PaintContainmentTest.cpp b/third_party/WebKit/Source/core/layout/PaintContainmentTest.cpp new file mode 100644 index 0000000..36547ba --- /dev/null +++ b/third_party/WebKit/Source/core/layout/PaintContainmentTest.cpp @@ -0,0 +1,55 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "config.h" + +#include "core/layout/LayoutBlock.h" +#include "core/layout/LayoutInline.h" +#include "core/layout/LayoutTestHelper.h" +#include "core/paint/PaintLayer.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { + +class PaintContainmentTest : public RenderingTest { +}; + +static void checkIsClippingStackingContextAndContainer(LayoutBoxModelObject& obj) +{ + EXPECT_TRUE(obj.canContainFixedPositionObjects()); + EXPECT_TRUE(obj.hasClipRelatedProperty()); + EXPECT_TRUE(obj.style()->containsPaint()); + + // TODO(leviw): Ideally, we wouldn't require a paint layer to handle the clipping + // and stacking performed by paint containment. + ASSERT(obj.layer()); + PaintLayer* layer = obj.layer(); + EXPECT_TRUE(layer->stackingNode() && layer->stackingNode()->isStackingContext()); +} + +TEST_F(PaintContainmentTest, BlockPaintContainment) +{ + setBodyInnerHTML("<div id='div' style='contain: paint'></div>"); + Element* div = document().getElementById(AtomicString("div")); + ASSERT(div); + LayoutObject* obj = div->layoutObject(); + ASSERT(obj && obj->isLayoutBlock()); + LayoutBlock& block = toLayoutBlock(*obj); + EXPECT_TRUE(block.createsNewFormattingContext()); + EXPECT_FALSE(block.canBeScrolledAndHasScrollableArea()); + checkIsClippingStackingContextAndContainer(block); +} + +TEST_F(PaintContainmentTest, InlinePaintContainment) +{ + setBodyInnerHTML("<div><span id='test' style='contain: paint'>Foo</span></div>"); + Element* span = document().getElementById(AtomicString("test")); + ASSERT(span); + LayoutObject* obj = span->layoutObject(); + ASSERT(obj && obj->isInline()); + LayoutInline& layoutInline = toLayoutInline(*obj); + checkIsClippingStackingContextAndContainer(layoutInline); +} + +} diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp index 485f65d7..5467894 100644 --- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp +++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp @@ -568,7 +568,7 @@ bool CompositedLayerMapping::updateGraphicsLayerConfiguration() static IntRect clipBox(LayoutBox* layoutObject) { LayoutRect result = LayoutRect(LayoutRect::infiniteIntRect()); - if (layoutObject->hasOverflowClip()) + if (layoutObject->hasOverflowClip() || layoutObject->style()->containsPaint()) result = layoutObject->overflowClipRect(LayoutPoint()); if (layoutObject->hasClip()) diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.cpp index 851df37..3ce313b 100644 --- a/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.cpp +++ b/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.cpp @@ -37,7 +37,7 @@ static const PaintLayer* findParentLayerOnClippingContainerChain(const PaintLaye for (current = current->parent(); current && !current->canContainFixedPositionObjects(); current = current->parent()) { // All types of clips apply to fixed-position descendants of other fixed-position elements. // Note: it's unclear whether this is what the spec says. Firefox does not clip, but Chrome does. - if (current->style()->position() == FixedPosition && current->hasClipOrOverflowClip()) { + if (current->style()->position() == FixedPosition && current->hasClipRelatedProperty()) { ASSERT(current->hasLayer()); return static_cast<const LayoutBoxModelObject*>(current)->layer(); } @@ -56,7 +56,7 @@ static const PaintLayer* findParentLayerOnClippingContainerChain(const PaintLaye if (current->hasLayer()) return static_cast<const LayoutBoxModelObject*>(current)->layer(); // Having clip or overflow clip forces the LayoutObject to become a layer. - ASSERT(!current->hasClipOrOverflowClip()); + ASSERT(!current->hasClipRelatedProperty()); } ASSERT_NOT_REACHED(); return nullptr; @@ -82,7 +82,7 @@ static bool hasClippedStackingAncestor(const PaintLayer* layer, const PaintLayer if (current == clippingLayer) return foundInterveningClip; - if (current->layoutObject()->hasClipOrOverflowClip() && !clippingLayoutObject->isDescendantOf(current->layoutObject())) + if (current->layoutObject()->hasClipRelatedProperty() && !clippingLayoutObject->isDescendantOf(current->layoutObject())) foundInterveningClip = true; if (const LayoutObject* container = current->clippingContainer()) { @@ -130,10 +130,10 @@ void CompositingInputsUpdater::updateRecursive(PaintLayer* layer, UpdateType upd bool layerIsFixedPosition = layer->layoutObject()->style()->position() == FixedPosition; properties.nearestFixedPositionLayer = layerIsFixedPosition ? layer : parent->nearestFixedPositionLayer(); - if (info.hasAncestorWithClipOrOverflowClip) { + if (info.hasAncestorWithClipRelatedProperty) { const PaintLayer* parentLayerOnClippingContainerChain = findParentLayerOnClippingContainerChain(layer); - const bool parentHasClipOrOverflowClip = parentLayerOnClippingContainerChain->layoutObject()->hasClipOrOverflowClip(); - properties.clippingContainer = parentHasClipOrOverflowClip ? parentLayerOnClippingContainerChain->layoutObject() : parentLayerOnClippingContainerChain->clippingContainer(); + const bool parentHasClipRelatedProperty = parentLayerOnClippingContainerChain->layoutObject()->hasClipRelatedProperty(); + properties.clippingContainer = parentHasClipRelatedProperty ? parentLayerOnClippingContainerChain->layoutObject() : parentLayerOnClippingContainerChain->clippingContainer(); } if (info.lastScrollingAncestor) { @@ -167,8 +167,8 @@ void CompositingInputsUpdater::updateRecursive(PaintLayer* layer, UpdateType upd if (layer->scrollsOverflow()) info.lastScrollingAncestor = layer; - if (layer->layoutObject()->hasClipOrOverflowClip()) - info.hasAncestorWithClipOrOverflowClip = true; + if (layer->layoutObject()->hasClipRelatedProperty()) + info.hasAncestorWithClipRelatedProperty = true; if (layer->layoutObject()->hasClipPath()) info.hasAncestorWithClipPath = true; diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.h b/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.h index 0c646a4..d182c926 100644 --- a/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.h +++ b/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.h @@ -35,7 +35,7 @@ private: : ancestorStackingContext(nullptr) , enclosingCompositedLayer(nullptr) , lastScrollingAncestor(nullptr) - , hasAncestorWithClipOrOverflowClip(false) + , hasAncestorWithClipRelatedProperty(false) , hasAncestorWithClipPath(false) { } @@ -48,7 +48,7 @@ private: // actually controls the scrolling of this layer, which we find on the // containing block chain. PaintLayer* lastScrollingAncestor; - bool hasAncestorWithClipOrOverflowClip; + bool hasAncestorWithClipRelatedProperty; bool hasAncestorWithClipPath; }; diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingRequirementsUpdater.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositingRequirementsUpdater.cpp index a58e642..69d03b0 100644 --- a/third_party/WebKit/Source/core/layout/compositing/CompositingRequirementsUpdater.cpp +++ b/third_party/WebKit/Source/core/layout/compositing/CompositingRequirementsUpdater.cpp @@ -166,7 +166,7 @@ static CompositingReasons subtreeReasonsForCompositing(PaintLayer* layer, bool h // FIXME: This should move into CompositingReasonFinder::potentialCompositingReasonsFromStyle, but // theres a poor interaction with LayoutTextControlSingleLine, which sets this hasOverflowClip directly. - if (layer->layoutObject()->hasClipOrOverflowClip()) + if (layer->layoutObject()->hasClipRelatedProperty()) subtreeReasons |= CompositingReasonClipsCompositingDescendants; if (layer->layoutObject()->style()->position() == FixedPosition) diff --git a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp b/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp index 969d1ef6..4146ce8 100644 --- a/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp +++ b/third_party/WebKit/Source/core/layout/compositing/PaintLayerCompositor.cpp @@ -777,7 +777,7 @@ bool PaintLayerCompositor::canBeComposited(const PaintLayer* layer) const // into the hierarchy between this layer and its children in the z-order hierarchy. bool PaintLayerCompositor::clipsCompositingDescendants(const PaintLayer* layer) const { - return layer->hasCompositingDescendant() && layer->layoutObject()->hasClipOrOverflowClip(); + return layer->hasCompositingDescendant() && layer->layoutObject()->hasClipRelatedProperty(); } // If an element has composited negative z-index children, those children paint in front of the diff --git a/third_party/WebKit/Source/core/paint/BoxClipper.cpp b/third_party/WebKit/Source/core/paint/BoxClipper.cpp index ac13973..09f10cf 100644 --- a/third_party/WebKit/Source/core/paint/BoxClipper.cpp +++ b/third_party/WebKit/Source/core/paint/BoxClipper.cpp @@ -24,9 +24,10 @@ BoxClipper::BoxClipper(const LayoutBox& box, const PaintInfo& paintInfo, const L return; bool isControlClip = m_box.hasControlClip(); - bool isOverflowClip = m_box.hasOverflowClip() && !m_box.layer()->isSelfPaintingLayer(); + bool isOverflowOrContainmentClip = (m_box.hasOverflowClip() && !m_box.layer()->isSelfPaintingLayer()) + || m_box.style()->containsPaint(); - if (!isControlClip && !isOverflowClip) + if (!isControlClip && !isOverflowOrContainmentClip) return; LayoutRect clipRect = isControlClip ? m_box.controlClipRect(accumulatedOffset) : m_box.overflowClipRect(accumulatedOffset); @@ -64,7 +65,7 @@ BoxClipper::~BoxClipper() if (m_clipType == DisplayItem::UninitializedType) return; - ASSERT(m_box.hasControlClip() || (m_box.hasOverflowClip() && !m_box.layer()->isSelfPaintingLayer())); + ASSERT(m_box.hasControlClip() || (m_box.hasOverflowClip() && !m_box.layer()->isSelfPaintingLayer()) || m_box.style()->containsPaint()); m_paintInfo.context.paintController().endItem<EndClipDisplayItem>(m_box, DisplayItem::clipTypeToEndClipType(m_clipType)); } diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp index a764e09..e28864f 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp @@ -752,15 +752,15 @@ bool PaintLayer::updateLayerPosition() } // Subtract our parent's scroll offset. - if (PaintLayer* positionedParent = layoutObject()->isOutOfFlowPositioned() ? enclosingPositionedAncestor() : nullptr) { + if (PaintLayer* containingLayer = layoutObject()->isOutOfFlowPositioned() ? containingLayerForOutOfFlowPositioned() : nullptr) { // For positioned layers, we subtract out the enclosing positioned layer's scroll offset. - if (positionedParent->layoutObject()->hasOverflowClip()) { - IntSize offset = positionedParent->layoutBox()->scrolledContentOffset(); + if (containingLayer->layoutObject()->hasOverflowClip()) { + IntSize offset = containingLayer->layoutBox()->scrolledContentOffset(); localPoint -= offset; } - if (positionedParent->layoutObject()->isInFlowPositioned() && positionedParent->layoutObject()->isLayoutInline()) { - LayoutSize offset = toLayoutInline(positionedParent->layoutObject())->offsetForInFlowPositionedInline(*toLayoutBox(layoutObject())); + if (containingLayer->layoutObject()->isInFlowPositioned() && containingLayer->layoutObject()->isLayoutInline()) { + LayoutSize offset = toLayoutInline(containingLayer->layoutObject())->offsetForInFlowPositionedInline(*toLayoutBox(layoutObject())); localPoint += offset; } } else if (parent() && parent()->layoutObject()->hasOverflowClip()) { @@ -818,19 +818,28 @@ FloatPoint PaintLayer::perspectiveOrigin() const return FloatPoint(floatValueForLength(style.perspectiveOriginX(), borderBox.width().toFloat()), floatValueForLength(style.perspectiveOriginY(), borderBox.height().toFloat())); } -static inline bool isFixedPositionedContainer(PaintLayer* layer) +static inline bool isContainerForFixedPositioned(PaintLayer* layer) { return layer->isRootLayer() || layer->hasTransformRelatedProperty(); } -PaintLayer* PaintLayer::enclosingPositionedAncestor(const PaintLayer* ancestor, bool* skippedAncestor) const +static inline bool isContainerForPositioned(PaintLayer* layer) +{ + // FIXME: This is not in sync with containingBlock. + // LayoutObject::canContainFixedPositionObjects() should probably be used + // instead. + LayoutBoxModelObject* layerlayoutObject = layer->layoutObject(); + return layer->isRootLayer() || layerlayoutObject->isPositioned() || layer->hasTransformRelatedProperty() || layerlayoutObject->style()->containsPaint(); +} + +PaintLayer* PaintLayer::containingLayerForOutOfFlowPositioned(const PaintLayer* ancestor, bool* skippedAncestor) const { ASSERT(!ancestor || skippedAncestor); // If we have specified an ancestor, surely the caller needs to know whether we skipped it. if (skippedAncestor) *skippedAncestor = false; if (layoutObject()->style()->position() == FixedPosition) { PaintLayer* curr = parent(); - while (curr && !isFixedPositionedContainer(curr)) { + while (curr && !isContainerForFixedPositioned(curr)) { if (skippedAncestor && curr == ancestor) *skippedAncestor = true; curr = curr->parent(); @@ -840,7 +849,7 @@ PaintLayer* PaintLayer::enclosingPositionedAncestor(const PaintLayer* ancestor, } PaintLayer* curr = parent(); - while (curr && !curr->isPositionedContainer()) { + while (curr && !isContainerForPositioned(curr)) { if (skippedAncestor && curr == ancestor) *skippedAncestor = true; curr = curr->parent(); @@ -1277,7 +1286,7 @@ static inline const PaintLayer* accumulateOffsetTowardsAncestor(const PaintLayer PaintLayer* parentLayer; if (position == AbsolutePosition || position == FixedPosition) { bool foundAncestorFirst; - parentLayer = layer->enclosingPositionedAncestor(ancestorLayer, &foundAncestorFirst); + parentLayer = layer->containingLayerForOutOfFlowPositioned(ancestorLayer, &foundAncestorFirst); if (foundAncestorFirst) { // Found ancestorLayer before the container of the out-of-flow object, so compute offset @@ -2371,7 +2380,7 @@ bool PaintLayer::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) // We can't consult child layers if we clip, since they might cover // parts of the rect that are clipped out. - if (layoutObject()->hasOverflowClip()) + if (layoutObject()->hasOverflowClip() || layoutObject()->style()->containsPaint()) return false; return childBackgroundIsKnownToBeOpaqueInRect(localRect); diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.h b/third_party/WebKit/Source/core/paint/PaintLayer.h index e02293d..17a1633 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayer.h +++ b/third_party/WebKit/Source/core/paint/PaintLayer.h @@ -261,14 +261,13 @@ public: bool hasVisibleNonLayerContent() const { return m_hasVisibleNonLayerContent; } bool hasNonCompositedChild() const { ASSERT(isAllowedToQueryCompositingState()); return m_hasNonCompositedChild; } - // Gets the ancestor layer that serves as the containing block of this layer. It is assumed - // that this layer is established by an out-of-flow positioned layout object (i.e. either - // absolutely or fixed positioned). + // Gets the ancestor layer that serves as the containing block of this layer. This is either + // another out of flow positioned layer, or one that contains paint. // If |ancestor| is specified, |*skippedAncestor| will be set to true if |ancestor| is found in // the ancestry chain between this layer and the containing block layer; if not found, it will // be set to false. Either both |ancestor| and |skippedAncestor| should be nullptr, or none of // them should. - PaintLayer* enclosingPositionedAncestor(const PaintLayer* ancestor = nullptr, bool* skippedAncestor = nullptr) const; + PaintLayer* containingLayerForOutOfFlowPositioned(const PaintLayer* ancestor = nullptr, bool* skippedAncestor = nullptr) const; bool isPaintInvalidationContainer() const; @@ -459,15 +458,6 @@ public: PaintLayerClipper& clipper() { return m_clipper; } const PaintLayerClipper& clipper() const { return m_clipper; } - inline bool isPositionedContainer() const - { - // FIXME: This is not in sync with containingBlock. - // LayoutObject::canContainFixedPositionObjects() should probably be used - // instead. - LayoutBoxModelObject* layerlayoutObject = layoutObject(); - return isRootLayer() || layerlayoutObject->isPositioned() || hasTransformRelatedProperty(); - } - bool scrollsOverflow() const; CompositingReasons potentialCompositingReasonsFromStyle() const { return m_potentialCompositingReasonsFromStyle; } diff --git a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp index 0ff40ac..3b11423 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp @@ -69,12 +69,12 @@ static void adjustClipRectsForChildren(const LayoutObject& layoutObject, ClipRec static void applyClipRects(const ClipRectsContext& context, const LayoutObject& layoutObject, LayoutPoint offset, ClipRects& clipRects) { - ASSERT(layoutObject.hasOverflowClip() || layoutObject.hasClip()); + ASSERT(layoutObject.hasOverflowClip() || layoutObject.hasClip() || layoutObject.style()->containsPaint()); LayoutView* view = layoutObject.view(); ASSERT(view); if (clipRects.fixed() && context.rootLayer->layoutObject() == view) offset -= toIntSize(view->frameView()->scrollPosition()); - if (layoutObject.hasOverflowClip()) { + if (layoutObject.hasOverflowClip() || layoutObject.style()->containsPaint()) { ClipRect newOverflowClip = toLayoutBox(layoutObject).overflowClipRect(offset, context.scrollbarRelevancy); newOverflowClip.setHasRadius(layoutObject.style()->hasBorderRadius()); clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect())); @@ -82,6 +82,10 @@ static void applyClipRects(const ClipRectsContext& context, const LayoutObject& clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect())); if (layoutObject.isLayoutView()) clipRects.setFixedClipRect(intersection(newOverflowClip, clipRects.fixedClipRect())); + if (layoutObject.style()->containsPaint()) { + clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect())); + clipRects.setFixedClipRect(intersection(newOverflowClip, clipRects.fixedClipRect())); + } } if (layoutObject.hasClip()) { LayoutRect newClip = toLayoutBox(layoutObject).clipRect(offset); @@ -213,7 +217,7 @@ void PaintLayerClipper::calculateRects(const ClipRectsContext& context, const La layerBounds = LayoutRect(offset, LayoutSize(m_layoutObject.layer()->size())); // Update the clip rects that will be passed to child layers. - if (m_layoutObject.hasOverflowClip() && shouldRespectOverflowClip(context)) { + if ((m_layoutObject.hasOverflowClip() && shouldRespectOverflowClip(context)) || m_layoutObject.style()->containsPaint()) { foregroundRect.intersect(toLayoutBox(m_layoutObject).overflowClipRect(offset, context.scrollbarRelevancy)); if (m_layoutObject.style()->hasBorderRadius()) foregroundRect.setHasRadius(true); @@ -267,7 +271,7 @@ void PaintLayerClipper::calculateClipRects(const ClipRectsContext& context, Clip adjustClipRectsForChildren(m_layoutObject, clipRects); - if ((m_layoutObject.hasOverflowClip() && shouldRespectOverflowClip(context)) || m_layoutObject.hasClip()) { + if ((m_layoutObject.hasOverflowClip() && shouldRespectOverflowClip(context)) || m_layoutObject.hasClip() || m_layoutObject.style()->containsPaint()) { // This offset cannot use convertToLayerCoords, because sometimes our rootLayer may be across // some transformed layer boundary, for example, in the PaintLayerCompositor overlapMap, where // clipRects are needed in view space. diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h index cd4edb0..2e1b0ea 100644 --- a/third_party/WebKit/Source/core/style/ComputedStyle.h +++ b/third_party/WebKit/Source/core/style/ComputedStyle.h @@ -826,6 +826,7 @@ public: bool hasVisualOverflowingEffect() const { return boxShadow() || hasBorderImageOutsets() || hasOutline(); } Containment contain() const { return static_cast<Containment>(rareNonInheritedData->m_contain); } + bool containsPaint() const { return rareNonInheritedData->m_contain & ContainsPaint; } EBoxSizing boxSizing() const { return m_box->boxSizing(); } EUserModify userModify() const { return static_cast<EUserModify>(rareInheritedData->userModify); } |