| // Copyright 2015 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 "core/layout/LayoutBlock.h" |
| #include "core/layout/LayoutInline.h" |
| #include "core/layout/compositing/CompositedLayerMapping.h" |
| #include "core/paint/PaintControllerPaintTest.h" |
| #include "platform/graphics/GraphicsContext.h" |
| #include "platform/testing/RuntimeEnabledFeaturesTestHelpers.h" |
| |
| namespace blink { |
| |
| struct PaintLayerPainterTestParam { |
| PaintLayerPainterTestParam(bool rootLayerScrolling, bool slimmingPaintV2) |
| : rootLayerScrolling(rootLayerScrolling), |
| slimmingPaintV2(slimmingPaintV2) {} |
| |
| bool rootLayerScrolling; |
| bool slimmingPaintV2; |
| }; |
| |
| class PaintLayerPainterTest |
| : public testing::WithParamInterface<PaintLayerPainterTestParam>, |
| private ScopedRootLayerScrollingForTest, |
| public PaintControllerPaintTestBase { |
| USING_FAST_MALLOC(PaintLayerPainterTest); |
| |
| public: |
| PaintLayerPainterTest() |
| : ScopedRootLayerScrollingForTest(GetParam().rootLayerScrolling), |
| PaintControllerPaintTestBase(GetParam().slimmingPaintV2) {} |
| }; |
| |
| INSTANTIATE_TEST_CASE_P( |
| All, |
| PaintLayerPainterTest, |
| ::testing::Values(PaintLayerPainterTestParam( |
| false, |
| false), // non-root-layer-scrolls, slimming-paint-v1 |
| PaintLayerPainterTestParam( |
| false, |
| true), // non-root-layer-scrolls, slimming-paint-v2 |
| PaintLayerPainterTestParam( |
| true, |
| false), // root-layer-scrolls, slimming-paint-v1 |
| PaintLayerPainterTestParam( |
| true, |
| true))); // root-layer-scrolls, slimming-paint-v2 |
| |
| TEST_P(PaintLayerPainterTest, CachedSubsequence) { |
| setBodyInnerHTML( |
| "<div id='container1' style='position: relative; z-index: 1; width: " |
| "200px; height: 200px; background-color: blue'>" |
| " <div id='content1' style='position: absolute; width: 100px; height: " |
| "100px; background-color: red'></div>" |
| "</div>" |
| "<div id='container2' style='position: relative; z-index: 1; width: " |
| "200px; height: 200px; background-color: blue'>" |
| " <div id='content2' style='position: absolute; width: 100px; height: " |
| "100px; background-color: green'></div>" |
| "</div>"); |
| document().view()->updateAllLifecyclePhases(); |
| |
| PaintLayer& htmlLayer = |
| *toLayoutBoxModelObject(document().documentElement()->layoutObject()) |
| ->layer(); |
| LayoutObject& container1 = |
| *document().getElementById("container1")->layoutObject(); |
| PaintLayer& container1Layer = *toLayoutBoxModelObject(container1).layer(); |
| LayoutObject& content1 = |
| *document().getElementById("content1")->layoutObject(); |
| LayoutObject& container2 = |
| *document().getElementById("container2")->layoutObject(); |
| PaintLayer& container2Layer = *toLayoutBoxModelObject(container2).layer(); |
| LayoutObject& content2 = |
| *document().getElementById("content2")->layoutObject(); |
| |
| if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
| EXPECT_DISPLAY_LIST( |
| rootPaintController().getDisplayItemList(), 15, |
| TestDisplayItem(layoutView(), |
| DisplayItem::kClipFrameToVisibleContentRect), |
| TestDisplayItem(*layoutView().layer(), DisplayItem::kSubsequence), |
| TestDisplayItem(layoutView(), documentBackgroundType), |
| TestDisplayItem(htmlLayer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1, backgroundType), |
| TestDisplayItem(content1, backgroundType), |
| TestDisplayItem(container1Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(container2Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container2, backgroundType), |
| TestDisplayItem(content2, backgroundType), |
| TestDisplayItem(container2Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(htmlLayer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(*layoutView().layer(), DisplayItem::kEndSubsequence), |
| TestDisplayItem(layoutView(), |
| DisplayItem::clipTypeToEndClipType( |
| DisplayItem::kClipFrameToVisibleContentRect))); |
| } else { |
| EXPECT_DISPLAY_LIST( |
| rootPaintController().getDisplayItemList(), 11, |
| TestDisplayItem(layoutView(), documentBackgroundType), |
| TestDisplayItem(htmlLayer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1, backgroundType), |
| TestDisplayItem(content1, backgroundType), |
| TestDisplayItem(container1Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(container2Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container2, backgroundType), |
| TestDisplayItem(content2, backgroundType), |
| TestDisplayItem(container2Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(htmlLayer, DisplayItem::kEndSubsequence)); |
| } |
| |
| toHTMLElement(content1.node()) |
| ->setAttribute(HTMLNames::styleAttr, |
| "position: absolute; width: 100px; height: 100px; " |
| "background-color: green"); |
| document().view()->updateAllLifecyclePhasesExceptPaint(); |
| EXPECT_TRUE(paintWithoutCommit()); |
| |
| EXPECT_EQ(6, numCachedNewItems()); |
| |
| commit(); |
| |
| if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
| EXPECT_DISPLAY_LIST( |
| rootPaintController().getDisplayItemList(), 15, |
| TestDisplayItem(layoutView(), |
| DisplayItem::kClipFrameToVisibleContentRect), |
| TestDisplayItem(*layoutView().layer(), DisplayItem::kSubsequence), |
| TestDisplayItem(layoutView(), documentBackgroundType), |
| TestDisplayItem(htmlLayer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1, backgroundType), |
| TestDisplayItem(content1, backgroundType), |
| TestDisplayItem(container1Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(container2Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container2, backgroundType), |
| TestDisplayItem(content2, backgroundType), |
| TestDisplayItem(container2Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(htmlLayer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(*layoutView().layer(), DisplayItem::kEndSubsequence), |
| TestDisplayItem(layoutView(), |
| DisplayItem::clipTypeToEndClipType( |
| DisplayItem::kClipFrameToVisibleContentRect))); |
| } else { |
| EXPECT_DISPLAY_LIST( |
| rootPaintController().getDisplayItemList(), 11, |
| TestDisplayItem(layoutView(), documentBackgroundType), |
| TestDisplayItem(htmlLayer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1, backgroundType), |
| TestDisplayItem(content1, backgroundType), |
| TestDisplayItem(container1Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(container2Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container2, backgroundType), |
| TestDisplayItem(content2, backgroundType), |
| TestDisplayItem(container2Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(htmlLayer, DisplayItem::kEndSubsequence)); |
| } |
| } |
| |
| TEST_P(PaintLayerPainterTest, CachedSubsequenceOnInterestRectChange) { |
| // TODO(wangxianzhu): SPv2 deals with interest rect differently, so disable |
| // this test for SPv2 temporarily. |
| if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) |
| return; |
| |
| setBodyInnerHTML( |
| "<div id='container1' style='position: relative; z-index: 1; width: " |
| "200px; height: 200px; background-color: blue'>" |
| " <div id='content1' style='position: absolute; width: 100px; height: " |
| "100px; background-color: green'></div>" |
| "</div>" |
| "<div id='container2' style='position: relative; z-index: 1; width: " |
| "200px; height: 200px; background-color: blue'>" |
| " <div id='content2a' style='position: absolute; width: 100px; height: " |
| "100px; background-color: green'></div>" |
| " <div id='content2b' style='position: absolute; top: 200px; width: " |
| "100px; height: 100px; background-color: green'></div>" |
| "</div>" |
| "<div id='container3' style='position: absolute; z-index: 2; left: " |
| "300px; top: 0; width: 200px; height: 200px; background-color: blue'>" |
| " <div id='content3' style='position: absolute; width: 200px; height: " |
| "200px; background-color: green'></div>" |
| "</div>"); |
| rootPaintController().invalidateAll(); |
| |
| PaintLayer& htmlLayer = |
| *toLayoutBoxModelObject(document().documentElement()->layoutObject()) |
| ->layer(); |
| LayoutObject& container1 = |
| *document().getElementById("container1")->layoutObject(); |
| PaintLayer& container1Layer = *toLayoutBoxModelObject(container1).layer(); |
| LayoutObject& content1 = |
| *document().getElementById("content1")->layoutObject(); |
| LayoutObject& container2 = |
| *document().getElementById("container2")->layoutObject(); |
| PaintLayer& container2Layer = *toLayoutBoxModelObject(container2).layer(); |
| LayoutObject& content2a = |
| *document().getElementById("content2a")->layoutObject(); |
| LayoutObject& content2b = |
| *document().getElementById("content2b")->layoutObject(); |
| LayoutObject& container3 = |
| *document().getElementById("container3")->layoutObject(); |
| PaintLayer& container3Layer = *toLayoutBoxModelObject(container3).layer(); |
| LayoutObject& content3 = |
| *document().getElementById("content3")->layoutObject(); |
| |
| document().view()->updateAllLifecyclePhasesExceptPaint(); |
| IntRect interestRect(0, 0, 400, 300); |
| paint(&interestRect); |
| |
| // Container1 is fully in the interest rect; |
| // Container2 is partly (including its stacking chidren) in the interest rect; |
| // Content2b is out of the interest rect and output nothing; |
| // Container3 is partly in the interest rect. |
| EXPECT_DISPLAY_LIST( |
| rootPaintController().getDisplayItemList(), 15, |
| TestDisplayItem(layoutView(), documentBackgroundType), |
| TestDisplayItem(htmlLayer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1, backgroundType), |
| TestDisplayItem(content1, backgroundType), |
| TestDisplayItem(container1Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(container2Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container2, backgroundType), |
| TestDisplayItem(content2a, backgroundType), |
| TestDisplayItem(container2Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(container3Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container3, backgroundType), |
| TestDisplayItem(content3, backgroundType), |
| TestDisplayItem(container3Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(htmlLayer, DisplayItem::kEndSubsequence)); |
| |
| document().view()->updateAllLifecyclePhasesExceptPaint(); |
| IntRect newInterestRect(0, 100, 300, 1000); |
| EXPECT_TRUE(paintWithoutCommit(&newInterestRect)); |
| |
| // Container1 becomes partly in the interest rect, but uses cached subsequence |
| // because it was fully painted before; |
| // Container2's intersection with the interest rect changes; |
| // Content2b is out of the interest rect and outputs nothing; |
| // Container3 becomes out of the interest rect and outputs empty subsequence |
| // pair. |
| EXPECT_EQ(7, numCachedNewItems()); |
| |
| commit(); |
| |
| EXPECT_DISPLAY_LIST( |
| rootPaintController().getDisplayItemList(), 14, |
| TestDisplayItem(layoutView(), documentBackgroundType), |
| TestDisplayItem(htmlLayer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1, backgroundType), |
| TestDisplayItem(content1, backgroundType), |
| TestDisplayItem(container1Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(container2Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container2, backgroundType), |
| TestDisplayItem(content2a, backgroundType), |
| TestDisplayItem(content2b, backgroundType), |
| TestDisplayItem(container2Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(container3Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container3Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(htmlLayer, DisplayItem::kEndSubsequence)); |
| } |
| |
| TEST_P(PaintLayerPainterTest, |
| CachedSubsequenceOnStyleChangeWithInterestRectClipping) { |
| setBodyInnerHTML( |
| "<div id='container1' style='position: relative; z-index: 1; width: " |
| "200px; height: 200px; background-color: blue'>" |
| " <div id='content1' style='position: absolute; width: 100px; height: " |
| "100px; background-color: red'></div>" |
| "</div>" |
| "<div id='container2' style='position: relative; z-index: 1; width: " |
| "200px; height: 200px; background-color: blue'>" |
| " <div id='content2' style='position: absolute; width: 100px; height: " |
| "100px; background-color: green'></div>" |
| "</div>"); |
| document().view()->updateAllLifecyclePhasesExceptPaint(); |
| // PaintResult of all subsequences will be MayBeClippedByPaintDirtyRect. |
| IntRect interestRect(0, 0, 50, 300); |
| paint(&interestRect); |
| |
| PaintLayer& htmlLayer = |
| *toLayoutBoxModelObject(document().documentElement()->layoutObject()) |
| ->layer(); |
| LayoutObject& container1 = |
| *document().getElementById("container1")->layoutObject(); |
| PaintLayer& container1Layer = *toLayoutBoxModelObject(container1).layer(); |
| LayoutObject& content1 = |
| *document().getElementById("content1")->layoutObject(); |
| LayoutObject& container2 = |
| *document().getElementById("container2")->layoutObject(); |
| PaintLayer& container2Layer = *toLayoutBoxModelObject(container2).layer(); |
| LayoutObject& content2 = |
| *document().getElementById("content2")->layoutObject(); |
| |
| if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
| EXPECT_DISPLAY_LIST( |
| rootPaintController().getDisplayItemList(), 15, |
| TestDisplayItem(layoutView(), |
| DisplayItem::kClipFrameToVisibleContentRect), |
| TestDisplayItem(*layoutView().layer(), DisplayItem::kSubsequence), |
| TestDisplayItem(layoutView(), documentBackgroundType), |
| TestDisplayItem(htmlLayer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1, backgroundType), |
| TestDisplayItem(content1, backgroundType), |
| TestDisplayItem(container1Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(container2Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container2, backgroundType), |
| TestDisplayItem(content2, backgroundType), |
| TestDisplayItem(container2Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(htmlLayer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(*layoutView().layer(), DisplayItem::kEndSubsequence), |
| TestDisplayItem(layoutView(), |
| DisplayItem::clipTypeToEndClipType( |
| DisplayItem::kClipFrameToVisibleContentRect))); |
| } else { |
| EXPECT_DISPLAY_LIST( |
| rootPaintController().getDisplayItemList(), 11, |
| TestDisplayItem(layoutView(), documentBackgroundType), |
| TestDisplayItem(htmlLayer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1, backgroundType), |
| TestDisplayItem(content1, backgroundType), |
| TestDisplayItem(container1Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(container2Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container2, backgroundType), |
| TestDisplayItem(content2, backgroundType), |
| TestDisplayItem(container2Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(htmlLayer, DisplayItem::kEndSubsequence)); |
| } |
| |
| toHTMLElement(content1.node()) |
| ->setAttribute(HTMLNames::styleAttr, |
| "position: absolute; width: 100px; height: 100px; " |
| "background-color: green"); |
| document().view()->updateAllLifecyclePhasesExceptPaint(); |
| EXPECT_TRUE(paintWithoutCommit(&interestRect)); |
| |
| EXPECT_EQ(6, numCachedNewItems()); |
| |
| commit(); |
| |
| if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
| EXPECT_DISPLAY_LIST( |
| rootPaintController().getDisplayItemList(), 15, |
| TestDisplayItem(layoutView(), |
| DisplayItem::kClipFrameToVisibleContentRect), |
| TestDisplayItem(*layoutView().layer(), DisplayItem::kSubsequence), |
| TestDisplayItem(layoutView(), documentBackgroundType), |
| TestDisplayItem(htmlLayer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1, backgroundType), |
| TestDisplayItem(content1, backgroundType), |
| TestDisplayItem(container1Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(container2Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container2, backgroundType), |
| TestDisplayItem(content2, backgroundType), |
| TestDisplayItem(container2Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(htmlLayer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(*layoutView().layer(), DisplayItem::kEndSubsequence), |
| TestDisplayItem(layoutView(), |
| DisplayItem::clipTypeToEndClipType( |
| DisplayItem::kClipFrameToVisibleContentRect))); |
| } else { |
| EXPECT_DISPLAY_LIST( |
| rootPaintController().getDisplayItemList(), 11, |
| TestDisplayItem(layoutView(), documentBackgroundType), |
| TestDisplayItem(htmlLayer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container1, backgroundType), |
| TestDisplayItem(content1, backgroundType), |
| TestDisplayItem(container1Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(container2Layer, DisplayItem::kSubsequence), |
| TestDisplayItem(container2, backgroundType), |
| TestDisplayItem(content2, backgroundType), |
| TestDisplayItem(container2Layer, DisplayItem::kEndSubsequence), |
| TestDisplayItem(htmlLayer, DisplayItem::kEndSubsequence)); |
| } |
| } |
| |
| TEST_P(PaintLayerPainterTest, PaintPhaseOutline) { |
| AtomicString styleWithoutOutline = |
| "width: 50px; height: 50px; background-color: green"; |
| AtomicString styleWithOutline = |
| "outline: 1px solid blue; " + styleWithoutOutline; |
| setBodyInnerHTML( |
| "<div id='self-painting-layer' style='position: absolute'>" |
| " <div id='non-self-painting-layer' style='overflow: hidden'>" |
| " <div>" |
| " <div id='outline'></div>" |
| " </div>" |
| " </div>" |
| "</div>"); |
| LayoutObject& outlineDiv = |
| *document().getElementById("outline")->layoutObject(); |
| toHTMLElement(outlineDiv.node()) |
| ->setAttribute(HTMLNames::styleAttr, styleWithoutOutline); |
| document().view()->updateAllLifecyclePhases(); |
| |
| LayoutBlock& selfPaintingLayerObject = *toLayoutBlock( |
| document().getElementById("self-painting-layer")->layoutObject()); |
| PaintLayer& selfPaintingLayer = *selfPaintingLayerObject.layer(); |
| ASSERT_TRUE(selfPaintingLayer.isSelfPaintingLayer()); |
| PaintLayer& nonSelfPaintingLayer = |
| *toLayoutBoxModelObject( |
| document().getElementById("non-self-painting-layer")->layoutObject()) |
| ->layer(); |
| ASSERT_FALSE(nonSelfPaintingLayer.isSelfPaintingLayer()); |
| ASSERT_TRUE(&nonSelfPaintingLayer == outlineDiv.enclosingLayer()); |
| |
| EXPECT_FALSE(selfPaintingLayer.needsPaintPhaseDescendantOutlines()); |
| EXPECT_FALSE(nonSelfPaintingLayer.needsPaintPhaseDescendantOutlines()); |
| |
| // Outline on the self-painting-layer node itself doesn't affect |
| // PaintPhaseDescendantOutlines. |
| toHTMLElement(selfPaintingLayerObject.node()) |
| ->setAttribute(HTMLNames::styleAttr, |
| "position: absolute; outline: 1px solid green"); |
| document().view()->updateAllLifecyclePhases(); |
| EXPECT_FALSE(selfPaintingLayer.needsPaintPhaseDescendantOutlines()); |
| EXPECT_FALSE(nonSelfPaintingLayer.needsPaintPhaseDescendantOutlines()); |
| EXPECT_TRUE(displayItemListContains( |
| rootPaintController().getDisplayItemList(), selfPaintingLayerObject, |
| DisplayItem::paintPhaseToDrawingType(PaintPhaseSelfOutlineOnly))); |
| |
| // needsPaintPhaseDescendantOutlines should be set when any descendant on the |
| // same layer has outline. |
| toHTMLElement(outlineDiv.node()) |
| ->setAttribute(HTMLNames::styleAttr, styleWithOutline); |
| document().view()->updateAllLifecyclePhasesExceptPaint(); |
| EXPECT_TRUE(selfPaintingLayer.needsPaintPhaseDescendantOutlines()); |
| EXPECT_FALSE(nonSelfPaintingLayer.needsPaintPhaseDescendantOutlines()); |
| paint(); |
| EXPECT_TRUE(displayItemListContains( |
| rootPaintController().getDisplayItemList(), outlineDiv, |
| DisplayItem::paintPhaseToDrawingType(PaintPhaseSelfOutlineOnly))); |
| |
| // needsPaintPhaseDescendantOutlines should be reset when no outline is |
| // actually painted. |
| toHTMLElement(outlineDiv.node()) |
| ->setAttribute(HTMLNames::styleAttr, styleWithoutOutline); |
| document().view()->updateAllLifecyclePhases(); |
| EXPECT_FALSE(selfPaintingLayer.needsPaintPhaseDescendantOutlines()); |
| } |
| |
| TEST_P(PaintLayerPainterTest, PaintPhaseFloat) { |
| AtomicString styleWithoutFloat = |
| "width: 50px; height: 50px; background-color: green"; |
| AtomicString styleWithFloat = "float: left; " + styleWithoutFloat; |
| setBodyInnerHTML( |
| "<div id='self-painting-layer' style='position: absolute'>" |
| " <div id='non-self-painting-layer' style='overflow: hidden'>" |
| " <div>" |
| " <div id='float' style='width: 10px; height: 10px; " |
| "background-color: blue'></div>" |
| " </div>" |
| " </div>" |
| "</div>"); |
| LayoutObject& floatDiv = *document().getElementById("float")->layoutObject(); |
| toHTMLElement(floatDiv.node()) |
| ->setAttribute(HTMLNames::styleAttr, styleWithoutFloat); |
| document().view()->updateAllLifecyclePhases(); |
| |
| LayoutBlock& selfPaintingLayerObject = *toLayoutBlock( |
| document().getElementById("self-painting-layer")->layoutObject()); |
| PaintLayer& selfPaintingLayer = *selfPaintingLayerObject.layer(); |
| ASSERT_TRUE(selfPaintingLayer.isSelfPaintingLayer()); |
| PaintLayer& nonSelfPaintingLayer = |
| *toLayoutBoxModelObject( |
| document().getElementById("non-self-painting-layer")->layoutObject()) |
| ->layer(); |
| ASSERT_FALSE(nonSelfPaintingLayer.isSelfPaintingLayer()); |
| ASSERT_TRUE(&nonSelfPaintingLayer == floatDiv.enclosingLayer()); |
| |
| EXPECT_FALSE(selfPaintingLayer.needsPaintPhaseFloat()); |
| EXPECT_FALSE(nonSelfPaintingLayer.needsPaintPhaseFloat()); |
| |
| // needsPaintPhaseFloat should be set when any descendant on the same layer |
| // has float. |
| toHTMLElement(floatDiv.node()) |
| ->setAttribute(HTMLNames::styleAttr, styleWithFloat); |
| document().view()->updateAllLifecyclePhasesExceptPaint(); |
| EXPECT_TRUE(selfPaintingLayer.needsPaintPhaseFloat()); |
| EXPECT_FALSE(nonSelfPaintingLayer.needsPaintPhaseFloat()); |
| paint(); |
| EXPECT_TRUE( |
| displayItemListContains(rootPaintController().getDisplayItemList(), |
| floatDiv, DisplayItem::kBoxDecorationBackground)); |
| |
| // needsPaintPhaseFloat should be reset when there is no float actually |
| // painted. |
| toHTMLElement(floatDiv.node()) |
| ->setAttribute(HTMLNames::styleAttr, styleWithoutFloat); |
| document().view()->updateAllLifecyclePhases(); |
| EXPECT_FALSE(selfPaintingLayer.needsPaintPhaseFloat()); |
| } |
| |
| TEST_P(PaintLayerPainterTest, PaintPhaseFloatUnderInlineLayer) { |
| setBodyInnerHTML( |
| "<div id='self-painting-layer' style='position: absolute'>" |
| " <div id='non-self-painting-layer' style='overflow: hidden'>" |
| " <span id='span' style='position: relative'>" |
| " <div id='float' style='width: 10px; height: 10px; " |
| "background-color: blue; float: left'></div>" |
| " </span>" |
| " </div>" |
| "</div>"); |
| document().view()->updateAllLifecyclePhases(); |
| |
| LayoutObject& floatDiv = *document().getElementById("float")->layoutObject(); |
| LayoutInline& span = |
| *toLayoutInline(document().getElementById("span")->layoutObject()); |
| PaintLayer& spanLayer = *span.layer(); |
| ASSERT_TRUE(&spanLayer == floatDiv.enclosingLayer()); |
| ASSERT_FALSE(spanLayer.needsPaintPhaseFloat()); |
| LayoutBlock& selfPaintingLayerObject = *toLayoutBlock( |
| document().getElementById("self-painting-layer")->layoutObject()); |
| PaintLayer& selfPaintingLayer = *selfPaintingLayerObject.layer(); |
| ASSERT_TRUE(selfPaintingLayer.isSelfPaintingLayer()); |
| PaintLayer& nonSelfPaintingLayer = |
| *toLayoutBoxModelObject( |
| document().getElementById("non-self-painting-layer")->layoutObject()) |
| ->layer(); |
| ASSERT_FALSE(nonSelfPaintingLayer.isSelfPaintingLayer()); |
| |
| EXPECT_TRUE(selfPaintingLayer.needsPaintPhaseFloat()); |
| EXPECT_FALSE(nonSelfPaintingLayer.needsPaintPhaseFloat()); |
| EXPECT_FALSE(spanLayer.needsPaintPhaseFloat()); |
| EXPECT_TRUE( |
| displayItemListContains(rootPaintController().getDisplayItemList(), |
| floatDiv, DisplayItem::kBoxDecorationBackground)); |
| } |
| |
| TEST_P(PaintLayerPainterTest, PaintPhaseBlockBackground) { |
| AtomicString styleWithoutBackground = "width: 50px; height: 50px"; |
| AtomicString styleWithBackground = |
| "background: blue; " + styleWithoutBackground; |
| setBodyInnerHTML( |
| "<div id='self-painting-layer' style='position: absolute'>" |
| " <div id='non-self-painting-layer' style='overflow: hidden'>" |
| " <div>" |
| " <div id='background'></div>" |
| " </div>" |
| " </div>" |
| "</div>"); |
| LayoutObject& backgroundDiv = |
| *document().getElementById("background")->layoutObject(); |
| toHTMLElement(backgroundDiv.node()) |
| ->setAttribute(HTMLNames::styleAttr, styleWithoutBackground); |
| document().view()->updateAllLifecyclePhases(); |
| |
| LayoutBlock& selfPaintingLayerObject = *toLayoutBlock( |
| document().getElementById("self-painting-layer")->layoutObject()); |
| PaintLayer& selfPaintingLayer = *selfPaintingLayerObject.layer(); |
| ASSERT_TRUE(selfPaintingLayer.isSelfPaintingLayer()); |
| PaintLayer& nonSelfPaintingLayer = |
| *toLayoutBoxModelObject( |
| document().getElementById("non-self-painting-layer")->layoutObject()) |
| ->layer(); |
| ASSERT_FALSE(nonSelfPaintingLayer.isSelfPaintingLayer()); |
| ASSERT_TRUE(&nonSelfPaintingLayer == backgroundDiv.enclosingLayer()); |
| |
| EXPECT_FALSE(selfPaintingLayer.needsPaintPhaseDescendantBlockBackgrounds()); |
| EXPECT_FALSE( |
| nonSelfPaintingLayer.needsPaintPhaseDescendantBlockBackgrounds()); |
| |
| // Background on the self-painting-layer node itself doesn't affect |
| // PaintPhaseDescendantBlockBackgrounds. |
| toHTMLElement(selfPaintingLayerObject.node()) |
| ->setAttribute(HTMLNames::styleAttr, |
| "position: absolute; background: green"); |
| document().view()->updateAllLifecyclePhases(); |
| EXPECT_FALSE(selfPaintingLayer.needsPaintPhaseDescendantBlockBackgrounds()); |
| EXPECT_FALSE( |
| nonSelfPaintingLayer.needsPaintPhaseDescendantBlockBackgrounds()); |
| EXPECT_TRUE(displayItemListContains( |
| rootPaintController().getDisplayItemList(), selfPaintingLayerObject, |
| DisplayItem::kBoxDecorationBackground)); |
| |
| // needsPaintPhaseDescendantBlockBackgrounds should be set when any descendant |
| // on the same layer has Background. |
| toHTMLElement(backgroundDiv.node()) |
| ->setAttribute(HTMLNames::styleAttr, styleWithBackground); |
| document().view()->updateAllLifecyclePhasesExceptPaint(); |
| EXPECT_TRUE(selfPaintingLayer.needsPaintPhaseDescendantBlockBackgrounds()); |
| EXPECT_FALSE( |
| nonSelfPaintingLayer.needsPaintPhaseDescendantBlockBackgrounds()); |
| paint(); |
| EXPECT_TRUE(displayItemListContains( |
| rootPaintController().getDisplayItemList(), backgroundDiv, |
| DisplayItem::kBoxDecorationBackground)); |
| |
| // needsPaintPhaseDescendantBlockBackgrounds should be reset when no outline |
| // is actually painted. |
| toHTMLElement(backgroundDiv.node()) |
| ->setAttribute(HTMLNames::styleAttr, styleWithoutBackground); |
| document().view()->updateAllLifecyclePhases(); |
| EXPECT_FALSE(selfPaintingLayer.needsPaintPhaseDescendantBlockBackgrounds()); |
| } |
| |
| TEST_P(PaintLayerPainterTest, PaintPhasesUpdateOnLayerRemoval) { |
| setBodyInnerHTML( |
| "<div id='layer' style='position: relative'>" |
| " <div style='height: 100px'>" |
| " <div style='height: 20px; outline: 1px solid red; background-color: " |
| "green'>outline and background</div>" |
| " <div style='float: left'>float</div>" |
| " </div>" |
| "</div>"); |
| |
| LayoutBlock& layerDiv = |
| *toLayoutBlock(document().getElementById("layer")->layoutObject()); |
| PaintLayer& layer = *layerDiv.layer(); |
| ASSERT_TRUE(layer.isSelfPaintingLayer()); |
| EXPECT_TRUE(layer.needsPaintPhaseDescendantOutlines()); |
| EXPECT_TRUE(layer.needsPaintPhaseFloat()); |
| EXPECT_TRUE(layer.needsPaintPhaseDescendantBlockBackgrounds()); |
| |
| PaintLayer& htmlLayer = |
| *toLayoutBlock(document().documentElement()->layoutObject())->layer(); |
| EXPECT_FALSE(htmlLayer.needsPaintPhaseDescendantOutlines()); |
| EXPECT_FALSE(htmlLayer.needsPaintPhaseFloat()); |
| EXPECT_FALSE(htmlLayer.needsPaintPhaseDescendantBlockBackgrounds()); |
| |
| toHTMLElement(layerDiv.node())->setAttribute(HTMLNames::styleAttr, ""); |
| document().view()->updateAllLifecyclePhases(); |
| |
| EXPECT_FALSE(layerDiv.hasLayer()); |
| EXPECT_TRUE(htmlLayer.needsPaintPhaseDescendantOutlines()); |
| EXPECT_TRUE(htmlLayer.needsPaintPhaseFloat()); |
| EXPECT_TRUE(htmlLayer.needsPaintPhaseDescendantBlockBackgrounds()); |
| } |
| |
| TEST_P(PaintLayerPainterTest, PaintPhasesUpdateOnLayerAddition) { |
| setBodyInnerHTML( |
| "<div id='will-be-layer'>" |
| " <div style='height: 100px'>" |
| " <div style='height: 20px; outline: 1px solid red; background-color: " |
| "green'>outline and background</div>" |
| " <div style='float: left'>float</div>" |
| " </div>" |
| "</div>"); |
| |
| LayoutBlock& layerDiv = *toLayoutBlock( |
| document().getElementById("will-be-layer")->layoutObject()); |
| EXPECT_FALSE(layerDiv.hasLayer()); |
| |
| PaintLayer& htmlLayer = |
| *toLayoutBlock(document().documentElement()->layoutObject())->layer(); |
| EXPECT_TRUE(htmlLayer.needsPaintPhaseDescendantOutlines()); |
| EXPECT_TRUE(htmlLayer.needsPaintPhaseFloat()); |
| EXPECT_TRUE(htmlLayer.needsPaintPhaseDescendantBlockBackgrounds()); |
| |
| toHTMLElement(layerDiv.node()) |
| ->setAttribute(HTMLNames::styleAttr, "position: relative"); |
| document().view()->updateAllLifecyclePhases(); |
| ASSERT_TRUE(layerDiv.hasLayer()); |
| PaintLayer& layer = *layerDiv.layer(); |
| ASSERT_TRUE(layer.isSelfPaintingLayer()); |
| EXPECT_TRUE(layer.needsPaintPhaseDescendantOutlines()); |
| EXPECT_TRUE(layer.needsPaintPhaseFloat()); |
| EXPECT_TRUE(layer.needsPaintPhaseDescendantBlockBackgrounds()); |
| } |
| |
| TEST_P(PaintLayerPainterTest, PaintPhasesUpdateOnBecomingSelfPainting) { |
| setBodyInnerHTML( |
| "<div id='will-be-self-painting' style='width: 100px; height: 100px; " |
| "overflow: hidden'>" |
| " <div>" |
| " <div style='outline: 1px solid red; background-color: " |
| "green'>outline and background</div>" |
| " </div>" |
| "</div>"); |
| |
| LayoutBlock& layerDiv = *toLayoutBlock( |
| document().getElementById("will-be-self-painting")->layoutObject()); |
| ASSERT_TRUE(layerDiv.hasLayer()); |
| EXPECT_FALSE(layerDiv.layer()->isSelfPaintingLayer()); |
| |
| PaintLayer& htmlLayer = |
| *toLayoutBlock(document().documentElement()->layoutObject())->layer(); |
| EXPECT_TRUE(htmlLayer.needsPaintPhaseDescendantOutlines()); |
| EXPECT_TRUE(htmlLayer.needsPaintPhaseDescendantBlockBackgrounds()); |
| |
| toHTMLElement(layerDiv.node()) |
| ->setAttribute( |
| HTMLNames::styleAttr, |
| "width: 100px; height: 100px; overflow: hidden; position: relative"); |
| document().view()->updateAllLifecyclePhases(); |
| PaintLayer& layer = *layerDiv.layer(); |
| ASSERT_TRUE(layer.isSelfPaintingLayer()); |
| EXPECT_TRUE(layer.needsPaintPhaseDescendantOutlines()); |
| EXPECT_TRUE(layer.needsPaintPhaseDescendantBlockBackgrounds()); |
| } |
| |
| TEST_P(PaintLayerPainterTest, PaintPhasesUpdateOnBecomingNonSelfPainting) { |
| setBodyInnerHTML( |
| "<div id='will-be-non-self-painting' style='width: 100px; height: 100px; " |
| "overflow: hidden; position: relative'>" |
| " <div>" |
| " <div style='outline: 1px solid red; background-color: " |
| "green'>outline and background</div>" |
| " </div>" |
| "</div>"); |
| |
| LayoutBlock& layerDiv = *toLayoutBlock( |
| document().getElementById("will-be-non-self-painting")->layoutObject()); |
| ASSERT_TRUE(layerDiv.hasLayer()); |
| PaintLayer& layer = *layerDiv.layer(); |
| EXPECT_TRUE(layer.isSelfPaintingLayer()); |
| EXPECT_TRUE(layer.needsPaintPhaseDescendantOutlines()); |
| EXPECT_TRUE(layer.needsPaintPhaseDescendantBlockBackgrounds()); |
| |
| PaintLayer& htmlLayer = |
| *toLayoutBlock(document().documentElement()->layoutObject())->layer(); |
| EXPECT_FALSE(htmlLayer.needsPaintPhaseDescendantOutlines()); |
| EXPECT_FALSE(htmlLayer.needsPaintPhaseDescendantBlockBackgrounds()); |
| |
| toHTMLElement(layerDiv.node()) |
| ->setAttribute(HTMLNames::styleAttr, |
| "width: 100px; height: 100px; overflow: hidden"); |
| document().view()->updateAllLifecyclePhases(); |
| EXPECT_FALSE(layer.isSelfPaintingLayer()); |
| EXPECT_TRUE(htmlLayer.needsPaintPhaseDescendantOutlines()); |
| EXPECT_TRUE(htmlLayer.needsPaintPhaseDescendantBlockBackgrounds()); |
| } |
| |
| TEST_P(PaintLayerPainterTest, |
| TableCollapsedBorderNeedsPaintPhaseDescendantBlockBackgrounds) { |
| // TODO(wangxianzhu): Enable this test slimmingPaintInvalidation when its |
| // fully functional. |
| if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled()) |
| return; |
| |
| // "position: relative" makes the table and td self-painting layers. |
| // The table's layer should be marked needsPaintPhaseDescendantBlockBackground |
| // because it will paint collapsed borders in the phase. |
| setBodyInnerHTML( |
| "<table id='table' style='position: relative; border-collapse: collapse'>" |
| " <tr><td style='position: relative; border: 1px solid " |
| "green'>Cell</td></tr>" |
| "</table>"); |
| |
| LayoutBlock& table = *toLayoutBlock(getLayoutObjectByElementId("table")); |
| ASSERT_TRUE(table.hasLayer()); |
| PaintLayer& layer = *table.layer(); |
| EXPECT_TRUE(layer.isSelfPaintingLayer()); |
| EXPECT_TRUE(layer.needsPaintPhaseDescendantBlockBackgrounds()); |
| } |
| |
| TEST_P(PaintLayerPainterTest, |
| TableCollapsedBorderNeedsPaintPhaseDescendantBlockBackgroundsDynamic) { |
| // TODO(wangxianzhu): Enable this test slimmingPaintInvalidation when its |
| // fully functional. |
| if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled()) |
| return; |
| |
| setBodyInnerHTML( |
| "<table id='table' style='position: relative'>" |
| " <tr><td style='position: relative; border: 1px solid " |
| "green'>Cell</td></tr>" |
| "</table>"); |
| |
| LayoutBlock& table = *toLayoutBlock(getLayoutObjectByElementId("table")); |
| ASSERT_TRUE(table.hasLayer()); |
| PaintLayer& layer = *table.layer(); |
| EXPECT_TRUE(layer.isSelfPaintingLayer()); |
| EXPECT_FALSE(layer.needsPaintPhaseDescendantBlockBackgrounds()); |
| |
| toHTMLElement(table.node()) |
| ->setAttribute(HTMLNames::styleAttr, |
| "position: relative; border-collapse: collapse"); |
| document().view()->updateAllLifecyclePhases(); |
| EXPECT_TRUE(layer.needsPaintPhaseDescendantBlockBackgrounds()); |
| } |
| |
| } // namespace blink |