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

Unified Diff: third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp

Issue 1364063007: Throttle rendering pipeline for invisible frames (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Might help to include the test source code. Created 5 years, 3 months 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/web/WebViewImpl.cpp ('k') | third_party/WebKit/Source/web/web.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp
diff --git a/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp b/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..824d8bfef4287d1c8b970b81679f657982391bf8
--- /dev/null
+++ b/third_party/WebKit/Source/web/tests/FrameThrottlingTest.cpp
@@ -0,0 +1,225 @@
+// 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 "config.h"
+
+#include "core/dom/Document.h"
+#include "core/frame/FrameView.h"
+#include "public/web/WebElement.h"
+#include "web/WebLocalFrameImpl.h"
+#include "web/tests/FrameTestHelpers.h"
+#include "web/tests/sim/SimCompositor.h"
+#include "web/tests/sim/SimDisplayItemList.h"
+#include "web/tests/sim/SimLayerTreeView.h"
+#include "web/tests/sim/SimWebViewClient.h"
+#include <gtest/gtest.h>
+
+namespace blink {
+
+class FrameThrottlingTest : public ::testing::Test {
+protected:
+ using SecurityOriginStatus = FrameView::SecurityOriginStatus;
+ using ViewportVisibility = FrameView::ViewportVisibility;
+
+ FrameThrottlingTest()
+ : m_webViewClient(m_layerTreeView)
+ , m_compositor(m_layerTreeView)
+ {
+ m_webViewHelper.initialize(true, &m_webFrameClient, &m_webViewClient);
+ m_compositor.setWebViewImpl(webView());
+ webView().resize(WebSize(640, 480));
+ }
+
+ ~FrameThrottlingTest() override { }
+
+ void setInnerHTML(const String& html)
+ {
+ document().documentElement()->setInnerHTML(html, ASSERT_NO_EXCEPTION);
+ m_webFrameClient.waitForLoadToComplete();
+ webView().layout();
+ }
+
+ void setupPageWithThrottleableFrame()
+ {
+ setInnerHTML("<iframe sandbox=\"\"></iframe>");
+ }
+
+ Document& document()
+ {
+ return *webView().mainFrameImpl()->frame()->document();
+ }
+
+ WebNode root()
+ {
+ return WebNode(document().documentElement());
+ }
+
+ WebViewImpl& webView()
+ {
+ return *m_webViewHelper.webViewImpl();
+ }
+
+ ViewportVisibility viewportVisibility(FrameView* frameView)
+ {
+ return frameView->m_viewportVisibility;
+ }
+
+ SimLayerTreeView m_layerTreeView;
+ SimWebViewClient m_webViewClient;
+ SimCompositor m_compositor;
+ FrameTestHelpers::TestWebFrameClient m_webFrameClient;
+ FrameTestHelpers::WebViewHelper m_webViewHelper;
+};
+
+TEST_F(FrameThrottlingTest, ThrottleInvisibleFrames)
+{
+ setupPageWithThrottleableFrame();
+
+ // Initially both frames are visible.
+ FrameView* frameView = document().view();
+ FrameView* childFrameView = toLocalFrame(frameView->frame().tree().firstChild())->view();
+ EXPECT_EQ(ViewportVisibility::Visible, viewportVisibility(frameView));
+ EXPECT_EQ(ViewportVisibility::Visible, viewportVisibility(childFrameView));
+
+ // Moving the child fully outside the parent makes it invisible.
+ childFrameView->move(0, frameView->height());
+ frameView->updateAllLifecyclePhases();
+ frameView->finalizeLifecycleUpdate();
+ EXPECT_EQ(ViewportVisibility::Visible, viewportVisibility(frameView));
+ EXPECT_EQ(ViewportVisibility::Hidden, viewportVisibility(childFrameView));
+
+ // A partially visible child is considered visible.
+ childFrameView->move(-childFrameView->width() / 2, 0);
+ frameView->updateAllLifecyclePhases();
+ frameView->finalizeLifecycleUpdate();
esprehn 2015/10/01 08:21:37 m_compositor.beginFrame()
Sami 2015/10/05 17:58:24 Done.
+ EXPECT_EQ(ViewportVisibility::Visible, viewportVisibility(frameView));
+ EXPECT_EQ(ViewportVisibility::Visible, viewportVisibility(childFrameView));
+}
+
+TEST_F(FrameThrottlingTest, viewportVisibilityFullyClipped)
+{
+ setupPageWithThrottleableFrame();
+
+ // A child which is fully clipped away by its ancestor should become invisible.
+ FrameView* frameView = document().view();
+ FrameView* childFrameView = toLocalFrame(frameView->frame().tree().firstChild())->view();
+ webView().resize(WebSize(0, 0));
+ webView().layout();
esprehn 2015/10/01 08:21:37 ditto, layout is only triggered from frames, so yo
Sami 2015/10/05 17:58:24 Done.
+ frameView->updateAllLifecyclePhases();
+ frameView->finalizeLifecycleUpdate();
esprehn 2015/10/01 08:21:36 and then you don't need this
Sami 2015/10/05 17:58:24 Done.
+ EXPECT_EQ(ViewportVisibility::Visible, viewportVisibility(frameView));
+ EXPECT_EQ(ViewportVisibility::Hidden, viewportVisibility(childFrameView));
+}
+
+TEST_F(FrameThrottlingTest, hiddenCrossOriginFramesAreThrottled)
+{
+ // Create a document with doubly nested iframes.
+ setInnerHTML("<iframe srcdoc=\"<iframe></iframe>\"></iframe>");
+
+ FrameView* frameView = document().view();
+ LocalFrame* childFrame = toLocalFrame(frameView->frame().tree().firstChild());
+ LocalFrame* grandChildFrame = toLocalFrame(childFrame->tree().firstChild());
+ FrameView* childFrameView = childFrame->view();
+ FrameView* grandChildFrameView = grandChildFrame->view();
+ EXPECT_FALSE(frameView->shouldThrottleRenderingPipeline());
+ EXPECT_FALSE(childFrameView->shouldThrottleRenderingPipeline());
+ EXPECT_FALSE(grandChildFrameView->shouldThrottleRenderingPipeline());
+
+ // Just being hidden doesn't make a frame throttled.
+ grandChildFrameView->move(0, frameView->height());
esprehn 2015/10/01 08:21:36 this can't happen in a real page, set some style t
Sami 2015/10/05 17:58:24 Done.
+ frameView->finalizeLifecycleUpdate();
+ EXPECT_FALSE(frameView->shouldThrottleRenderingPipeline());
+ EXPECT_FALSE(childFrameView->shouldThrottleRenderingPipeline());
+ EXPECT_FALSE(grandChildFrameView->shouldThrottleRenderingPipeline());
+
+ // Making the middle frame cross origin enables throttling for the grand child.
+ childFrame->securityContext()->setSecurityOrigin(SecurityOrigin::createUnique());
+ frameView->finalizeLifecycleUpdate();
esprehn 2015/10/01 08:21:36 why would this happen again in a real page?
Sami 2015/10/05 17:58:24 You're right, it wouldn't. To make this more reali
+ EXPECT_FALSE(frameView->shouldThrottleRenderingPipeline());
+ EXPECT_FALSE(childFrameView->shouldThrottleRenderingPipeline());
+ EXPECT_TRUE(grandChildFrameView->shouldThrottleRenderingPipeline());
+}
+
+TEST_F(FrameThrottlingTest, throttledLifecycleUpdate)
+{
+ setupPageWithThrottleableFrame();
+
+ FrameView* frameView = document().view();
+ LocalFrame* childFrame = toLocalFrame(frameView->frame().tree().firstChild());
+ FrameView* childFrameView = childFrame->view();
+
+ // Enable throttling for the child frame.
+ childFrameView->move(0, frameView->height());
esprehn 2015/10/01 08:21:36 move with style, real pages can't go through ->mov
Sami 2015/10/05 17:58:25 Done.
+ frameView->updateAllLifecyclePhases();
+ frameView->finalizeLifecycleUpdate();
esprehn 2015/10/01 08:21:36 ditto, beginFrame()
Sami 2015/10/05 17:58:24 Done.
+ EXPECT_TRUE(childFrameView->shouldThrottleRenderingPipeline());
+
+ // Doing a lifecycle update while allowing throttling shouldn't clear the
+ // needs layout bit on the child frame.
+ childFrameView->setNeedsLayout();
esprehn 2015/10/01 08:21:37 don't artificially cause layout, do something real
Sami 2015/10/05 17:58:24 Done.
+ EXPECT_TRUE(childFrameView->needsLayout());
+ frameView->updateAllLifecyclePhases(DocumentLifecycle::ThrottlingMode::Allow);
esprehn 2015/10/01 08:21:37 this can't really happen
Sami 2015/10/05 17:58:24 Replaced with another beginFrame().
+ EXPECT_TRUE(childFrameView->needsLayout());
+
+ frameView->updateAllLifecyclePhases(DocumentLifecycle::ThrottlingMode::Disallow);
+ EXPECT_FALSE(childFrameView->needsLayout());
+}
+
+TEST_F(FrameThrottlingTest, unthrottlingFrameSchedulesAnimation)
+{
+ setupPageWithThrottleableFrame();
+ FrameView* frameView = document().view();
+ LocalFrame* childFrame = toLocalFrame(frameView->frame().tree().firstChild());
+ FrameView* childFrameView = childFrame->view();
+
+ // First make the child hidden to enable throttling.
+ childFrameView->move(0, frameView->height());
esprehn 2015/10/01 08:21:37 ditto
Sami 2015/10/05 17:58:24 Done.
+ frameView->updateAllLifecyclePhases(DocumentLifecycle::ThrottlingMode::Allow);
+ m_layerTreeView.clearNeedsAnimate();
+ frameView->finalizeLifecycleUpdate();
+ EXPECT_FALSE(m_layerTreeView.needsAnimate());
+
+ // Then bring it back on-screen. This should schedule an animation update.
+ childFrameView->move(0, 0);
+ frameView->updateAllLifecyclePhases(DocumentLifecycle::ThrottlingMode::Allow);
+ m_layerTreeView.clearNeedsAnimate();
esprehn 2015/10/01 08:21:36 beginFrame() clears this bit, real pages never cle
Sami 2015/10/05 17:58:24 Thanks, replaced this with beginFrame too, but had
+ frameView->finalizeLifecycleUpdate();
+ EXPECT_TRUE(m_layerTreeView.needsAnimate());
+}
+
+TEST_F(FrameThrottlingTest, mutatingThrottledFrameDoesNotCauseAnimation)
+{
+ setInnerHTML("<iframe id=\"frame\" sandbox=\"\" srcdoc=\"<style> html { background: red; } </style>\"></iframe>");
+ WebExceptionCode ec;
+ WebElement frameElement = root().querySelector("#frame", ec);
+ EXPECT_EQ(0, ec);
+
+ // Check that the frame initially shows up.
+ m_layerTreeView.setDeferCommits(false);
+ SimDisplayItemList displayItems1 = m_compositor.beginFrame();
+ EXPECT_TRUE(displayItems1.contains(SimCanvas::Rect, "red"));
+
+ // Move the frame offscreen to throttle it.
+ FrameView* frameView = document().view();
+ LocalFrame* childFrame = toLocalFrame(frameView->frame().tree().firstChild());
+ frameElement.setAttribute("style", "transform: translateY(480px)");
+ webView().layout();
+ frameView->finalizeLifecycleUpdate();
+
+ // Mutating the throttled frame should not cause an animation to be scheduled.
+ m_layerTreeView.clearNeedsAnimate();
+ childFrame->document()->documentElement()->setInnerHTML("<style> html { background: green; } </style>", ASSERT_NO_EXCEPTION);
+ EXPECT_FALSE(m_layerTreeView.needsAnimate());
+
+ // Moving the frame back on screen should make its new contents show up.
+ frameElement.setAttribute("style", "");
+ EXPECT_TRUE(m_layerTreeView.needsAnimate());
+ webView().layout();
esprehn 2015/10/01 08:21:36 beginFrame()
+ frameView->finalizeLifecycleUpdate();
esprehn 2015/10/01 08:21:36 How does this happen in a real page? You cause an
Sami 2015/10/05 17:58:24 Replaced this with a series of composites that sho
+
+ SimDisplayItemList displayItems2 = m_compositor.beginFrame();
+ EXPECT_TRUE(displayItems2.contains(SimCanvas::Rect, "green"));
+}
+
+} // namespace blink
« no previous file with comments | « third_party/WebKit/Source/web/WebViewImpl.cpp ('k') | third_party/WebKit/Source/web/web.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698