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

Unified Diff: third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp

Issue 2589003002: Split paint property update tests out of PaintPropertyTreeBuilderTest (Closed)
Patch Set: Rebase, minor cleanup Created 4 years 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 | « third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e983490c89dc7f94ba7b167c155eb4c6399d4b10
--- /dev/null
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeUpdateTests.cpp
@@ -0,0 +1,444 @@
+// Copyright 2016 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/html/HTMLIFrameElement.h"
+#include "core/paint/PaintPropertyTreeBuilderTest.h"
+#include "core/paint/PaintPropertyTreePrinter.h"
+
+namespace blink {
+
+// Tests covering incremental updates of paint property trees.
+class PaintPropertyTreeUpdateTest : public PaintPropertyTreeBuilderTest {};
+
+TEST_P(PaintPropertyTreeUpdateTest,
+ ThreadedScrollingDisabledMainThreadScrollReason) {
+ setBodyInnerHTML(
+ "<style>"
+ " #overflowA {"
+ " position: absolute;"
+ " overflow: scroll;"
+ " width: 20px;"
+ " height: 20px;"
+ " }"
+ " .forceScroll {"
+ " height: 4000px;"
+ " }"
+ "</style>"
+ "<div id='overflowA'>"
+ " <div class='forceScroll'></div>"
+ "</div>"
+ "<div class='forceScroll'></div>");
+ Element* overflowA = document().getElementById("overflowA");
+ EXPECT_FALSE(frameScroll()->threadedScrollingDisabled());
+ EXPECT_FALSE(overflowA->layoutObject()
+ ->paintProperties()
+ ->scroll()
+ ->threadedScrollingDisabled());
+
+ document().settings()->setThreadedScrollingEnabled(false);
+ // TODO(pdr): The main thread scrolling setting should invalidate properties.
+ document().view()->setNeedsPaintPropertyUpdate();
+ overflowA->layoutObject()->setNeedsPaintPropertyUpdate();
+ document().view()->updateAllLifecyclePhases();
+
+ EXPECT_TRUE(frameScroll()->threadedScrollingDisabled());
+ EXPECT_TRUE(overflowA->layoutObject()
+ ->paintProperties()
+ ->scroll()
+ ->threadedScrollingDisabled());
+}
+
+TEST_P(PaintPropertyTreeUpdateTest,
+ BackgroundAttachmentFixedMainThreadScrollReasonsWithNestedScrollers) {
+ setBodyInnerHTML(
+ "<style>"
+ " #overflowA {"
+ " position: absolute;"
+ " overflow: scroll;"
+ " width: 20px;"
+ " height: 20px;"
+ " }"
+ " #overflowB {"
+ " position: absolute;"
+ " overflow: scroll;"
+ " width: 5px;"
+ " height: 3px;"
+ " }"
+ " .backgroundAttachmentFixed {"
+ " background-image: url('foo');"
+ " background-attachment: fixed;"
+ " }"
+ " .forceScroll {"
+ " height: 4000px;"
+ " }"
+ "</style>"
+ "<div id='overflowA'>"
+ " <div id='overflowB' class='backgroundAttachmentFixed'>"
+ " <div class='forceScroll'></div>"
+ " </div>"
+ " <div class='forceScroll'></div>"
+ "</div>"
+ "<div class='forceScroll'></div>");
+ Element* overflowA = document().getElementById("overflowA");
+ Element* overflowB = document().getElementById("overflowB");
+
+ EXPECT_TRUE(frameScroll()->hasBackgroundAttachmentFixedDescendants());
+ EXPECT_TRUE(overflowA->layoutObject()
+ ->paintProperties()
+ ->scroll()
+ ->hasBackgroundAttachmentFixedDescendants());
+ EXPECT_FALSE(overflowB->layoutObject()
+ ->paintProperties()
+ ->scroll()
+ ->hasBackgroundAttachmentFixedDescendants());
+
+ // Removing a main thread scrolling reason should update the entire tree.
+ overflowB->removeAttribute("class");
+ document().view()->updateAllLifecyclePhases();
+ EXPECT_FALSE(frameScroll()->hasBackgroundAttachmentFixedDescendants());
+ EXPECT_FALSE(overflowA->layoutObject()
+ ->paintProperties()
+ ->scroll()
+ ->hasBackgroundAttachmentFixedDescendants());
+ EXPECT_FALSE(overflowB->layoutObject()
+ ->paintProperties()
+ ->scroll()
+ ->hasBackgroundAttachmentFixedDescendants());
+
+ // Adding a main thread scrolling reason should update the entire tree.
+ overflowB->setAttribute(HTMLNames::classAttr, "backgroundAttachmentFixed");
+ document().view()->updateAllLifecyclePhases();
+ EXPECT_TRUE(frameScroll()->hasBackgroundAttachmentFixedDescendants());
+ EXPECT_TRUE(overflowA->layoutObject()
+ ->paintProperties()
+ ->scroll()
+ ->hasBackgroundAttachmentFixedDescendants());
+ EXPECT_FALSE(overflowB->layoutObject()
+ ->paintProperties()
+ ->scroll()
+ ->hasBackgroundAttachmentFixedDescendants());
+}
+
+TEST_P(PaintPropertyTreeUpdateTest,
+ BackgroundAttachmentFixedMainThreadScrollReasonsWithFixedScroller) {
+ setBodyInnerHTML(
+ "<style>"
+ " #overflowA {"
+ " position: absolute;"
+ " overflow: scroll;"
+ " width: 20px;"
+ " height: 20px;"
+ " }"
+ " #overflowB {"
+ " position: fixed;"
+ " overflow: scroll;"
+ " width: 5px;"
+ " height: 3px;"
+ " }"
+ " .backgroundAttachmentFixed {"
+ " background-image: url('foo');"
+ " background-attachment: fixed;"
+ " }"
+ " .forceScroll {"
+ " height: 4000px;"
+ " }"
+ "</style>"
+ "<div id='overflowA'>"
+ " <div id='overflowB' class='backgroundAttachmentFixed'>"
+ " <div class='forceScroll'></div>"
+ " </div>"
+ " <div class='forceScroll'></div>"
+ "</div>"
+ "<div class='forceScroll'></div>");
+ Element* overflowA = document().getElementById("overflowA");
+ Element* overflowB = document().getElementById("overflowB");
+
+ // This should be false. We are not as strict about main thread scrolling
+ // reasons as we could be.
+ EXPECT_TRUE(overflowA->layoutObject()
+ ->paintProperties()
+ ->scroll()
+ ->hasBackgroundAttachmentFixedDescendants());
+ EXPECT_FALSE(overflowB->layoutObject()
+ ->paintProperties()
+ ->scroll()
+ ->hasBackgroundAttachmentFixedDescendants());
+ EXPECT_TRUE(overflowB->layoutObject()
+ ->paintProperties()
+ ->scroll()
+ ->parent()
+ ->isRoot());
+
+ // Removing a main thread scrolling reason should update the entire tree.
+ overflowB->removeAttribute("class");
+ document().view()->updateAllLifecyclePhases();
+ EXPECT_FALSE(overflowA->layoutObject()
+ ->paintProperties()
+ ->scroll()
+ ->hasBackgroundAttachmentFixedDescendants());
+ EXPECT_FALSE(overflowB->layoutObject()
+ ->paintProperties()
+ ->scroll()
+ ->hasBackgroundAttachmentFixedDescendants());
+ EXPECT_FALSE(overflowB->layoutObject()
+ ->paintProperties()
+ ->scroll()
+ ->parent()
+ ->hasBackgroundAttachmentFixedDescendants());
+}
+
+TEST_P(PaintPropertyTreeUpdateTest, DescendantNeedsUpdateAcrossFrames) {
+ setBodyInnerHTML(
+ "<style>body { margin: 0; }</style>"
+ "<div id='divWithTransform' style='transform: translate3d(1px,2px,3px);'>"
+ " <iframe style='border: 7px solid black'></iframe>"
+ "</div>");
+ setChildFrameHTML(
+ "<style>body { margin: 0; }</style><div id='transform' style='transform: "
+ "translate3d(4px, 5px, 6px); width: 100px; height: 200px'></div>");
+
+ FrameView* frameView = document().view();
+ frameView->updateAllLifecyclePhases();
+
+ LayoutObject* divWithTransform =
+ document().getElementById("divWithTransform")->layoutObject();
+ LayoutObject* childLayoutView = childDocument().layoutView();
+ LayoutObject* innerDivWithTransform =
+ childDocument().getElementById("transform")->layoutObject();
+
+ // Initially, no objects should need a descendant update.
+ EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
+ EXPECT_FALSE(divWithTransform->descendantNeedsPaintPropertyUpdate());
+ EXPECT_FALSE(childLayoutView->descendantNeedsPaintPropertyUpdate());
+ EXPECT_FALSE(innerDivWithTransform->descendantNeedsPaintPropertyUpdate());
+
+ // Marking the child div as needing a paint property update should propagate
+ // up the tree and across frames.
+ innerDivWithTransform->setNeedsPaintPropertyUpdate();
+ EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
+ EXPECT_TRUE(divWithTransform->descendantNeedsPaintPropertyUpdate());
+ EXPECT_TRUE(childLayoutView->descendantNeedsPaintPropertyUpdate());
+ EXPECT_TRUE(innerDivWithTransform->needsPaintPropertyUpdate());
+ EXPECT_FALSE(innerDivWithTransform->descendantNeedsPaintPropertyUpdate());
+
+ // After a lifecycle update, no nodes should need a descendant update.
+ frameView->updateAllLifecyclePhases();
+ EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
+ EXPECT_FALSE(divWithTransform->descendantNeedsPaintPropertyUpdate());
+ EXPECT_FALSE(childLayoutView->descendantNeedsPaintPropertyUpdate());
+ EXPECT_FALSE(innerDivWithTransform->descendantNeedsPaintPropertyUpdate());
+
+ // A child frame marked as needing a paint property update should not be
+ // skipped if the owning layout tree does not need an update.
+ FrameView* childFrameView = childDocument().view();
+ childFrameView->setNeedsPaintPropertyUpdate();
+ EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
+ frameView->updateAllLifecyclePhases();
+ EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
+ EXPECT_FALSE(frameView->needsPaintPropertyUpdate());
+ EXPECT_FALSE(childFrameView->needsPaintPropertyUpdate());
+}
+
+TEST_P(PaintPropertyTreeUpdateTest, UpdatingFrameViewContentClip) {
+ setBodyInnerHTML("hello world.");
+ EXPECT_EQ(FloatRoundedRect(0, 0, 800, 600), frameContentClip()->clipRect());
+ document().view()->resize(800, 599);
+ document().view()->updateAllLifecyclePhases();
+ EXPECT_EQ(FloatRoundedRect(0, 0, 800, 599), frameContentClip()->clipRect());
+ document().view()->resize(800, 600);
+ document().view()->updateAllLifecyclePhases();
+ EXPECT_EQ(FloatRoundedRect(0, 0, 800, 600), frameContentClip()->clipRect());
+ document().view()->resize(5, 5);
+ document().view()->updateAllLifecyclePhases();
+ EXPECT_EQ(FloatRoundedRect(0, 0, 5, 5), frameContentClip()->clipRect());
+}
+
+TEST_P(PaintPropertyTreeUpdateTest, BuildingStopsAtThrottledFrames) {
+ setBodyInnerHTML(
+ "<style>body { margin: 0; }</style>"
+ "<div id='transform' style='transform: translate3d(4px, 5px, 6px);'>"
+ "</div>"
+ "<iframe id='iframe' sandbox></iframe>");
+ setChildFrameHTML(
+ "<style>body { margin: 0; }</style>"
+ "<div id='iframeTransform'"
+ " style='transform: translate3d(4px, 5px, 6px);'/>");
+
+ // Move the child frame offscreen so it becomes available for throttling.
+ auto* iframe = toHTMLIFrameElement(document().getElementById("iframe"));
+ iframe->setAttribute(HTMLNames::styleAttr, "transform: translateY(5555px)");
+ document().view()->updateAllLifecyclePhases();
+ // Ensure intersection observer notifications get delivered.
+ testing::runPendingTasks();
+ EXPECT_FALSE(document().view()->isHiddenForThrottling());
+ EXPECT_TRUE(childDocument().view()->isHiddenForThrottling());
+
+ auto* transform = document().getElementById("transform")->layoutObject();
+ auto* iframeLayoutView = childDocument().layoutView();
+ auto* iframeTransform =
+ childDocument().getElementById("iframeTransform")->layoutObject();
+
+ // Invalidate properties in the iframe and ensure ancestors are marked.
+ iframeTransform->setNeedsPaintPropertyUpdate();
+ EXPECT_FALSE(document().layoutView()->needsPaintPropertyUpdate());
+ EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
+ EXPECT_FALSE(transform->needsPaintPropertyUpdate());
+ EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate());
+ EXPECT_FALSE(iframeLayoutView->needsPaintPropertyUpdate());
+ EXPECT_TRUE(iframeLayoutView->descendantNeedsPaintPropertyUpdate());
+ EXPECT_TRUE(iframeTransform->needsPaintPropertyUpdate());
+ EXPECT_FALSE(iframeTransform->descendantNeedsPaintPropertyUpdate());
+
+ transform->setNeedsPaintPropertyUpdate();
+ EXPECT_TRUE(transform->needsPaintPropertyUpdate());
+ EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate());
+
+ {
+ DocumentLifecycle::AllowThrottlingScope throttlingScope(
+ document().lifecycle());
+ EXPECT_FALSE(document().view()->shouldThrottleRendering());
+ EXPECT_TRUE(childDocument().view()->shouldThrottleRendering());
+
+ // A lifecycle update should update all properties except those with
+ // actively throttled descendants.
+ document().view()->updateAllLifecyclePhases();
+ EXPECT_FALSE(document().layoutView()->needsPaintPropertyUpdate());
+ EXPECT_TRUE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
+ EXPECT_FALSE(transform->needsPaintPropertyUpdate());
+ EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate());
+ EXPECT_FALSE(iframeLayoutView->needsPaintPropertyUpdate());
+ EXPECT_TRUE(iframeLayoutView->descendantNeedsPaintPropertyUpdate());
+ EXPECT_TRUE(iframeTransform->needsPaintPropertyUpdate());
+ EXPECT_FALSE(iframeTransform->descendantNeedsPaintPropertyUpdate());
+ }
+
+ EXPECT_FALSE(document().view()->shouldThrottleRendering());
+ EXPECT_FALSE(childDocument().view()->shouldThrottleRendering());
+ // Once unthrottled, a lifecycel update should update all properties.
+ document().view()->updateAllLifecyclePhases();
+ EXPECT_FALSE(document().layoutView()->needsPaintPropertyUpdate());
+ EXPECT_FALSE(document().layoutView()->descendantNeedsPaintPropertyUpdate());
+ EXPECT_FALSE(transform->needsPaintPropertyUpdate());
+ EXPECT_FALSE(transform->descendantNeedsPaintPropertyUpdate());
+ EXPECT_FALSE(iframeLayoutView->needsPaintPropertyUpdate());
+ EXPECT_FALSE(iframeLayoutView->descendantNeedsPaintPropertyUpdate());
+ EXPECT_FALSE(iframeTransform->needsPaintPropertyUpdate());
+ EXPECT_FALSE(iframeTransform->descendantNeedsPaintPropertyUpdate());
+}
+
+TEST_P(PaintPropertyTreeUpdateTest, ClipChangesUpdateOverflowClip) {
+ setBodyInnerHTML(
+ "<style>"
+ " body { margin:0 }"
+ " #div { overflow:hidden; height:0px; }"
+ "</style>"
+ "<div id='div'></div>");
+ auto* div = document().getElementById("div");
+ div->setAttribute(HTMLNames::styleAttr, "display:inline-block; width:7px;");
+ document().view()->updateAllLifecyclePhases();
+ auto* clipProperties = div->layoutObject()->paintProperties()->overflowClip();
+ EXPECT_EQ(FloatRect(0, 0, 7, 0), clipProperties->clipRect().rect());
+
+ // Width changes should update the overflow clip.
+ div->setAttribute(HTMLNames::styleAttr, "display:inline-block; width:7px;");
+ document().view()->updateAllLifecyclePhases();
+ clipProperties = div->layoutObject()->paintProperties()->overflowClip();
+ EXPECT_EQ(FloatRect(0, 0, 7, 0), clipProperties->clipRect().rect());
+ div->setAttribute(HTMLNames::styleAttr, "display:inline-block; width:9px;");
+ document().view()->updateAllLifecyclePhases();
+ EXPECT_EQ(FloatRect(0, 0, 9, 0), clipProperties->clipRect().rect());
+
+ // An inline block's overflow clip should be updated when padding changes,
+ // even if the border box remains unchanged.
+ div->setAttribute(HTMLNames::styleAttr,
+ "display:inline-block; width:7px; padding-right:3px;");
+ document().view()->updateAllLifecyclePhases();
+ clipProperties = div->layoutObject()->paintProperties()->overflowClip();
+ EXPECT_EQ(FloatRect(0, 0, 10, 0), clipProperties->clipRect().rect());
+ div->setAttribute(HTMLNames::styleAttr,
+ "display:inline-block; width:8px; padding-right:2px;");
+ document().view()->updateAllLifecyclePhases();
+ EXPECT_EQ(FloatRect(0, 0, 10, 0), clipProperties->clipRect().rect());
+ div->setAttribute(HTMLNames::styleAttr,
+ "display:inline-block; width:8px;"
+ "padding-right:1px; padding-left:1px;");
+ document().view()->updateAllLifecyclePhases();
+ EXPECT_EQ(FloatRect(0, 0, 10, 0), clipProperties->clipRect().rect());
+
+ // An block's overflow clip should be updated when borders change.
+ div->setAttribute(HTMLNames::styleAttr, "border-right:3px solid red;");
+ document().view()->updateAllLifecyclePhases();
+ clipProperties = div->layoutObject()->paintProperties()->overflowClip();
+ EXPECT_EQ(FloatRect(0, 0, 797, 0), clipProperties->clipRect().rect());
+ div->setAttribute(HTMLNames::styleAttr, "border-right:5px solid red;");
+ document().view()->updateAllLifecyclePhases();
+ EXPECT_EQ(FloatRect(0, 0, 795, 0), clipProperties->clipRect().rect());
+
+ // Removing overflow clip should remove the property.
+ div->setAttribute(HTMLNames::styleAttr, "overflow:hidden;");
+ document().view()->updateAllLifecyclePhases();
+ clipProperties = div->layoutObject()->paintProperties()->overflowClip();
+ EXPECT_EQ(FloatRect(0, 0, 800, 0), clipProperties->clipRect().rect());
+ div->setAttribute(HTMLNames::styleAttr, "overflow:visible;");
+ document().view()->updateAllLifecyclePhases();
+ EXPECT_TRUE(!div->layoutObject()->paintProperties() ||
+ !div->layoutObject()->paintProperties()->overflowClip());
+}
+
+TEST_P(PaintPropertyTreeUpdateTest, ContainPaintChangesUpdateOverflowClip) {
+ setBodyInnerHTML(
+ "<style>"
+ " body { margin:0 }"
+ " #div { will-change:transform; width:7px; height:6px; }"
+ "</style>"
+ "<div id='div' style='contain:paint;'></div>");
+ document().view()->updateAllLifecyclePhases();
+ auto* div = document().getElementById("div");
+ auto* properties = div->layoutObject()->paintProperties()->overflowClip();
+ EXPECT_EQ(FloatRect(0, 0, 7, 6), properties->clipRect().rect());
+
+ div->setAttribute(HTMLNames::styleAttr, "");
+ document().view()->updateAllLifecyclePhases();
+ EXPECT_TRUE(!div->layoutObject()->paintProperties() ||
+ !div->layoutObject()->paintProperties()->overflowClip());
+}
+
+// A basic sanity check for over-invalidation of paint properties.
+TEST_P(PaintPropertyTreeUpdateTest, NoPaintPropertyUpdateOnBackgroundChange) {
+ setBodyInnerHTML("<div id='div' style='background-color: blue'>DIV</div>");
+ auto* div = document().getElementById("div");
+
+ document().view()->updateAllLifecyclePhases();
+ div->setAttribute(HTMLNames::styleAttr, "background-color: green");
+ document().view()->updateLifecycleToLayoutClean();
+ EXPECT_FALSE(div->layoutObject()->needsPaintPropertyUpdate());
+}
+
+// Disabled due to stale scrollsOverflow values, see: https://crbug.com/675296.
+TEST_P(PaintPropertyTreeUpdateTest,
+ DISABLED_FrameVisibilityChangeUpdatesProperties) {
+ setBodyInnerHTML(
+ "<style>body { margin: 0; }</style>"
+ "<div id='iframeContainer'>"
+ " <iframe id='iframe' style='width: 100px; height: 100px;'></iframe>"
+ "</div>");
+ setChildFrameHTML(
+ "<style>body { margin: 0; }</style>"
+ "<div id='forceScroll' style='height: 3000px;'></div>");
+
+ FrameView* frameView = document().view();
+ frameView->updateAllLifecyclePhases();
+ EXPECT_EQ(nullptr, frameScroll(frameView));
+ FrameView* childFrameView = childDocument().view();
+ EXPECT_NE(nullptr, frameScroll(childFrameView));
+
+ auto* iframeContainer = document().getElementById("iframeContainer");
+ iframeContainer->setAttribute(HTMLNames::styleAttr, "visibility: hidden;");
+ frameView->updateAllLifecyclePhases();
+
+ EXPECT_EQ(nullptr, frameScroll(frameView));
+ EXPECT_EQ(nullptr, frameScroll(childFrameView));
+}
+
+} // namespace blink
« no previous file with comments | « third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698