#include <memory>
#include <string>
#include <utility>
#include <stdint.h>
#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/task/current_thread.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_timeouts.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "cc/slim/layer_tree.h"
#include "cc/slim/surface_layer.h"
#include "components/viz/common/features.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/renderer_host/browser_compositor_ios.h"
#include "content/browser/renderer_host/dip_util.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/browser/renderer_host/test_render_widget_host_view_ios_factory.h"
#include "content/browser/renderer_host/visible_time_request_trigger.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/content_navigation_policy.h"
#include "content/public/browser/gpu_data_manager.h"
#include "content/public/browser/navigation_handle.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/common/content_paths.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/back_forward_cache_util.h"
#include "content/public/test/browser_test.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/public/test/slow_http_response.h"
#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/test/content_browser_test_utils_internal.h"
#include "content/test/did_commit_navigation_interceptor.h"
#include "content/test/render_document_feature.h"
#include "net/base/filename_util.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/default_handlers.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/page/content_to_visible_time_reporter.h"
#include "third_party/blink/public/mojom/page/page_visibility_state.mojom-shared.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/display/display_switches.h"
#include "ui/gfx/geometry/size_conversions.h"
#if defined(USE_AURA)
#include "content/browser/renderer_host/delegated_frame_host.h"
#include "content/browser/renderer_host/render_widget_host_view_aura.h"
#endif
#if BUILDFLAG(IS_ANDROID)
#include "content/browser/renderer_host/compositor_impl_android.h"
#include "content/browser/renderer_host/render_widget_host_view_android.h"
#include "ui/android/delegated_frame_host_android.h"
#endif
#if BUILDFLAG(IS_MAC)
#include "content/browser/renderer_host/browser_compositor_view_mac.h"
#include "content/browser/renderer_host/delegated_frame_host.h"
#include "content/browser/renderer_host/test_render_widget_host_view_mac_factory.h"
#include "content/public/browser/context_factory.h"
#include "third_party/blink/public/common/page/content_to_visible_time_reporter.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/recyclable_compositor_mac.h"
#endif
namespace content {
namespace {
#define SET_UP_SURFACE_OR_PASS_TEST(wait_message) …
}
class RenderWidgetHostViewBrowserTest : public ContentBrowserTest { … };
class CommitBeforeSwapAckSentHelper : public DidCommitNavigationInterceptor { … };
class RenderWidgetHostViewBrowserTestBase : public ContentBrowserTest { … };
class NoCompositingRenderWidgetHostViewBrowserTest
: public RenderWidgetHostViewBrowserTest { … };
class PaintHoldingRenderWidgetHostViewBrowserTest
: public NoCompositingRenderWidgetHostViewBrowserTest { … };
IN_PROC_BROWSER_TEST_F(NoCompositingRenderWidgetHostViewBrowserTest,
ValidLocalSurfaceIdAfterInitialNavigation) { … }
IN_PROC_BROWSER_TEST_F(PaintHoldingRenderWidgetHostViewBrowserTest,
PaintHoldingOnNavigation) { … }
#if !BUILDFLAG(IS_MAC)
IN_PROC_BROWSER_TEST_F(NoCompositingRenderWidgetHostViewBrowserTest,
ValidLocalSurfaceIdAfterHiddenNavigation) { … }
IN_PROC_BROWSER_TEST_F(NoCompositingRenderWidgetHostViewBrowserTest,
NoFallbackAfterHiddenNavigationFails) { … }
#endif
namespace {
#if BUILDFLAG(IS_ANDROID)
ui::DelegatedFrameHostAndroid* GetDelegatedFrameHost(
RenderWidgetHostView* view) {
return static_cast<RenderWidgetHostViewAndroid*>(view)
->delegated_frame_host_for_testing();
}
#else
DelegatedFrameHost* GetDelegatedFrameHost(RenderWidgetHostView* view) { … }
#endif
viz::SurfaceId GetCurrentSurfaceIdOnDelegatedFrameHost(
RenderWidgetHostView* view) { … }
viz::SurfaceId GetPreNavigationSurfaceIdOnDelegatedFrameHost(
RenderWidgetHostView* view) { … }
viz::SurfaceId GetFallbackSurfaceId(RenderWidgetHostView* view) { … }
class BFCachedRenderWidgetHostViewBrowserTest
: public NoCompositingRenderWidgetHostViewBrowserTest { … };
}
IN_PROC_BROWSER_TEST_F(BFCachedRenderWidgetHostViewBrowserTest,
BFCacheRestoredPageHasNewLocalSurfaceId) { … }
IN_PROC_BROWSER_TEST_F(
BFCachedRenderWidgetHostViewBrowserTest,
BFCachedPageResizedWhileHiddenShouldNotHavePreservedFallback) { … }
IN_PROC_BROWSER_TEST_F(BFCachedRenderWidgetHostViewBrowserTest,
BFCachedPageNoopResizedWhileHiddenHasPreservedFallback) { … }
IN_PROC_BROWSER_TEST_F(BFCachedRenderWidgetHostViewBrowserTest,
BFCachedViewShouldNotBeEvicted) { … }
IN_PROC_BROWSER_TEST_F(NoCompositingRenderWidgetHostViewBrowserTest,
NoFallbackIfSwapFailedBeforeNavigation) { … }
namespace {
std::unique_ptr<net::test_server::HttpResponse> HandleSlowStyleSheet(
const net::test_server::HttpRequest& request) { … }
class DOMContentLoadedObserver : public WebContentsObserver { … };
}
IN_PROC_BROWSER_TEST_F(NoCompositingRenderWidgetHostViewBrowserTest,
ColorSchemeMetaBackground) { … }
IN_PROC_BROWSER_TEST_F(NoCompositingRenderWidgetHostViewBrowserTest,
NoColorSchemeMetaBackground) { … }
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewBrowserTestBase,
CompositorWorksWhenReusingRenderer) { … }
enum CompositingMode { … };
class CompositingRenderWidgetHostViewBrowserTest
: public RenderWidgetHostViewBrowserTest,
public testing::WithParamInterface<CompositingMode> { … };
#if !BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest,
CopyFromSurface) { … }
IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTest,
CopyFromSurface_CallbackDespiteDelete) { … }
class CompositingRenderWidgetHostViewBrowserTestTabCapture
: public CompositingRenderWidgetHostViewBrowserTest { … };
IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
CopyFromSurface_Origin_Unscaled) { … }
IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
CopyFromSurface_Origin_Scaled) { … }
IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
CopyFromSurface_Cropped_Unscaled) { … }
IN_PROC_BROWSER_TEST_P(CompositingRenderWidgetHostViewBrowserTestTabCapture,
CopyFromSurface_Cropped_Scaled) { … }
class CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI
: public CompositingRenderWidgetHostViewBrowserTestTabCapture { … };
#if BUILDFLAG(IS_WIN)
#define MAYBE_CopyToBitmap_EntireRegion …
#define MAYBE_CopyToBitmap_CenterRegion …
#define MAYBE_CopyToBitmap_ScaledResult …
#else
#define MAYBE_CopyToBitmap_EntireRegion …
#define MAYBE_CopyToBitmap_CenterRegion …
#define MAYBE_CopyToBitmap_ScaledResult …
#endif
IN_PROC_BROWSER_TEST_P(
CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
MAYBE_CopyToBitmap_EntireRegion) { … }
IN_PROC_BROWSER_TEST_P(
CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
MAYBE_CopyToBitmap_CenterRegion) { … }
IN_PROC_BROWSER_TEST_P(
CompositingRenderWidgetHostViewBrowserTestTabCaptureHighDPI,
MAYBE_CopyToBitmap_ScaledResult) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
static const auto kTestCompositingModes = testing::Values(GL_COMPOSITING);
#else
static const auto kTestCompositingModes = …;
#endif
INSTANTIATE_TEST_SUITE_P(…);
INSTANTIATE_TEST_SUITE_P(…);
INSTANTIATE_TEST_SUITE_P(…);
class RenderWidgetHostViewPresentationFeedbackBrowserTest
: public NoCompositingRenderWidgetHostViewBrowserTest { … };
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#define MAYBE_Show …
#else
#define MAYBE_Show …
#endif
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewPresentationFeedbackBrowserTest,
MAYBE_Show) { … }
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewPresentationFeedbackBrowserTest,
ShowThenHide) { … }
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewPresentationFeedbackBrowserTest,
HiddenButPainting) { … }
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#define MAYBE_ShowWhileCapturing …
#else
#define MAYBE_ShowWhileCapturing …
#endif
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewPresentationFeedbackBrowserTest,
MAYBE_ShowWhileCapturing) { … }
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewPresentationFeedbackBrowserTest,
HideWhileCapturing) { … }
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewPresentationFeedbackBrowserTest,
ShowWithoutTabSwitchRequest) { … }
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewPresentationFeedbackBrowserTest,
ShowThenHideWithoutTabSwitchRequest) { … }
#if BUILDFLAG(IS_MAC)
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewPresentationFeedbackBrowserTest,
DISABLED_ShowWithParentLayer) {
CreateVisibleTimeRequest();
ScopedParentLayer parent_layer(GetBrowserCompositor());
GetBrowserCompositor()->SetParentUiLayer(parent_layer.layer());
GetRenderWidgetHostView()->ShowWithVisibility(PageVisibilityState::kVisible);
ExpectPresentationFeedback(TabSwitchResult::kSuccess);
}
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewPresentationFeedbackBrowserTest,
DISABLED_ShowThenAddParentLayer) {
CreateVisibleTimeRequest();
GetRenderWidgetHostView()->ShowWithVisibility(PageVisibilityState::kVisible);
ScopedParentLayer parent_layer(GetBrowserCompositor());
GetBrowserCompositor()->SetParentUiLayer(parent_layer.layer());
ExpectPresentationFeedback(TabSwitchResult::kSuccess);
}
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewPresentationFeedbackBrowserTest,
DISABLED_ShowThenRemoveParentLayer) {
CreateVisibleTimeRequest();
ScopedParentLayer parent_layer(GetBrowserCompositor());
GetBrowserCompositor()->SetParentUiLayer(parent_layer.layer());
GetRenderWidgetHostView()->ShowWithVisibility(PageVisibilityState::kVisible);
GetBrowserCompositor()->SetParentUiLayer(nullptr);
ExpectPresentationFeedback(TabSwitchResult::kSuccess);
}
#endif
#endif
#if BUILDFLAG(IS_ANDROID)
void CheckSurfaceRangeRemovedAfterCopy(viz::SurfaceRange range,
CompositorImpl* compositor,
base::RepeatingClosure resume_test,
const SkBitmap& btimap) {
ASSERT_FALSE(!compositor->GetLayerTreeForTesting()
->GetSurfaceRangesForTesting()
.contains(range));
std::move(resume_test).Run();
}
class RenderWidgetHostViewCopyFromSurfaceBrowserTest
: public RenderWidgetHostViewBrowserTest {
public:
RenderWidgetHostViewCopyFromSurfaceBrowserTest() {
InitAndEnableRenderDocumentFeature(&scoped_feature_list_render_document_,
RenderDocumentFeatureFullyEnabled()[0]);
}
void SetUpOnMainThread() override {
host_resolver()->AddRule("*", "127.0.0.1");
embedded_test_server()->ServeFilesFromSourceDirectory(
GetTestDataFilePath());
net::test_server::RegisterDefaultHandlers(embedded_test_server());
ASSERT_TRUE(embedded_test_server()->Start());
RenderWidgetHostViewBrowserTest::SetUpOnMainThread();
}
~RenderWidgetHostViewCopyFromSurfaceBrowserTest() override = default;
bool SetUpSourceSurface(const char* wait_message) override { return false; }
private:
base::test::ScopedFeatureList scoped_feature_list_render_document_;
};
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewCopyFromSurfaceBrowserTest,
AsyncCopyFromSurface) {
EXPECT_TRUE(
NavigateToURL(shell(), embedded_test_server()->GetURL("/empty.html")));
auto* rwhv_android = static_cast<RenderWidgetHostViewAndroid*>(
GetRenderViewHost()->GetWidget()->GetView());
auto* compositor = static_cast<CompositorImpl*>(
rwhv_android->GetNativeView()->GetWindowAndroid()->GetCompositor());
const viz::SurfaceRange range_for_copy(rwhv_android->GetCurrentSurfaceId(),
rwhv_android->GetCurrentSurfaceId());
const viz::SurfaceRange range_for_mainframe(
std::nullopt, rwhv_android->GetCurrentSurfaceId());
base::RunLoop run_loop;
GetRenderViewHost()->GetWidget()->GetView()->CopyFromSurface(
gfx::Rect(), gfx::Size(),
base::BindOnce(&CheckSurfaceRangeRemovedAfterCopy, range_for_copy,
compositor, run_loop.QuitClosure()));
EXPECT_THAT(
compositor->GetLayerTreeForTesting()->GetSurfaceRangesForTesting(),
testing::UnorderedElementsAre(std::make_pair(range_for_copy, 1),
std::make_pair(range_for_mainframe, 1)));
run_loop.Run(FROM_HERE);
}
namespace {
void AssertSnapshotIsPureWhite(base::RepeatingClosure resume_test,
const SkBitmap& snapshot) {
for (int r = 0; r < snapshot.height(); ++r) {
for (int c = 0; c < snapshot.width(); ++c) {
ASSERT_EQ(snapshot.getColor(c, r), SK_ColorWHITE);
}
}
std::move(resume_test).Run();
}
class ScopedSnapshotWaiter : public WebContentsObserver {
public:
ScopedSnapshotWaiter(WebContents* wc, const GURL& destination)
: WebContentsObserver(wc), destination_(destination) {}
ScopedSnapshotWaiter(const ScopedSnapshotWaiter&) = delete;
ScopedSnapshotWaiter& operator=(const ScopedSnapshotWaiter&) = delete;
~ScopedSnapshotWaiter() override = default;
void Wait() { run_loop_.Run(); }
private:
void DidStartNavigation(NavigationHandle* handle) override {
if (handle->GetURL() != destination_) {
return;
}
auto* request = NavigationRequest::From(handle);
request->set_ready_to_commit_callback_for_testing(base::BindOnce(
[](RenderWidgetHostView* old_view,
base::OnceCallback<bool()> renderer_swapped,
base::RepeatingClosure resume) {
ASSERT_TRUE(std::move(renderer_swapped).Run());
ASSERT_TRUE(old_view);
static_cast<RenderWidgetHostViewBase*>(old_view)
->CopyFromExactSurface(gfx::Rect(), gfx::Size(),
base::BindOnce(&AssertSnapshotIsPureWhite,
std::move(resume)));
},
request->frame_tree_node()->current_frame_host()->GetView(),
base::BindOnce(
base::BindLambdaForTesting([](NavigationRequest* request) {
return request->GetRenderFrameHost() !=
request->frame_tree_node()
->render_manager()
->current_frame_host();
}),
base::Unretained(request)),
run_loop_.QuitClosure()));
}
const GURL destination_;
base::RunLoop run_loop_;
};
}
IN_PROC_BROWSER_TEST_F(RenderWidgetHostViewCopyFromSurfaceBrowserTest,
CopyExactSurfaceDuringCrossRendererNavigations) {
ASSERT_TRUE(
NavigateToURL(shell()->web_contents(),
embedded_test_server()->GetURL("a.com", "/empty.html")));
WaitForCopyableViewInWebContents(shell()->web_contents());
const auto cross_renderer_url =
embedded_test_server()->GetURL("b.com", "/title1.html");
ScopedSnapshotWaiter waiter(shell()->web_contents(), cross_renderer_url);
ASSERT_TRUE(NavigateToURL(shell()->web_contents(), cross_renderer_url));
WaitForCopyableViewInWebContents(shell()->web_contents());
waiter.Wait();
}
#endif
namespace {
class RenderWidgetHostViewOOPIFNavigatesMainFrameLocationReplaceBrowserTest
: public RenderWidgetHostViewBrowserTest,
public ::testing::WithParamInterface<bool> { … };
std::string DescribeBFCacheFeatureStatus(
const ::testing::TestParamInfo<bool>& info) { … }
}
IN_PROC_BROWSER_TEST_P(
RenderWidgetHostViewOOPIFNavigatesMainFrameLocationReplaceBrowserTest,
NonHistoryTraversablePageShouldNotBeBFCached) { … }
#if BUILDFLAG(IS_ANDROID)
IN_PROC_BROWSER_TEST_P(
RenderWidgetHostViewOOPIFNavigatesMainFrameLocationReplaceBrowserTest,
TouchEventsForwardedToTheCorrectRenderWidgetHostView) {
ASSERT_TRUE(NavigateToURL(web_contents(),
https_server()->GetURL("a.test", "/title1.html")));
RenderFrameHostWrapper subframe_rfh(AddSubframe(
web_contents(), https_server()->GetURL("b.test", "/title2.html")));
RenderFrameHostWrapper old_main_frame(web_contents()->GetPrimaryMainFrame());
NavigateMainFrameFromSubframeAndWait(
subframe_rfh.get(),
https_server()->GetURL(
"b.test", "/set-header?Cross-Origin-Opener-Policy: same-origin"));
bool bfcache_enabled = GetParam();
if (!bfcache_enabled) {
ASSERT_TRUE(old_main_frame.WaitUntilRenderFrameDeleted());
ASSERT_TRUE(subframe_rfh.WaitUntilRenderFrameDeleted());
}
size_t num_expected_rwhv = bfcache_enabled ? 3u : 1u;
size_t num_actual_rwhv = 0u;
static_cast<WebContents*>(web_contents())
->ForEachRenderFrameHost([&num_actual_rwhv](RenderFrameHost* rfh) {
if (rfh->GetView()) {
++num_actual_rwhv;
}
});
ASSERT_EQ(num_actual_rwhv, num_expected_rwhv);
size_t num_expected_native_view = bfcache_enabled ? 2u : 1u;
auto* web_contents_view_android =
static_cast<ui::ViewAndroid*>(web_contents()->GetNativeView());
ASSERT_EQ(web_contents_view_android->GetChildrenCountForTesting(),
num_expected_native_view);
ASSERT_EQ(web_contents_view_android->GetTopMostChildForTesting(),
web_contents()->GetPrimaryMainFrame()->GetNativeView());
}
#endif
INSTANTIATE_TEST_SUITE_P(…);
}