chromium/content/renderer/render_view_browsertest.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/342213636): Remove this and spanify to fix the errors.
#pragma allow_unsafe_buffers
#endif

#include <stddef.h>
#include <stdint.h>

#include <algorithm>
#include <memory>
#include <optional>
#include <tuple>

#include "base/command_line.h"
#include "base/containers/heap_array.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/bind.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "base/values.h"
#include "build/build_config.h"
#include "cc/input/browser_controls_state.h"
#include "cc/trees/layer_tree_host.h"
#include "components/input/native_web_keyboard_event.h"
#include "content/common/renderer.mojom.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/renderer_preferences_util.h"
#include "content/public/browser/web_ui_controller.h"
#include "content/public/browser/web_ui_controller_factory.h"
#include "content/public/common/bindings_policy.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/url_utils.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/fake_render_widget_host.h"
#include "content/public/test/frame_load_waiter.h"
#include "content/public/test/local_frame_host_interceptor.h"
#include "content/public/test/policy_container_utils.h"
#include "content/public/test/render_view_test.h"
#include "content/public/test/test_utils.h"
#include "content/renderer/accessibility/render_accessibility_impl.h"
#include "content/renderer/accessibility/render_accessibility_manager.h"
#include "content/renderer/agent_scheduling_group.h"
#include "content/renderer/document_state.h"
#include "content/renderer/navigation_state.h"
#include "content/renderer/render_process.h"
#include "content/renderer/service_worker/service_worker_network_provider_for_frame.h"
#include "content/shell/browser/shell.h"
#include "content/shell/browser/shell_browser_context.h"
#include "content/test/mock_keyboard.h"
#include "content/test/test_render_frame.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/mojom/base/text_direction.mojom-blink.h"
#include "net/base/net_errors.h"
#include "net/cert/cert_status_flags.h"
#include "net/dns/public/resolve_error_info.h"
#include "net/http/http_util.h"
#include "services/network/public/cpp/resource_request_body.h"
#include "skia/ext/legacy_display_globals.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/dom_storage/session_storage_namespace_id.h"
#include "third_party/blink/public/common/navigation/navigation_params.h"
#include "third_party/blink/public/common/origin_trials/scoped_test_origin_trial_policy.h"
#include "third_party/blink/public/common/origin_trials/trial_token_validator.h"
#include "third_party/blink/public/common/page/page_zoom.h"
#include "third_party/blink/public/common/switches.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/common/widget/device_emulation_params.h"
#include "third_party/blink/public/mojom/frame/frame_owner_properties.mojom.h"
#include "third_party/blink/public/mojom/frame/frame_replication_state.mojom.h"
#include "third_party/blink/public/mojom/frame/remote_frame.mojom.h"
#include "third_party/blink/public/mojom/frame/tree_scope_type.mojom.h"
#include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom.h"
#include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
#include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
#include "third_party/blink/public/platform/web_data.h"
#include "third_party/blink/public/platform/web_http_body.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url_response.h"
#include "third_party/blink/public/test/test_web_frame_content_dumper.h"
#include "third_party/blink/public/web/web_autofill_client.h"
#include "third_party/blink/public/web/web_document_loader.h"
#include "third_party/blink/public/web/web_frame_widget.h"
#include "third_party/blink/public/web/web_history_commit_type.h"
#include "third_party/blink/public/web/web_history_item.h"
#include "third_party/blink/public/web/web_input_method_controller.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_navigation_params.h"
#include "third_party/blink/public/web/web_navigation_type.h"
#include "third_party/blink/public/web/web_origin_trials.h"
#include "third_party/blink/public/web/web_page_popup.h"
#include "third_party/blink/public/web/web_performance_metrics_for_reporting.h"
#include "third_party/blink/public/web/web_picture_in_picture_window_options.h"
#include "third_party/blink/public/web/web_remote_frame.h"
#include "third_party/blink/public/web/web_script_source.h"
#include "third_party/blink/public/web/web_settings.h"
#include "third_party/blink/public/web/web_view.h"
#include "third_party/blink/public/web/web_window_features.h"
#include "ui/accessibility/ax_mode.h"
#include "ui/base/ime/mojom/text_input_state.mojom.h"
#include "ui/base/ui_base_features.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/types/event_type.h"
#include "ui/gfx/codec/jpeg_codec.h"
#include "ui/gfx/range/range.h"
#include "url/url_constants.h"

#if BUILDFLAG(IS_ANDROID)
#include "third_party/blink/public/common/input/web_coalesced_input_event.h"
#include "third_party/blink/public/common/input/web_gesture_device.h"
#include "third_party/blink/public/common/input/web_gesture_event.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#endif

#if BUILDFLAG(IS_OZONE)
#include "ui/events/keycodes/keyboard_code_conversion.h"
#endif

TestWebFrameContentDumper;
WebFrame;
WebGestureEvent;
WebInputEvent;
WebLocalFrame;
WebMouseEvent;
WebString;
WebURLError;

namespace content {

namespace {

static const int kProxyRoutingId =;

#if BUILDFLAG(IS_OZONE)
// Converts MockKeyboard::Modifiers to ui::EventFlags.
int ConvertMockKeyboardModifier(MockKeyboard::Modifiers modifiers) {}
#endif

class WebUITestWebUIControllerFactory : public WebUIControllerFactory {};

// FrameReplicationState is normally maintained in the browser process,
// but the function below provides a way for tests to construct a partial
// FrameReplicationState within the renderer process.  We say "partial",
// because some fields of FrameReplicationState cannot be filled out
// by content-layer, renderer code (still the constructed, partial
// FrameReplicationState is sufficiently complete to avoid trigerring
// asserts that a default/empty FrameReplicationState would).
blink::mojom::FrameReplicationStatePtr ReconstructReplicationStateForTesting(
    TestRenderFrame* test_render_frame) {}

// Returns mojom::CommonNavigationParams for a normal navigation to a data: url,
// with navigation_start set to Now() plus the given offset.
blink::mojom::CommonNavigationParamsPtr MakeCommonNavigationParams(
    base::TimeDelta navigation_start_offset) {}

template <class MockedLocalFrameHostInterceptor>
class MockedLocalFrameHostInterceptorTestRenderFrame : public TestRenderFrame {};

blink::mojom::CommitNavigationParamsPtr DummyCommitNavigationParams() {}

blink::mojom::RemoteFrameInterfacesFromBrowserPtr
CreateStubRemoteFrameInterfaces() {}

blink::mojom::RemoteMainFrameInterfacesPtr
CreateStubRemoteMainFrameInterfaces() {}

// Helper that collects the CommonNavigationParams off of WebDocumentLoader's
// NavigationState during commit. The NavigationState is cleared when commit
// notifications are done, so any assertions about the CommonNavigationParams
// post-commit require the CommonNavigationParams to be stored manually.
class CommonParamsFrameLoadWaiter : public FrameLoadWaiter {};

}  // namespace

class RenderViewImplTest : public RenderViewTest {};

class RenderViewImplBlinkSettingsTest : public RenderViewImplTest {};

class RenderViewImplScaleFactorTest : public RenderViewImplTest {};

TEST_F(RenderViewImplTest, IsPinchGestureActivePropagatesToProxies) {}

// Test that we get form state change notifications when input fields change.
TEST_F(RenderViewImplTest, OnNavStateChanged) {}

TEST_F(RenderViewImplTest, OnNavigationHttpPost) {}

#if BUILDFLAG(IS_ANDROID)
namespace {
class UpdateTitleLocalFrameHost : public LocalFrameHostInterceptor {
 public:
  explicit UpdateTitleLocalFrameHost(
      blink::AssociatedInterfaceProvider* provider)
      : LocalFrameHostInterceptor(provider) {}

  MOCK_METHOD2(UpdateTitle,
               void(const std::optional<::std::u16string>& title,
                    base::i18n::TextDirection title_direction));
};
}  // namespace

class RenderViewImplUpdateTitleTest : public RenderViewImplTest {
 public:
  using MockedTestRenderFrame =
      MockedLocalFrameHostInterceptorTestRenderFrame<UpdateTitleLocalFrameHost>;

  RenderViewImplUpdateTitleTest()
      : RenderViewImplTest(&MockedTestRenderFrame::CreateTestRenderFrame) {}

  UpdateTitleLocalFrameHost* title_mock_frame_host() {
    return static_cast<MockedTestRenderFrame*>(frame())
        ->mock_local_frame_host();
  }
};

TEST_F(RenderViewImplUpdateTitleTest, OnNavigationLoadDataWithBaseURL) {
  auto common_params = blink::CreateCommonNavigationParams();
  common_params->url = GURL("data:text/html,");
  common_params->navigation_type =
      blink::mojom::NavigationType::DIFFERENT_DOCUMENT;
  common_params->transition = ui::PAGE_TRANSITION_TYPED;
  common_params->base_url_for_data_url = GURL("about:blank");
  auto commit_params = DummyCommitNavigationParams();
  commit_params->data_url_as_string =
      "data:text/html,<html><head><title>Data page</title></head></html>";

  const std::optional<::std::u16string>& title =
      std::make_optional(u"Data page");
  EXPECT_CALL(*title_mock_frame_host(), UpdateTitle(title, testing::_))
      .Times(1);
  FrameLoadWaiter waiter(frame());
  frame()->Navigate(std::move(common_params), std::move(commit_params));
  waiter.Wait();

  base::RunLoop().RunUntilIdle();
  testing::Mock::VerifyAndClearExpectations(title_mock_frame_host());
}
#endif

TEST_F(RenderViewImplTest, BeginNavigation) {}

TEST_F(RenderViewImplTest, BeginNavigationHandlesAllTopLevel) {}

TEST_F(RenderViewImplTest, BeginNavigationForWebUI) {}

// This test verifies that when device emulation is enabled, WebRemoteFrame
// continues to receive the original ScreenInfo and not the emualted
// ScreenInfo.
TEST_F(RenderViewImplScaleFactorTest, DeviceEmulationWithOOPIF) {}

// Verify that security origins are replicated properly to RenderFrameProxies
// when unloading.
TEST_F(RenderViewImplTest, OriginReplicationForUnload) {}

// Test that when navigating cross-origin, which creates a new main frame
// RenderWidget, that the device scale is set correctly for that RenderWidget
// the WebView and frames.
// See crbug.com/737777#c37.
TEST_F(RenderViewImplScaleFactorTest, DeviceScaleCorrectAfterCrossOriginNav) {}

// Test that when a parent detaches a remote child after the provisional
// RenderFrame is created but before it is navigated, the RenderFrame is
// destroyed along with the proxy.  This protects against races in
// https://crbug.com/526304 and https://crbug.com/568676.
TEST_F(RenderViewImplTest, DetachingProxyAlsoDestroysProvisionalFrame) {}

// Verify that the renderer process doesn't crash when device scale factor
// changes after a cross-process navigation has commited.
// See https://crbug.com/571603.
TEST_F(RenderViewImplScaleFactorTest, SetZoomLevelAfterCrossProcessNavigation) {}

class TextInputStateFakeRenderWidgetHost : public FakeRenderWidgetHost {};

class RenderViewImplTextInputStateChanged : public RenderViewImplTest {};

// Test that our IME backend sends a notification message when the input focus
// changes.
TEST_F(RenderViewImplTextInputStateChanged, OnImeTypeChanged) {}

TEST_F(RenderViewImplTextInputStateChanged,
       ShouldSuppressKeyboardIsPropagated) {}

TEST_F(RenderViewImplTextInputStateChanged,
       EditContextGetLayoutBoundsAndInputPanelPolicy) {}

TEST_F(RenderViewImplTextInputStateChanged,
       EditContextGetLayoutBoundsWithFloatingValues) {}

TEST_F(RenderViewImplTextInputStateChanged,
       EditContextGetLayoutBoundsWithOverflowFloatingValues) {}

TEST_F(RenderViewImplTextInputStateChanged, ActiveElementGetLayoutBounds) {}

TEST_F(RenderViewImplTextInputStateChanged,
       ActiveElementMultipleLayoutBoundsUpdates) {}

TEST_F(RenderViewImplTextInputStateChanged,
       ActiveElementLayoutBoundsUpdatesDuringBrowserZoom) {}

TEST_F(RenderViewImplTextInputStateChanged, VirtualKeyboardPolicyAuto) {}

TEST_F(RenderViewImplTextInputStateChanged, VirtualKeyboardPolicyAutoToManual) {}

TEST_F(RenderViewImplTextInputStateChanged,
       VirtualKeyboardPolicyManualAndShowHideAPIsCalledInInsecureContext) {}

TEST_F(RenderViewImplTextInputStateChanged,
       VirtualKeyboardPolicyAutoAndShowHideAPIsCalled) {}

// Test that our IME backend can compose CJK words.
// Our IME front-end sends many platform-independent messages to the IME backend
// while it composes CJK words. This test sends the minimal messages captured
// on my local environment directly to the IME backend to verify if the backend
// can compose CJK words without any problems.
// This test uses an array of command sets because an IME composotion does not
// only depends on IME events, but also depends on window events, e.g. moving
// the window focus while composing a CJK text. To handle such complicated
// cases, this test should not only call IME-related functions in the
// RenderWidget class, but also call some RenderWidget members, e.g.
// ExecuteJavaScriptForTests(), RenderWidget::OnSetFocus(), etc.
TEST_F(RenderViewImplTest, ImeComposition) {}

// Test that the RenderView::OnSetTextDirection() function can change the text
// direction of the selected input element.
TEST_F(RenderViewImplTest, OnSetTextDirection) {}

TEST_F(RenderViewImplTest, DroppedNavigationStaysInViewSourceMode) {}

namespace {

class ContextMenuFrameHost : public LocalFrameHostInterceptor {};

}  // namespace

class RenderViewImplContextMenuTest : public RenderViewImplTest {};

#if !BUILDFLAG(IS_ANDROID)
TEST_F(RenderViewImplContextMenuTest, ContextMenu) {}

#else
TEST_F(RenderViewImplContextMenuTest, AndroidContextMenuSelectionOrdering) {
  LoadHTML("<div>Page A</div><div id=result>Not selected</div>");

  ExecuteJavaScriptForTests(
      "document.onselectionchange = function() { "
      "document.getElementById('result').innerHTML = 'Selected'}");

  // Create a long press in the center of the iframe. (I'm hoping this will
  // make this a bit more robust in case of some other formatting or other bug.)
  WebGestureEvent gesture_event(WebInputEvent::Type::kGestureLongPress,
                                WebInputEvent::kNoModifiers,
                                ui::EventTimeForNow());
  gesture_event.SetPositionInWidget(gfx::PointF(250, 250));

  EXPECT_CALL(*context_menu_frame_host(),
              ShowContextMenu(testing::_, testing::_))
      .Times(0);

  SendWebGestureEvent(gesture_event);

  EXPECT_CALL(*context_menu_frame_host(),
              ShowContextMenu(testing::_, testing::_))
      .Times(1);

  scoped_refptr<content::MessageLoopRunner> message_loop_runner =
      new content::MessageLoopRunner;
  blink::scheduler::GetSingleThreadTaskRunnerForTesting()->PostTask(
      FROM_HERE, message_loop_runner->QuitClosure());

  message_loop_runner->Run();

  int did_select = -1;
  std::u16string check_did_select =
      u"Number(document.getElementById('result').innerHTML == 'Selected')";
  EXPECT_TRUE(
      ExecuteJavaScriptAndReturnIntValue(check_did_select, &did_select));
  EXPECT_EQ(1, did_select);
}
#endif

TEST_F(RenderViewImplTest, TestBackForward) {}

#if BUILDFLAG(IS_MAC) || defined(USE_AURA)
TEST_F(RenderViewImplTest, GetCompositionCharacterBoundsTest) {}
#endif

TEST_F(RenderViewImplTest, SetEditableSelectionAndComposition) {}

TEST_F(RenderViewImplTest, OnExtendSelectionAndDelete) {}

TEST_F(RenderViewImplTest, OnDeleteSurroundingText) {}

#if BUILDFLAG(IS_ANDROID)
// Failing on Android M: http://crbug.com/873580
#define MAYBE_OnDeleteSurroundingTextInCodePoints
#else
#define MAYBE_OnDeleteSurroundingTextInCodePoints
#endif
TEST_F(RenderViewImplTest, MAYBE_OnDeleteSurroundingTextInCodePoints) {}

// Test that the navigating specific frames works correctly.
TEST_F(RenderViewImplTest, NavigateSubframe) {}

// This test ensures that a RenderFrame object is created for the top level
// frame in the RenderView.
TEST_F(RenderViewImplTest, BasicRenderFrame) {}

namespace {
class MessageOrderFakeRenderWidgetHost : public FakeRenderWidgetHost {};

class TextSelectionChangedLocalFrameHost : public LocalFrameHostInterceptor {};
}  // namespace

class RenderViewImplTextInputMessageOrder : public RenderViewImplTest {};

// Failing on Windows; see https://crbug.com/1134571.
#if BUILDFLAG(IS_WIN)
#define MAYBE_MessageOrderInDidChangeSelection
#else
#define MAYBE_MessageOrderInDidChangeSelection
#endif
TEST_F(RenderViewImplTextInputMessageOrder,
       MAYBE_MessageOrderInDidChangeSelection) {}

class RendererErrorPageTest : public RenderViewImplTest {};

TEST_F(RendererErrorPageTest, RegularError) {}

TEST_F(RenderViewImplTest, SetAccessibilityMode) {}

TEST_F(RenderViewImplTest, AccessibilityModeOnClosingConnection) {}

// Checks that when a navigation starts in the renderer, |navigation_start| is
// recorded at an appropriate time and is passed in the corresponding message.
TEST_F(RenderViewImplTest, RendererNavigationStartTransmittedToBrowser) {}

// Checks that a browser-initiated navigation in an initial document that was
// not accessed uses browser-side timestamp.
// This test assumes that |frame()| contains an unaccessed initial document at
// start.
TEST_F(RenderViewImplTest, BrowserNavigationStart) {}

// Sanity check for the Navigation Timing API |navigationStart| override. We
// are asserting only most basic constraints, as TimeTicks (passed as the
// override) are not comparable with the wall time (returned by the Blink API).
TEST_F(RenderViewImplTest, BrowserNavigationStartSanitized) {}

// Checks that a browser-initiated navigation in an initial document that has
// been accessed uses browser-side timestamp (there may be arbitrary
// content and/or scripts injected, including beforeunload handler that shows
// a confirmation dialog).
TEST_F(RenderViewImplTest, NavigationStartWhenInitialDocumentWasAccessed) {}

TEST_F(RenderViewImplTest, NavigationStartForReload) {}

TEST_F(RenderViewImplTest, NavigationStartForSameProcessHistoryNavigation) {}

TEST_F(RenderViewImplTest, NavigationStartForCrossProcessHistoryNavigation) {}

TEST_F(RenderViewImplTest, PreferredSizeZoomed) {}

TEST_F(RenderViewImplScaleFactorTest, PreferredSizeWithScaleFactor) {}

// Ensure the `blink::WebView` history list is properly updated when starting a
// new browser-initiated navigation.
TEST_F(RenderViewImplTest, HistoryIsProperlyUpdatedOnNavigation) {}

// Ensure the `blink::WebView` history list is properly updated when starting a
// new history browser-initiated navigation.
TEST_F(RenderViewImplTest, HistoryIsProperlyUpdatedOnHistoryNavigation) {}

// Ensure the `blink::WebView` history list is properly updated when starting a
// new history browser-initiated navigation with should_clear_history_list
TEST_F(RenderViewImplTest, HistoryIsProperlyUpdatedOnShouldClearHistoryList) {}

namespace {
class AddMessageToConsoleMockLocalFrameHost : public LocalFrameHostInterceptor {};
}  // namespace

class RenderViewImplAddMessageToConsoleTest : public RenderViewImplTest {};

// Tests that there's no UaF after dispatchBeforeUnloadEvent.
// See https://crbug.com/666714.
TEST_F(RenderViewImplAddMessageToConsoleTest,
       DispatchBeforeUnloadCanDetachFrame) {}

namespace {
class AlertDialogMockLocalFrameHost : public LocalFrameHostInterceptor {};
}  // namespace

class RenderViewImplModalDialogTest : public RenderViewImplTest {};

// Test that invoking one of the modal dialogs doesn't crash.
TEST_F(RenderViewImplModalDialogTest, ModalDialogs) {}

TEST_F(RenderViewImplBlinkSettingsTest, Default) {}

TEST_F(RenderViewImplBlinkSettingsTest, CommandLine) {}

// Ensure that setting default page scale limits immediately recomputes the
// minimum scale factor to the final value. With
// shrinks_viewport_contents_to_fit, Blink clamps the minimum cased on the
// content width. In this case, that'll always be 1.
TEST_F(RenderViewImplBlinkSettingsTest, DefaultPageScaleSettings) {}

TEST_F(RenderViewImplScaleFactorTest, ScreenMetricsEmulationWithOriginalDSF1) {}

TEST_F(RenderViewImplScaleFactorTest, ScreenMetricsEmulationWithOriginalDSF2) {}

TEST_F(RenderViewImplScaleFactorTest, ConvertViewportToWindow) {}

#if BUILDFLAG(IS_MAC) || defined(USE_AURA)
TEST_F(RenderViewImplScaleFactorTest,
       DISABLED_GetCompositionCharacterBoundsTest) {}
#endif

#if !BUILDFLAG(IS_ANDROID)
// No extensions/autoresize on Android.
namespace {

// Don't use text as it text will change the size in DIP at different
// scale factor.
const char kAutoResizeTestPage[] =;

}  // namespace

TEST_F(RenderViewImplScaleFactorTest, AutoResize) {}

TEST_F(RenderViewImplTest, ZoomLevelUpdate) {}

#endif

TEST_F(RenderViewImplTest, OriginTrialDisabled) {}

TEST_F(RenderViewImplTest, OriginTrialEnabled) {}

TEST_F(RenderViewImplTest, CollapseSelectionNotChangeFocus) {}

#if BUILDFLAG(IS_WIN)
class RenderViewImplContrastGammaSettingsTest : public RenderViewImplTest {
 protected:
  void SetUp() override {
    RenderViewImplTest::SetUp();
    feature_list_.InitAndEnableFeature(
        features::kUseGammaContrastRegistrySettings);
  }
  base::test::ScopedFeatureList feature_list_;
};

TEST_F(RenderViewImplContrastGammaSettingsTest,
       ContrastGammaSetRendererPreferences) {
  LoadHTML(R"HTML(
      <input id='test' type='text'></input>
    )HTML");

  // Use non-default values for contrast and gamma.
  constexpr float test_contrast = 0.95;
  static_assert(test_contrast != SK_GAMMA_CONTRAST);
  static_assert(test_contrast >= SkSurfaceProps::kMinContrastInclusive);
  static_assert(test_contrast <= SkSurfaceProps::kMaxContrastInclusive);

  constexpr float test_gamma = 3.99;
  static_assert(test_gamma != SK_GAMMA_EXPONENT);
  static_assert(test_gamma >= SkSurfaceProps::kMinGammaInclusive);
  static_assert(test_gamma < SkSurfaceProps::kMaxGammaExclusive);

  blink::RendererPreferences renderer_preferences =
      web_view_->GetRendererPreferences();
  EXPECT_NE(renderer_preferences.text_contrast, test_contrast);
  EXPECT_NE(renderer_preferences.text_gamma, test_gamma);

  // Set the non-default values on `RendererPreferences`.
  renderer_preferences.text_contrast = test_contrast;
  renderer_preferences.text_gamma = test_gamma;
  web_view_->SetRendererPreferences(renderer_preferences);

  // `GetSkSurfaceProps` should have the updated contrast and
  // gamma properties from above.
  SkSurfaceProps surface_props =
      skia::LegacyDisplayGlobals::GetSkSurfaceProps();
  EXPECT_EQ(surface_props.textContrast(), test_contrast);
  EXPECT_EQ(surface_props.textGamma(), test_gamma);
}
#endif  // BUILDFLAG(IS_WIN)

}  // namespace content