blob: cba3ee9b598ca81c147034df5455d26db0ea27ee [file] [log] [blame]
// Copyright 2018 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 "content/browser/renderer_host/render_widget_host_view_aura.h"
#include "base/bind.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/browser/renderer_host/delegated_frame_host.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_aura.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
namespace content {
namespace {
#if defined(OS_CHROMEOS)
const char kMinimalPageDataURL[] =
"data:text/html,<html><head></head><body>Hello, world</body></html>";
// Run the current message loop for a short time without unwinding the current
// call stack.
void GiveItSomeTime() {
base::RunLoop run_loop;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE, run_loop.QuitClosure(),
base::TimeDelta::FromMilliseconds(250));
run_loop.Run();
}
#endif // defined(OS_CHROMEOS)
class FakeWebContentsDelegate : public WebContentsDelegate {
public:
FakeWebContentsDelegate() = default;
~FakeWebContentsDelegate() override = default;
void SetShowStaleContentOnEviction(bool value) {
show_stale_content_on_eviction_ = value;
}
bool ShouldShowStaleContentOnEviction(WebContents* source) override {
return show_stale_content_on_eviction_;
}
private:
bool show_stale_content_on_eviction_ = false;
DISALLOW_COPY_AND_ASSIGN(FakeWebContentsDelegate);
};
} // namespace
class RenderWidgetHostViewAuraBrowserTest : public ContentBrowserTest {
public:
RenderViewHost* GetRenderViewHost() const {
RenderViewHost* const rvh = shell()->web_contents()->GetRenderViewHost();
CHECK(rvh);
return rvh;
}
RenderWidgetHostViewAura* GetRenderWidgetHostView() const {
return static_cast<RenderWidgetHostViewAura*>(
GetRenderViewHost()->GetWidget()->GetView());
}
DelegatedFrameHost* GetDelegatedFrameHost() const {
return GetRenderWidgetHostView()->delegated_frame_host_.get();
}
};
#if defined(OS_CHROMEOS)
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewAuraBrowserTest,
StaleFrameContentOnEvictionNormal) {
NavigateToURL(shell(), GURL(kMinimalPageDataURL));
// Wait for first frame activation when a surface is embedded.
while (!GetDelegatedFrameHost()->HasSavedFrame())
GiveItSomeTime();
FakeWebContentsDelegate delegate;
delegate.SetShowStaleContentOnEviction(true);
shell()->web_contents()->SetDelegate(&delegate);
// Initially there should be no stale content set.
EXPECT_FALSE(
GetDelegatedFrameHost()->stale_content_layer_->has_external_content());
EXPECT_EQ(GetDelegatedFrameHost()->frame_eviction_state_,
DelegatedFrameHost::FrameEvictionState::kNotStarted);
// Hide the view and evict the frame. This should trigger a copy of the stale
// frame content.
GetRenderWidgetHostView()->Hide();
static_cast<viz::FrameEvictorClient*>(GetDelegatedFrameHost())
->EvictDelegatedFrame();
EXPECT_EQ(GetDelegatedFrameHost()->frame_eviction_state_,
DelegatedFrameHost::FrameEvictionState::kPendingEvictionRequests);
// Wait until the stale frame content is copied and set onto the layer.
while (!GetDelegatedFrameHost()->stale_content_layer_->has_external_content())
GiveItSomeTime();
EXPECT_EQ(GetDelegatedFrameHost()->frame_eviction_state_,
DelegatedFrameHost::FrameEvictionState::kNotStarted);
// Unhidding the view should reset the stale content layer to show the new
// frame content.
GetRenderWidgetHostView()->Show();
EXPECT_FALSE(
GetDelegatedFrameHost()->stale_content_layer_->has_external_content());
}
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewAuraBrowserTest,
StaleFrameContentOnEvictionRejected) {
NavigateToURL(shell(), GURL(kMinimalPageDataURL));
// Wait for first frame activation when a surface is embedded.
while (!GetDelegatedFrameHost()->HasSavedFrame())
GiveItSomeTime();
FakeWebContentsDelegate delegate;
delegate.SetShowStaleContentOnEviction(true);
shell()->web_contents()->SetDelegate(&delegate);
// Initially there should be no stale content set.
EXPECT_FALSE(
GetDelegatedFrameHost()->stale_content_layer_->has_external_content());
EXPECT_EQ(GetDelegatedFrameHost()->frame_eviction_state_,
DelegatedFrameHost::FrameEvictionState::kNotStarted);
// Hide the view and evict the frame. This should trigger a copy of the stale
// frame content.
GetRenderWidgetHostView()->Hide();
static_cast<viz::FrameEvictorClient*>(GetDelegatedFrameHost())
->EvictDelegatedFrame();
EXPECT_EQ(GetDelegatedFrameHost()->frame_eviction_state_,
DelegatedFrameHost::FrameEvictionState::kPendingEvictionRequests);
GetRenderWidgetHostView()->Show();
EXPECT_EQ(GetDelegatedFrameHost()->frame_eviction_state_,
DelegatedFrameHost::FrameEvictionState::kNotStarted);
// Wait until the stale frame content is copied and the result callback is
// complete.
GiveItSomeTime();
// This should however not set the stale content as the view is visible and
// new frames are being submitted.
EXPECT_FALSE(
GetDelegatedFrameHost()->stale_content_layer_->has_external_content());
}
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewAuraBrowserTest,
StaleFrameContentOnEvictionNone) {
NavigateToURL(shell(), GURL(kMinimalPageDataURL));
// Wait for first frame activation when a surface is embedded.
while (!GetDelegatedFrameHost()->HasSavedFrame())
GiveItSomeTime();
FakeWebContentsDelegate delegate;
delegate.SetShowStaleContentOnEviction(false);
shell()->web_contents()->SetDelegate(&delegate);
// Initially there should be no stale content set.
EXPECT_FALSE(
GetDelegatedFrameHost()->stale_content_layer_->has_external_content());
EXPECT_EQ(GetDelegatedFrameHost()->frame_eviction_state_,
DelegatedFrameHost::FrameEvictionState::kNotStarted);
// Hide the view and evict the frame. This should not trigger a copy of the
// stale frame content as the WebContentDelegate returns false.
GetRenderWidgetHostView()->Hide();
static_cast<viz::FrameEvictorClient*>(GetDelegatedFrameHost())
->EvictDelegatedFrame();
EXPECT_EQ(GetDelegatedFrameHost()->frame_eviction_state_,
DelegatedFrameHost::FrameEvictionState::kNotStarted);
// Wait for a while to ensure any copy requests that were sent out are not
// completed. There shouldnt be any requests sent however.
GiveItSomeTime();
EXPECT_FALSE(
GetDelegatedFrameHost()->stale_content_layer_->has_external_content());
}
#endif // #if defined(OS_CHROMEOS)
} // namespace content