2 * Copyright (C) 2011, 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "third_party/blink/renderer/core/exported/web_view_impl.h"
36 #include "base/command_line.h"
37 #include "base/debug/crash_logging.h"
38 #include "base/debug/dump_without_crashing.h"
39 #include "base/memory/scoped_refptr.h"
40 #include "base/metrics/histogram_macros.h"
41 #include "base/observer_list.h"
42 #include "base/time/time.h"
43 #include "build/build_config.h"
44 #include "cc/layers/picture_layer.h"
45 #include "components/viz/common/features.h"
46 #include "media/base/media_switches.h"
47 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
48 #include "third_party/blink/public/common/features.h"
49 #include "third_party/blink/public/common/history/session_history_constants.h"
50 #include "third_party/blink/public/common/input/web_input_event.h"
51 #include "third_party/blink/public/common/input/web_menu_source_type.h"
52 #include "third_party/blink/public/common/page/page_zoom.h"
53 #include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h"
54 #include "third_party/blink/public/common/switches.h"
55 #include "third_party/blink/public/common/web_preferences/web_preferences.h"
56 #include "third_party/blink/public/mojom/frame/frame_replication_state.mojom-blink.h"
57 #include "third_party/blink/public/mojom/input/focus_type.mojom-blink.h"
58 #include "third_party/blink/public/mojom/window_features/window_features.mojom-blink.h"
59 #include "third_party/blink/public/platform/interface_registry.h"
60 #include "third_party/blink/public/platform/platform.h"
61 #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
62 #include "third_party/blink/public/platform/web_media_player.h"
63 #include "third_party/blink/public/platform/web_network_state_notifier.h"
64 #include "third_party/blink/public/platform/web_runtime_features.h"
65 #include "third_party/blink/public/platform/web_text_input_info.h"
66 #include "third_party/blink/public/platform/web_url_request.h"
67 #include "third_party/blink/public/platform/web_vector.h"
68 #include "third_party/blink/public/web/web_autofill_client.h"
69 #include "third_party/blink/public/web/web_console_message.h"
70 #include "third_party/blink/public/web/web_element.h"
71 #include "third_party/blink/public/web/web_frame.h"
72 #include "third_party/blink/public/web/web_hit_test_result.h"
73 #include "third_party/blink/public/web/web_input_element.h"
74 #include "third_party/blink/public/web/web_local_frame_client.h"
75 #include "third_party/blink/public/web/web_meaningful_layout.h"
76 #include "third_party/blink/public/web/web_navigation_type.h"
77 #include "third_party/blink/public/web/web_node.h"
78 #include "third_party/blink/public/web/web_plugin.h"
79 #include "third_party/blink/public/web/web_range.h"
80 #include "third_party/blink/public/web/web_render_theme.h"
81 #include "third_party/blink/public/web/web_view_client.h"
82 #include "third_party/blink/public/web/web_window_features.h"
83 #include "third_party/blink/renderer/core/clipboard/data_object.h"
84 #include "third_party/blink/renderer/core/content_capture/content_capture_manager.h"
85 #include "third_party/blink/renderer/core/core_initializer.h"
86 #include "third_party/blink/renderer/core/css_value_keywords.h"
87 #include "third_party/blink/renderer/core/dom/document.h"
88 #include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
89 #include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
90 #include "third_party/blink/renderer/core/dom/text.h"
91 #include "third_party/blink/renderer/core/editing/editing_utilities.h"
92 #include "third_party/blink/renderer/core/editing/editor.h"
93 #include "third_party/blink/renderer/core/editing/ephemeral_range.h"
94 #include "third_party/blink/renderer/core/editing/frame_selection.h"
95 #include "third_party/blink/renderer/core/editing/ime/edit_context.h"
96 #include "third_party/blink/renderer/core/editing/ime/input_method_controller.h"
97 #include "third_party/blink/renderer/core/editing/iterators/text_iterator.h"
98 #include "third_party/blink/renderer/core/editing/selection_template.h"
99 #include "third_party/blink/renderer/core/editing/serializers/html_interchange.h"
100 #include "third_party/blink/renderer/core/editing/serializers/serialization.h"
101 #include "third_party/blink/renderer/core/events/current_input_event.h"
102 #include "third_party/blink/renderer/core/events/keyboard_event.h"
103 #include "third_party/blink/renderer/core/events/ui_event_with_key_state.h"
104 #include "third_party/blink/renderer/core/events/web_input_event_conversion.h"
105 #include "third_party/blink/renderer/core/events/wheel_event.h"
106 #include "third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h"
107 #include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
108 #include "third_party/blink/renderer/core/exported/web_settings_impl.h"
109 #include "third_party/blink/renderer/core/frame/browser_controls.h"
110 #include "third_party/blink/renderer/core/frame/dom_window.h"
111 #include "third_party/blink/renderer/core/frame/event_handler_registry.h"
112 #include "third_party/blink/renderer/core/frame/fullscreen_controller.h"
113 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
114 #include "third_party/blink/renderer/core/frame/local_frame.h"
115 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
116 #include "third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h"
117 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
118 #include "third_party/blink/renderer/core/frame/page_scale_constraints_set.h"
119 #include "third_party/blink/renderer/core/frame/remote_frame.h"
120 #include "third_party/blink/renderer/core/frame/resize_viewport_anchor.h"
121 #include "third_party/blink/renderer/core/frame/rotation_viewport_anchor.h"
122 #include "third_party/blink/renderer/core/frame/settings.h"
123 #include "third_party/blink/renderer/core/frame/viewport_data.h"
124 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
125 #include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
126 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
127 #include "third_party/blink/renderer/core/frame/web_remote_frame_impl.h"
128 #include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
129 #include "third_party/blink/renderer/core/html/forms/html_text_area_element.h"
130 #include "third_party/blink/renderer/core/html/html_plugin_element.h"
131 #include "third_party/blink/renderer/core/html/plugin_document.h"
132 #include "third_party/blink/renderer/core/html_names.h"
133 #include "third_party/blink/renderer/core/input/context_menu_allowed_scope.h"
134 #include "third_party/blink/renderer/core/input/event_handler.h"
135 #include "third_party/blink/renderer/core/input/touch_action_util.h"
136 #include "third_party/blink/renderer/core/inspector/dev_tools_emulator.h"
137 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
138 #include "third_party/blink/renderer/core/layout/layout_view.h"
139 #include "third_party/blink/renderer/core/layout/text_autosizer.h"
140 #include "third_party/blink/renderer/core/loader/document_loader.h"
141 #include "third_party/blink/renderer/core/loader/frame_load_request.h"
142 #include "third_party/blink/renderer/core/loader/frame_loader.h"
143 #include "third_party/blink/renderer/core/loader/interactive_detector.h"
144 #include "third_party/blink/renderer/core/loader/no_state_prefetch_client.h"
145 #include "third_party/blink/renderer/core/page/chrome_client_impl.h"
146 #include "third_party/blink/renderer/core/page/context_menu_controller.h"
147 #include "third_party/blink/renderer/core/page/context_menu_provider.h"
148 #include "third_party/blink/renderer/core/page/focus_controller.h"
149 #include "third_party/blink/renderer/core/page/frame_tree.h"
150 #include "third_party/blink/renderer/core/page/link_highlight.h"
151 #include "third_party/blink/renderer/core/page/page.h"
152 #include "third_party/blink/renderer/core/page/page_popup_client.h"
153 #include "third_party/blink/renderer/core/page/pointer_lock_controller.h"
154 #include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
155 #include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
156 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
157 #include "third_party/blink/renderer/core/paint/timing/paint_timing.h"
158 #include "third_party/blink/renderer/core/paint/timing/paint_timing_detector.h"
159 #include "third_party/blink/renderer/core/probe/core_probes.h"
160 #include "third_party/blink/renderer/core/scroll/scroll_into_view_util.h"
161 #include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
162 #include "third_party/blink/renderer/core/speculation_rules/document_speculation_rules.h"
163 #include "third_party/blink/renderer/core/timing/dom_window_performance.h"
164 #include "third_party/blink/renderer/core/timing/performance.h"
165 #include "third_party/blink/renderer/core/timing/window_performance.h"
166 #include "third_party/blink/renderer/core/view_transition/view_transition_supplement.h"
167 #include "third_party/blink/renderer/platform/fonts/font_cache.h"
168 #include "third_party/blink/renderer/platform/fonts/generic_font_family_settings.h"
169 #include "third_party/blink/renderer/platform/graphics/image.h"
170 #include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
171 #include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h"
172 #include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
173 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
174 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
175 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
176 #include "third_party/blink/renderer/platform/keyboard_codes.h"
177 #include "third_party/blink/renderer/platform/loader/fetch/unique_identifier.h"
178 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
179 #include "third_party/blink/renderer/platform/scheduler/public/page_scheduler.h"
180 #include "third_party/blink/renderer/platform/theme/web_theme_engine_helper.h"
181 #include "third_party/blink/renderer/platform/weborigin/known_ports.h"
182 #include "third_party/blink/renderer/platform/widget/widget_base.h"
183 #include "third_party/blink/renderer/platform/wtf/casting.h"
184 #include "third_party/icu/source/common/unicode/uscript.h"
185 #include "ui/base/ui_base_features.h"
186 #include "ui/gfx/geometry/skia_conversions.h"
188 #if !BUILDFLAG(IS_MAC)
189 #include "skia/ext/legacy_display_globals.h"
190 #include "third_party/blink/public/platform/web_font_render_style.h"
191 #include "ui/gfx/font_render_params.h"
194 #if BUILDFLAG(IS_WIN)
195 #include "third_party/blink/public/web/win/web_font_rendering.h"
198 #if BUILDFLAG(IS_EFL)
199 #include "third_party/blink/renderer/core/dom/container_node.h"
200 #include "third_party/blink/renderer/core/dom/static_node_list.h"
201 #include "third_party/blink/renderer/core/html/forms/html_form_element.h"
202 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
203 #include "third_party/blink/renderer/core/html/forms/html_select_element.h"
206 #if BUILDFLAG(IS_TIZEN)
207 #include "tizen/system_info.h"
210 #if BUILDFLAG(IS_TIZEN_TV)
211 #include "third_party/blink/public/platform/web_application_type.h"
212 #include "third_party/blink/renderer/core/page/spatial_navigation_controller.h"
213 #include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
214 #include "third_party/blink/public/web/web_security_policy.h"
217 // Get rid of WTF's pow define so we can use std::pow.
219 #include <cmath> // for std::pow
221 #include "build/chromeos_buildflags.h"
223 // The following constants control parameters for automated scaling of webpages
224 // (such as due to a double tap gesture or find in page etc.). These are
225 // experimentally determined.
226 static const int touchPointPadding = 32;
227 static const int nonUserInitiatedPointPadding = 11;
228 static const float minScaleDifference = 0.01f;
229 static const float doubleTapZoomContentDefaultMargin = 5;
230 static const float doubleTapZoomContentMinimumMargin = 2;
231 static constexpr base::TimeDelta kDoubleTapZoomAnimationDuration =
232 base::Milliseconds(250);
233 static const float doubleTapZoomAlreadyLegibleRatio = 1.2f;
235 static constexpr base::TimeDelta kFindInPageAnimationDuration;
237 // Constants for viewport anchoring on resize.
238 static const float viewportAnchorCoordX = 0.5f;
239 static const float viewportAnchorCoordY = 0;
241 // Constants for zooming in on a focused text field.
242 static constexpr base::TimeDelta kScrollAndScaleAnimationDuration =
243 base::Milliseconds(200);
244 static const int minReadableCaretHeight = 16;
245 static const int minReadableCaretHeightForTextArea = 13;
246 static const float minScaleChangeToTriggerZoom = 1.5f;
247 static const float leftBoxRatio = 0.3f;
248 static const int caretPadding = 10;
252 using mojom::blink::EffectiveConnectionType;
254 // Historically, these values came from Webkit in
255 // WebKitLegacy/mac/WebView/WebView.mm (named MinimumZoomMultiplier and
256 // MaximumZoomMultiplier there).
257 const double WebView::kMinTextSizeMultiplier = 0.5;
258 const double WebView::kMaxTextSizeMultiplier = 3.0;
261 HashSet<WebViewImpl*>& WebViewImpl::AllInstances() {
262 DEFINE_STATIC_LOCAL(HashSet<WebViewImpl*>, all_instances, ());
263 return all_instances;
266 static bool g_should_use_external_popup_menus = false;
268 void WebView::SetUseExternalPopupMenus(bool use_external_popup_menus) {
269 g_should_use_external_popup_menus = use_external_popup_menus;
272 bool WebViewImpl::UseExternalPopupMenus() {
273 return g_should_use_external_popup_menus;
278 class EmptyEventListener final : public NativeEventListener {
280 void Invoke(ExecutionContext* execution_context, Event*) override {}
283 typedef void (*SetFontFamilyWrapper)(blink::WebSettings*,
284 const std::u16string&,
287 void SetStandardFontFamilyWrapper(WebSettings* settings,
288 const std::u16string& font,
289 UScriptCode script) {
290 settings->SetStandardFontFamily(WebString::FromUTF16(font), script);
293 void SetFixedFontFamilyWrapper(WebSettings* settings,
294 const std::u16string& font,
295 UScriptCode script) {
296 settings->SetFixedFontFamily(WebString::FromUTF16(font), script);
299 void SetSerifFontFamilyWrapper(WebSettings* settings,
300 const std::u16string& font,
301 UScriptCode script) {
302 settings->SetSerifFontFamily(WebString::FromUTF16(font), script);
305 void SetSansSerifFontFamilyWrapper(WebSettings* settings,
306 const std::u16string& font,
307 UScriptCode script) {
308 settings->SetSansSerifFontFamily(WebString::FromUTF16(font), script);
311 void SetCursiveFontFamilyWrapper(WebSettings* settings,
312 const std::u16string& font,
313 UScriptCode script) {
314 settings->SetCursiveFontFamily(WebString::FromUTF16(font), script);
317 void SetFantasyFontFamilyWrapper(WebSettings* settings,
318 const std::u16string& font,
319 UScriptCode script) {
320 settings->SetFantasyFontFamily(WebString::FromUTF16(font), script);
323 void SetMathFontFamilyWrapper(WebSettings* settings,
324 const std::u16string& font,
325 UScriptCode script) {
326 settings->SetMathFontFamily(WebString::FromUTF16(font), script);
329 // If |scriptCode| is a member of a family of "similar" script codes, returns
330 // the script code in that family that is used by WebKit for font selection
331 // purposes. For example, USCRIPT_KATAKANA_OR_HIRAGANA and USCRIPT_JAPANESE are
332 // considered equivalent for the purposes of font selection. WebKit uses the
333 // script code USCRIPT_KATAKANA_OR_HIRAGANA. So, if |scriptCode| is
334 // USCRIPT_JAPANESE, the function returns USCRIPT_KATAKANA_OR_HIRAGANA. WebKit
335 // uses different scripts than the ones in Chrome pref names because the version
336 // of ICU included on certain ports does not have some of the newer scripts. If
337 // |scriptCode| is not a member of such a family, returns |scriptCode|.
338 UScriptCode GetScriptForWebSettings(UScriptCode scriptCode) {
339 switch (scriptCode) {
340 case USCRIPT_HIRAGANA:
341 case USCRIPT_KATAKANA:
342 case USCRIPT_JAPANESE:
343 return USCRIPT_KATAKANA_OR_HIRAGANA;
345 return USCRIPT_HANGUL;
351 void ApplyFontsFromMap(const web_pref::ScriptFontFamilyMap& map,
352 SetFontFamilyWrapper setter,
353 WebSettings* settings) {
354 for (auto& it : map) {
355 int32_t script = u_getPropertyValueEnum(UCHAR_SCRIPT, (it.first).c_str());
356 if (script >= 0 && script < USCRIPT_CODE_LIMIT) {
357 UScriptCode code = static_cast<UScriptCode>(script);
358 (*setter)(settings, it.second, GetScriptForWebSettings(code));
363 void ApplyCommandLineToSettings(WebSettings* settings) {
364 const base::CommandLine& command_line =
365 *base::CommandLine::ForCurrentProcess();
367 std::string touch_text_selection_strategy =
368 command_line.GetSwitchValueASCII(switches::kTouchTextSelectionStrategy);
369 if (touch_text_selection_strategy ==
370 switches::kTouchTextSelectionStrategy_Character) {
371 settings->SetSelectionStrategy(
372 WebSettings::SelectionStrategyType::kCharacter);
373 } else if (touch_text_selection_strategy ==
374 switches::kTouchTextSelectionStrategy_Direction) {
375 settings->SetSelectionStrategy(
376 WebSettings::SelectionStrategyType::kDirection);
379 WebString network_quiet_timeout = WebString::FromUTF8(
380 command_line.GetSwitchValueASCII(switches::kNetworkQuietTimeout));
381 if (!network_quiet_timeout.IsEmpty()) {
383 double network_quiet_timeout_seconds =
384 String(network_quiet_timeout).ToDouble(&ok);
386 settings->SetNetworkQuietTimeout(network_quiet_timeout_seconds);
389 if (command_line.HasSwitch(switches::kBlinkSettings)) {
390 Vector<String> blink_settings;
391 String command_line_settings =
392 command_line.GetSwitchValueASCII(switches::kBlinkSettings).c_str();
393 command_line_settings.Split(",", blink_settings);
394 for (const String& setting : blink_settings) {
395 wtf_size_t pos = setting.find('=');
396 settings->SetFromStrings(
397 WebString(setting.Substring(0, pos)),
398 WebString(pos == kNotFound ? "" : setting.Substring(pos + 1)));
403 ui::mojom::blink::WindowOpenDisposition NavigationPolicyToDisposition(
404 NavigationPolicy policy) {
406 case kNavigationPolicyDownload:
407 return ui::mojom::blink::WindowOpenDisposition::SAVE_TO_DISK;
408 case kNavigationPolicyCurrentTab:
409 return ui::mojom::blink::WindowOpenDisposition::CURRENT_TAB;
410 case kNavigationPolicyNewBackgroundTab:
411 return ui::mojom::blink::WindowOpenDisposition::NEW_BACKGROUND_TAB;
412 case kNavigationPolicyNewForegroundTab:
413 return ui::mojom::blink::WindowOpenDisposition::NEW_FOREGROUND_TAB;
414 case kNavigationPolicyNewWindow:
415 return ui::mojom::blink::WindowOpenDisposition::NEW_WINDOW;
416 case kNavigationPolicyNewPopup:
417 return ui::mojom::blink::WindowOpenDisposition::NEW_POPUP;
418 case kNavigationPolicyPictureInPicture:
419 return ui::mojom::blink::WindowOpenDisposition::NEW_PICTURE_IN_PICTURE;
420 case kNavigationPolicyLinkPreview:
421 NOTREACHED_NORETURN();
423 NOTREACHED() << "Unexpected NavigationPolicy";
424 return ui::mojom::blink::WindowOpenDisposition::IGNORE_ACTION;
427 // Records the queuing duration for activation IPC.
428 void RecordPrerenderActivationSignalDelay() {
429 auto* task = base::TaskAnnotator::CurrentTaskForThread();
431 // It should be a Mojo call, so `RunTask` executes it as a non-delayed task.
433 CHECK(task->delayed_run_time.is_null());
434 base::TimeDelta queueing_time =
435 !task->queue_time.is_null() ? base::TimeTicks::Now() - task->queue_time
437 base::UmaHistogramTimes("Prerender.Experimental.ActivationIPCDelay",
441 #if !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_WIN)
442 SkFontHinting RendererPreferencesToSkiaHinting(
443 const blink::RendererPreferences& prefs) {
444 // TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
446 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
447 if (!prefs.should_antialias_text) {
448 // When anti-aliasing is off, GTK maps all non-zero hinting settings to
449 // 'Normal' hinting so we do the same. Otherwise, folks who have 'Slight'
450 // hinting selected will see readable text in everything expect Chromium.
451 switch (prefs.hinting) {
452 case gfx::FontRenderParams::HINTING_NONE:
453 return SkFontHinting::kNone;
454 case gfx::FontRenderParams::HINTING_SLIGHT:
455 case gfx::FontRenderParams::HINTING_MEDIUM:
456 case gfx::FontRenderParams::HINTING_FULL:
457 return SkFontHinting::kNormal;
460 return SkFontHinting::kNormal;
465 switch (prefs.hinting) {
466 case gfx::FontRenderParams::HINTING_NONE:
467 return SkFontHinting::kNone;
468 case gfx::FontRenderParams::HINTING_SLIGHT:
469 return SkFontHinting::kSlight;
470 case gfx::FontRenderParams::HINTING_MEDIUM:
471 return SkFontHinting::kNormal;
472 case gfx::FontRenderParams::HINTING_FULL:
473 return SkFontHinting::kFull;
476 return SkFontHinting::kNormal;
479 #endif // !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_WIN)
483 // WebView ----------------------------------------------------------------
485 WebView* WebView::Create(
486 WebViewClient* client,
488 bool is_prerendering,
489 bool is_inside_portal,
490 absl::optional<blink::FencedFrame::DeprecatedFencedFrameMode>
492 bool compositing_enabled,
493 bool widgets_never_composited,
495 CrossVariantMojoAssociatedReceiver<mojom::PageBroadcastInterfaceBase>
497 scheduler::WebAgentGroupScheduler& agent_group_scheduler,
498 const SessionStorageNamespaceId& session_storage_namespace_id,
499 absl::optional<SkColor> page_base_background_color,
500 const BrowsingContextGroupInfo& browsing_context_group_info) {
501 return WebViewImpl::Create(
503 is_hidden ? mojom::blink::PageVisibilityState::kHidden
504 : mojom::blink::PageVisibilityState::kVisible,
505 is_prerendering, is_inside_portal, fenced_frame_mode, compositing_enabled,
506 widgets_never_composited, To<WebViewImpl>(opener), std::move(page_handle),
507 agent_group_scheduler, session_storage_namespace_id,
508 std::move(page_base_background_color), browsing_context_group_info);
511 WebViewImpl* WebViewImpl::Create(
512 WebViewClient* client,
513 mojom::blink::PageVisibilityState visibility,
514 bool is_prerendering,
515 bool is_inside_portal,
516 absl::optional<blink::FencedFrame::DeprecatedFencedFrameMode>
518 bool compositing_enabled,
519 bool widgets_never_composited,
521 mojo::PendingAssociatedReceiver<mojom::blink::PageBroadcast> page_handle,
522 blink::scheduler::WebAgentGroupScheduler& agent_group_scheduler,
523 const SessionStorageNamespaceId& session_storage_namespace_id,
524 absl::optional<SkColor> page_base_background_color,
525 const BrowsingContextGroupInfo& browsing_context_group_info) {
526 // Take a self-reference for WebViewImpl that is released by calling Close(),
527 // then return a raw pointer to the caller.
528 auto web_view = base::AdoptRef(new WebViewImpl(
529 client, visibility, is_prerendering, is_inside_portal, fenced_frame_mode,
530 compositing_enabled, widgets_never_composited, opener,
531 std::move(page_handle), agent_group_scheduler,
532 session_storage_namespace_id, std::move(page_base_background_color),
533 browsing_context_group_info));
535 return web_view.get();
538 size_t WebView::GetWebViewCount() {
539 return WebViewImpl::AllInstances().size();
542 void WebView::UpdateVisitedLinkState(uint64_t link_hash) {
543 Page::VisitedStateChanged(link_hash);
546 void WebView::ResetVisitedLinkState(bool invalidate_visited_link_hashes) {
547 Page::AllVisitedStateChanged(invalidate_visited_link_hashes);
550 void WebViewImpl::SetNoStatePrefetchClient(
551 WebNoStatePrefetchClient* no_state_prefetch_client) {
553 ProvideNoStatePrefetchClientTo(*page_,
554 MakeGarbageCollected<NoStatePrefetchClient>(
555 *page_, no_state_prefetch_client));
558 void WebViewImpl::CloseWindowSoon() {
559 // Ask the RenderViewHost with a local main frame to initiate close. We
560 // could be called from deep in Javascript. If we ask the RenderViewHost to
561 // close now, the window could be closed before the JS finishes executing,
562 // thanks to nested message loops running and handling the resulting
563 // disconnecting `page_broadcast_`. So instead, post a message back to the
564 // message loop, which won't run until the JS is complete, and then the
565 // RouteCloseEvent/RequestClose request can be sent.
568 ->GetAgentGroupScheduler()
570 ->PostTask(FROM_HERE,
571 WTF::BindOnce(&WebViewImpl::DoDeferredCloseWindowSoon,
572 weak_ptr_factory_.GetWeakPtr()));
575 void WebViewImpl::DoDeferredCloseWindowSoon() {
576 // Have the browser process a close request. We should have either a
577 // |local_main_frame_host_remote_| or |remote_main_frame_host_remote_|.
578 // This method will not execute if Close has been called as WeakPtrs
579 // will be invalidated in Close.
580 if (GetPage()->MainFrame()->IsLocalFrame()) {
581 DCHECK(local_main_frame_host_remote_);
582 local_main_frame_host_remote_->RequestClose();
584 DCHECK(remote_main_frame_host_remote_);
585 remote_main_frame_host_remote_->RouteCloseEvent();
589 WebViewImpl::WebViewImpl(
590 WebViewClient* client,
591 mojom::blink::PageVisibilityState visibility,
592 bool is_prerendering,
593 bool is_inside_portal,
594 absl::optional<blink::FencedFrame::DeprecatedFencedFrameMode>
597 bool widgets_never_composited,
599 mojo::PendingAssociatedReceiver<mojom::blink::PageBroadcast> page_handle,
600 blink::scheduler::WebAgentGroupScheduler& agent_group_scheduler,
601 const SessionStorageNamespaceId& session_storage_namespace_id,
602 absl::optional<SkColor> page_base_background_color,
603 const BrowsingContextGroupInfo& browsing_context_group_info)
604 : widgets_never_composited_(widgets_never_composited),
605 web_view_client_(client),
606 chrome_client_(MakeGarbageCollected<ChromeClientImpl>(this)),
607 minimum_zoom_level_(PageZoomFactorToZoomLevel(kMinimumPageZoomFactor)),
608 maximum_zoom_level_(PageZoomFactorToZoomLevel(kMaximumPageZoomFactor)),
609 does_composite_(does_composite),
610 fullscreen_controller_(std::make_unique<FullscreenController>(this)),
611 page_base_background_color_(
612 page_base_background_color.value_or(SK_ColorWHITE)),
614 std::move(page_handle),
615 agent_group_scheduler.DefaultTaskRunner()),
616 session_storage_namespace_id_(session_storage_namespace_id),
617 web_agent_group_scheduler_(agent_group_scheduler) {
619 // Typically, the browser process closes the corresponding peer handle
620 // to signal the renderer process to destroy `this`. In certain
621 // situations where the lifetime of `this` is not controlled by a
622 // corresponding browser-side `RenderViewHostImpl` (e.g. tests or
623 // printing), call `Close()` directly instead to delete `this`.
624 receiver_.set_disconnect_handler(
625 WTF::BindOnce(&WebViewImpl::MojoDisconnected, WTF::Unretained(this)));
627 if (!web_view_client_)
628 DCHECK(!does_composite_);
629 page_ = Page::CreateOrdinary(*chrome_client_,
630 opener ? opener->GetPage() : nullptr,
631 agent_group_scheduler.GetAgentGroupScheduler(),
632 browsing_context_group_info);
633 CoreInitializer::GetInstance().ProvideModulesToPage(
634 *page_, session_storage_namespace_id_);
636 SetVisibilityState(visibility, /*is_initial_state=*/true);
637 page_->SetIsPrerendering(is_prerendering);
639 // We pass this state to Page, but it's only used by the main frame in the
641 SetInsidePortal(is_inside_portal);
643 if (fenced_frame_mode && features::IsFencedFramesEnabled()) {
644 page_->SetIsMainFrameFencedFrameRoot();
645 page_->SetDeprecatedFencedFrameMode(*fenced_frame_mode);
647 // `fenced_frame_mode` should only be set if creating an MPArch
649 DCHECK(!fenced_frame_mode);
652 // When not compositing, keep the Page in the loop so that it will paint all
653 // content into the root layer, as multiple layers can only be used when
654 // compositing them together later.
656 page_->GetSettings().SetAcceleratedCompositingEnabled(true);
658 dev_tools_emulator_ = MakeGarbageCollected<DevToolsEmulator>(this);
660 AllInstances().insert(this);
662 resize_viewport_anchor_ = MakeGarbageCollected<ResizeViewportAnchor>(*page_);
664 // Ensure we have valid page scale constraints even if the embedder never
666 GetPageScaleConstraintsSet().ComputeFinalConstraints();
669 WebViewImpl::~WebViewImpl() {
673 WebDevToolsAgentImpl* WebViewImpl::MainFrameDevToolsAgentImpl() {
674 WebLocalFrameImpl* main_frame = MainFrameImpl();
675 return main_frame ? main_frame->DevToolsAgentImpl() : nullptr;
678 void WebViewImpl::SetTabKeyCyclesThroughElements(bool value) {
680 page_->SetTabKeyCyclesThroughElements(value);
683 bool WebViewImpl::StartPageScaleAnimation(const gfx::Point& target_position,
686 base::TimeDelta duration) {
687 // PageScaleFactor is a property of the main frame only, and only exists when
689 DCHECK(MainFrameImpl());
690 DCHECK(does_composite_);
692 VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
693 DCHECK(visual_viewport.IsActiveViewport());
695 gfx::Point clamped_point = target_position;
698 visual_viewport.ClampDocumentOffsetAtScale(target_position, new_scale);
700 // TODO(bokan): Why special case duration zero? PageScaleAnimation should
702 if (duration.is_zero()) {
703 SetPageScaleFactor(new_scale);
705 LocalFrameView* view = MainFrameImpl()->GetFrameView();
706 if (view && view->GetScrollableArea()) {
707 view->GetScrollableArea()->SetScrollOffset(
708 ScrollOffset(gfx::Vector2dF(clamped_point.OffsetFromOrigin())),
709 mojom::blink::ScrollType::kProgrammatic);
715 if (use_anchor && new_scale == PageScaleFactor())
718 if (enable_fake_page_scale_animation_for_testing_) {
719 fake_page_scale_animation_target_position_ = target_position;
720 fake_page_scale_animation_use_anchor_ = use_anchor;
721 fake_page_scale_animation_page_scale_factor_ = new_scale;
723 MainFrameImpl()->FrameWidgetImpl()->StartPageScaleAnimation(
724 target_position, use_anchor, new_scale, duration);
729 void WebViewImpl::EnableFakePageScaleAnimationForTesting(bool enable) {
730 enable_fake_page_scale_animation_for_testing_ = enable;
731 fake_page_scale_animation_target_position_ = gfx::Point();
732 fake_page_scale_animation_use_anchor_ = false;
733 fake_page_scale_animation_page_scale_factor_ = 0;
736 void WebViewImpl::AcceptLanguagesChanged() {
737 FontCache::AcceptLanguagesChanged(
738 String::FromUTF8(renderer_preferences_.accept_languages));
743 GetPage()->AcceptLanguagesChanged();
746 gfx::Rect WebViewImpl::WidenRectWithinPageBounds(const gfx::Rect& source,
748 int minimum_margin) {
749 // Caller should guarantee that the main frame exists and is local.
751 DCHECK(MainFrame()->IsWebLocalFrame());
752 gfx::Size max_size = MainFrame()->ToWebLocalFrame()->DocumentSize();
753 gfx::PointF scroll_offset = MainFrame()->ToWebLocalFrame()->GetScrollOffset();
755 int left_margin = target_margin;
756 int right_margin = target_margin;
758 const int absolute_source_x = source.x() + scroll_offset.x();
759 if (left_margin > absolute_source_x) {
760 left_margin = absolute_source_x;
761 right_margin = std::max(left_margin, minimum_margin);
764 const int maximum_right_margin =
765 max_size.width() - (source.width() + absolute_source_x);
766 if (right_margin > maximum_right_margin) {
767 right_margin = maximum_right_margin;
768 left_margin = std::min(left_margin, std::max(right_margin, minimum_margin));
771 const int new_width = source.width() + left_margin + right_margin;
772 const int new_x = source.x() - left_margin;
774 DCHECK_GE(new_width, 0);
775 DCHECK_LE(scroll_offset.x() + new_x + new_width, max_size.width());
777 return gfx::Rect(new_x, source.y(), new_width, source.height());
780 float WebViewImpl::MaximumLegiblePageScale() const {
781 // Pages should be as legible as on desktop when at dpi scale, so no
782 // need to zoom in further when automatically determining zoom level
783 // (after double tap, find in page, etc), though the user should still
784 // be allowed to manually pinch zoom in further if they desire.
786 return maximum_legible_scale_ *
787 GetPage()->GetSettings().GetAccessibilityFontScaleFactor();
789 return maximum_legible_scale_;
792 void WebViewImpl::ComputeScaleAndScrollForBlockRect(
793 const gfx::Point& hit_point_in_root_frame,
794 const gfx::Rect& block_rect_in_root_frame,
796 float default_scale_when_already_legible,
798 gfx::Point& scroll) {
799 DCHECK(GetPage()->GetVisualViewport().IsActiveViewport());
800 scale = PageScaleFactor();
801 scroll = gfx::Point();
803 gfx::Rect rect = block_rect_in_root_frame;
805 if (!rect.IsEmpty()) {
806 float default_margin = doubleTapZoomContentDefaultMargin;
807 float minimum_margin = doubleTapZoomContentMinimumMargin;
808 // We want the margins to have the same physical size, which means we
809 // need to express them in post-scale size. To do that we'd need to know
810 // the scale we're scaling to, but that depends on the margins. Instead
811 // we express them as a fraction of the target rectangle: this will be
812 // correct if we end up fully zooming to it, and won't matter if we
814 rect = WidenRectWithinPageBounds(
815 rect, static_cast<int>(default_margin * rect.width() / size_.width()),
816 static_cast<int>(minimum_margin * rect.width() / size_.width()));
817 // Fit block to screen, respecting limits.
818 scale = static_cast<float>(size_.width()) / rect.width();
819 scale = std::min(scale, MaximumLegiblePageScale());
820 if (PageScaleFactor() < default_scale_when_already_legible)
821 scale = std::max(scale, default_scale_when_already_legible);
822 scale = ClampPageScaleFactorToLimits(scale);
825 // FIXME: If this is being called for auto zoom during find in page,
826 // then if the user manually zooms in it'd be nice to preserve the
827 // relative increase in zoom they caused (if they zoom out then it's ok
828 // to zoom them back in again). This isn't compatible with our current
829 // double-tap zoom strategy (fitting the containing block to the screen)
832 float screen_width = size_.width() / scale;
833 float screen_height = size_.height() / scale;
835 // Scroll to vertically align the block.
836 if (rect.height() < screen_height) {
837 // Vertically center short blocks.
838 rect.Offset(0, -0.5 * (screen_height - rect.height()));
840 // Ensure position we're zooming to (+ padding) isn't off the bottom of
842 rect.set_y(std::max<float>(
843 rect.y(), hit_point_in_root_frame.y() + padding - screen_height));
844 } // Otherwise top align the block.
846 // Do the same thing for horizontal alignment.
847 if (rect.width() < screen_width) {
848 rect.Offset(-0.5 * (screen_width - rect.width()), 0);
850 rect.set_x(std::max<float>(
851 rect.x(), hit_point_in_root_frame.x() + padding - screen_width));
853 scroll.set_x(rect.x());
854 scroll.set_y(rect.y());
856 scale = ClampPageScaleFactorToLimits(scale);
857 scroll = MainFrameImpl()->GetFrameView()->RootFrameToDocument(scroll);
859 GetPage()->GetVisualViewport().ClampDocumentOffsetAtScale(scroll, scale);
862 static Node* FindLinkHighlightAncestor(Node* node) {
863 // Go up the tree to find the node that defines a mouse cursor style
865 const LinkHighlightCandidate type = node->IsLinkHighlightCandidate();
866 if (type == LinkHighlightCandidate::kYes)
868 if (type == LinkHighlightCandidate::kNo)
870 node = LayoutTreeBuilderTraversal::Parent(*node);
875 #if BUILDFLAG(IS_EFL)
876 static bool IsClickableOrFocusable(Node* focusable_node) {
877 return (focusable_node->IsHTMLElement() &&
878 To<HTMLElement>(focusable_node)->IsFocusable()) ||
879 focusable_node->HasEventListeners(event_type_names::kClick) ||
880 focusable_node->HasEventListeners(event_type_names::kMousedown) ||
881 focusable_node->HasEventListeners(event_type_names::kMouseup);
885 // This is for tap (link) highlight and is tested in
886 // link_highlight_impl_test.cc.
887 Node* WebViewImpl::BestTapNode(
888 const GestureEventWithHitTestResults& targeted_tap_event) {
889 TRACE_EVENT0("input", "WebViewImpl::bestTapNode");
891 Page* page = page_.Get();
892 if (!page || !page->MainFrame())
895 Node* best_touch_node = targeted_tap_event.GetHitTestResult().InnerNode();
896 if (!best_touch_node)
899 // We might hit something like an image map that has no layoutObject on it
900 // Walk up the tree until we have a node with an attached layoutObject
901 while (!best_touch_node->GetLayoutObject()) {
902 best_touch_node = LayoutTreeBuilderTraversal::Parent(*best_touch_node);
903 if (!best_touch_node)
907 // Editable nodes should not be highlighted (e.g., <input>)
908 if (IsEditable(*best_touch_node))
911 #if BUILDFLAG(IS_EFL)
912 // If we hit HTMLButtonElement, then show tap highlight on it.
913 if (RuntimeEnabledFeatures::TizenCompatibilityModeEnabled()) {
914 auto focusable = best_touch_node;
916 if (IsClickableOrFocusable(focusable)) {
917 if (focusable->IsContainerNode() && !focusable->IsLink()) {
919 static_cast<const ContainerNode*>(focusable)->firstChild();
921 if (IsClickableOrFocusable(child))
924 child = NodeTraversal::Next(*child, focusable);
929 } while (focusable && (focusable = focusable->parentNode()));
933 Node* hand_cursor_ancestor = FindLinkHighlightAncestor(best_touch_node);
934 // We show a highlight on tap only when the current node shows a hand cursor
935 if (!hand_cursor_ancestor) {
939 // We should pick the largest enclosing node with hand cursor set. We do this
940 // by first jumping up to the closest ancestor with hand cursor set. Then we
941 // locate the next ancestor up in the the tree and repeat the jumps as long as
942 // the node has hand cursor set.
944 best_touch_node = hand_cursor_ancestor;
945 hand_cursor_ancestor = FindLinkHighlightAncestor(
946 LayoutTreeBuilderTraversal::Parent(*best_touch_node));
947 } while (hand_cursor_ancestor);
949 // This happens in cases like:
950 // <div style="display: contents; cursor: pointer">Text</div>.
951 // The text node inherits cursor: pointer and the div doesn't have a
952 // LayoutObject, so |best_touch_node| is the text node here. We should not
953 // return the text node because it can't have touch actions.
954 if (best_touch_node->IsTextNode())
957 return best_touch_node;
960 void WebViewImpl::EnableTapHighlightAtPoint(
961 const GestureEventWithHitTestResults& targeted_tap_event) {
962 DCHECK(MainFrameImpl());
963 Node* touch_node = BestTapNode(targeted_tap_event);
964 GetPage()->GetLinkHighlight().SetTapHighlight(touch_node);
965 MainFrameWidget()->UpdateLifecycle(WebLifecycleUpdate::kAll,
966 DocumentUpdateReason::kTapHighlight);
969 void WebViewImpl::AnimateDoubleTapZoom(const gfx::Point& point_in_root_frame,
970 const gfx::Rect& rect_to_zoom) {
971 DCHECK(MainFrameImpl());
976 ComputeScaleAndScrollForBlockRect(
977 point_in_root_frame, rect_to_zoom, touchPointPadding,
978 MinimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio, scale,
981 bool still_at_previous_double_tap_scale =
982 (PageScaleFactor() == double_tap_zoom_page_scale_factor_ &&
983 double_tap_zoom_page_scale_factor_ != MinimumPageScaleFactor()) ||
984 double_tap_zoom_pending_;
986 bool scale_unchanged = fabs(PageScaleFactor() - scale) < minScaleDifference;
987 bool should_zoom_out = rect_to_zoom.IsEmpty() || scale_unchanged ||
988 still_at_previous_double_tap_scale;
992 if (should_zoom_out) {
993 scale = MinimumPageScaleFactor();
994 gfx::Point target_position =
995 MainFrameImpl()->GetFrameView()->RootFrameToDocument(
996 gfx::Point(point_in_root_frame.x(), point_in_root_frame.y()));
997 is_animating = StartPageScaleAnimation(target_position, true, scale,
998 kDoubleTapZoomAnimationDuration);
1000 is_animating = StartPageScaleAnimation(scroll, false, scale,
1001 kDoubleTapZoomAnimationDuration);
1004 // TODO(dglazkov): The only reason why we're using isAnimating and not just
1005 // checking for layer_tree_view_->HasPendingPageScaleAnimation() is because of
1006 // fake page scale animation plumbing for testing, which doesn't actually
1007 // initiate a page scale animation.
1009 double_tap_zoom_page_scale_factor_ = scale;
1010 double_tap_zoom_pending_ = true;
1014 void WebViewImpl::ZoomToFindInPageRect(const gfx::Rect& rect_in_root_frame) {
1015 DCHECK(MainFrameImpl());
1017 gfx::Rect block_bounds =
1018 MainFrameImpl()->FrameWidgetImpl()->ComputeBlockBound(
1019 gfx::Point(rect_in_root_frame.x() + rect_in_root_frame.width() / 2,
1020 rect_in_root_frame.y() + rect_in_root_frame.height() / 2),
1023 if (block_bounds.IsEmpty()) {
1024 // Keep current scale (no need to scroll as x,y will normally already
1025 // be visible). FIXME: Revisit this if it isn't always true.
1032 ComputeScaleAndScrollForBlockRect(rect_in_root_frame.origin(), block_bounds,
1033 nonUserInitiatedPointPadding,
1034 MinimumPageScaleFactor(), scale, scroll);
1036 StartPageScaleAnimation(scroll, false, scale, kFindInPageAnimationDuration);
1039 #if !BUILDFLAG(IS_MAC)
1040 // Mac has no way to open a context menu based on a keyboard event.
1041 WebInputEventResult WebViewImpl::SendContextMenuEvent() {
1042 // The contextMenuController() holds onto the last context menu that was
1043 // popped up on the page until a new one is created. We need to clear
1044 // this menu before propagating the event through the DOM so that we can
1045 // detect if we create a new menu for this event, since we won't create
1046 // a new menu if the DOM swallows the event and the defaultEventHandler does
1048 GetPage()->GetContextMenuController().ClearContextMenu();
1051 ContextMenuAllowedScope scope;
1052 Frame* focused_frame = GetPage()->GetFocusController().FocusedOrMainFrame();
1053 auto* focused_local_frame = DynamicTo<LocalFrame>(focused_frame);
1054 if (!focused_local_frame)
1055 return WebInputEventResult::kNotHandled;
1056 // Firefox reveal focus based on "keydown" event but not "contextmenu"
1057 // event, we match FF.
1058 if (Element* focused_element =
1059 focused_local_frame->GetDocument()->FocusedElement())
1060 focused_element->scrollIntoViewIfNeeded();
1061 return focused_local_frame->GetEventHandler().ShowNonLocatedContextMenu(
1062 nullptr, kMenuSourceKeyboard);
1066 WebInputEventResult WebViewImpl::SendContextMenuEvent() {
1067 return WebInputEventResult::kNotHandled;
1071 WebPagePopupImpl* WebViewImpl::OpenPagePopup(PagePopupClient* client) {
1074 // This guarantees there is never more than 1 PagePopup active at a time.
1076 DCHECK(!page_popup_);
1078 LocalFrame* opener_frame = client->OwnerElement().GetDocument().GetFrame();
1079 WebLocalFrameImpl* web_opener_frame =
1080 WebLocalFrameImpl::FromFrame(opener_frame);
1082 mojo::PendingAssociatedRemote<mojom::blink::Widget> widget;
1083 mojo::PendingAssociatedReceiver<mojom::blink::Widget> widget_receiver =
1084 widget.InitWithNewEndpointAndPassReceiver();
1086 mojo::PendingAssociatedRemote<mojom::blink::WidgetHost> widget_host;
1087 mojo::PendingAssociatedReceiver<mojom::blink::WidgetHost>
1088 widget_host_receiver = widget_host.InitWithNewEndpointAndPassReceiver();
1090 mojo::PendingAssociatedRemote<mojom::blink::PopupWidgetHost>
1092 mojo::PendingAssociatedReceiver<mojom::blink::PopupWidgetHost>
1093 popup_widget_host_receiver =
1094 popup_widget_host.InitWithNewEndpointAndPassReceiver();
1096 opener_frame->GetLocalFrameHostRemote().CreateNewPopupWidget(
1097 std::move(popup_widget_host_receiver), std::move(widget_host_receiver),
1099 WebFrameWidgetImpl* opener_widget = web_opener_frame->LocalRootFrameWidget();
1101 AgentGroupScheduler& agent_group_scheduler =
1102 opener_frame->GetPage()->GetPageScheduler()->GetAgentGroupScheduler();
1103 // The returned WebPagePopup is self-referencing, so the pointer here is not
1104 // an owning pointer. It is de-referenced by the PopupWidgetHost disconnecting
1105 // and calling Close().
1106 page_popup_ = WebPagePopupImpl::Create(
1107 std::move(popup_widget_host), std::move(widget_host),
1108 std::move(widget_receiver), this, agent_group_scheduler,
1109 opener_widget->GetOriginalScreenInfos(), client);
1110 EnablePopupMouseWheelEventListener(web_opener_frame->LocalRoot());
1111 return page_popup_.get();
1114 void WebViewImpl::CancelPagePopup() {
1116 page_popup_->Cancel();
1119 void WebViewImpl::ClosePagePopup(PagePopup* popup) {
1121 auto* popup_impl = To<WebPagePopupImpl>(popup);
1122 DCHECK_EQ(page_popup_.get(), popup_impl);
1123 if (page_popup_.get() != popup_impl)
1125 page_popup_->ClosePopup();
1128 void WebViewImpl::CleanupPagePopup() {
1129 page_popup_ = nullptr;
1130 DisablePopupMouseWheelEventListener();
1133 void WebViewImpl::UpdatePagePopup() {
1135 page_popup_->Update();
1138 void WebViewImpl::EnablePopupMouseWheelEventListener(
1139 WebLocalFrameImpl* local_root) {
1140 DCHECK(!popup_mouse_wheel_event_listener_);
1141 Document* document = local_root->GetDocument();
1143 // We register an empty event listener, EmptyEventListener, so that mouse
1144 // wheel events get sent to the WebView.
1145 popup_mouse_wheel_event_listener_ =
1146 MakeGarbageCollected<EmptyEventListener>();
1147 document->addEventListener(event_type_names::kMousewheel,
1148 popup_mouse_wheel_event_listener_, false);
1149 local_root_with_empty_mouse_wheel_listener_ = local_root;
1152 void WebViewImpl::DisablePopupMouseWheelEventListener() {
1153 // TODO(kenrb): Concerns the same as in enablePopupMouseWheelEventListener.
1154 // See https://crbug.com/566130
1155 DCHECK(popup_mouse_wheel_event_listener_);
1156 Document* document =
1157 local_root_with_empty_mouse_wheel_listener_->GetDocument();
1159 // Document may have already removed the event listener, for instance, due
1160 // to a navigation, but remove it anyway.
1161 document->removeEventListener(event_type_names::kMousewheel,
1162 popup_mouse_wheel_event_listener_.Release(),
1164 local_root_with_empty_mouse_wheel_listener_ = nullptr;
1167 LocalDOMWindow* WebViewImpl::PagePopupWindow() const {
1168 return page_popup_ ? page_popup_->Window() : nullptr;
1171 Frame* WebViewImpl::FocusedCoreFrame() const {
1172 Page* page = page_.Get();
1173 return page ? page->GetFocusController().FocusedOrMainFrame() : nullptr;
1176 // WebWidget ------------------------------------------------------------------
1178 void WebViewImpl::Close() {
1179 // Closership is a single relationship, so only 1 call to Close() should
1182 DCHECK(AllInstances().Contains(this));
1183 AllInstances().erase(this);
1185 // Ensure if we have a page popup we cancel it immediately as we do not
1186 // want page popups to re-enter WebViewImpl during our shutdown.
1189 // Invalidate any weak ptrs as we are starting to shutdown.
1190 weak_ptr_factory_.InvalidateWeakPtrs();
1193 // Initiate shutdown for the entire frameset. This will cause a lot of
1194 // notifications to be sent. This will detach all frames in this WebView's
1196 page_->WillBeDestroyed();
1199 if (web_view_client_)
1200 web_view_client_->OnDestruct();
1202 // Reset the delegate to prevent notifications being sent as we're being
1204 web_view_client_ = nullptr;
1206 for (auto& observer : observers_)
1207 observer.WebViewDestroyed();
1209 Release(); // Balances a reference acquired in WebView::Create
1212 gfx::Size WebViewImpl::Size() {
1216 void WebViewImpl::ResizeVisualViewport(const gfx::Size& new_size) {
1217 GetPage()->GetVisualViewport().SetSize(new_size);
1218 GetPage()->GetVisualViewport().ClampToBoundaries();
1221 void WebViewImpl::DidFirstVisuallyNonEmptyPaint() {
1222 DCHECK(MainFrameImpl());
1223 local_main_frame_host_remote_->DidFirstVisuallyNonEmptyPaint();
1226 void WebViewImpl::UpdateICBAndResizeViewport(
1227 const gfx::Size& visible_viewport_size) {
1228 // We'll keep the initial containing block size from changing when the top
1229 // controls hide so that the ICB will always be the same size as the
1230 // viewport with the browser controls shown.
1231 gfx::Size icb_size = size_;
1232 if (GetBrowserControls().PermittedState() ==
1233 cc::BrowserControlsState::kBoth &&
1234 !GetBrowserControls().ShrinkViewport()) {
1235 icb_size.Enlarge(0, -(GetBrowserControls().TotalHeight() -
1236 GetBrowserControls().TotalMinHeight()));
1239 GetPageScaleConstraintsSet().DidChangeInitialContainingBlockSize(icb_size);
1241 UpdatePageDefinedViewportConstraints(MainFrameImpl()
1245 .GetViewportDescription());
1246 UpdateMainFrameLayoutSize();
1248 GetPage()->GetVisualViewport().SetSize(visible_viewport_size);
1250 if (MainFrameImpl()->GetFrameView()) {
1251 if (!MainFrameImpl()->GetFrameView()->NeedsLayout())
1252 resize_viewport_anchor_->ResizeFrameView(MainFrameSize());
1255 // The boundaries are not properly established until after the frame view is
1256 // also resized, as demonstrated by
1257 // VisualViewportTest.TestBrowserControlsAdjustmentAndResize.
1258 GetPage()->GetVisualViewport().ClampToBoundaries();
1261 void WebViewImpl::UpdateBrowserControlsConstraint(
1262 cc::BrowserControlsState constraint) {
1263 cc::BrowserControlsState old_permitted_state =
1264 GetBrowserControls().PermittedState();
1266 GetBrowserControls().UpdateConstraintsAndState(
1267 constraint, cc::BrowserControlsState::kBoth);
1269 // If the controls are going from a locked hidden to unlocked state, or vice
1270 // versa, the ICB size needs to change but we can't rely on getting a
1271 // WebViewImpl::resize since the top controls shown state may not have
1273 if ((old_permitted_state == cc::BrowserControlsState::kHidden &&
1274 constraint == cc::BrowserControlsState::kBoth) ||
1275 (old_permitted_state == cc::BrowserControlsState::kBoth &&
1276 constraint == cc::BrowserControlsState::kHidden)) {
1277 UpdateICBAndResizeViewport(GetPage()->GetVisualViewport().Size());
1281 void WebViewImpl::DidUpdateBrowserControls() {
1282 // BrowserControls are a feature whereby the browser can introduce an
1283 // interactable element [e.g. search box] that grows/shrinks in height as the
1284 // user scrolls the web contents.
1286 // This method is called by the BrowserControls class to let the compositor
1287 // know that the browser controls have been updated. This is only relevant if
1288 // the main frame is local because BrowserControls only affects the main
1289 // frame's viewport, and are only affected by main frame scrolling.
1291 // The relevant state is stored on the BrowserControls object even if the main
1292 // frame is remote. If the main frame becomes local, the state will be
1293 // restored by the first commit, since the state is checked in every call to
1294 // ApplyScrollAndScale().
1295 WebLocalFrameImpl* main_frame = MainFrameImpl();
1296 if (!main_frame || !main_frame->IsOutermostMainFrame())
1299 WebFrameWidgetImpl* widget = main_frame->LocalRootFrameWidget();
1300 widget->SetBrowserControlsShownRatio(GetBrowserControls().TopShownRatio(),
1301 GetBrowserControls().BottomShownRatio());
1302 widget->SetBrowserControlsParams(GetBrowserControls().Params());
1304 VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
1305 DCHECK(visual_viewport.IsActiveViewport());
1308 // This object will save the current visual viewport offset w.r.t. the
1309 // document and restore it when the object goes out of scope. It's
1310 // needed since the browser controls adjustment will change the maximum
1311 // scroll offset and we may need to reposition them to keep the user's
1312 // apparent position unchanged.
1313 ResizeViewportAnchor::ResizeScope resize_scope(*resize_viewport_anchor_);
1315 visual_viewport.SetBrowserControlsAdjustment(
1316 GetBrowserControls().UnreportedSizeAdjustment());
1320 #if BUILDFLAG(IS_TIZEN)
1321 void WebViewImpl::PauseScheduledTasks() {
1322 if (!MainFrameImpl())
1325 if (Page* page = GetPage()) {
1326 page->SetIsSuspended(true);
1327 page->SetPaused(true);
1330 #if BUILDFLAG(IS_TIZEN_TV)
1331 // when browser/app switch to BG and did not hidden webview ,the behavior cause
1332 // high cpu issue.So we need to suspend compositor thread.
1333 LOG(INFO) << "APP now suspend";
1334 MainFrameImpl()->FrameWidgetImpl()->SetCompositorVisible(false);
1338 void WebViewImpl::UnpauseScheduledTasks() {
1339 if (!MainFrameImpl())
1341 Page* page = GetPage();
1344 #if BUILDFLAG(IS_TIZEN_TV)
1345 // If floating video window existed and not current page, need to prevent
1347 LOG(INFO) << "APP now resume";
1348 if (IsWebBrowser()) {
1349 if (Client()->HasFloatingVideoWindowOn() &&
1350 page->IsFloatingPage()) {
1351 LOG(INFO) << "Floating video window existed, but not current page";
1352 page->NotifyViewResumedByTabSwitching(true);
1354 page->NotifyViewResumedByTabSwitching(false);
1357 MainFrameImpl()->FrameWidgetImpl()->SetCompositorVisible(true);
1360 page->SetIsSuspended(false);
1361 page->SetPaused(false);
1365 BrowserControls& WebViewImpl::GetBrowserControls() {
1366 return GetPage()->GetBrowserControls();
1369 void WebViewImpl::ResizeViewWhileAnchored(
1370 cc::BrowserControlsParams params,
1371 const gfx::Size& visible_viewport_size) {
1372 DCHECK(MainFrameImpl());
1374 bool old_viewport_shrink = GetBrowserControls().ShrinkViewport();
1376 GetBrowserControls().SetParams(params);
1378 if (old_viewport_shrink != GetBrowserControls().ShrinkViewport())
1379 MainFrameImpl()->GetFrameView()->DynamicViewportUnitsChanged();
1382 // Avoids unnecessary invalidations while various bits of state in
1383 // TextAutosizer are updated.
1384 TextAutosizer::DeferUpdatePageInfo defer_update_page_info(GetPage());
1385 LocalFrameView* frame_view = MainFrameImpl()->GetFrameView();
1386 gfx::Size old_size = frame_view->Size();
1387 UpdateICBAndResizeViewport(visible_viewport_size);
1388 if (old_size != frame_view->Size()) {
1389 frame_view->InvalidateLayoutForViewportConstrainedObjects();
1393 fullscreen_controller_->UpdateSize();
1395 if (!scoped_defer_main_frame_update_) {
1396 // Page scale constraints may need to be updated; running layout now will
1398 MainFrameWidget()->UpdateLifecycle(WebLifecycleUpdate::kLayout,
1399 DocumentUpdateReason::kSizeChange);
1403 void WebViewImpl::ResizeWithBrowserControls(
1404 const gfx::Size& new_size,
1405 float top_controls_height,
1406 float bottom_controls_height,
1407 bool browser_controls_shrink_layout) {
1408 ResizeWithBrowserControls(
1410 {top_controls_height, GetBrowserControls().TopMinHeight(),
1411 bottom_controls_height, GetBrowserControls().BottomMinHeight(),
1412 GetBrowserControls().AnimateHeightChanges(),
1413 browser_controls_shrink_layout});
1416 void WebViewImpl::ResizeWithBrowserControls(
1417 const gfx::Size& main_frame_widget_size,
1418 const gfx::Size& visible_viewport_size,
1419 cc::BrowserControlsParams browser_controls_params) {
1420 if (should_auto_resize_) {
1421 // When auto-resizing only the viewport size comes from the browser, while
1422 // the widget size is determined in the renderer.
1423 ResizeVisualViewport(visible_viewport_size);
1427 if (size_ == main_frame_widget_size &&
1428 GetPage()->GetVisualViewport().Size() == visible_viewport_size &&
1429 GetBrowserControls().Params() == browser_controls_params)
1432 if (GetPage()->MainFrame() && !GetPage()->MainFrame()->IsLocalFrame()) {
1433 // Viewport resize for a remote main frame does not require any
1434 // particular action, but the state needs to reflect the correct size
1435 // so that it can be used for initialization if the main frame gets
1436 // swapped to a LocalFrame at a later time.
1437 size_ = main_frame_widget_size;
1438 GetPageScaleConstraintsSet().DidChangeInitialContainingBlockSize(size_);
1439 GetPage()->GetVisualViewport().SetSize(size_);
1440 GetPage()->GetBrowserControls().SetParams(browser_controls_params);
1444 WebLocalFrameImpl* main_frame = MainFrameImpl();
1448 LocalFrameView* view = main_frame->GetFrameView();
1452 VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
1455 GetPage()->GetSettings().GetMainFrameResizesAreOrientationChanges() &&
1456 size_.width() && ContentsSize().width() &&
1457 main_frame_widget_size.width() != size_.width() &&
1458 !fullscreen_controller_->IsFullscreenOrTransitioning();
1459 size_ = main_frame_widget_size;
1461 if (!main_frame->IsOutermostMainFrame()) {
1462 // Anchoring should not be performed from embedded frames (not even
1463 // portals) as anchoring should only be performed when the size/orientation
1464 // is user controlled.
1465 ResizeViewWhileAnchored(browser_controls_params, visible_viewport_size);
1466 } else if (is_rotation) {
1467 gfx::PointF viewport_anchor_coords(viewportAnchorCoordX,
1468 viewportAnchorCoordY);
1469 RotationViewportAnchor anchor(*view, visual_viewport,
1470 viewport_anchor_coords,
1471 GetPageScaleConstraintsSet());
1472 ResizeViewWhileAnchored(browser_controls_params, visible_viewport_size);
1474 DCHECK(visual_viewport.IsActiveViewport());
1475 ResizeViewportAnchor::ResizeScope resize_scope(*resize_viewport_anchor_);
1476 ResizeViewWhileAnchored(browser_controls_params, visible_viewport_size);
1479 // TODO(bokan): This will send a resize event even if the innerHeight on the
1480 // page didn't change (e.g. virtual keyboard causes resize of only visual
1481 // viewport). Lets remove this and have the frame send this event when its
1482 // frame rect is resized (as noted by the ancient FIXME inside this method).
1483 // https://crbug.com/1353728.
1484 SendResizeEventForMainFrame();
1487 void WebViewImpl::Resize(const gfx::Size& new_size) {
1488 if (should_auto_resize_ || size_ == new_size)
1491 ResizeWithBrowserControls(new_size, GetBrowserControls().TopHeight(),
1492 GetBrowserControls().BottomHeight(),
1493 GetBrowserControls().ShrinkViewport());
1496 void WebViewImpl::SetScreenOrientationOverrideForTesting(
1497 absl::optional<display::mojom::blink::ScreenOrientation> orientation) {
1498 screen_orientation_override_ = orientation;
1500 // Since we updated the override value, notify all widgets.
1501 for (WebFrame* frame = MainFrame(); frame; frame = frame->TraverseNext()) {
1502 if (frame->IsWebLocalFrame()) {
1503 if (WebFrameWidgetImpl* widget = static_cast<WebFrameWidgetImpl*>(
1504 frame->ToWebLocalFrame()->FrameWidget())) {
1505 widget->UpdateScreenInfo(widget->GetScreenInfos());
1511 void WebViewImpl::SetWindowRectSynchronouslyForTesting(
1512 const gfx::Rect& new_window_rect) {
1513 web_widget_->SetWindowRectSynchronouslyForTesting(new_window_rect);
1516 absl::optional<display::mojom::blink::ScreenOrientation>
1517 WebViewImpl::ScreenOrientationOverride() {
1518 return screen_orientation_override_;
1521 void WebViewImpl::DidEnterFullscreen() {
1522 fullscreen_controller_->DidEnterFullscreen();
1525 void WebViewImpl::DidExitFullscreen() {
1526 fullscreen_controller_->DidExitFullscreen();
1529 void WebViewImpl::SetMainFrameViewWidget(WebFrameWidgetImpl* widget) {
1530 DCHECK(!widget || widget->ForMainFrame());
1531 web_widget_ = widget;
1534 void WebViewImpl::SetMouseOverURL(const KURL& url) {
1535 mouse_over_url_ = url;
1536 UpdateTargetURL(mouse_over_url_, focus_url_);
1539 void WebViewImpl::SetKeyboardFocusURL(const KURL& url) {
1541 UpdateTargetURL(focus_url_, mouse_over_url_);
1544 WebFrameWidgetImpl* WebViewImpl::MainFrameViewWidget() {
1548 void WebViewImpl::PaintContent(cc::PaintCanvas* canvas, const gfx::Rect& rect) {
1549 // This should only be used when compositing is not being used for this
1550 // WebView, and it is painting into the recording of its parent.
1551 DCHECK(!does_composite_);
1552 // Non-composited WebViews always have a local main frame.
1553 DCHECK(MainFrameImpl());
1558 LocalFrameView& main_view = *MainFrameImpl()->GetFrame()->View();
1559 // TODO(crbug.com/1442088): Investigate the reason.
1560 if (!main_view.GetLayoutView()
1562 .HasLocalBorderBoxProperties()) {
1565 DCHECK_EQ(main_view.GetLayoutView()->GetDocument().Lifecycle().GetState(),
1566 DocumentLifecycle::kPaintClean);
1568 auto* builder = MakeGarbageCollected<PaintRecordBuilder>();
1569 main_view.PaintOutsideOfLifecycleWithThrottlingAllowed(
1570 builder->Context(), PaintFlag::kNoFlag, CullRect(rect));
1571 // Don't bother to save/restore here as the caller is expecting the canvas
1572 // to be modified and take care of it.
1573 canvas->clipRect(gfx::RectToSkRect(rect));
1574 builder->EndRecording(*canvas, main_view.GetLayoutView()
1576 .LocalBorderBoxProperties()
1581 void WebView::ApplyWebPreferences(const web_pref::WebPreferences& prefs,
1582 WebView* web_view) {
1583 WebViewImpl* web_view_impl = To<WebViewImpl>(web_view);
1584 WebSettings* settings = web_view->GetSettings();
1585 ApplyFontsFromMap(prefs.standard_font_family_map,
1586 SetStandardFontFamilyWrapper, settings);
1587 ApplyFontsFromMap(prefs.fixed_font_family_map, SetFixedFontFamilyWrapper,
1589 ApplyFontsFromMap(prefs.serif_font_family_map, SetSerifFontFamilyWrapper,
1591 ApplyFontsFromMap(prefs.sans_serif_font_family_map,
1592 SetSansSerifFontFamilyWrapper, settings);
1593 ApplyFontsFromMap(prefs.cursive_font_family_map, SetCursiveFontFamilyWrapper,
1595 ApplyFontsFromMap(prefs.fantasy_font_family_map, SetFantasyFontFamilyWrapper,
1597 ApplyFontsFromMap(prefs.math_font_family_map, SetMathFontFamilyWrapper,
1599 settings->SetDefaultFontSize(prefs.default_font_size);
1600 settings->SetDefaultFixedFontSize(prefs.default_fixed_font_size);
1601 settings->SetMinimumFontSize(prefs.minimum_font_size);
1602 settings->SetMinimumLogicalFontSize(prefs.minimum_logical_font_size);
1603 settings->SetDefaultTextEncodingName(
1604 WebString::FromASCII(prefs.default_encoding));
1605 settings->SetJavaScriptEnabled(prefs.javascript_enabled);
1606 settings->SetWebSecurityEnabled(prefs.web_security_enabled);
1607 settings->SetLoadsImagesAutomatically(prefs.loads_images_automatically);
1608 settings->SetImagesEnabled(prefs.images_enabled);
1609 settings->SetPluginsEnabled(prefs.plugins_enabled);
1610 settings->SetDOMPasteAllowed(prefs.dom_paste_enabled);
1611 settings->SetTextAreasAreResizable(prefs.text_areas_are_resizable);
1612 settings->SetAllowScriptsToCloseWindows(prefs.allow_scripts_to_close_windows);
1613 settings->SetDownloadableBinaryFontsEnabled(prefs.remote_fonts_enabled);
1614 settings->SetJavaScriptCanAccessClipboard(
1615 prefs.javascript_can_access_clipboard);
1616 settings->SetDNSPrefetchingEnabled(prefs.dns_prefetching_enabled);
1617 blink::WebNetworkStateNotifier::SetSaveDataEnabled(prefs.data_saver_enabled);
1618 settings->SetLocalStorageEnabled(prefs.local_storage_enabled);
1619 settings->SetSyncXHRInDocumentsEnabled(prefs.sync_xhr_in_documents_enabled);
1620 settings->SetTargetBlankImpliesNoOpenerEnabledWillBeRemoved(
1621 prefs.target_blank_implies_no_opener_enabled_will_be_removed);
1622 settings->SetAllowNonEmptyNavigatorPlugins(
1623 prefs.allow_non_empty_navigator_plugins);
1624 RuntimeEnabledFeatures::SetDatabaseEnabled(prefs.databases_enabled);
1625 settings->SetShouldProtectAgainstIpcFlooding(
1626 !prefs.disable_ipc_flooding_protection);
1627 settings->SetHyperlinkAuditingEnabled(prefs.hyperlink_auditing_enabled);
1628 settings->SetCookieEnabled(prefs.cookie_enabled);
1630 // By default, allow_universal_access_from_file_urls is set to false and thus
1631 // we mitigate attacks from local HTML files by not granting file:// URLs
1632 // universal access. Only test shell will enable this.
1633 settings->SetAllowUniversalAccessFromFileURLs(
1634 prefs.allow_universal_access_from_file_urls);
1635 settings->SetAllowFileAccessFromFileURLs(
1636 prefs.allow_file_access_from_file_urls);
1638 settings->SetWebGL1Enabled(prefs.webgl1_enabled);
1639 settings->SetWebGL2Enabled(prefs.webgl2_enabled);
1641 // Enable WebGL errors to the JS console if requested.
1642 settings->SetWebGLErrorsToConsoleEnabled(
1643 prefs.webgl_errors_to_console_enabled);
1645 settings->SetHideScrollbars(prefs.hide_scrollbars);
1647 RuntimeEnabledFeatures::SetWebKitScrollbarStylingEnabled(
1648 prefs.enable_webkit_scrollbar_styling);
1650 // Enable gpu-accelerated 2d canvas if requested on the command line.
1651 RuntimeEnabledFeatures::SetAccelerated2dCanvasEnabled(
1652 prefs.accelerated_2d_canvas_enabled);
1654 RuntimeEnabledFeatures::SetCanvas2dLayersEnabled(
1655 prefs.canvas_2d_layers_enabled);
1657 // Disable antialiasing for 2d canvas if requested on the command line.
1658 settings->SetAntialiased2dCanvasEnabled(
1659 !prefs.antialiased_2d_canvas_disabled);
1661 // Disable antialiasing of clips for 2d canvas if requested on the command
1663 settings->SetAntialiasedClips2dCanvasEnabled(
1664 prefs.antialiased_clips_2d_canvas_enabled);
1666 // Tabs to link is not part of the settings. WebCore calls
1667 // ChromeClient::tabsToLinks which is part of the glue code.
1668 web_view_impl->SetTabsToLinks(prefs.tabs_to_links);
1670 DCHECK(!(web_view_impl->IsFencedFrameRoot() &&
1671 prefs.allow_running_insecure_content));
1672 settings->SetAllowRunningOfInsecureContent(
1673 prefs.allow_running_insecure_content);
1674 settings->SetDisableReadingFromCanvas(prefs.disable_reading_from_canvas);
1675 settings->SetStrictMixedContentChecking(prefs.strict_mixed_content_checking);
1677 settings->SetStrictlyBlockBlockableMixedContent(
1678 prefs.strictly_block_blockable_mixed_content);
1680 settings->SetStrictMixedContentCheckingForPlugin(
1681 prefs.block_mixed_plugin_content);
1683 settings->SetStrictPowerfulFeatureRestrictions(
1684 prefs.strict_powerful_feature_restrictions);
1685 settings->SetAllowGeolocationOnInsecureOrigins(
1686 prefs.allow_geolocation_on_insecure_origins);
1687 settings->SetPasswordEchoEnabled(prefs.password_echo_enabled);
1688 settings->SetShouldPrintBackgrounds(prefs.should_print_backgrounds);
1689 settings->SetShouldClearDocumentBackground(
1690 prefs.should_clear_document_background);
1691 settings->SetEnableScrollAnimator(prefs.enable_scroll_animator);
1692 settings->SetPrefersReducedMotion(prefs.prefers_reduced_motion);
1693 settings->SetPrefersReducedTransparency(prefs.prefers_reduced_transparency);
1694 settings->SetInvertedColors(prefs.inverted_colors);
1696 RuntimeEnabledFeatures::SetTouchEventFeatureDetectionEnabled(
1697 prefs.touch_event_feature_detection_enabled);
1698 settings->SetMaxTouchPoints(prefs.pointer_events_max_touch_points);
1699 settings->SetAvailablePointerTypes(prefs.available_pointer_types);
1700 settings->SetPrimaryPointerType(prefs.primary_pointer_type);
1701 settings->SetAvailableHoverTypes(prefs.available_hover_types);
1702 settings->SetPrimaryHoverType(prefs.primary_hover_type);
1703 settings->SetOutputDeviceUpdateAbilityType(
1704 prefs.output_device_update_ability_type);
1705 settings->SetBarrelButtonForDragEnabled(prefs.barrel_button_for_drag_enabled);
1707 settings->SetEditingBehavior(prefs.editing_behavior);
1709 settings->SetSupportsMultipleWindows(prefs.supports_multiple_windows);
1711 settings->SetMainFrameClipsContent(!prefs.record_whole_document);
1713 RuntimeEnabledFeatures::SetStylusHandwritingEnabled(
1714 prefs.stylus_handwriting_enabled);
1716 settings->SetSmartInsertDeleteEnabled(prefs.smart_insert_delete_enabled);
1718 settings->SetSpatialNavigationEnabled(prefs.spatial_navigation_enabled);
1719 // Spatnav depends on KeyboardFocusableScrollers. The WebUI team has
1720 // disabled KFS because they need more time to update their custom elements,
1721 // crbug.com/907284. Meanwhile, we pre-ship KFS to spatnav users.
1722 if (prefs.spatial_navigation_enabled)
1723 RuntimeEnabledFeatures::SetKeyboardFocusableScrollersEnabled(true);
1725 settings->SetSelectionIncludesAltImageText(true);
1727 RuntimeEnabledFeatures::SetFakeNoAllocDirectCallForTestingEnabled(
1728 prefs.fake_no_alloc_direct_call_for_testing_enabled);
1730 settings->SetV8CacheOptions(prefs.v8_cache_options);
1732 settings->SetImageAnimationPolicy(prefs.animation_policy);
1734 settings->SetPresentationRequiresUserGesture(
1735 prefs.user_gesture_required_for_presentation);
1737 if (prefs.text_tracks_enabled) {
1738 settings->SetTextTrackKindUserPreference(
1739 WebSettings::TextTrackKindUserPreference::kCaptions);
1741 settings->SetTextTrackKindUserPreference(
1742 WebSettings::TextTrackKindUserPreference::kDefault);
1744 settings->SetTextTrackBackgroundColor(
1745 WebString::FromASCII(prefs.text_track_background_color));
1746 settings->SetTextTrackTextColor(
1747 WebString::FromASCII(prefs.text_track_text_color));
1748 settings->SetTextTrackTextSize(
1749 WebString::FromASCII(prefs.text_track_text_size));
1750 settings->SetTextTrackTextShadow(
1751 WebString::FromASCII(prefs.text_track_text_shadow));
1752 settings->SetTextTrackFontFamily(
1753 WebString::FromASCII(prefs.text_track_font_family));
1754 settings->SetTextTrackFontStyle(
1755 WebString::FromASCII(prefs.text_track_font_style));
1756 settings->SetTextTrackFontVariant(
1757 WebString::FromASCII(prefs.text_track_font_variant));
1758 settings->SetTextTrackMarginPercentage(prefs.text_track_margin_percentage);
1759 settings->SetTextTrackWindowColor(
1760 WebString::FromASCII(prefs.text_track_window_color));
1761 settings->SetTextTrackWindowRadius(
1762 WebString::FromASCII(prefs.text_track_window_radius));
1764 // Needs to happen before SetDefaultPageScaleLimits below since that'll
1765 // recalculate the final page scale limits and that depends on this setting.
1766 settings->SetShrinksViewportContentToFit(
1767 prefs.shrinks_viewport_contents_to_fit);
1769 // Needs to happen before SetIgnoreViewportTagScaleLimits below.
1770 web_view->SetDefaultPageScaleLimits(prefs.default_minimum_page_scale_factor,
1771 prefs.default_maximum_page_scale_factor);
1773 settings->SetFullscreenSupported(prefs.fullscreen_supported);
1774 settings->SetTextAutosizingEnabled(prefs.text_autosizing_enabled);
1775 settings->SetDoubleTapToZoomEnabled(prefs.double_tap_to_zoom_enabled);
1776 blink::WebNetworkStateNotifier::SetNetworkQualityWebHoldback(
1777 static_cast<blink::WebEffectiveConnectionType>(
1778 prefs.network_quality_estimator_web_holdback));
1780 settings->SetDontSendKeyEventsToJavascript(
1781 prefs.dont_send_key_events_to_javascript);
1782 settings->SetWebAppScope(WebString::FromASCII(prefs.web_app_scope.spec()));
1783 settings->SetLoadWithOverviewMode(prefs.initialize_at_minimum_page_scale);
1784 #if defined(TIZEN_ATK_SUPPORT)
1785 settings->SetAccessibilityEnabled(prefs.atk_enabled);
1788 #if BUILDFLAG(IS_TIZEN_TV)
1789 settings->SetAllowFileAccessFromExternalURLs(
1790 prefs.allow_file_access_from_external_urls);
1791 settings->SetMediaPlaybackNotificationEnabled(
1792 prefs.media_playback_notification_enabled);
1793 settings->SetUseArrowScroll(prefs.use_arrow_scroll);
1794 settings->SetUseScrollbarThumbFocusNotifications(
1795 prefs.use_scrollbar_thumb_focus_notifications);
1798 #if BUILDFLAG(IS_EFL)
1799 settings->SetTizenVersion(prefs.tizen_version_major,
1800 prefs.tizen_version_minor,
1801 prefs.tizen_version_release);
1802 web_view_impl->SetIgnoreViewportTagScaleLimits(prefs.force_enable_zoom);
1803 settings->SetLoadWithOverviewMode(prefs.shrinks_viewport_contents_to_fit);
1804 settings->SetUsesEncodingDetector(prefs.uses_encoding_detector);
1805 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
1806 blink::switches::kUseInternalPopupMenu)) {
1807 RuntimeEnabledFeatures::SetPagePopupEnabled(false);
1811 #if BUILDFLAG(IS_TIZEN)
1812 settings->SetLinkEffectEnabled(prefs.link_effect_enabled);
1815 #if BUILDFLAG(IS_ANDROID)
1816 settings->SetAllowCustomScrollbarInMainFrame(false);
1817 settings->SetAccessibilityFontScaleFactor(prefs.font_scale_factor);
1818 settings->SetAccessibilityFontWeightAdjustment(prefs.font_weight_adjustment);
1819 settings->SetAccessibilityTextSizeContrastFactor(
1820 prefs.text_size_contrast_factor);
1821 settings->SetDeviceScaleAdjustment(prefs.device_scale_adjustment);
1822 web_view_impl->SetIgnoreViewportTagScaleLimits(prefs.force_enable_zoom);
1823 settings->SetDefaultVideoPosterURL(
1824 WebString::FromASCII(prefs.default_video_poster_url.spec()));
1825 settings->SetSupportDeprecatedTargetDensityDPI(
1826 prefs.support_deprecated_target_density_dpi);
1827 settings->SetUseLegacyBackgroundSizeShorthandBehavior(
1828 prefs.use_legacy_background_size_shorthand_behavior);
1829 settings->SetWideViewportQuirkEnabled(prefs.wide_viewport_quirk);
1830 settings->SetUseWideViewport(prefs.use_wide_viewport);
1831 settings->SetForceZeroLayoutHeight(prefs.force_zero_layout_height);
1832 settings->SetViewportMetaMergeContentQuirk(
1833 prefs.viewport_meta_merge_content_quirk);
1834 settings->SetViewportMetaNonUserScalableQuirk(
1835 prefs.viewport_meta_non_user_scalable_quirk);
1836 settings->SetViewportMetaZeroValuesQuirk(
1837 prefs.viewport_meta_zero_values_quirk);
1838 settings->SetClobberUserAgentInitialScaleQuirk(
1839 prefs.clobber_user_agent_initial_scale_quirk);
1840 settings->SetIgnoreMainFrameOverflowHiddenQuirk(
1841 prefs.ignore_main_frame_overflow_hidden_quirk);
1842 settings->SetReportScreenSizeInPhysicalPixelsQuirk(
1843 prefs.report_screen_size_in_physical_pixels_quirk);
1844 settings->SetShouldReuseGlobalForUnownedMainFrame(
1845 prefs.reuse_global_for_unowned_main_frame);
1846 settings->SetPreferHiddenVolumeControls(true);
1847 settings->SetSpellCheckEnabledByDefault(prefs.spellcheck_enabled_by_default);
1849 RuntimeEnabledFeatures::SetVideoFullscreenOrientationLockEnabled(
1850 prefs.video_fullscreen_orientation_lock_enabled);
1851 RuntimeEnabledFeatures::SetVideoRotateToFullscreenEnabled(
1852 prefs.video_rotate_to_fullscreen_enabled);
1853 settings->SetEmbeddedMediaExperienceEnabled(
1854 prefs.embedded_media_experience_enabled);
1855 settings->SetImmersiveModeEnabled(prefs.immersive_mode_enabled);
1856 settings->SetDoNotUpdateSelectionOnMutatingSelectionRange(
1857 prefs.do_not_update_selection_on_mutating_selection_range);
1858 RuntimeEnabledFeatures::SetCSSHexAlphaColorEnabled(
1859 prefs.css_hex_alpha_color_enabled);
1860 RuntimeEnabledFeatures::SetScrollTopLeftInteropEnabled(
1861 prefs.scroll_top_left_interop_enabled);
1862 RuntimeEnabledFeatures::SetAcceleratedSmallCanvasesEnabled(
1863 !prefs.disable_accelerated_small_canvases);
1864 #endif // BUILDFLAG(IS_ANDROID)
1866 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
1867 RuntimeEnabledFeatures::SetWebAuthEnabled(!prefs.disable_webauthn);
1868 #endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
1870 settings->SetForceDarkModeEnabled(prefs.force_dark_mode_enabled);
1872 settings->SetAccessibilityAlwaysShowFocus(prefs.always_show_focus);
1873 settings->SetAutoplayPolicy(prefs.autoplay_policy);
1874 settings->SetRequireTransientActivationForGetDisplayMedia(
1875 prefs.require_transient_activation_for_get_display_media);
1876 settings->SetRequireTransientActivationForShowFileOrDirectoryPicker(
1877 prefs.require_transient_activation_for_show_file_or_directory_picker);
1878 settings->SetViewportEnabled(prefs.viewport_enabled);
1879 settings->SetViewportMetaEnabled(prefs.viewport_meta_enabled);
1880 settings->SetViewportStyle(prefs.viewport_style);
1881 settings->SetAutoZoomFocusedEditableToLegibleScale(
1882 prefs.auto_zoom_focused_editable_to_legible_scale);
1884 settings->SetMainFrameResizesAreOrientationChanges(
1885 prefs.main_frame_resizes_are_orientation_changes);
1887 settings->SetShowContextMenuOnMouseUp(prefs.context_menu_on_mouse_up);
1888 settings->SetAlwaysShowContextMenuOnTouch(
1889 prefs.always_show_context_menu_on_touch);
1890 settings->SetSmoothScrollForFindEnabled(prefs.smooth_scroll_for_find_enabled);
1892 settings->SetHideDownloadUI(prefs.hide_download_ui);
1894 settings->SetPresentationReceiver(prefs.presentation_receiver);
1896 settings->SetMediaControlsEnabled(prefs.media_controls_enabled);
1898 settings->SetLowPriorityIframesThreshold(
1899 static_cast<blink::WebEffectiveConnectionType>(
1900 prefs.low_priority_iframes_threshold));
1902 settings->SetPictureInPictureEnabled(prefs.picture_in_picture_enabled &&
1903 ::features::UseSurfaceLayerForVideo());
1905 settings->SetLazyLoadEnabled(prefs.lazy_load_enabled);
1906 settings->SetPreferredColorScheme(prefs.preferred_color_scheme);
1907 settings->SetPreferredContrast(prefs.preferred_contrast);
1909 settings->SetTouchDragDropEnabled(prefs.touch_drag_drop_enabled);
1910 settings->SetTouchDragEndContextMenu(prefs.touch_dragend_context_menu);
1911 settings->SetWebXRImmersiveArAllowed(prefs.webxr_immersive_ar_allowed);
1912 settings->SetModalContextMenu(prefs.modal_context_menu);
1914 #if defined(TIZEN_VIDEO_HOLE)
1915 settings->SetVideoHoleEnabled(prefs.video_hole_enabled);
1918 #if BUILDFLAG(IS_TIZEN_TV)
1919 for (const auto& scheme : prefs.additional_shared_array_buffer_schemes) {
1920 blink::WebSecurityPolicy::RegisterURLSchemeAsAllowingSharedArrayBuffers(
1921 blink::WebString::FromUTF8(scheme));
1925 #if BUILDFLAG(IS_MAC)
1926 web_view_impl->SetMaximumLegibleScale(
1927 prefs.default_maximum_page_scale_factor);
1930 #if BUILDFLAG(IS_WIN)
1931 RuntimeEnabledFeatures::SetMiddleClickAutoscrollEnabled(true);
1934 RuntimeEnabledFeatures::SetTranslateServiceEnabled(
1935 prefs.translate_service_available);
1937 #if BUILDFLAG(IS_WIN)
1938 if (web_view_impl->GetPage() &&
1939 base::FeatureList::IsEnabled(features::kPrewarmDefaultFontFamilies)) {
1940 if (auto* prewarmer = WebFontRendering::GetFontPrewarmer()) {
1941 GenericFontFamilySettings& font_settings =
1942 web_view_impl->GetPage()
1944 .GetGenericFontFamilySettings();
1945 if (features::kPrewarmStandard.Get())
1946 prewarmer->PrewarmFamily(font_settings.Standard());
1947 if (features::kPrewarmFixed.Get())
1948 prewarmer->PrewarmFamily(font_settings.Fixed());
1949 if (features::kPrewarmSerif.Get())
1950 prewarmer->PrewarmFamily(font_settings.Serif());
1951 if (features::kPrewarmSansSerif.Get())
1952 prewarmer->PrewarmFamily(font_settings.SansSerif());
1953 if (features::kPrewarmCursive.Get())
1954 prewarmer->PrewarmFamily(font_settings.Cursive());
1955 if (features::kPrewarmFantasy.Get())
1956 prewarmer->PrewarmFamily(font_settings.Fantasy());
1961 // Disabling the StrictMimetypeCheckForWorkerScriptsEnabled enterprise policy
1962 // overrides the corresponding RuntimeEnabledFeature (via its Pref).
1963 if (!prefs.strict_mime_type_check_for_worker_scripts_enabled) {
1964 RuntimeEnabledFeatures::SetStrictMimeTypesForWorkersEnabled(false);
1968 void WebViewImpl::ThemeChanged() {
1969 if (auto* page = GetPage())
1970 page->InvalidatePaint();
1973 void WebViewImpl::EnterFullscreen(LocalFrame& frame,
1974 const FullscreenOptions* options,
1975 FullscreenRequestType request_type) {
1976 fullscreen_controller_->EnterFullscreen(frame, options, request_type);
1979 void WebViewImpl::ExitFullscreen(LocalFrame& frame) {
1980 fullscreen_controller_->ExitFullscreen(frame);
1983 void WebViewImpl::FullscreenElementChanged(Element* old_element,
1984 Element* new_element,
1985 const FullscreenOptions* options,
1986 FullscreenRequestType request_type) {
1987 fullscreen_controller_->FullscreenElementChanged(old_element, new_element,
1988 options, request_type);
1991 bool WebViewImpl::HasHorizontalScrollbar() {
1992 return MainFrameImpl()
1995 ->HorizontalScrollbar();
1998 bool WebViewImpl::HasVerticalScrollbar() {
1999 return MainFrameImpl()->GetFrameView()->LayoutViewport()->VerticalScrollbar();
2002 void WebViewImpl::SetPageFocus(bool enable) {
2003 page_->GetFocusController().SetFocused(enable);
2005 LocalFrame* focused_frame = page_->GetFocusController().FocusedFrame();
2006 if (focused_frame) {
2007 Element* element = focused_frame->GetDocument()->FocusedElement();
2008 if (element && focused_frame->Selection()
2009 .ComputeVisibleSelectionInDOMTreeDeprecated()
2011 // If the selection was cleared while the WebView was not
2012 // focused, then the focus element shows with a focus ring but
2013 // no caret and does respond to keyboard inputs.
2014 focused_frame->GetDocument()->UpdateStyleAndLayoutTree();
2015 if (element->IsTextControl()) {
2016 element->UpdateSelectionOnFocus(SelectionBehaviorOnFocus::kRestore);
2017 } else if (IsEditable(*element)) {
2018 // updateFocusAppearance() selects all the text of
2019 // contentseditable DIVs. So we set the selection explicitly
2020 // instead. Note that this has the side effect of moving the
2021 // caret back to the beginning of the text.
2022 Position position(element, 0);
2023 focused_frame->Selection().SetSelectionAndEndTyping(
2024 SelectionInDOMTree::Builder().Collapse(position).Build());
2027 #if BUILDFLAG(IS_TIZEN_TV)
2028 // Trigger auto show IME when webview focus in
2030 if (MainFrameImpl() && MainFrameImpl()->FrameWidgetImpl()) {
2033 ->DidUpdateTextOfFocusedElementByNonUserInput();
2038 // Accessibility needs to be informed that system focus has moved
2039 // into the web area again, even if focus did not change within
2040 // WebCore. send the notification even if the element is the same.
2041 AXObjectCache* cache =
2042 focused_frame->GetDocument()->ExistingAXObjectCache();
2044 cache->HandleFocusedUIElementChanged(0, element);
2046 // if no focus element and spatial navigation enabled,
2047 // move to the first top element by send a fake arrow down
2048 if (IsSpatialNavigationEnabled(focused_frame) && IsWebBrowser()) {
2049 LOG(INFO) << "No focused element in view, navigate downward";
2051 ->GetSpatialNavigationController()
2052 .HandleSpatialNavigationDirection(
2053 SpatialNavigationDirection::kDown);
2061 LocalFrame* focused_frame = page_->GetFocusController().FocusedFrame();
2062 if (focused_frame) {
2063 // Finish an ongoing composition to delete the composition node.
2064 if (focused_frame->GetInputMethodController().GetActiveEditContext()) {
2065 focused_frame->GetInputMethodController()
2066 .GetActiveEditContext()
2067 ->FinishComposingText(WebInputMethodController::kKeepSelection);
2068 } else if (focused_frame->GetInputMethodController().HasComposition()) {
2069 // TODO(editing-dev): The use of
2070 // UpdateStyleAndLayout needs to be audited.
2071 // See http://crbug.com/590369 for more details.
2072 focused_frame->GetDocument()->UpdateStyleAndLayout(
2073 DocumentUpdateReason::kFocus);
2075 focused_frame->GetInputMethodController().FinishComposingText(
2076 InputMethodController::kKeepSelection);
2082 // WebView --------------------------------------------------------------------
2084 WebSettingsImpl* WebViewImpl::SettingsImpl() {
2085 if (!web_settings_) {
2086 web_settings_ = std::make_unique<WebSettingsImpl>(
2087 &page_->GetSettings(), dev_tools_emulator_.Get());
2089 DCHECK(web_settings_);
2090 return web_settings_.get();
2093 WebSettings* WebViewImpl::GetSettings() {
2094 return SettingsImpl();
2097 WebString WebViewImpl::PageEncoding() const {
2101 auto* main_frame = DynamicTo<LocalFrame>(page_->MainFrame());
2105 // FIXME: Is this check needed?
2106 if (!main_frame->GetDocument()->Loader())
2109 return main_frame->GetDocument()->EncodingName();
2112 WebFrame* WebViewImpl::MainFrame() {
2113 Page* page = page_.Get();
2114 return WebFrame::FromCoreFrame(page ? page->MainFrame() : nullptr);
2117 const WebFrame* WebViewImpl::MainFrame() const {
2118 Page* page = page_.Get();
2119 return WebFrame::FromCoreFrame(page ? page->MainFrame() : nullptr);
2122 WebLocalFrameImpl* WebViewImpl::MainFrameImpl() const {
2123 Page* page = page_.Get();
2126 return WebLocalFrameImpl::FromFrame(DynamicTo<LocalFrame>(page->MainFrame()));
2129 std::string WebViewImpl::GetNullFrameReasonForBug1139104() const {
2130 Page* page = page_.Get();
2132 return "WebViewImpl::page";
2133 if (!page->MainFrame())
2134 return "WebViewImpl::page->MainFrame";
2135 LocalFrame* local_frame = DynamicTo<LocalFrame>(page->MainFrame());
2137 return "WebViewImpl::local_frame";
2138 return WebLocalFrameImpl::GetNullFrameReasonForBug1139104(local_frame);
2141 void WebViewImpl::DidAttachLocalMainFrame() {
2142 DCHECK(MainFrameImpl());
2143 DCHECK(!remote_main_frame_host_remote_);
2145 LocalFrame* local_frame = MainFrameImpl()->GetFrame();
2146 local_frame->WasAttachedAsLocalMainFrame();
2148 local_frame->GetRemoteNavigationAssociatedInterfaces()->GetInterface(
2149 local_main_frame_host_remote_.BindNewEndpointAndPassReceiver(
2151 ->GetPageScheduler()
2152 ->GetAgentGroupScheduler()
2153 .DefaultTaskRunner()));
2155 auto& viewport = GetPage()->GetVisualViewport();
2156 if (does_composite_) {
2157 // When attaching a local main frame, set up any state on the compositor.
2158 MainFrameImpl()->FrameWidgetImpl()->SetBackgroundColor(BackgroundColor());
2159 MainFrameImpl()->FrameWidgetImpl()->SetPrefersReducedMotion(
2160 web_preferences_.prefers_reduced_motion);
2161 MainFrameImpl()->FrameWidgetImpl()->SetPageScaleStateAndLimits(
2162 viewport.Scale(), viewport.IsPinchGestureActive(),
2163 MinimumPageScaleFactor(), MaximumPageScaleFactor());
2164 // Prevent main frame updates while the main frame is loading until enough
2165 // progress is made and BeginMainFrames are explicitly asked for.
2166 scoped_defer_main_frame_update_ =
2167 MainFrameImpl()->FrameWidgetImpl()->DeferMainFrameUpdate();
2170 // It's possible that at the time that `local_frame` attached its document it
2171 // was provisional so it couldn't initialize the root scroller. Try again now
2172 // that the frame has been attached; this is a no-op if the root scroller is
2173 // already initialized.
2174 if (viewport.IsActiveViewport()) {
2175 DCHECK(local_frame->GetDocument());
2176 // DidAttachLocalMainFrame can be called before a new document is attached
2177 // so ensure we don't try to initialize the root scroller on a stopped
2179 if (local_frame->GetDocument()->IsActive())
2180 local_frame->View()->InitializeRootScroller();
2184 void WebViewImpl::DidAttachRemoteMainFrame(
2185 CrossVariantMojoAssociatedRemote<
2186 mojom::blink::RemoteMainFrameHostInterfaceBase> main_frame_host,
2187 CrossVariantMojoAssociatedReceiver<
2188 mojom::blink::RemoteMainFrameInterfaceBase> main_frame) {
2189 DCHECK(!MainFrameImpl());
2190 DCHECK(!local_main_frame_host_remote_);
2191 // Note that we didn't DCHECK the `main_frame_host` and `main_frame`, because
2192 // it's possible for those to be null, in case the remote main frame is a
2193 // placeholder RemoteFrame that does not have any browser-side counterpart.
2194 // This is possible when the WebView is created in preparation for a main
2195 // frame LocalFrame <-> LocalFrame swap. See the comments in
2196 // `AgentSchedulingGroup::CreateWebView()` for more details.
2198 RemoteFrame* remote_frame = DynamicTo<RemoteFrame>(GetPage()->MainFrame());
2199 remote_frame->WasAttachedAsRemoteMainFrame(std::move(main_frame));
2201 remote_main_frame_host_remote_.Bind(std::move(main_frame_host));
2203 auto& viewport = GetPage()->GetVisualViewport();
2204 DCHECK(!viewport.IsActiveViewport());
2208 void WebViewImpl::DidDetachLocalMainFrame() {
2209 // The WebFrameWidget that generated the |scoped_defer_main_frame_update_|
2210 // for a local main frame is going away.
2211 scoped_defer_main_frame_update_ = nullptr;
2212 local_main_frame_host_remote_.reset();
2215 void WebViewImpl::DidDetachRemoteMainFrame() {
2216 remote_main_frame_host_remote_.reset();
2219 WebLocalFrame* WebViewImpl::FocusedFrame() {
2220 Frame* frame = FocusedCoreFrame();
2221 // TODO(yabinh): focusedCoreFrame() should always return a local frame, and
2222 // the following check should be unnecessary.
2223 // See crbug.com/625068
2224 return WebLocalFrameImpl::FromFrame(DynamicTo<LocalFrame>(frame));
2227 void WebViewImpl::SetFocusedFrame(WebFrame* frame) {
2229 // Clears the focused frame if any.
2230 Frame* focused_frame = FocusedCoreFrame();
2231 if (auto* focused_local_frame = DynamicTo<LocalFrame>(focused_frame))
2232 focused_local_frame->Selection().SetFrameIsFocused(false);
2235 LocalFrame* core_frame = To<WebLocalFrameImpl>(frame)->GetFrame();
2236 core_frame->GetPage()->GetFocusController().SetFocusedFrame(core_frame);
2239 void WebViewImpl::FinishScrollFocusedEditableIntoView(
2240 const gfx::RectF& caret_rect_in_root_frame,
2241 mojom::blink::ScrollIntoViewParamsPtr params) {
2242 DCHECK(MainFrameImpl());
2243 DCHECK(!IsFencedFrameRoot());
2244 DCHECK(!caret_rect_in_root_frame.IsEmpty());
2245 DCHECK(params->for_focused_editable);
2248 // (1) Zoom to legible scale is enabled (i.e. Android)
2249 // (2) We're on a non-mobile-friendly page
2250 // (3) The element doesn't explicitly block pinch-zoom gestures so the user
2251 // can zoom back out.
2252 bool zoom_into_legible_scale =
2253 web_settings_->AutoZoomFocusedEditableToLegibleScale() &&
2254 !GetPage()->GetVisualViewport().ShouldDisableDesktopWorkarounds() &&
2255 params->for_focused_editable->can_zoom;
2257 // Reconstruct the editable element's absolute rect from the caret-relative
2259 gfx::RectF editable_rect_in_root_frame =
2260 scroll_into_view_util::FocusedEditableBoundsFromParams(
2261 caret_rect_in_root_frame, params);
2263 DCHECK(!editable_rect_in_root_frame.IsEmpty());
2267 bool need_animation = false;
2268 ComputeScaleAndScrollForEditableElementRects(
2269 gfx::ToEnclosedRect(editable_rect_in_root_frame),
2270 gfx::ToEnclosedRect(caret_rect_in_root_frame), zoom_into_legible_scale,
2271 scale, scroll, need_animation);
2273 if (need_animation) {
2274 StartPageScaleAnimation(scroll, false, scale,
2275 kScrollAndScaleAnimationDuration);
2279 void WebViewImpl::SmoothScroll(int target_x,
2281 base::TimeDelta duration) {
2282 gfx::Point target_position(target_x, target_y);
2283 StartPageScaleAnimation(target_position, false, PageScaleFactor(), duration);
2286 void WebViewImpl::ComputeScaleAndScrollForEditableElementRects(
2287 const gfx::Rect& element_bounds_in_root_frame,
2288 const gfx::Rect& caret_bounds_in_root_frame,
2289 bool zoom_into_legible_scale,
2291 gfx::Point& new_scroll_position,
2292 bool& need_animation) {
2293 VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
2295 TopDocumentRootScrollerController& controller =
2296 GetPage()->GlobalRootScrollerController();
2297 Node* root_scroller = controller.GlobalRootScroller();
2299 gfx::Rect element_bounds_in_content;
2300 gfx::Rect caret_bounds_in_content;
2302 // If the page has a non-default root scroller then we need to put the
2303 // "in_content" coordinates into that scroller's coordinate space, rather
2304 // than the root frame's.
2305 if (root_scroller != MainFrameImpl()->GetFrame()->GetDocument() &&
2306 controller.RootScrollerArea()) {
2307 ScrollOffset offset = controller.RootScrollerArea()->GetScrollOffset();
2309 element_bounds_in_content = element_bounds_in_root_frame;
2310 caret_bounds_in_content = caret_bounds_in_root_frame;
2312 element_bounds_in_content.Offset(gfx::ToFlooredVector2d(offset));
2313 caret_bounds_in_content.Offset(gfx::ToFlooredVector2d(offset));
2315 element_bounds_in_content =
2316 MainFrameImpl()->GetFrameView()->RootFrameToDocument(
2317 element_bounds_in_root_frame);
2318 caret_bounds_in_content =
2319 MainFrameImpl()->GetFrameView()->RootFrameToDocument(
2320 caret_bounds_in_root_frame);
2323 if (!zoom_into_legible_scale) {
2324 new_scale = PageScaleFactor();
2326 // Pick a scale which is reasonably readable. This is the scale at which
2327 // the caret height will become minReadableCaretHeightForNode (adjusted
2328 // for dpi and font scale factor).
2329 const int min_readable_caret_height_for_node =
2330 (element_bounds_in_content.height() >=
2331 2 * caret_bounds_in_content.height()
2332 ? minReadableCaretHeightForTextArea
2333 : minReadableCaretHeight) *
2334 MainFrameImpl()->GetFrame()->PageZoomFactor();
2335 new_scale = ClampPageScaleFactorToLimits(
2336 MaximumLegiblePageScale() * min_readable_caret_height_for_node /
2337 caret_bounds_in_content.height());
2338 new_scale = std::max(new_scale, PageScaleFactor());
2340 const float delta_scale = new_scale / PageScaleFactor();
2342 need_animation = false;
2344 // If we are at less than the target zoom level, zoom in.
2345 if (delta_scale > minScaleChangeToTriggerZoom)
2346 need_animation = true;
2348 new_scale = PageScaleFactor();
2350 ScrollableArea* root_viewport =
2351 MainFrameImpl()->GetFrame()->View()->GetScrollableArea();
2353 // If the caret is offscreen, then animate.
2354 if (!root_viewport->VisibleContentRect().Contains(caret_bounds_in_content))
2355 need_animation = true;
2357 // If the box is partially offscreen and it's possible to bring it fully
2358 // onscreen, then animate.
2359 if (visual_viewport.VisibleRect().width() >=
2360 element_bounds_in_content.width() &&
2361 visual_viewport.VisibleRect().height() >=
2362 element_bounds_in_content.height() &&
2363 !root_viewport->VisibleContentRect().Contains(element_bounds_in_content))
2364 need_animation = true;
2366 if (!need_animation)
2369 gfx::SizeF target_viewport_size(visual_viewport.Size());
2370 target_viewport_size.Scale(1 / new_scale);
2372 // TODO(bokan): The logic below is all tailored assuming LTR writing mode.
2373 // Ideally, it'd perform its computations based on writing mode.
2374 ScrollOffset scroll_offset;
2375 if (element_bounds_in_content.width() <= target_viewport_size.width()) {
2376 // Field is narrower than screen. Try to leave padding on left so field's
2377 // label is visible, but it's more important to ensure entire field is
2379 int ideal_left_padding = target_viewport_size.width() * leftBoxRatio;
2380 int max_left_padding_keeping_box_onscreen =
2381 target_viewport_size.width() - element_bounds_in_content.width();
2382 scroll_offset.set_x(element_bounds_in_content.x() -
2383 std::min<int>(ideal_left_padding,
2384 max_left_padding_keeping_box_onscreen));
2386 // Field is wider than screen. Try to left-align field, unless caret would
2387 // be offscreen, in which case right-align the caret.
2388 scroll_offset.set_x(std::max<int>(
2389 element_bounds_in_content.x(),
2390 caret_bounds_in_content.x() + caret_bounds_in_content.width() +
2391 caretPadding - target_viewport_size.width()));
2393 if (element_bounds_in_content.height() <= target_viewport_size.height()) {
2394 // Field is shorter than screen. Vertically center it.
2395 scroll_offset.set_y(
2396 element_bounds_in_content.y() -
2397 (target_viewport_size.height() - element_bounds_in_content.height()) /
2400 // Field is taller than screen. Try to top align field, unless caret would
2401 // be offscreen, in which case bottom-align the caret.
2402 scroll_offset.set_y(std::max<int>(
2403 element_bounds_in_content.y(),
2404 caret_bounds_in_content.y() + caret_bounds_in_content.height() +
2405 caretPadding - target_viewport_size.height()));
2408 // The output scroll will be used by the compositor so we must convert the
2409 // scroll-origin relative (i.e. writing-mode dependent) ScrollOffset with a
2410 // top-left relative scroll position.
2411 new_scroll_position =
2412 ToFlooredPoint(root_viewport->ScrollOffsetToPosition(scroll_offset));
2415 void WebViewImpl::AdvanceFocus(bool reverse) {
2416 GetPage()->GetFocusController().AdvanceFocus(
2417 reverse ? mojom::blink::FocusType::kBackward
2418 : mojom::blink::FocusType::kForward);
2421 double WebViewImpl::ZoomLevel() {
2425 void WebViewImpl::PropagateZoomFactorToLocalFrameRoots(Frame* frame,
2426 float zoom_factor) {
2427 auto* local_frame = DynamicTo<LocalFrame>(frame);
2428 if (local_frame && local_frame->IsLocalRoot()) {
2429 if (Document* document = local_frame->GetDocument()) {
2430 auto* plugin_document = DynamicTo<PluginDocument>(document);
2431 if (!plugin_document || !plugin_document->GetPluginView()) {
2432 local_frame->SetPageZoomFactor(zoom_factor);
2437 for (Frame* child = frame->Tree().FirstChild(); child;
2438 child = child->Tree().NextSibling())
2439 PropagateZoomFactorToLocalFrameRoots(child, zoom_factor);
2442 double WebViewImpl::SetZoomLevel(double zoom_level) {
2443 double old_zoom_level = zoom_level_;
2444 if (zoom_level < minimum_zoom_level_)
2445 zoom_level_ = minimum_zoom_level_;
2446 else if (zoom_level > maximum_zoom_level_)
2447 zoom_level_ = maximum_zoom_level_;
2449 zoom_level_ = zoom_level;
2452 zoom_factor_override_
2453 ? zoom_factor_override_
2454 : static_cast<float>(PageZoomLevelToZoomFactor(zoom_level_));
2455 if (zoom_factor_for_device_scale_factor_) {
2456 if (compositor_device_scale_factor_override_) {
2457 page_->SetInspectorDeviceScaleFactorOverride(
2458 zoom_factor_for_device_scale_factor_ /
2459 compositor_device_scale_factor_override_);
2461 zoom_factor *= compositor_device_scale_factor_override_;
2463 page_->SetInspectorDeviceScaleFactorOverride(1.0f);
2464 zoom_factor *= zoom_factor_for_device_scale_factor_;
2467 PropagateZoomFactorToLocalFrameRoots(page_->MainFrame(), zoom_factor);
2469 if (old_zoom_level != zoom_level_) {
2470 for (auto& observer : observers_)
2471 observer.OnZoomLevelChanged();
2478 float WebViewImpl::PageScaleFactor() const {
2482 return GetPage()->GetVisualViewport().Scale();
2485 float WebViewImpl::ClampPageScaleFactorToLimits(float scale_factor) const {
2486 return GetPageScaleConstraintsSet().FinalConstraints().ClampToConstraints(
2490 void WebViewImpl::SetVisualViewportOffset(const gfx::PointF& offset) {
2492 GetPage()->GetVisualViewport().SetLocation(offset);
2495 gfx::PointF WebViewImpl::VisualViewportOffset() const {
2497 return GetPage()->GetVisualViewport().VisibleRect().origin();
2500 gfx::SizeF WebViewImpl::VisualViewportSize() const {
2502 return GetPage()->GetVisualViewport().VisibleRect().size();
2505 void WebViewImpl::SetPageScaleFactorAndLocation(float scale_factor,
2506 bool is_pinch_gesture_active,
2507 const gfx::PointF& location) {
2510 GetPage()->GetVisualViewport().SetScaleAndLocation(
2511 ClampPageScaleFactorToLimits(scale_factor), is_pinch_gesture_active,
2515 void WebViewImpl::SetPageScaleFactor(float scale_factor) {
2517 DCHECK(MainFrameImpl());
2519 if (LocalFrame* frame = MainFrameImpl()->GetFrame()) {
2520 frame->SetScaleFactor(scale_factor);
2524 void WebViewImpl::SetZoomFactorForDeviceScaleFactor(
2525 float zoom_factor_for_device_scale_factor) {
2526 DCHECK(does_composite_);
2527 // We can't early-return here if these are already equal, because we may
2528 // need to propagate the correct zoom factor to newly navigated frames.
2529 zoom_factor_for_device_scale_factor_ = zoom_factor_for_device_scale_factor;
2530 SetZoomLevel(zoom_level_);
2533 void WebViewImpl::SetPageLifecycleStateFromNewPageCommit(
2534 mojom::blink::PageVisibilityState visibility,
2535 mojom::blink::PagehideDispatch pagehide_dispatch) {
2536 TRACE_EVENT0("navigation",
2537 "WebViewImpl::SetPageLifecycleStateFromNewPageCommit");
2538 mojom::blink::PageLifecycleStatePtr state =
2539 GetPage()->GetPageLifecycleState().Clone();
2540 state->visibility = visibility;
2541 state->pagehide_dispatch = pagehide_dispatch;
2542 SetPageLifecycleStateInternal(std::move(state),
2543 /*page_restore_params=*/nullptr);
2546 void WebViewImpl::SetPageLifecycleState(
2547 mojom::blink::PageLifecycleStatePtr state,
2548 mojom::blink::PageRestoreParamsPtr page_restore_params,
2549 SetPageLifecycleStateCallback callback) {
2550 TRACE_EVENT0("navigation", "WebViewImpl::SetPageLifecycleState");
2551 SetPageLifecycleStateInternal(std::move(state),
2552 std::move(page_restore_params));
2553 // Tell the browser that the lifecycle update was successful.
2554 std::move(callback).Run();
2557 // Returns true if this state update is for the page being restored from
2558 // back-forward cache, causing the pageshow event to fire with persisted=true.
2559 bool IsRestoredFromBackForwardCache(
2560 const mojom::blink::PageLifecycleStatePtr& old_state,
2561 const mojom::blink::PageLifecycleStatePtr& new_state) {
2564 bool old_state_hidden = old_state->pagehide_dispatch !=
2565 mojom::blink::PagehideDispatch::kNotDispatched;
2566 bool new_state_shown = new_state->pagehide_dispatch ==
2567 mojom::blink::PagehideDispatch::kNotDispatched;
2568 // It's a pageshow but it can't be the initial pageshow since it was already
2569 // hidden. So it must be a back-forward cache restore.
2570 return old_state_hidden && new_state_shown;
2573 void WebViewImpl::SetPageLifecycleStateInternal(
2574 mojom::blink::PageLifecycleStatePtr new_state,
2575 mojom::blink::PageRestoreParamsPtr page_restore_params) {
2576 Page* page = GetPage();
2579 auto& old_state = page->GetPageLifecycleState();
2580 TRACE_EVENT2("navigation", "WebViewImpl::SetPageLifecycleStateInternal",
2581 "old_state", old_state, "new_state", new_state);
2583 bool storing_in_bfcache = new_state->is_in_back_forward_cache &&
2584 !old_state->is_in_back_forward_cache;
2585 bool restoring_from_bfcache = !new_state->is_in_back_forward_cache &&
2586 old_state->is_in_back_forward_cache;
2587 // `hiding_page` indicates that the page is switching visibility states in a
2588 // way that we should treat as a change. There are two definitions of this
2589 // (see below), but both require that the new state is not `kVisible`.
2591 new_state->visibility != mojom::blink::PageVisibilityState::kVisible;
2592 if (RuntimeEnabledFeatures::DispatchHiddenVisibilityTransitionsEnabled()) {
2593 // Dispatch a visibility change from `kVisible` to either hidden state, and
2594 // also between the two hidden states.
2595 hiding_page &= (old_state->visibility != new_state->visibility);
2597 // Dispatch a visibility change only when entering or leaving `kVisible` to
2598 // one of the two hidden states, but not when switching between `kHidden`
2599 // and `kHiddenButPainting` in either direction.
2601 (old_state->visibility == mojom::blink::PageVisibilityState::kVisible);
2604 (new_state->visibility == mojom::blink::PageVisibilityState::kVisible) &&
2605 (old_state->visibility != mojom::blink::PageVisibilityState::kVisible);
2606 bool freezing_page = new_state->is_frozen && !old_state->is_frozen;
2607 bool resuming_page = !new_state->is_frozen && old_state->is_frozen;
2608 bool dispatching_pagehide =
2609 (new_state->pagehide_dispatch !=
2610 mojom::blink::PagehideDispatch::kNotDispatched) &&
2611 !GetPage()->DispatchedPagehideAndStillHidden();
2612 bool dispatching_pageshow =
2613 IsRestoredFromBackForwardCache(old_state, new_state);
2614 bool eviction_changed =
2615 new_state->eviction_enabled != old_state->eviction_enabled;
2617 if (dispatching_pagehide) {
2618 RemoveFocusAndTextInputState();
2620 if (dispatching_pagehide) {
2621 // Note that |dispatching_pagehide| is different than |hiding_page|.
2622 // |dispatching_pagehide| will only be true when we're navigating away from
2623 // a page, while |hiding_page| might be true in other cases too such as when
2624 // the tab containing a page is backgrounded, and might be false even when
2625 // we're navigating away from a page, if the page is already hidden.
2626 DispatchPagehide(new_state->pagehide_dispatch);
2629 SetVisibilityState(new_state->visibility, /*is_initial_state=*/false);
2631 if (storing_in_bfcache) {
2632 // TODO(https://crbug.com/1378279): Consider moving this to happen earlier
2633 // and together with other page state updates so that the ordering is clear.
2634 Scheduler()->SetPageBackForwardCached(new_state->is_in_back_forward_cache);
2637 if (freezing_page) {
2638 // Notify all local frames that we are about to freeze.
2639 for (WebFrame* frame = MainFrame(); frame; frame = frame->TraverseNext()) {
2640 if (frame->IsWebLocalFrame()) {
2641 frame->ToWebLocalFrame()->Client()->WillFreezePage();
2645 // TODO(https://crbug.com/1378279): Consider moving this to happen earlier
2646 // and together with other page state updates so that the ordering is clear.
2647 SetPageFrozen(true);
2650 if (restoring_from_bfcache) {
2651 DCHECK(page_restore_params);
2652 // Update the history offset and length value, as pages that are kept in
2653 // the back-forward cache do not get notified about updates on these
2654 // values, so the currently saved value might be stale.
2655 SetHistoryOffsetAndLength(page_restore_params->pending_history_list_offset,
2656 page_restore_params->current_history_list_length);
2658 if (eviction_changed)
2659 HookBackForwardCacheEviction(new_state->eviction_enabled);
2660 if (resuming_page) {
2661 // TODO(https://crbug.com/1378279): Consider moving this to happen earlier
2662 // and together with other page state updates so that the ordering is clear.
2663 SetPageFrozen(false);
2666 SetVisibilityState(new_state->visibility, /*is_initial_state=*/false);
2668 if (restoring_from_bfcache) {
2669 DCHECK(dispatching_pageshow);
2670 DCHECK(page_restore_params);
2671 // Increment the navigation counter on the main frame and all nested frames
2672 // in its frame tree.
2673 // Navigation Id increment should happen before a
2674 // BackForwardCacheRestoration instance is created which happens inside the
2675 // DispatchPageshow method.
2676 for (Frame* frame = page->MainFrame(); frame;
2677 frame = frame->Tree().TraverseNext()) {
2678 auto* local_frame = DynamicTo<LocalFrame>(frame);
2679 if (local_frame && local_frame->View()) {
2680 DCHECK(local_frame->DomWindow());
2681 local_frame->DomWindow()->GenerateNewNavigationId();
2685 DispatchPersistedPageshow(page_restore_params->navigation_start);
2687 // TODO(https://crbug.com/1378279): Consider moving this to happen earlier
2688 // and together with other page state updates so that the ordering is clear.
2689 Scheduler()->SetPageBackForwardCached(new_state->is_in_back_forward_cache);
2690 if (MainFrame()->IsWebLocalFrame()) {
2691 LocalFrame* local_frame = To<LocalFrame>(page->MainFrame());
2692 probe::DidRestoreFromBackForwardCache(local_frame);
2694 if (base::FeatureList::IsEnabled(
2695 blink::features::kRetriggerPreloadingOnBFCacheRestoration)) {
2696 if (local_frame->IsOutermostMainFrame()) {
2697 Document* document = local_frame->GetDocument();
2698 if (auto* document_rules =
2699 DocumentSpeculationRules::FromIfExists(*document)) {
2700 document_rules->DocumentRestoredFromBFCache();
2707 // Make sure no TrackedFeaturesUpdate message is sent after the ACK
2708 // TODO(carlscab): Do we really need to go through LocalFrame =>
2709 // platform/scheduler/ => LocalFrame to report the features? We can probably
2710 // move SchedulerTrackedFeatures to core/ and remove the back and forth.
2711 ReportActiveSchedulerTrackedFeatures();
2713 // TODO(https://crbug.com/1378279): Consider moving this to happen earlier
2714 // and together with other page state updates so that the ordering is clear.
2715 GetPage()->SetPageLifecycleState(std::move(new_state));
2717 // Notify all local frames that we've updated the page lifecycle state.
2718 for (WebFrame* frame = MainFrame(); frame; frame = frame->TraverseNext()) {
2719 if (frame->IsWebLocalFrame()) {
2720 frame->ToWebLocalFrame()->Client()->DidSetPageLifecycleState();
2724 UpdateViewTransitionState(restoring_from_bfcache, storing_in_bfcache,
2725 page_restore_params);
2727 if (RuntimeEnabledFeatures::PageRevealEventEnabled()) {
2728 if (restoring_from_bfcache) {
2729 if (auto* main_frame = DynamicTo<LocalFrame>(GetPage()->MainFrame())) {
2730 main_frame->GetDocument()->EnqueuePageRevealEvent();
2736 void WebViewImpl::UpdateViewTransitionState(
2737 bool restoring_from_bfcache,
2738 bool storing_in_bfcache,
2739 const mojom::blink::PageRestoreParamsPtr& page_restore_params) {
2740 // If we have view_transition_state, then we must be a main frame.
2741 DCHECK(!page_restore_params || !page_restore_params->view_transition_state ||
2742 MainFrame()->IsWebLocalFrame());
2743 // We can't be both restoring and storing things.
2744 DCHECK(!restoring_from_bfcache || !storing_in_bfcache);
2746 if (!MainFrame()->IsWebLocalFrame()) {
2749 LocalFrame* local_frame = To<LocalFrame>(GetPage()->MainFrame());
2750 DCHECK(local_frame);
2752 // When restoring from BFCache, start a transition if we have a view
2753 // transition state.
2754 if (restoring_from_bfcache && page_restore_params->view_transition_state) {
2755 if (auto* document = local_frame->GetDocument()) {
2756 ViewTransitionSupplement::CreateFromSnapshotForNavigation(
2757 *document, std::move(*page_restore_params->view_transition_state));
2761 // If we're storing the page in BFCache, abort any pending transitions. This
2762 // is important since when we bring the page back from BFCache, we might
2763 // attempt to create a transition and fail if there is one already happening.
2764 // Note that even if we won't be creating a transition, it's harmless to abort
2765 // the main frame transition when going into BFCache.
2766 if (storing_in_bfcache) {
2767 if (auto* document = local_frame->GetDocument()) {
2768 ViewTransitionSupplement::AbortTransition(*document);
2773 void WebViewImpl::ReportActiveSchedulerTrackedFeatures() {
2774 Page* page = GetPage();
2778 for (Frame* frame = page->MainFrame(); frame;
2779 frame = frame->Tree().TraverseNext()) {
2780 if (!frame->IsLocalFrame())
2782 auto* local_frame = DynamicTo<LocalFrame>(frame);
2783 if (!local_frame->GetFrameScheduler())
2785 local_frame->GetFrameScheduler()->ReportActiveSchedulerTrackedFeatures();
2789 void WebViewImpl::AudioStateChanged(bool is_audio_playing) {
2790 GetPage()->GetPageScheduler()->AudioStateChanged(is_audio_playing);
2793 void WebViewImpl::RemoveFocusAndTextInputState() {
2794 auto& focus_controller = GetPage()->GetFocusController();
2795 auto* focused_frame = focus_controller.FocusedFrame();
2798 // Remove focus from the currently focused element and frame.
2799 focus_controller.SetFocusedElement(nullptr, nullptr);
2800 // Clear composing state, and make sure we send a TextInputState update.
2801 // Note that the TextInputState itself is cleared when we clear the focus,
2802 // but no updates to the browser will be triggered until the next animation
2803 // frame, which won't happen if we're freezing the page.
2804 if (auto* widget = static_cast<WebFrameWidgetImpl*>(
2805 focused_frame->GetWidgetForLocalRoot())) {
2806 widget->FinishComposingText(false /* keep_selection */);
2807 widget->UpdateTextInputState();
2811 void WebViewImpl::DispatchPagehide(
2812 mojom::blink::PagehideDispatch pagehide_dispatch) {
2813 DCHECK_NE(pagehide_dispatch, mojom::blink::PagehideDispatch::kNotDispatched);
2814 bool persisted = (pagehide_dispatch ==
2815 mojom::blink::PagehideDispatch::kDispatchedPersisted);
2816 // Dispatch pagehide on all frames.
2817 for (Frame* frame = GetPage()->MainFrame(); frame;
2818 frame = frame->Tree().TraverseNext()) {
2819 if (frame->DomWindow() && frame->DomWindow()->IsLocalDOMWindow()) {
2820 frame->DomWindow()->ToLocalDOMWindow()->DispatchPagehideEvent(
2822 ? PageTransitionEventPersistence::kPageTransitionEventPersisted
2823 : PageTransitionEventPersistence::
2824 kPageTransitionEventNotPersisted);
2829 void WebViewImpl::DispatchPersistedPageshow(base::TimeTicks navigation_start) {
2830 for (Frame* frame = GetPage()->MainFrame(); frame;
2831 frame = frame->Tree().TraverseNext()) {
2832 auto* local_frame = DynamicTo<LocalFrame>(frame);
2833 // Record the metics.
2834 if (local_frame && local_frame->View()) {
2835 Document* document = local_frame->GetDocument();
2837 PaintTiming::From(*document).OnRestoredFromBackForwardCache();
2838 InteractiveDetector::From(*document)->OnRestoredFromBackForwardCache();
2840 DocumentLoader* loader = local_frame->Loader().GetDocumentLoader();
2842 loader->GetTiming().SetBackForwardCacheRestoreNavigationStart(
2846 if (frame->DomWindow() && frame->DomWindow()->IsLocalDOMWindow()) {
2847 auto pageshow_start_time = base::TimeTicks::Now();
2848 LocalDOMWindow* window = frame->DomWindow()->ToLocalDOMWindow();
2850 window->DispatchPersistedPageshowEvent(navigation_start);
2852 if (RuntimeEnabledFeatures::NavigationIdEnabled(window)) {
2853 auto pageshow_end_time = base::TimeTicks::Now();
2855 WindowPerformance* performance =
2856 DOMWindowPerformance::performance(*window);
2857 DCHECK(performance);
2859 performance->AddBackForwardCacheRestoration(
2860 navigation_start, pageshow_start_time, pageshow_end_time);
2862 if (frame->IsOutermostMainFrame()) {
2863 UMA_HISTOGRAM_BOOLEAN(
2864 "BackForwardCache.MainFrameHasPageshowListenersOnRestore",
2865 window->HasEventListeners(event_type_names::kPageshow));
2871 void WebViewImpl::HookBackForwardCacheEviction(bool hook) {
2873 for (Frame* frame = GetPage()->MainFrame(); frame;
2874 frame = frame->Tree().TraverseNext()) {
2875 auto* local_frame = DynamicTo<LocalFrame>(frame);
2879 local_frame->HookBackForwardCacheEviction();
2881 local_frame->RemoveBackForwardCacheEviction();
2885 void WebViewImpl::EnableAutoResizeMode(const gfx::Size& min_size,
2886 const gfx::Size& max_size) {
2887 should_auto_resize_ = true;
2888 min_auto_size_ = min_size;
2889 max_auto_size_ = max_size;
2890 ConfigureAutoResizeMode();
2893 void WebViewImpl::DisableAutoResizeMode() {
2894 should_auto_resize_ = false;
2895 ConfigureAutoResizeMode();
2898 bool WebViewImpl::AutoResizeMode() {
2899 return should_auto_resize_;
2902 void WebViewImpl::EnableAutoResizeForTesting(const gfx::Size& min_window_size,
2903 const gfx::Size& max_window_size) {
2904 EnableAutoResizeMode(web_widget_->DIPsToCeiledBlinkSpace(min_window_size),
2905 web_widget_->DIPsToCeiledBlinkSpace(max_window_size));
2908 void WebViewImpl::DisableAutoResizeForTesting(
2909 const gfx::Size& new_window_size) {
2910 if (!should_auto_resize_)
2912 DisableAutoResizeMode();
2914 // The |new_size| is empty when resetting auto resize in between tests. In
2915 // this case the current size should just be preserved.
2916 if (!new_window_size.IsEmpty()) {
2917 web_widget_->Resize(web_widget_->DIPsToCeiledBlinkSpace(new_window_size));
2921 void WebViewImpl::SetDefaultPageScaleLimits(float min_scale, float max_scale) {
2922 dev_tools_emulator_->SetDefaultPageScaleLimits(min_scale, max_scale);
2925 void WebViewImpl::SetInitialPageScaleOverride(
2926 float initial_page_scale_factor_override) {
2927 PageScaleConstraints constraints =
2928 GetPageScaleConstraintsSet().UserAgentConstraints();
2929 constraints.initial_scale = initial_page_scale_factor_override;
2931 if (constraints == GetPageScaleConstraintsSet().UserAgentConstraints())
2934 GetPageScaleConstraintsSet().SetNeedsReset(true);
2935 GetPage()->SetUserAgentPageScaleConstraints(constraints);
2938 void WebViewImpl::SetMaximumLegibleScale(float maximum_legible_scale) {
2939 maximum_legible_scale_ = maximum_legible_scale;
2942 void WebViewImpl::SetIgnoreViewportTagScaleLimits(bool ignore) {
2943 PageScaleConstraints constraints =
2944 GetPageScaleConstraintsSet().UserAgentConstraints();
2946 // Don't ignore the minimum limits in touchless mode to prevent wide
2947 // loading elements from causing us to zoom pages out beyond their layout
2948 // which is fairly common.
2949 if (!RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) {
2950 constraints.minimum_scale =
2951 GetPageScaleConstraintsSet().DefaultConstraints().minimum_scale;
2953 constraints.maximum_scale =
2954 GetPageScaleConstraintsSet().DefaultConstraints().maximum_scale;
2956 if (!RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) {
2957 constraints.minimum_scale = -1;
2959 constraints.maximum_scale = -1;
2961 GetPage()->SetUserAgentPageScaleConstraints(constraints);
2964 gfx::Size WebViewImpl::MainFrameSize() {
2965 // The frame size should match the viewport size at minimum scale, since the
2966 // viewport must always be contained by the frame.
2967 return gfx::ScaleToCeiledSize(size_, 1 / MinimumPageScaleFactor());
2970 PageScaleConstraintsSet& WebViewImpl::GetPageScaleConstraintsSet() const {
2971 return GetPage()->GetPageScaleConstraintsSet();
2974 void WebViewImpl::RefreshPageScaleFactor() {
2975 if (!MainFrame() || !GetPage() || !GetPage()->MainFrame() ||
2976 !GetPage()->MainFrame()->IsLocalFrame() ||
2977 !GetPage()->DeprecatedLocalMainFrame()->View())
2979 UpdatePageDefinedViewportConstraints(MainFrameImpl()
2983 .GetViewportDescription());
2984 GetPageScaleConstraintsSet().ComputeFinalConstraints();
2986 float new_page_scale_factor = PageScaleFactor();
2987 if (GetPageScaleConstraintsSet().NeedsReset() &&
2988 GetPageScaleConstraintsSet().FinalConstraints().initial_scale != -1) {
2989 new_page_scale_factor =
2990 GetPageScaleConstraintsSet().FinalConstraints().initial_scale;
2991 GetPageScaleConstraintsSet().SetNeedsReset(false);
2993 SetPageScaleFactor(new_page_scale_factor);
2995 // The constraints may have changed above which affects the page scale limits,
2996 // so we must update those even though SetPageScaleFactor() may do the same if
2997 // the scale factor is changed.
2998 if (does_composite_) {
2999 auto& viewport = GetPage()->GetVisualViewport();
3000 MainFrameImpl()->FrameWidgetImpl()->SetPageScaleStateAndLimits(
3001 viewport.Scale(), viewport.IsPinchGestureActive(),
3002 MinimumPageScaleFactor(), MaximumPageScaleFactor());
3006 void WebViewImpl::UpdatePageDefinedViewportConstraints(
3007 const ViewportDescription& description) {
3008 if (!GetPage() || (!size_.width() && !size_.height()))
3010 // The viewport is a property of the main frame and its widget, so ignore it
3011 // when the main frame is remote.
3012 // TODO(danakj): Remove calls to this method from ChromeClient and DCHECK this
3014 if (!GetPage()->MainFrame()->IsLocalFrame())
3017 if (virtual_keyboard_mode_ != description.virtual_keyboard_mode) {
3018 // TODO(bokan): This should handle portals.
3019 DCHECK(MainFrameImpl()->IsOutermostMainFrame());
3020 virtual_keyboard_mode_ = description.virtual_keyboard_mode;
3021 mojom::blink::LocalFrameHost& frame_host =
3022 MainFrameImpl()->GetFrame()->GetLocalFrameHostRemote();
3024 frame_host.SetVirtualKeyboardMode(virtual_keyboard_mode_);
3027 if (!GetSettings()->ViewportEnabled()) {
3028 GetPageScaleConstraintsSet().ClearPageDefinedConstraints();
3029 UpdateMainFrameLayoutSize();
3033 Document* document = GetPage()->DeprecatedLocalMainFrame()->GetDocument();
3035 Length default_min_width =
3036 document->GetViewportData().ViewportDefaultMinWidth();
3037 if (default_min_width.IsAuto())
3038 default_min_width = Length::ExtendToZoom();
3040 float old_initial_scale =
3041 GetPageScaleConstraintsSet().PageDefinedConstraints().initial_scale;
3043 #if BUILDFLAG(IS_TIZEN)
3044 float old_min_scale =
3045 GetPageScaleConstraintsSet().PageDefinedConstraints().minimum_scale;
3046 float old_max_scale =
3047 GetPageScaleConstraintsSet().PageDefinedConstraints().maximum_scale;
3050 GetPageScaleConstraintsSet().UpdatePageDefinedConstraints(description,
3053 if (SettingsImpl()->ClobberUserAgentInitialScaleQuirk() &&
3054 GetPageScaleConstraintsSet().UserAgentConstraints().initial_scale != -1 &&
3055 GetPageScaleConstraintsSet().UserAgentConstraints().initial_scale <= 1) {
3056 if (description.max_width == Length::DeviceWidth() ||
3057 (description.max_width.IsAuto() &&
3058 GetPageScaleConstraintsSet().PageDefinedConstraints().initial_scale ==
3060 SetInitialPageScaleOverride(-1);
3063 Settings& page_settings = GetPage()->GetSettings();
3064 GetPageScaleConstraintsSet().AdjustForAndroidWebViewQuirks(
3065 description, default_min_width.IntValue(),
3066 SettingsImpl()->SupportDeprecatedTargetDensityDPI(),
3067 page_settings.GetWideViewportQuirkEnabled(),
3068 page_settings.GetUseWideViewport(),
3069 page_settings.GetLoadWithOverviewMode(),
3070 SettingsImpl()->ViewportMetaNonUserScalableQuirk());
3071 float new_initial_scale =
3072 GetPageScaleConstraintsSet().PageDefinedConstraints().initial_scale;
3073 #if BUILDFLAG(IS_TIZEN)
3074 float new_min_scale =
3075 GetPageScaleConstraintsSet().PageDefinedConstraints().minimum_scale;
3076 float new_max_scale =
3077 GetPageScaleConstraintsSet().PageDefinedConstraints().maximum_scale;
3080 if (old_initial_scale != new_initial_scale && new_initial_scale != -1) {
3081 GetPageScaleConstraintsSet().SetNeedsReset(true);
3082 if (MainFrameImpl() && MainFrameImpl()->GetFrameView())
3083 MainFrameImpl()->GetFrameView()->SetNeedsLayout();
3085 #if BUILDFLAG(IS_TIZEN)
3086 else if (old_min_scale != -1 &&
3087 (old_min_scale != new_min_scale || old_max_scale != new_max_scale)) {
3088 if (MainFrameImpl() && MainFrameImpl()->GetFrameView()) {
3089 MainFrameImpl()->GetFrameView()->SetNeedsLayout();
3094 if (does_composite_) {
3095 MainFrameImpl()->FrameWidgetImpl()->UpdateViewportDescription(description);
3098 UpdateMainFrameLayoutSize();
3101 void WebViewImpl::UpdateMainFrameLayoutSize() {
3102 if (should_auto_resize_ || !MainFrameImpl())
3105 LocalFrameView* view = MainFrameImpl()->GetFrameView();
3109 gfx::Size layout_size = size_;
3111 if (GetSettings()->ViewportEnabled())
3112 layout_size = GetPageScaleConstraintsSet().GetLayoutSize();
3114 if (GetPage()->GetSettings().GetForceZeroLayoutHeight())
3115 layout_size.set_height(0);
3117 view->SetLayoutSize(layout_size);
3120 gfx::Size WebViewImpl::ContentsSize() const {
3121 if (!GetPage()->MainFrame()->IsLocalFrame())
3124 GetPage()->DeprecatedLocalMainFrame()->ContentLayoutObject();
3127 return ToPixelSnappedRect(layout_view->DocumentRect()).size();
3130 gfx::Size WebViewImpl::ContentsPreferredMinimumSize() {
3131 DCHECK(page_->MainFrame()->IsLocalFrame());
3133 auto* main_local_frame = DynamicTo<LocalFrame>(page_->MainFrame());
3134 Document* document = main_local_frame->GetDocument();
3135 if (!document || !document->GetLayoutView() || !document->documentElement() ||
3136 !document->documentElement()->GetLayoutBox())
3139 // The preferred size requires an up-to-date layout tree.
3140 DCHECK(!document->NeedsLayoutTreeUpdate() &&
3141 !document->View()->NeedsLayout());
3143 // Needed for computing MinPreferredWidth.
3144 FontCachePurgePreventer fontCachePurgePreventer;
3145 // Already accounts for zoom.
3146 int width_scaled = document->GetLayoutView()->ComputeMinimumWidth().Round();
3148 document->documentElement()->GetLayoutBox()->ScrollHeight().Round();
3149 return gfx::Size(width_scaled, height_scaled);
3152 void WebViewImpl::UpdatePreferredSize() {
3153 // We don't always want to send the change messages over IPC, only if we've
3154 // been put in that mode by getting a |ViewMsg_EnablePreferredSizeChangedMode|
3156 if (!send_preferred_size_changes_ || !MainFrameImpl())
3159 if (!needs_preferred_size_update_)
3161 needs_preferred_size_update_ = false;
3163 gfx::Size size_in_dips =
3164 MainFrameImpl()->LocalRootFrameWidget()->BlinkSpaceToFlooredDIPs(
3165 gfx::Size(ContentsPreferredMinimumSize()));
3167 if (size_in_dips != preferred_size_in_dips_) {
3168 preferred_size_in_dips_ = size_in_dips;
3169 local_main_frame_host_remote_->ContentsPreferredSizeChanged(size_in_dips);
3173 void WebViewImpl::EnablePreferredSizeChangedMode() {
3174 if (send_preferred_size_changes_)
3176 send_preferred_size_changes_ = true;
3177 needs_preferred_size_update_ = true;
3179 // We need to ensure |UpdatePreferredSize| gets called. If a layout is needed,
3180 // force an update here which will call |DidUpdateMainFrameLayout|.
3181 if (MainFrameWidget()) {
3182 MainFrameWidget()->UpdateLifecycle(WebLifecycleUpdate::kLayout,
3183 DocumentUpdateReason::kSizeChange);
3186 // If a layout was not needed, |DidUpdateMainFrameLayout| will not be called.
3187 // We explicitly update the preferred size here to ensure the preferred size
3188 // notification is sent.
3189 UpdatePreferredSize();
3192 void WebViewImpl::Focus() {
3193 if (GetPage()->MainFrame()->IsLocalFrame()) {
3194 DCHECK(local_main_frame_host_remote_);
3195 local_main_frame_host_remote_->FocusPage();
3197 DCHECK(remote_main_frame_host_remote_);
3198 remote_main_frame_host_remote_->FocusPage();
3202 void WebViewImpl::TakeFocus(bool reverse) {
3203 if (GetPage()->MainFrame()->IsLocalFrame()) {
3204 DCHECK(local_main_frame_host_remote_);
3205 local_main_frame_host_remote_->TakeFocus(reverse);
3207 DCHECK(remote_main_frame_host_remote_);
3208 remote_main_frame_host_remote_->TakeFocus(reverse);
3212 void WebViewImpl::Show(const LocalFrameToken& opener_frame_token,
3213 NavigationPolicy policy,
3214 const gfx::Rect& requested_rect,
3215 const gfx::Rect& adjusted_rect,
3216 bool opened_by_user_gesture) {
3217 // This is only called on local main frames.
3218 DCHECK(local_main_frame_host_remote_);
3219 DCHECK(web_widget_);
3220 web_widget_->SetPendingWindowRect(adjusted_rect);
3221 const WebWindowFeatures& web_window_features = page_->GetWindowFeatures();
3222 mojom::blink::WindowFeaturesPtr window_features =
3223 mojom::blink::WindowFeatures::New();
3224 window_features->bounds = requested_rect;
3225 window_features->has_x = web_window_features.x_set;
3226 window_features->has_y = web_window_features.y_set;
3227 window_features->has_width = web_window_features.width_set;
3228 window_features->has_height = web_window_features.height_set;
3229 window_features->is_popup = web_window_features.is_popup;
3230 local_main_frame_host_remote_->ShowCreatedWindow(
3231 opener_frame_token, NavigationPolicyToDisposition(policy),
3232 std::move(window_features), opened_by_user_gesture,
3233 WTF::BindOnce(&WebViewImpl::DidShowCreatedWindow, WTF::Unretained(this)));
3235 MainFrameDevToolsAgentImpl()->DidShowNewWindow();
3238 void WebViewImpl::DidShowCreatedWindow() {
3239 web_widget_->AckPendingWindowRect();
3242 void WebViewImpl::SendWindowRectToMainFrameHost(
3243 const gfx::Rect& bounds,
3244 base::OnceClosure ack_callback) {
3245 DCHECK(local_main_frame_host_remote_);
3246 local_main_frame_host_remote_->SetWindowRect(bounds, std::move(ack_callback));
3249 void WebViewImpl::DidAccessInitialMainDocument() {
3250 DCHECK(local_main_frame_host_remote_);
3251 local_main_frame_host_remote_->DidAccessInitialMainDocument();
3254 void WebViewImpl::SetResizable(bool resizable) {
3255 DCHECK(local_main_frame_host_remote_);
3256 local_main_frame_host_remote_->SetResizable(resizable);
3259 void WebViewImpl::UpdateTargetURL(const WebURL& url,
3260 const WebURL& fallback_url) {
3261 KURL latest_url = KURL(url.IsEmpty() ? fallback_url : url);
3262 if (latest_url == target_url_)
3265 // Tell the browser to display a destination link.
3266 if (target_url_status_ == TARGET_INFLIGHT ||
3267 target_url_status_ == TARGET_PENDING) {
3268 // If we have a request in-flight, save the URL to be sent when we
3269 // receive an ACK to the in-flight request. We can happily overwrite
3270 // any existing pending sends.
3271 pending_target_url_ = latest_url;
3272 target_url_status_ = TARGET_PENDING;
3274 // URLs larger than |kMaxURLChars| cannot be sent through IPC -
3275 // see |ParamTraits<GURL>|.
3276 if (latest_url.GetString().length() > url::kMaxURLChars)
3277 latest_url = KURL();
3278 SendUpdatedTargetURLToBrowser(latest_url);
3279 target_url_ = latest_url;
3280 target_url_status_ = TARGET_INFLIGHT;
3284 void WebViewImpl::SendUpdatedTargetURLToBrowser(const KURL& target_url) {
3285 // Note: WTF::Unretained() usage below is safe, since `this` owns both
3286 // `mojo::Remote` objects.
3287 if (GetPage()->MainFrame()->IsLocalFrame()) {
3288 DCHECK(local_main_frame_host_remote_);
3289 local_main_frame_host_remote_->UpdateTargetURL(
3290 target_url, WTF::BindOnce(&WebViewImpl::TargetURLUpdatedInBrowser,
3291 WTF::Unretained(this)));
3293 DCHECK(remote_main_frame_host_remote_);
3294 remote_main_frame_host_remote_->UpdateTargetURL(
3295 target_url, WTF::BindOnce(&WebViewImpl::TargetURLUpdatedInBrowser,
3296 WTF::Unretained(this)));
3300 void WebViewImpl::TargetURLUpdatedInBrowser() {
3301 // Check if there is a targeturl waiting to be sent.
3302 if (target_url_status_ == TARGET_PENDING)
3303 SendUpdatedTargetURLToBrowser(pending_target_url_);
3305 target_url_status_ = TARGET_NONE;
3308 float WebViewImpl::DefaultMinimumPageScaleFactor() const {
3309 return GetPageScaleConstraintsSet().DefaultConstraints().minimum_scale;
3312 float WebViewImpl::DefaultMaximumPageScaleFactor() const {
3313 return GetPageScaleConstraintsSet().DefaultConstraints().maximum_scale;
3316 float WebViewImpl::MinimumPageScaleFactor() const {
3317 return GetPageScaleConstraintsSet().FinalConstraints().minimum_scale;
3320 float WebViewImpl::MaximumPageScaleFactor() const {
3321 return GetPageScaleConstraintsSet().FinalConstraints().maximum_scale;
3324 void WebViewImpl::ResetScaleStateImmediately() {
3325 GetPageScaleConstraintsSet().SetNeedsReset(true);
3328 void WebViewImpl::ResetScrollAndScaleState() {
3329 GetPage()->GetVisualViewport().Reset();
3331 auto* main_local_frame = DynamicTo<LocalFrame>(GetPage()->MainFrame());
3332 if (!main_local_frame)
3335 if (LocalFrameView* frame_view = main_local_frame->View()) {
3336 ScrollableArea* scrollable_area = frame_view->LayoutViewport();
3338 if (!scrollable_area->GetScrollOffset().IsZero()) {
3339 scrollable_area->SetScrollOffset(ScrollOffset(),
3340 mojom::blink::ScrollType::kProgrammatic);
3344 if (Document* document = main_local_frame->GetDocument()) {
3345 if (DocumentLoader* loader = document->Loader()) {
3346 if (HistoryItem* item = loader->GetHistoryItem())
3347 item->ClearViewState();
3351 GetPageScaleConstraintsSet().SetNeedsReset(true);
3354 void WebViewImpl::SendResizeEventForMainFrame() {
3355 // FIXME: This is wrong. The LocalFrameView is responsible sending a
3356 // resizeEvent as part of layout. Layout is also responsible for sending
3357 // invalidations to the embedder. This method and all callers may be wrong. --
3359 if (MainFrameImpl()->GetFrameView()) {
3360 // Enqueues the resize event.
3361 MainFrameImpl()->GetFrame()->GetDocument()->EnqueueResizeEvent();
3364 // A resized main frame can change the page scale limits.
3365 if (does_composite_) {
3366 auto& viewport = GetPage()->GetVisualViewport();
3367 MainFrameImpl()->FrameWidgetImpl()->SetPageScaleStateAndLimits(
3368 viewport.Scale(), viewport.IsPinchGestureActive(),
3369 MinimumPageScaleFactor(), MaximumPageScaleFactor());
3373 void WebViewImpl::ConfigureAutoResizeMode() {
3374 if (!MainFrameImpl() || !MainFrameImpl()->GetFrame() ||
3375 !MainFrameImpl()->GetFrame()->View())
3378 if (should_auto_resize_) {
3379 MainFrameImpl()->GetFrame()->View()->EnableAutoSizeMode(min_auto_size_,
3382 MainFrameImpl()->GetFrame()->View()->DisableAutoSizeMode();
3386 void WebViewImpl::SetCompositorDeviceScaleFactorOverride(
3387 float device_scale_factor) {
3388 if (compositor_device_scale_factor_override_ == device_scale_factor)
3390 compositor_device_scale_factor_override_ = device_scale_factor;
3391 if (zoom_factor_for_device_scale_factor_) {
3392 SetZoomLevel(ZoomLevel());
3397 void WebViewImpl::SetDeviceEmulationTransform(const gfx::Transform& transform) {
3398 if (transform == device_emulation_transform_)
3400 device_emulation_transform_ = transform;
3401 UpdateDeviceEmulationTransform();
3404 gfx::Transform WebViewImpl::GetDeviceEmulationTransform() const {
3405 return device_emulation_transform_;
3408 void WebViewImpl::EnableDeviceEmulation(const DeviceEmulationParams& params) {
3409 web_widget_->EnableDeviceEmulation(params);
3412 void WebViewImpl::ActivateDevToolsTransform(
3413 const DeviceEmulationParams& params) {
3414 gfx::Transform device_emulation_transform =
3415 dev_tools_emulator_->EnableDeviceEmulation(params);
3416 SetDeviceEmulationTransform(device_emulation_transform);
3419 void WebViewImpl::DisableDeviceEmulation() {
3420 web_widget_->DisableDeviceEmulation();
3423 void WebViewImpl::DeactivateDevToolsTransform() {
3424 dev_tools_emulator_->DisableDeviceEmulation();
3425 SetDeviceEmulationTransform(gfx::Transform());
3428 void WebViewImpl::PerformCustomContextMenuAction(unsigned action) {
3430 page_->GetContextMenuController().CustomContextMenuItemSelected(action);
3434 void WebViewImpl::DidCloseContextMenu() {
3435 LocalFrame* frame = page_->GetFocusController().FocusedFrame();
3437 frame->Selection().SetCaretBlinkingSuspended(false);
3440 SkColor WebViewImpl::BackgroundColor() const {
3441 if (background_color_override_for_fullscreen_controller_)
3442 return background_color_override_for_fullscreen_controller_.value();
3443 Page* page = page_.Get();
3445 return BaseBackgroundColor().Rgb();
3446 if (auto* main_local_frame = DynamicTo<LocalFrame>(page->MainFrame())) {
3447 LocalFrameView* view = main_local_frame->View();
3449 return view->DocumentBackgroundColor().Rgb();
3451 return BaseBackgroundColor().Rgb();
3454 Color WebViewImpl::BaseBackgroundColor() const {
3455 if (override_base_background_color_to_transparent_)
3456 return Color::kTransparent;
3457 // TODO(https://crbug.com/1351544): The base background color override should
3458 // be an SkColor4f or a Color.
3459 if (base_background_color_override_for_inspector_) {
3460 return Color::FromSkColor(
3461 base_background_color_override_for_inspector_.value());
3463 // Use the page background color if this is the WebView of the main frame.
3464 if (MainFrameImpl())
3465 return Color::FromSkColor(page_base_background_color_);
3466 return Color::kWhite;
3469 void WebViewImpl::SetPageBaseBackgroundColor(absl::optional<SkColor> color) {
3470 SkColor new_color = color.value_or(SK_ColorWHITE);
3471 if (page_base_background_color_ == new_color)
3473 page_base_background_color_ = new_color;
3474 UpdateBaseBackgroundColor();
3477 void WebViewImpl::SetBaseBackgroundColorOverrideTransparent(
3478 bool override_to_transparent) {
3479 DCHECK(does_composite_);
3480 if (override_base_background_color_to_transparent_ == override_to_transparent)
3482 override_base_background_color_to_transparent_ = override_to_transparent;
3483 UpdateBaseBackgroundColor();
3486 void WebViewImpl::SetBaseBackgroundColorOverrideForInspector(
3487 absl::optional<SkColor> optional_color) {
3488 if (base_background_color_override_for_inspector_ == optional_color)
3490 base_background_color_override_for_inspector_ = optional_color;
3491 UpdateBaseBackgroundColor();
3494 void WebViewImpl::UpdateBaseBackgroundColor() {
3495 if (MainFrameImpl()) {
3496 // Force lifecycle update to ensure we're good to call
3497 // LocalFrameView::setBaseBackgroundColor().
3498 MainFrameImpl()->GetFrame()->View()->UpdateAllLifecyclePhasesExceptPaint(
3499 DocumentUpdateReason::kBaseColor);
3502 Color color = BaseBackgroundColor();
3503 if (auto* local_frame = DynamicTo<LocalFrame>(page_->MainFrame())) {
3504 LocalFrameView* view = local_frame->View();
3505 view->UpdateBaseBackgroundColorRecursively(color);
3509 void WebViewImpl::UpdateFontRenderingFromRendererPrefs() {
3510 #if !BUILDFLAG(IS_MAC)
3511 skia::LegacyDisplayGlobals::SetCachedPixelGeometry(
3512 gfx::FontRenderParams::SubpixelRenderingToSkiaPixelGeometry(
3513 renderer_preferences_.subpixel_rendering));
3514 #if BUILDFLAG(IS_WIN)
3515 // Cache the system font metrics in blink.
3516 WebFontRendering::SetMenuFontMetrics(
3517 WebString::FromUTF16(renderer_preferences_.menu_font_family_name),
3518 renderer_preferences_.menu_font_height);
3519 WebFontRendering::SetSmallCaptionFontMetrics(
3520 WebString::FromUTF16(
3521 renderer_preferences_.small_caption_font_family_name),
3522 renderer_preferences_.small_caption_font_height);
3523 WebFontRendering::SetStatusFontMetrics(
3524 WebString::FromUTF16(renderer_preferences_.status_font_family_name),
3525 renderer_preferences_.status_font_height);
3526 WebFontRendering::SetAntialiasedTextEnabled(
3527 renderer_preferences_.should_antialias_text);
3528 WebFontRendering::SetLCDTextEnabled(
3529 renderer_preferences_.subpixel_rendering !=
3530 gfx::FontRenderParams::SUBPIXEL_RENDERING_NONE);
3532 WebFontRenderStyle::SetHinting(
3533 RendererPreferencesToSkiaHinting(renderer_preferences_));
3534 WebFontRenderStyle::SetAutoHint(renderer_preferences_.use_autohinter);
3535 WebFontRenderStyle::SetUseBitmaps(renderer_preferences_.use_bitmaps);
3536 WebFontRenderStyle::SetAntiAlias(renderer_preferences_.should_antialias_text);
3537 WebFontRenderStyle::SetSubpixelRendering(
3538 renderer_preferences_.subpixel_rendering !=
3539 gfx::FontRenderParams::SUBPIXEL_RENDERING_NONE);
3540 WebFontRenderStyle::SetSubpixelPositioning(
3541 renderer_preferences_.use_subpixel_positioning);
3542 // TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
3544 #if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && \
3545 !BUILDFLAG(IS_ANDROID)
3546 if (!renderer_preferences_.system_font_family_name.empty()) {
3547 WebFontRenderStyle::SetSystemFontFamily(blink::WebString::FromUTF8(
3548 renderer_preferences_.system_font_family_name));
3550 #endif // (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) &&
3551 // !BUILDFLAG(IS_ANDROID)
3552 #endif // BUILDFLAG(IS_WIN)
3553 #endif // !BUILDFLAG(IS_MAC)
3556 void WebViewImpl::ActivatePrerenderedPage(
3557 mojom::blink::PrerenderPageActivationParamsPtr
3558 prerender_page_activation_params,
3559 ActivatePrerenderedPageCallback callback) {
3560 TRACE_EVENT0("navigation", "WebViewImpl::ActivatePrerenderedPage");
3562 // From here all new documents will have prerendering false.
3563 GetPage()->SetIsPrerendering(false);
3565 // Collect local documents. This is because we are about to run the
3566 // prerenderchange event and post-prerendering activation steps on each
3567 // document, which could mutate the frame tree and make iteration over it
3569 HeapVector<Member<Document>> child_frame_documents;
3570 Member<Document> main_frame_document;
3571 if (auto* local_frame = DynamicTo<LocalFrame>(GetPage()->MainFrame())) {
3572 main_frame_document = local_frame->GetDocument();
3574 if (main_frame_document) {
3575 RecordPrerenderActivationSignalDelay();
3578 for (Frame* frame = GetPage()->MainFrame(); frame;
3579 frame = frame->Tree().TraverseNext()) {
3580 if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
3581 if (local_frame->GetDocument() != main_frame_document) {
3582 child_frame_documents.push_back(local_frame->GetDocument());
3587 // A null `activation_start` is sent to the WebViewImpl that does not host the
3588 // main frame, in which case we expect that it does not have any documents
3589 // since cross-origin documents are not loaded during prerendering.
3590 DCHECK((!main_frame_document && child_frame_documents.size() == 0) ||
3591 !prerender_page_activation_params->activation_start.is_null());
3592 // We also only send view_transition_state to the main frame.
3593 DCHECK(main_frame_document ||
3594 !prerender_page_activation_params->view_transition_state);
3596 if (main_frame_document) {
3597 main_frame_document->ActivateForPrerendering(
3598 *prerender_page_activation_params);
3599 prerender_page_activation_params->view_transition_state.reset();
3602 // While the spec says to post a task on the networking task source for each
3603 // document, we don't post a task here for simplicity. This allows dispatching
3604 // the event on all documents without a chance for other IPCs from the browser
3605 // to arrive in the intervening time, resulting in an unclear state.
3606 for (auto& document : child_frame_documents) {
3607 document->ActivateForPrerendering(*prerender_page_activation_params);
3610 std::move(callback).Run();
3613 void WebViewImpl::SetInsidePortal(bool inside_portal) {
3614 GetPage()->SetInsidePortal(inside_portal);
3616 // We may not have created the frame widget yet but that's ok because it'll
3617 // be created with this value correctly initialized. This can also be null if
3618 // the main frame is remote.
3620 web_widget_->SetIsNestedMainFrameWidget(inside_portal);
3623 void WebViewImpl::RegisterRendererPreferenceWatcher(
3624 CrossVariantMojoRemote<mojom::RendererPreferenceWatcherInterfaceBase>
3626 renderer_preference_watchers_.Add(std::move(watcher));
3629 void WebViewImpl::SetRendererPreferences(
3630 const RendererPreferences& preferences) {
3631 UpdateRendererPreferences(preferences);
3634 const RendererPreferences& WebViewImpl::GetRendererPreferences() const {
3635 return renderer_preferences_;
3638 void WebViewImpl::UpdateRendererPreferences(
3639 const RendererPreferences& preferences) {
3640 std::string old_accept_languages = renderer_preferences_.accept_languages;
3641 renderer_preferences_ = preferences;
3643 for (auto& watcher : renderer_preference_watchers_)
3644 watcher->NotifyUpdate(renderer_preferences_);
3646 WebThemeEngineHelper::DidUpdateRendererPreferences(preferences);
3647 UpdateFontRenderingFromRendererPrefs();
3649 blink::SetCaretBlinkInterval(
3650 renderer_preferences_.caret_blink_interval.has_value()
3651 ? renderer_preferences_.caret_blink_interval.value()
3652 : base::Milliseconds(
3653 mojom::blink::kDefaultCaretBlinkIntervalInMilliseconds));
3655 #if defined(USE_AURA)
3656 if (renderer_preferences_.use_custom_colors) {
3657 #if !BUILDFLAG(IS_TIZEN_TV)
3658 // It will set focus ring color to default, but for tizen TV,
3659 // focus ring color will be set in layout_theme_chromium_tizen.cc.
3660 SetFocusRingColor(renderer_preferences_.focus_ring_color);
3662 SetSelectionColors(renderer_preferences_.active_selection_bg_color,
3663 renderer_preferences_.active_selection_fg_color,
3664 renderer_preferences_.inactive_selection_bg_color,
3665 renderer_preferences_.inactive_selection_fg_color);
3670 #if !BUILDFLAG(IS_TIZEN_TV)
3671 // It will set focus ring color to default, but for tizen TV,
3672 // focus ring color will be set in layout_theme_chromium_tizen.cc.
3673 if (renderer_preferences_.use_custom_colors) {
3674 SetFocusRingColor(renderer_preferences_.focus_ring_color);
3678 if (old_accept_languages != renderer_preferences_.accept_languages)
3679 AcceptLanguagesChanged();
3681 GetSettings()->SetCaretBrowsingEnabled(
3682 renderer_preferences_.caret_browsing_enabled);
3684 #if BUILDFLAG(IS_OZONE)
3685 GetSettings()->SetSelectionClipboardBufferAvailable(
3686 renderer_preferences_.selection_clipboard_buffer_available);
3687 #endif // BUILDFLAG(IS_OZONE)
3689 SetExplicitlyAllowedPorts(
3690 renderer_preferences_.explicitly_allowed_network_ports);
3693 void WebViewImpl::SetHistoryOffsetAndLength(int32_t history_offset,
3694 int32_t history_length) {
3695 // -1 <= history_offset < history_length <= kMaxSessionHistoryEntries.
3696 DCHECK_LE(-1, history_offset);
3697 DCHECK_LT(history_offset, history_length);
3698 DCHECK_LE(history_length, kMaxSessionHistoryEntries);
3700 history_list_offset_ = history_offset;
3701 history_list_length_ = history_length;
3704 void WebViewImpl::SetHistoryListFromNavigation(
3705 int32_t history_offset,
3706 absl::optional<int32_t> history_length) {
3707 if (!history_length.has_value()) {
3708 history_list_offset_ = history_offset;
3712 SetHistoryOffsetAndLength(history_offset, *history_length);
3715 void WebViewImpl::IncreaseHistoryListFromNavigation() {
3716 // Advance our offset in session history, applying the length limit.
3717 // There is now no forward history.
3718 history_list_offset_ =
3719 std::min(history_list_offset_ + 1, kMaxSessionHistoryEntries - 1);
3720 history_list_length_ = history_list_offset_ + 1;
3723 int32_t WebViewImpl::HistoryBackListCount() const {
3724 return std::max(history_list_offset_, 0);
3727 int32_t WebViewImpl::HistoryForwardListCount() const {
3728 return history_list_length_ - HistoryBackListCount() - 1;
3731 void WebViewImpl::SetWebPreferences(
3732 const web_pref::WebPreferences& preferences) {
3733 UpdateWebPreferences(preferences);
3736 const web_pref::WebPreferences& WebViewImpl::GetWebPreferences() {
3737 return web_preferences_;
3740 void WebViewImpl::UpdateWebPreferences(
3741 const blink::web_pref::WebPreferences& preferences) {
3742 web_preferences_ = preferences;
3744 if (IsFencedFrameRoot()) {
3745 // The main frame of a fenced frame should not behave like a top level
3746 // frame in terms of viewport behavior. i.e. It shouldn't allow zooming,
3747 // either explicitly or to fit content, and it should not interpret the
3748 // viewport <meta> tag. Text autosizing is disabled since it is only
3749 // determined by the outermost page and having the outermost page pass
3750 // it into the fenced frame can create a communication channel.
3751 web_preferences_.viewport_enabled = false;
3752 web_preferences_.viewport_meta_enabled = false;
3753 web_preferences_.default_minimum_page_scale_factor = 1.f;
3754 web_preferences_.default_maximum_page_scale_factor = 1.f;
3755 web_preferences_.shrinks_viewport_contents_to_fit = false;
3756 web_preferences_.main_frame_resizes_are_orientation_changes = false;
3757 web_preferences_.text_autosizing_enabled = false;
3759 // Insecure content should not be allowed in a fenced frame.
3760 web_preferences_.allow_running_insecure_content = false;
3762 #if BUILDFLAG(IS_ANDROID)
3763 // Reusing the global for unowned main frame is only used for
3764 // Android WebView. Since this is a fenced frame it is not the
3765 // outermost main frame so we can safely disable this feature.
3766 web_preferences_.reuse_global_for_unowned_main_frame = false;
3770 if (MainFrameImpl()) {
3771 MainFrameImpl()->FrameWidgetImpl()->SetPrefersReducedMotion(
3772 web_preferences_.prefers_reduced_motion);
3775 ApplyWebPreferences(web_preferences_, this);
3776 ApplyCommandLineToSettings(SettingsImpl());
3779 #if BUILDFLAG(IS_TIZEN)
3780 void WebViewImpl::EnterDragState() {
3781 if (MainFrameImpl())
3782 MainFrameImpl()->EnterDragState();
3786 void WebViewImpl::AddObserver(WebViewObserver* observer) {
3787 observers_.AddObserver(observer);
3790 void WebViewImpl::RemoveObserver(WebViewObserver* observer) {
3791 observers_.RemoveObserver(observer);
3794 #if BUILDFLAG(IS_TIZEN_TV)
3795 bool WebViewImpl::IsHitScrollbar() {
3796 const LocalFrame* frame =
3797 DynamicTo<LocalFrame>(page_->GetFocusController().FocusedOrMainFrame());
3800 return frame->GetEventHandler().PressedScrollbar();
3803 bool WebViewImpl::IsMouseDownEventSwallowed() {
3804 if (!MainFrameImpl() || !MainFrameImpl()->GetFrame())
3806 return MainFrameImpl()
3809 .MousePressEventSwallowed();
3812 void WebViewImpl::SetFloatVideoWindowState(bool enable) {
3816 LOG(INFO) << __FUNCTION__ << " enable : " << enable;
3817 GetPage()->SetFloatVideoWindowState(enable);
3821 void WebViewImpl::SetIsActive(bool active) {
3823 GetPage()->GetFocusController().SetActive(active);
3826 bool WebViewImpl::IsActive() const {
3827 return GetPage() ? GetPage()->GetFocusController().IsActive() : false;
3830 void WebViewImpl::SetWindowFeatures(const WebWindowFeatures& features) {
3831 page_->SetWindowFeatures(features);
3834 void WebViewImpl::SetOpenedByDOM() {
3835 page_->SetOpenedByDOM();
3838 void WebViewImpl::DidCommitLoad(bool is_new_navigation,
3839 bool is_navigation_within_page) {
3840 if (!is_navigation_within_page) {
3842 web_widget_->ResetMeaningfulLayoutStateForMainFrame();
3844 if (is_new_navigation)
3845 GetPageScaleConstraintsSet().SetNeedsReset(true);
3848 // Give the visual viewport's scroll layer its initial size.
3849 GetPage()->GetVisualViewport().MainFrameDidChangeSize();
3852 void WebViewImpl::DidCommitCompositorFrameForLocalMainFrame() {
3853 for (auto& observer : observers_)
3854 observer.DidCommitCompositorFrame();
3857 void WebViewImpl::ResizeAfterLayout() {
3858 DCHECK(MainFrameImpl());
3860 if (!web_view_client_)
3863 if (should_auto_resize_) {
3864 LocalFrameView* view = MainFrameImpl()->GetFrame()->View();
3865 gfx::Size frame_size = view->Size();
3866 if (frame_size != size_) {
3869 GetPage()->GetVisualViewport().SetSize(size_);
3870 GetPageScaleConstraintsSet().DidChangeInitialContainingBlockSize(size_);
3872 web_view_client_->DidAutoResize(size_);
3873 web_widget_->DidAutoResize(size_);
3874 SendResizeEventForMainFrame();
3878 if (does_composite_ && GetPageScaleConstraintsSet().ConstraintsDirty())
3879 RefreshPageScaleFactor();
3881 resize_viewport_anchor_->ResizeFrameView(MainFrameSize());
3884 void WebViewImpl::MainFrameLayoutUpdated() {
3885 DCHECK(MainFrameImpl());
3886 if (!web_view_client_)
3889 for (auto& observer : observers_)
3890 observer.DidUpdateMainFrameLayout();
3891 needs_preferred_size_update_ = true;
3894 void WebViewImpl::DidChangeContentsSize() {
3895 auto* local_frame = DynamicTo<LocalFrame>(GetPage()->MainFrame());
3899 LocalFrameView* view = local_frame->View();
3901 int vertical_scrollbar_width = 0;
3902 if (view && view->LayoutViewport()) {
3903 Scrollbar* vertical_scrollbar = view->LayoutViewport()->VerticalScrollbar();
3904 if (vertical_scrollbar && !vertical_scrollbar->IsOverlayScrollbar())
3905 vertical_scrollbar_width = vertical_scrollbar->Width();
3908 GetPageScaleConstraintsSet().DidChangeContentsSize(
3909 ContentsSize(), vertical_scrollbar_width, PageScaleFactor());
3912 void WebViewImpl::PageScaleFactorChanged() {
3913 // This is called from the VisualViewport which only is used to control the
3914 // page scale/scroll viewport for a local main frame, and only when
3915 // compositing as PageScaleFactor doesn't exist otherwise.
3916 DCHECK(MainFrameImpl());
3917 DCHECK(does_composite_);
3919 GetPageScaleConstraintsSet().SetNeedsReset(false);
3920 // Set up the compositor and inform the browser of the PageScaleFactor,
3921 // which is tracked per-view.
3922 auto& viewport = GetPage()->GetVisualViewport();
3923 DCHECK(viewport.IsActiveViewport());
3924 MainFrameImpl()->FrameWidgetImpl()->SetPageScaleStateAndLimits(
3925 viewport.Scale(), viewport.IsPinchGestureActive(),
3926 MinimumPageScaleFactor(), MaximumPageScaleFactor());
3928 local_main_frame_host_remote_->ScaleFactorChanged(viewport.Scale());
3930 if (dev_tools_emulator_->HasViewportOverride()) {
3931 // TODO(bokan): Can HasViewportOverride be set on a nested main frame? If
3932 // not, we can enforce that when setting it and DCHECK IsOutermostMainFrame
3934 if (MainFrameImpl()->IsOutermostMainFrame()) {
3935 gfx::Transform device_emulation_transform =
3936 dev_tools_emulator_->OutermostMainFrameScrollOrScaleChanged();
3937 SetDeviceEmulationTransform(device_emulation_transform);
3942 void WebViewImpl::OutermostMainFrameScrollOffsetChanged() {
3943 DCHECK(MainFrameImpl());
3944 DCHECK(MainFrameImpl()->IsOutermostMainFrame());
3945 if (dev_tools_emulator_->HasViewportOverride()) {
3946 gfx::Transform device_emulation_transform =
3947 dev_tools_emulator_->OutermostMainFrameScrollOrScaleChanged();
3948 SetDeviceEmulationTransform(device_emulation_transform);
3952 void WebViewImpl::TextAutosizerPageInfoChanged(
3953 const mojom::blink::TextAutosizerPageInfo& page_info) {
3954 DCHECK(MainFrameImpl());
3955 local_main_frame_host_remote_->TextAutosizerPageInfoChanged(
3959 void WebViewImpl::SetBackgroundColorOverrideForFullscreenController(
3960 absl::optional<SkColor> optional_color) {
3961 DCHECK(does_composite_);
3963 background_color_override_for_fullscreen_controller_ = optional_color;
3964 if (MainFrameImpl()) {
3965 MainFrameImpl()->FrameWidgetImpl()->SetBackgroundColor(BackgroundColor());
3969 void WebViewImpl::SetZoomFactorOverride(float zoom_factor) {
3970 zoom_factor_override_ = zoom_factor;
3971 SetZoomLevel(ZoomLevel());
3974 Element* WebViewImpl::FocusedElement() const {
3975 LocalFrame* frame = page_->GetFocusController().FocusedFrame();
3979 Document* document = frame->GetDocument();
3983 return document->FocusedElement();
3986 WebHitTestResult WebViewImpl::HitTestResultForTap(
3987 const gfx::Point& tap_point_window_pos,
3988 const gfx::Size& tap_area) {
3989 auto* main_frame = DynamicTo<LocalFrame>(page_->MainFrame());
3991 return HitTestResult();
3993 WebGestureEvent tap_event(WebInputEvent::Type::kGestureTap,
3994 WebInputEvent::kNoModifiers, base::TimeTicks::Now(),
3995 WebGestureDevice::kTouchscreen);
3996 // GestureTap is only ever from a touchscreen.
3997 tap_event.SetPositionInWidget(gfx::PointF(tap_point_window_pos));
3998 tap_event.data.tap.tap_count = 1;
3999 tap_event.data.tap.width = tap_area.width();
4000 tap_event.data.tap.height = tap_area.height();
4002 WebGestureEvent scaled_event =
4003 TransformWebGestureEvent(MainFrameImpl()->GetFrameView(), tap_event);
4005 HitTestResult result =
4006 main_frame->GetEventHandler()
4007 .HitTestResultForGestureEvent(
4008 scaled_event, HitTestRequest::kReadOnly | HitTestRequest::kActive)
4009 .GetHitTestResult();
4011 result.SetToShadowHostIfInUAShadowRoot();
4015 void WebViewImpl::SetTabsToLinks(bool enable) {
4016 tabs_to_links_ = enable;
4019 bool WebViewImpl::TabsToLinks() const {
4020 return tabs_to_links_;
4023 void WebViewImpl::DidChangeRootLayer(bool root_layer_exists) {
4024 // The Layer is removed when the main frame's `Document` changes. It also is
4025 // removed when the whole `LocalFrame` goes away, in which case we don't
4026 // need to DeferMainFrameUpdate() as we will do so if a local MainFrame is
4027 // attached in the future.
4028 if (!MainFrameImpl()) {
4029 DCHECK(!root_layer_exists);
4032 if (root_layer_exists) {
4033 if (!device_emulation_transform_.IsIdentity())
4034 UpdateDeviceEmulationTransform();
4036 // When the document in an already-attached main frame is being replaced by
4037 // a navigation then DidChangeRootLayer(false) will be called. Since we are
4038 // navigating, defer BeginMainFrames until the new document is ready for
4041 // TODO(crbug.com/936696): This should not be needed once we always swap
4042 // frames when swapping documents.
4043 scoped_defer_main_frame_update_ =
4044 MainFrameImpl()->FrameWidgetImpl()->DeferMainFrameUpdate();
4048 void WebViewImpl::InvalidateContainer() {
4049 // This is only for non-composited WebViewPlugin.
4050 if (!does_composite_ && web_view_client_)
4051 web_view_client_->InvalidateContainer();
4054 void WebViewImpl::ApplyViewportChanges(const ApplyViewportChangesArgs& args) {
4055 // TODO(https://crbug.com/1160652): Figure out if Page is null.
4058 VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
4059 DCHECK(visual_viewport.IsActiveViewport());
4061 // Store the desired offsets the visual viewport before setting the top
4062 // controls ratio since doing so will change the bounds and move the
4063 // viewports to keep the offsets valid. The compositor may have already
4064 // done that so we don't want to double apply the deltas here.
4065 gfx::PointF visual_viewport_offset = visual_viewport.VisibleRect().origin();
4066 visual_viewport_offset.Offset(args.inner_delta.x(), args.inner_delta.y());
4068 GetBrowserControls().SetShownRatio(
4069 GetBrowserControls().TopShownRatio() + args.top_controls_delta,
4070 GetBrowserControls().BottomShownRatio() + args.bottom_controls_delta);
4072 SetPageScaleFactorAndLocation(PageScaleFactor() * args.page_scale_delta,
4073 args.is_pinch_gesture_active,
4074 visual_viewport_offset);
4076 if (args.page_scale_delta != 1) {
4077 double_tap_zoom_pending_ = false;
4080 elastic_overscroll_ += args.elastic_overscroll_delta;
4081 UpdateBrowserControlsConstraint(args.browser_controls_constraint);
4083 if (args.scroll_gesture_did_end) {
4084 // TODO(https://crbug.com/1160652): Figure out if MainFrameImpl is null.
4085 CHECK(MainFrameImpl());
4086 MainFrameImpl()->GetFrame()->GetEventHandler().MarkHoverStateDirty();
4090 Node* WebViewImpl::FindNodeFromScrollableCompositorElementId(
4091 cc::ElementId element_id) const {
4095 if (element_id == GetPage()->GetVisualViewport().GetScrollElementId()) {
4096 // Return the Document in this case since the window.visualViewport DOM
4097 // object is not a node.
4098 if (MainFrameImpl())
4099 return MainFrameImpl()->GetDocument();
4102 if (!GetPage()->GetScrollingCoordinator())
4104 ScrollableArea* scrollable_area =
4106 ->GetScrollingCoordinator()
4107 ->ScrollableAreaWithElementIdInAllLocalFrames(element_id);
4108 if (!scrollable_area || !scrollable_area->GetLayoutBox())
4111 return scrollable_area->GetLayoutBox()->GetNode();
4114 void WebViewImpl::UpdateDeviceEmulationTransform() {
4115 if (GetPage()->GetVisualViewport().IsActiveViewport())
4116 GetPage()->GetVisualViewport().SetNeedsPaintPropertyUpdate();
4118 if (auto* main_frame = MainFrameImpl()) {
4119 // When the device emulation transform is updated, to avoid incorrect
4120 // scales and fuzzy raster from the compositor, force all content to
4121 // pick ideal raster scales.
4122 // TODO(wjmaclean): This is only done on the main frame's widget currently,
4123 // it should update all local frames.
4124 main_frame->FrameWidgetImpl()->SetNeedsRecalculateRasterScales();
4126 // Device emulation transform also affects the overriding visible rect
4127 // which is used as the overflow rect of the main frame layout view.
4128 if (auto* view = main_frame->GetFrameView())
4129 view->SetNeedsPaintPropertyUpdate();
4133 PageScheduler* WebViewImpl::Scheduler() const {
4135 return GetPage()->GetPageScheduler();
4138 void WebViewImpl::SetVisibilityState(
4139 mojom::blink::PageVisibilityState visibility_state,
4140 bool is_initial_state) {
4142 GetPage()->SetVisibilityState(visibility_state, is_initial_state);
4143 // Do not throttle if the page should be painting.
4145 visibility_state == mojom::blink::PageVisibilityState::kVisible;
4146 if (RuntimeEnabledFeatures::DispatchHiddenVisibilityTransitionsEnabled()) {
4147 // Treat `kHiddenButPainting` as visible for page scheduling; we don't want
4148 // to throttle timers, etc.
4149 is_visible |= visibility_state ==
4150 mojom::blink::PageVisibilityState::kHiddenButPainting;
4152 GetPage()->GetPageScheduler()->SetPageVisible(is_visible);
4153 // Notify observers of the change.
4154 if (!is_initial_state) {
4155 for (auto& observer : observers_)
4156 observer.OnPageVisibilityChanged(visibility_state);
4160 mojom::blink::PageVisibilityState WebViewImpl::GetVisibilityState() {
4162 return GetPage()->GetVisibilityState();
4165 LocalFrame* WebViewImpl::FocusedLocalFrameInWidget() const {
4166 if (!MainFrameImpl())
4169 auto* focused_frame = To<LocalFrame>(FocusedCoreFrame());
4170 if (focused_frame->LocalFrameRoot() != MainFrameImpl()->GetFrame())
4172 return focused_frame;
4175 void WebViewImpl::SetPageFrozen(bool frozen) {
4176 Scheduler()->SetPageFrozen(frozen);
4179 WebFrameWidget* WebViewImpl::MainFrameWidget() {
4183 void WebViewImpl::AddAutoplayFlags(int32_t value) {
4184 page_->AddAutoplayFlags(value);
4187 void WebViewImpl::ClearAutoplayFlags() {
4188 page_->ClearAutoplayFlags();
4191 int32_t WebViewImpl::AutoplayFlagsForTest() {
4192 return page_->AutoplayFlags();
4195 gfx::Size WebViewImpl::GetPreferredSizeForTest() {
4196 return preferred_size_in_dips_;
4199 void WebViewImpl::StopDeferringMainFrameUpdate() {
4200 scoped_defer_main_frame_update_ = nullptr;
4203 void WebViewImpl::SetDeviceColorSpaceForTesting(
4204 const gfx::ColorSpace& color_space) {
4205 web_widget_->SetDeviceColorSpaceForTesting(color_space);
4208 const SessionStorageNamespaceId& WebViewImpl::GetSessionStorageNamespaceId() {
4209 CHECK(!session_storage_namespace_id_.empty());
4210 return session_storage_namespace_id_;
4213 bool WebViewImpl::IsFencedFrameRoot() const {
4214 return GetPage()->IsMainFrameFencedFrameRoot();
4217 void WebViewImpl::MojoDisconnected() {
4218 // This IPC can be called from re-entrant contexts. We can't destroy a
4219 // RenderViewImpl while references still exist on the stack, so we dispatch a
4220 // non-nestable task. This method is called exactly once by the browser
4221 // process, and is used to release ownership of the corresponding
4222 // RenderViewImpl instance. https://crbug.com/1000035.
4223 GetPage()->GetAgentGroupScheduler().DefaultTaskRunner()->PostNonNestableTask(
4224 FROM_HERE, WTF::BindOnce(&WebViewImpl::Close, WTF::Unretained(this)));
4227 void WebViewImpl::CreateRemoteMainFrame(
4228 const RemoteFrameToken& frame_token,
4229 const absl::optional<FrameToken>& opener_frame_token,
4230 mojom::blink::FrameReplicationStatePtr replicated_state,
4232 const base::UnguessableToken& devtools_frame_token,
4233 mojom::blink::RemoteFrameInterfacesFromBrowserPtr remote_frame_interfaces,
4234 mojom::blink::RemoteMainFrameInterfacesPtr remote_main_frame_interfaces) {
4235 blink::WebFrame* opener = nullptr;
4236 if (opener_frame_token)
4237 opener = WebFrame::FromFrameToken(*opener_frame_token);
4238 // Create a top level WebRemoteFrame.
4239 WebRemoteFrameImpl::CreateMainFrame(
4240 this, frame_token, is_loading, devtools_frame_token, opener,
4241 std::move(remote_frame_interfaces->frame_host),
4242 std::move(remote_frame_interfaces->frame_receiver),
4243 std::move(replicated_state));
4244 // Root frame proxy has no ancestors to point to their RenderWidget.
4246 // The WebRemoteFrame created here was already attached to the Page as its
4247 // main frame, so we can call WebView's DidAttachRemoteMainFrame().
4248 DidAttachRemoteMainFrame(
4249 std::move(remote_main_frame_interfaces->main_frame_host),
4250 std::move(remote_main_frame_interfaces->main_frame));
4253 scheduler::WebAgentGroupScheduler& WebViewImpl::GetWebAgentGroupScheduler() {
4254 return web_agent_group_scheduler_;
4257 void WebViewImpl::UpdatePageBrowsingContextGroup(
4258 const BrowsingContextGroupInfo& browsing_context_group_info) {
4259 Page* page = GetPage();
4262 page->UpdateBrowsingContextGroup(browsing_context_group_info);
4265 void WebViewImpl::SetPageAttributionSupport(
4266 network::mojom::AttributionSupport support) {
4267 Page* page = GetPage();
4270 page->SetAttributionSupport(support);
4273 #if BUILDFLAG(IS_EFL)
4274 bool WebViewImpl::PaintSoftBitmap(SkCanvas* canvas, const gfx::Rect& rect) {
4278 if (!MainFrameImpl() || !MainFrameImpl()->GetFrameView())
4281 LocalFrameView* view = MainFrameImpl()->GetFrameView();
4282 view->UpdateAllLifecyclePhases(DocumentUpdateReason::kOverlay);
4284 gfx::PointF offset = MainFrame()->ToWebLocalFrame()->GetScrollOffset();
4285 gfx::Rect dirty_rect(rect.x() + offset.x(), rect.y() + offset.y(),
4286 rect.width(), rect.height());
4287 PaintRecordBuilder builder;
4289 // FIXME: scaleFactor should be ideally pagescalefactor * devicescale
4290 // here we are assuming pagescalefactor as 1 always, this needs to
4291 // be taken care with a proper fix for capturing zoomed contents.
4292 LocalFrame& frame = view->GetFrame();
4293 ChromeClient& chrome_client = frame.GetChromeClient();
4294 float scale_factor = chrome_client.GetScreenInfo(frame).device_scale_factor;
4295 GraphicsContext& context = builder.Context();
4296 #if !defined(EWK_BRINGUP) // FIXME: m114 bringup
4297 context.SetDeviceScaleFactor(scale_factor);
4299 AffineTransform transform;
4300 transform.Scale(scale_factor);
4301 transform.Translate(static_cast<float>(-dirty_rect.x()),
4302 static_cast<float>(-dirty_rect.y()));
4304 // FIXME: Use the page-background color to clear instead for half
4306 SkColor color = SkColorSetARGB(0xff, 0xff, 0xff, 0xff);
4307 canvas->clear(color);
4308 view->PaintOutsideOfLifecycle(context, PaintFlag::kOmitCompositingInfo,
4309 CullRect(dirty_rect));
4311 builder.EndRecording().Playback(canvas);
4315 bool WebViewImpl::HasAcceleratedCanvasWithinViewport() const {
4316 if (!MainFrameImpl() || !MainFrameImpl()->GetFrameView())
4319 Document* document = MainFrameImpl()->GetFrame()->GetDocument();
4323 StaticElementList* canvas_elements =
4324 document->QuerySelectorAll(AtomicString("canvas"), ASSERT_NO_EXCEPTION);
4325 if (!canvas_elements)
4328 gfx::Rect visible_content_rect =
4329 MainFrameImpl()->GetFrameView()->LayoutViewport()->VisibleContentRect();
4330 for (unsigned i = 0; i < canvas_elements->length(); ++i) {
4331 if (visible_content_rect.Intersects(
4332 canvas_elements->item(i)->BoundsInWidget())) {
4340 gfx::Rect WebViewImpl::CurrentSelectionRect() const {
4344 LocalFrame* frame = DynamicTo<LocalFrame>(
4345 GetPage()->GetFocusController().FocusedOrMainFrame());
4349 FrameSelection& selection = frame->Selection();
4350 if (!selection.ComputeVisibleSelectionInDOMTreeDeprecated().IsRange())
4353 Range* range = CreateRange(frame->Selection()
4354 .ComputeVisibleSelectionInDOMTreeDeprecated()
4355 .ToNormalizedEphemeralRange());
4359 Vector<gfx::QuadF> quads;
4360 gfx::RectF result_rect;
4361 range->TextAndImagesBoundingBox(quads);
4362 for (const gfx::QuadF& quad : quads)
4363 result_rect.Union(quad.BoundingBox());
4364 gfx::Rect selection_rect =
4365 frame->View()->FrameToViewport(gfx::ToEnclosingRect(result_rect));
4366 return gfx::Rect(selection_rect);
4369 void WebViewImpl::SetLongPollingGlobalTimeout(uint64_t timeout) {
4372 GetPage()->SetLongPollingGlobalTimeout(timeout);
4375 void WebViewImpl::ScrollFocusedNodeIntoView() {
4376 if (Element* element = FocusedElement())
4377 element->scrollIntoViewIfNeeded(true /*centerIfNeeded*/);
4380 bool WebViewImpl::FiltersInSelectElement(WebView::TraverseFocusThrough filter) {
4381 return static_cast<bool>((char)filter &
4382 (char)WebView::TraverseFocusThrough::SelectElement);
4385 bool WebViewImpl::FiltersInEditableElement(
4386 WebView::TraverseFocusThrough filter) {
4387 return static_cast<bool>(
4388 (char)filter & (char)WebView::TraverseFocusThrough::EditableElement);
4391 bool WebViewImpl::IsFormNavigationTextInput(Element& element) const {
4392 if (element.HasTagName(html_names::kInputTag) &&
4393 DynamicTo<HTMLInputElement>(element)->IsReadOnly()) {
4396 #if !defined(EWK_BRINGUP) // FIXME: m114 bringup
4397 LayoutObject* renderer = element.GetLayoutObject();
4399 (IsEditable(element) || renderer->IsTextControlIncludingNG());
4405 bool WebViewImpl::IsSelectElement(const Element& element) const {
4406 return element.GetLayoutObject() &&
4407 element.HasTagName(html_names::kSelectTag);
4410 gfx::Rect WebViewImpl::GetElementBounds(const Element& element) const {
4411 element.GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kFocus);
4412 gfx::Rect absolute_rect = ToPixelSnappedRect(element.Node::BoundingBox());
4413 return (element.GetDocument().View()
4414 ? element.GetDocument().View()->FrameToViewport(absolute_rect)
4418 bool WebViewImpl::PerformClickOnElement(Element& element) {
4419 if (gfx::Rect() == GetElementBounds(element))
4422 // Set focus to false to compare it with focusedElement of document.
4425 Element* focus_element = FocusedElement();
4427 if (!focus_element || focus_element != &element)
4430 // SimulatedClickCreationScope::kFromAccessibility simulates MouseUpDown
4432 focus_element->DispatchSimulatedClick(
4433 nullptr, SimulatedClickCreationScope::kFromAccessibility);
4435 if (IsFormNavigationTextInput(*focus_element)) {
4436 LocalFrame* focused_frame = DynamicTo<LocalFrame>(FocusedCoreFrame());
4437 WebTextInputInfo info =
4438 focused_frame->GetInputMethodController().TextInputInfo();
4439 focused_frame->GetInputMethodController().SetEditableSelectionOffsets(
4440 PlainTextRange(info.selection_start, info.selection_end));
4446 Element* WebViewImpl::NextTextOrSelectElement(Element* element,
4447 TraverseFocusThrough filter) {
4451 Element* next_element = element;
4453 if (next_element->IsFrameOwnerElement()) {
4454 HTMLFrameOwnerElement& htmlFrameOwnerElement =
4455 *DynamicTo<HTMLFrameOwnerElement>(next_element);
4457 // Checks if the frame is empty or not.
4458 if (!htmlFrameOwnerElement.ContentFrame())
4461 Document* owner_document = htmlFrameOwnerElement.contentDocument();
4462 if (!owner_document || !(next_element = owner_document->body()))
4465 // Checks if content editable flag on body has set.
4466 if (IsEditable(*next_element) && FiltersInEditableElement(filter))
4467 return next_element;
4470 while ((next_element = ElementTraversal::Next(*next_element))) {
4471 if (next_element->HasTagName(html_names::kIFrameTag) ||
4472 next_element->HasTagName(html_names::kFrameTag)) {
4473 Element* frame_owner_element = next_element;
4475 next_element = NextTextOrSelectElement(next_element, filter);
4476 if (!next_element) {
4477 next_element = frame_owner_element;
4481 if (FiltersInSelectElement(filter) && IsSelectElement(*next_element))
4485 // If couldn't find anything in the current document scope,
4486 // try finding in other document scope if present any.
4487 if (!next_element) {
4488 if (element->GetDocument().GetFrame() != MainFrameImpl()->GetFrame() &&
4489 !element->IsFrameOwnerElement()) {
4490 next_element = NextTextOrSelectElement(
4491 ElementTraversal::Next(*element->GetDocument().LocalOwner()), filter);
4495 return next_element;
4498 Element* WebViewImpl::PreviousTextOrSelectElement(Element* element,
4499 TraverseFocusThrough filter) {
4503 Element* previous_element = element;
4505 if (previous_element->IsFrameOwnerElement()) {
4506 HTMLFrameOwnerElement& htmlFrameOwnerElement =
4507 *DynamicTo<HTMLFrameOwnerElement>(previous_element);
4508 // Checks if the frame is empty or not.
4509 if (!htmlFrameOwnerElement.ContentFrame())
4512 Document* owner_document = htmlFrameOwnerElement.contentDocument();
4513 if (!owner_document)
4516 previous_element = owner_document->lastElementChild();
4517 while (previous_element && ElementTraversal::FirstWithin(*previous_element))
4518 previous_element = previous_element->lastElementChild();
4520 if (!previous_element)
4523 if (previous_element->IsFocusable()) {
4524 if (FiltersInEditableElement(filter) &&
4525 IsFormNavigationTextInput(*previous_element))
4526 return previous_element;
4527 if (FiltersInSelectElement(filter) && IsSelectElement(*previous_element))
4528 return previous_element;
4532 while ((previous_element = ElementTraversal::Previous(*previous_element))) {
4533 if (previous_element->HasTagName(html_names::kIFrameTag) ||
4534 previous_element->HasTagName(html_names::kFrameTag)) {
4535 Element* frame_owner_element = previous_element;
4537 previous_element = PreviousTextOrSelectElement(previous_element, filter);
4538 if (!previous_element) {
4539 previous_element = frame_owner_element;
4544 if (!previous_element->IsFocusable())
4547 if (FiltersInEditableElement(filter) &&
4548 IsFormNavigationTextInput(*previous_element)) {
4552 if (FiltersInSelectElement(filter) && IsSelectElement(*previous_element))
4556 // If couldn't find anything in the current document scope,
4557 // try finding in other document scope if present any.
4558 if (!previous_element &&
4559 element->GetDocument().GetFrame() != MainFrameImpl()->GetFrame() &&
4560 !element->IsFrameOwnerElement()) {
4561 previous_element = PreviousTextOrSelectElement(
4562 ElementTraversal::Previous(*element->GetDocument().LocalOwner()),
4566 return previous_element;
4569 bool WebViewImpl::MoveFocusToNext(TraverseFocusThrough filter) {
4570 Element* focus_element = FocusedElement();
4571 if (!focus_element || (!IsFormNavigationTextInput(*focus_element) &&
4572 !IsSelectElement(*focus_element))) {
4576 Element* next_element = NextTextOrSelectElement(focus_element, filter);
4580 // Scroll the element into center of screen.
4581 next_element->scrollIntoViewIfNeeded(true /*centerIfNeeded*/);
4583 bool handled = PerformClickOnElement(*next_element);
4585 if (FocusedFrame() && IsFormNavigationTextInput(*next_element))
4586 FocusedFrame()->ExecuteCommand(WebString::FromUTF8("MoveToEndOfDocument"));
4591 bool WebViewImpl::MoveFocusToPrevious(TraverseFocusThrough filter) {
4592 Element* focus_element = FocusedElement();
4594 if (!focus_element || (!IsFormNavigationTextInput(*focus_element) &&
4595 !IsSelectElement(*focus_element))) {
4599 Element* previous_element =
4600 PreviousTextOrSelectElement(focus_element, filter);
4601 if (!previous_element)
4604 // Scroll the element into center of screen.
4605 previous_element->scrollIntoViewIfNeeded(true /*centerIfNeeded*/);
4607 bool handled = PerformClickOnElement(*previous_element);
4609 if (FocusedFrame() && IsFormNavigationTextInput(*previous_element))
4610 FocusedFrame()->ExecuteCommand(WebString::FromUTF8("MoveToEndOfDocument"));
4615 void WebViewImpl::SetScrollOffset(float x, float y) {
4616 if (auto* focused_frame = FocusedFrame())
4617 focused_frame->SetScrollOffset(gfx::PointF(x, y));
4620 #if BUILDFLAG(IS_TIZEN_TV)
4621 void WebViewImpl::SuspendNetworkLoading() {
4625 GetPage()->SetDefersLoading(true);
4628 void WebViewImpl::ResumeNetworkLoading() {
4632 GetPage()->SetDefersLoading(false);
4634 #endif // IS_TIZEN_TV
4637 #if defined(TIZEN_VIDEO_HOLE)
4638 bool WebViewImpl::IsVideoHoleForRender() const {
4639 return GetPage()->GetSettings().GetVideoHoleEnabled();
4643 #if BUILDFLAG(IS_TIZEN_TV)
4644 bool WebViewImpl::EdgeScrollBy(const ScrollOffset& scroll_offset,
4645 const gfx::Point& mouse_point) {
4646 if (!MainFrameImpl())
4648 const LocalFrameView* view = MainFrameImpl()->GetFrameView();
4652 LayoutView* const layout_view = view->GetLayoutView();
4656 const gfx::Point point(mouse_point);
4657 HitTestLocation location(point);
4658 const HitTestRequest request(HitTestRequest::kReadOnly |
4659 HitTestRequest::kAllowChildFrameContent);
4660 HitTestResult result(request, location);
4662 layout_view->HitTest(location, result);
4664 const LocalFrame* frame = result.InnerNodeFrame();
4666 frame = DynamicTo<LocalFrame>(
4667 page_->GetFocusController().FocusedOrMainFrame());
4670 return frame->GetEventHandler().ScrollWithMultiplier(scroll_offset,
4671 result.InnerNode());
4674 void WebViewImpl::SetTranslatedURL(const WebString url) {
4675 if (!MainFrameImpl())
4678 for (const Frame* frame = MainFrameImpl()->GetFrame(); frame;
4679 frame = frame->Tree().TraverseNext()) {
4680 Document* document = To<LocalFrame>(frame)->GetDocument();
4682 document->SetTranslatedURL(url);
4686 void WebViewImpl::SetParentalRatingResult(const WebString& url, bool is_pass) {
4687 if (!MainFrameImpl()){
4688 LOG(ERROR) << "no main frame.";
4692 for (const Frame* frame = MainFrameImpl()->GetFrame(); frame;
4693 frame = frame->Tree().TraverseNext()) {
4694 Document* document = To<LocalFrame>(frame)->GetDocument();
4696 document->SetParentalRatingResult(url, is_pass);
4700 bool WebViewImpl::IsVideoPlaying() const {
4701 if (!MainFrameImpl()){
4702 LOG(ERROR) << "no main frame.";
4706 for (const Frame* frame = MainFrameImpl()->GetFrame(); frame;
4707 frame = frame->Tree().TraverseNext()) {
4708 Document* document = To<LocalFrame>(frame)->GetDocument();
4710 if (document->IsVideoPlaying())
4715 void WebViewImpl::SetPreferTextLang(const WebString& lang) {
4716 if (!MainFrameImpl()) {
4717 LOG(ERROR) << "no main frame.";
4721 for (const Frame* frame = MainFrameImpl()->GetFrame(); frame;
4722 frame = frame->Tree().TraverseNext()) {
4723 Document* document = To<LocalFrame>(frame)->GetDocument();
4725 document->SetPreferTextLang(lang);
4730 } // namespace blink