[M120 Migration] Fix show IME
[platform/framework/web/chromium-efl.git] / third_party / blink / renderer / core / exported / web_view_impl.cc
1 /*
2  * Copyright (C) 2011, 2012 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
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
13  * distribution.
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.
17  *
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.
29  */
30 #include "third_party/blink/renderer/core/exported/web_view_impl.h"
31
32 #include <algorithm>
33 #include <memory>
34 #include <utility>
35
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"
187
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"
192 #endif
193
194 #if BUILDFLAG(IS_WIN)
195 #include "third_party/blink/public/web/win/web_font_rendering.h"
196 #endif
197
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"
204 #endif
205
206 #if BUILDFLAG(IS_TIZEN)
207 #include "tizen/system_info.h"
208 #endif
209
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"
215 #endif
216
217 // Get rid of WTF's pow define so we can use std::pow.
218 #undef pow
219 #include <cmath>  // for std::pow
220
221 #include "build/chromeos_buildflags.h"
222
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;
234
235 static constexpr base::TimeDelta kFindInPageAnimationDuration;
236
237 // Constants for viewport anchoring on resize.
238 static const float viewportAnchorCoordX = 0.5f;
239 static const float viewportAnchorCoordY = 0;
240
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;
249
250 namespace blink {
251
252 using mojom::blink::EffectiveConnectionType;
253
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;
259
260 // static
261 HashSet<WebViewImpl*>& WebViewImpl::AllInstances() {
262   DEFINE_STATIC_LOCAL(HashSet<WebViewImpl*>, all_instances, ());
263   return all_instances;
264 }
265
266 static bool g_should_use_external_popup_menus = false;
267
268 void WebView::SetUseExternalPopupMenus(bool use_external_popup_menus) {
269   g_should_use_external_popup_menus = use_external_popup_menus;
270 }
271
272 bool WebViewImpl::UseExternalPopupMenus() {
273   return g_should_use_external_popup_menus;
274 }
275
276 namespace {
277
278 class EmptyEventListener final : public NativeEventListener {
279  public:
280   void Invoke(ExecutionContext* execution_context, Event*) override {}
281 };
282
283 typedef void (*SetFontFamilyWrapper)(blink::WebSettings*,
284                                      const std::u16string&,
285                                      UScriptCode);
286
287 void SetStandardFontFamilyWrapper(WebSettings* settings,
288                                   const std::u16string& font,
289                                   UScriptCode script) {
290   settings->SetStandardFontFamily(WebString::FromUTF16(font), script);
291 }
292
293 void SetFixedFontFamilyWrapper(WebSettings* settings,
294                                const std::u16string& font,
295                                UScriptCode script) {
296   settings->SetFixedFontFamily(WebString::FromUTF16(font), script);
297 }
298
299 void SetSerifFontFamilyWrapper(WebSettings* settings,
300                                const std::u16string& font,
301                                UScriptCode script) {
302   settings->SetSerifFontFamily(WebString::FromUTF16(font), script);
303 }
304
305 void SetSansSerifFontFamilyWrapper(WebSettings* settings,
306                                    const std::u16string& font,
307                                    UScriptCode script) {
308   settings->SetSansSerifFontFamily(WebString::FromUTF16(font), script);
309 }
310
311 void SetCursiveFontFamilyWrapper(WebSettings* settings,
312                                  const std::u16string& font,
313                                  UScriptCode script) {
314   settings->SetCursiveFontFamily(WebString::FromUTF16(font), script);
315 }
316
317 void SetFantasyFontFamilyWrapper(WebSettings* settings,
318                                  const std::u16string& font,
319                                  UScriptCode script) {
320   settings->SetFantasyFontFamily(WebString::FromUTF16(font), script);
321 }
322
323 void SetMathFontFamilyWrapper(WebSettings* settings,
324                               const std::u16string& font,
325                               UScriptCode script) {
326   settings->SetMathFontFamily(WebString::FromUTF16(font), script);
327 }
328
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;
344     case USCRIPT_KOREAN:
345       return USCRIPT_HANGUL;
346     default:
347       return scriptCode;
348   }
349 }
350
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));
359     }
360   }
361 }
362
363 void ApplyCommandLineToSettings(WebSettings* settings) {
364   const base::CommandLine& command_line =
365       *base::CommandLine::ForCurrentProcess();
366
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);
377   }
378
379   WebString network_quiet_timeout = WebString::FromUTF8(
380       command_line.GetSwitchValueASCII(switches::kNetworkQuietTimeout));
381   if (!network_quiet_timeout.IsEmpty()) {
382     bool ok;
383     double network_quiet_timeout_seconds =
384         String(network_quiet_timeout).ToDouble(&ok);
385     if (ok)
386       settings->SetNetworkQuietTimeout(network_quiet_timeout_seconds);
387   }
388
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)));
399     }
400   }
401 }
402
403 ui::mojom::blink::WindowOpenDisposition NavigationPolicyToDisposition(
404     NavigationPolicy policy) {
405   switch (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();
422   }
423   NOTREACHED() << "Unexpected NavigationPolicy";
424   return ui::mojom::blink::WindowOpenDisposition::IGNORE_ACTION;
425 }
426
427 // Records the queuing duration for activation IPC.
428 void RecordPrerenderActivationSignalDelay() {
429   auto* task = base::TaskAnnotator::CurrentTaskForThread();
430
431   // It should be a Mojo call, so `RunTask` executes it as a non-delayed task.
432   CHECK(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
436                                   : base::TimeDelta();
437   base::UmaHistogramTimes("Prerender.Experimental.ActivationIPCDelay",
438                           queueing_time);
439 }
440
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
445 // complete.
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;
458       default:
459         NOTREACHED();
460         return SkFontHinting::kNormal;
461     }
462   }
463 #endif
464
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;
474     default:
475       NOTREACHED();
476       return SkFontHinting::kNormal;
477   }
478 }
479 #endif  // !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_WIN)
480
481 }  // namespace
482
483 // WebView ----------------------------------------------------------------
484
485 WebView* WebView::Create(
486     WebViewClient* client,
487     bool is_hidden,
488     bool is_prerendering,
489     bool is_inside_portal,
490     absl::optional<blink::FencedFrame::DeprecatedFencedFrameMode>
491         fenced_frame_mode,
492     bool compositing_enabled,
493     bool widgets_never_composited,
494     WebView* opener,
495     CrossVariantMojoAssociatedReceiver<mojom::PageBroadcastInterfaceBase>
496         page_handle,
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(
502       client,
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);
509 }
510
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>
517         fenced_frame_mode,
518     bool compositing_enabled,
519     bool widgets_never_composited,
520     WebViewImpl* opener,
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));
534   web_view->AddRef();
535   return web_view.get();
536 }
537
538 size_t WebView::GetWebViewCount() {
539   return WebViewImpl::AllInstances().size();
540 }
541
542 void WebView::UpdateVisitedLinkState(uint64_t link_hash) {
543   Page::VisitedStateChanged(link_hash);
544 }
545
546 void WebView::ResetVisitedLinkState(bool invalidate_visited_link_hashes) {
547   Page::AllVisitedStateChanged(invalidate_visited_link_hashes);
548 }
549
550 void WebViewImpl::SetNoStatePrefetchClient(
551     WebNoStatePrefetchClient* no_state_prefetch_client) {
552   DCHECK(page_);
553   ProvideNoStatePrefetchClientTo(*page_,
554                                  MakeGarbageCollected<NoStatePrefetchClient>(
555                                      *page_, no_state_prefetch_client));
556 }
557
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.
566   GetPage()
567       ->GetPageScheduler()
568       ->GetAgentGroupScheduler()
569       .DefaultTaskRunner()
570       ->PostTask(FROM_HERE,
571                  WTF::BindOnce(&WebViewImpl::DoDeferredCloseWindowSoon,
572                                weak_ptr_factory_.GetWeakPtr()));
573 }
574
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();
583   } else {
584     DCHECK(remote_main_frame_host_remote_);
585     remote_main_frame_host_remote_->RouteCloseEvent();
586   }
587 }
588
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>
595         fenced_frame_mode,
596     bool does_composite,
597     bool widgets_never_composited,
598     WebViewImpl* opener,
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)),
613       receiver_(this,
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) {
618   if (receiver_) {
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)));
626   }
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_);
635
636   SetVisibilityState(visibility, /*is_initial_state=*/true);
637   page_->SetIsPrerendering(is_prerendering);
638
639   // We pass this state to Page, but it's only used by the main frame in the
640   // page.
641   SetInsidePortal(is_inside_portal);
642
643   if (fenced_frame_mode && features::IsFencedFramesEnabled()) {
644     page_->SetIsMainFrameFencedFrameRoot();
645     page_->SetDeprecatedFencedFrameMode(*fenced_frame_mode);
646   } else {
647     // `fenced_frame_mode` should only be set if creating an MPArch
648     // fenced frame.
649     DCHECK(!fenced_frame_mode);
650   }
651
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.
655   if (does_composite_)
656     page_->GetSettings().SetAcceleratedCompositingEnabled(true);
657
658   dev_tools_emulator_ = MakeGarbageCollected<DevToolsEmulator>(this);
659
660   AllInstances().insert(this);
661
662   resize_viewport_anchor_ = MakeGarbageCollected<ResizeViewportAnchor>(*page_);
663
664   // Ensure we have valid page scale constraints even if the embedder never
665   // changes defaults.
666   GetPageScaleConstraintsSet().ComputeFinalConstraints();
667 }
668
669 WebViewImpl::~WebViewImpl() {
670   DCHECK(!page_);
671 }
672
673 WebDevToolsAgentImpl* WebViewImpl::MainFrameDevToolsAgentImpl() {
674   WebLocalFrameImpl* main_frame = MainFrameImpl();
675   return main_frame ? main_frame->DevToolsAgentImpl() : nullptr;
676 }
677
678 void WebViewImpl::SetTabKeyCyclesThroughElements(bool value) {
679   if (page_)
680     page_->SetTabKeyCyclesThroughElements(value);
681 }
682
683 bool WebViewImpl::StartPageScaleAnimation(const gfx::Point& target_position,
684                                           bool use_anchor,
685                                           float new_scale,
686                                           base::TimeDelta duration) {
687   // PageScaleFactor is a property of the main frame only, and only exists when
688   // compositing.
689   DCHECK(MainFrameImpl());
690   DCHECK(does_composite_);
691
692   VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
693   DCHECK(visual_viewport.IsActiveViewport());
694
695   gfx::Point clamped_point = target_position;
696   if (!use_anchor) {
697     clamped_point =
698         visual_viewport.ClampDocumentOffsetAtScale(target_position, new_scale);
699
700     // TODO(bokan): Why special case duration zero? PageScaleAnimation should
701     // work ok for that.
702     if (duration.is_zero()) {
703       SetPageScaleFactor(new_scale);
704
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);
710       }
711
712       return false;
713     }
714   }
715   if (use_anchor && new_scale == PageScaleFactor())
716     return false;
717
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;
722   } else {
723     MainFrameImpl()->FrameWidgetImpl()->StartPageScaleAnimation(
724         target_position, use_anchor, new_scale, duration);
725   }
726   return true;
727 }
728
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;
734 }
735
736 void WebViewImpl::AcceptLanguagesChanged() {
737   FontCache::AcceptLanguagesChanged(
738       String::FromUTF8(renderer_preferences_.accept_languages));
739
740   if (!GetPage())
741     return;
742
743   GetPage()->AcceptLanguagesChanged();
744 }
745
746 gfx::Rect WebViewImpl::WidenRectWithinPageBounds(const gfx::Rect& source,
747                                                  int target_margin,
748                                                  int minimum_margin) {
749   // Caller should guarantee that the main frame exists and is local.
750   DCHECK(MainFrame());
751   DCHECK(MainFrame()->IsWebLocalFrame());
752   gfx::Size max_size = MainFrame()->ToWebLocalFrame()->DocumentSize();
753   gfx::PointF scroll_offset = MainFrame()->ToWebLocalFrame()->GetScrollOffset();
754
755   int left_margin = target_margin;
756   int right_margin = target_margin;
757
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);
762   }
763
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));
769   }
770
771   const int new_width = source.width() + left_margin + right_margin;
772   const int new_x = source.x() - left_margin;
773
774   DCHECK_GE(new_width, 0);
775   DCHECK_LE(scroll_offset.x() + new_x + new_width, max_size.width());
776
777   return gfx::Rect(new_x, source.y(), new_width, source.height());
778 }
779
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.
785   if (GetPage()) {
786     return maximum_legible_scale_ *
787            GetPage()->GetSettings().GetAccessibilityFontScaleFactor();
788   }
789   return maximum_legible_scale_;
790 }
791
792 void WebViewImpl::ComputeScaleAndScrollForBlockRect(
793     const gfx::Point& hit_point_in_root_frame,
794     const gfx::Rect& block_rect_in_root_frame,
795     float padding,
796     float default_scale_when_already_legible,
797     float& scale,
798     gfx::Point& scroll) {
799   DCHECK(GetPage()->GetVisualViewport().IsActiveViewport());
800   scale = PageScaleFactor();
801   scroll = gfx::Point();
802
803   gfx::Rect rect = block_rect_in_root_frame;
804
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
813     // don't.
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);
823   }
824
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)
830   // though.
831
832   float screen_width = size_.width() / scale;
833   float screen_height = size_.height() / scale;
834
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()));
839   } else {
840     // Ensure position we're zooming to (+ padding) isn't off the bottom of
841     // the screen.
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.
845
846   // Do the same thing for horizontal alignment.
847   if (rect.width() < screen_width) {
848     rect.Offset(-0.5 * (screen_width - rect.width()), 0);
849   } else {
850     rect.set_x(std::max<float>(
851         rect.x(), hit_point_in_root_frame.x() + padding - screen_width));
852   }
853   scroll.set_x(rect.x());
854   scroll.set_y(rect.y());
855
856   scale = ClampPageScaleFactorToLimits(scale);
857   scroll = MainFrameImpl()->GetFrameView()->RootFrameToDocument(scroll);
858   scroll =
859       GetPage()->GetVisualViewport().ClampDocumentOffsetAtScale(scroll, scale);
860 }
861
862 static Node* FindLinkHighlightAncestor(Node* node) {
863   // Go up the tree to find the node that defines a mouse cursor style
864   while (node) {
865     const LinkHighlightCandidate type = node->IsLinkHighlightCandidate();
866     if (type == LinkHighlightCandidate::kYes)
867       return node;
868     if (type == LinkHighlightCandidate::kNo)
869       return nullptr;
870     node = LayoutTreeBuilderTraversal::Parent(*node);
871   }
872   return nullptr;
873 }
874
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);
882 }
883 #endif
884
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");
890
891   Page* page = page_.Get();
892   if (!page || !page->MainFrame())
893     return nullptr;
894
895   Node* best_touch_node = targeted_tap_event.GetHitTestResult().InnerNode();
896   if (!best_touch_node)
897     return nullptr;
898
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)
904       return nullptr;
905   }
906
907   // Editable nodes should not be highlighted (e.g., <input>)
908   if (IsEditable(*best_touch_node))
909     return nullptr;
910
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;
915     do {
916       if (IsClickableOrFocusable(focusable)) {
917         if (focusable->IsContainerNode() && !focusable->IsLink()) {
918           auto child =
919               static_cast<const ContainerNode*>(focusable)->firstChild();
920           while (child) {
921             if (IsClickableOrFocusable(child))
922               return nullptr;
923
924             child = NodeTraversal::Next(*child, focusable);
925           }
926         }
927         return focusable;
928       }
929     } while (focusable && (focusable = focusable->parentNode()));
930   }
931 #endif
932
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) {
936     return nullptr;
937   }
938
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.
943   do {
944     best_touch_node = hand_cursor_ancestor;
945     hand_cursor_ancestor = FindLinkHighlightAncestor(
946         LayoutTreeBuilderTraversal::Parent(*best_touch_node));
947   } while (hand_cursor_ancestor);
948
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())
955     return nullptr;
956
957   return best_touch_node;
958 }
959
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);
967 }
968
969 void WebViewImpl::AnimateDoubleTapZoom(const gfx::Point& point_in_root_frame,
970                                        const gfx::Rect& rect_to_zoom) {
971   DCHECK(MainFrameImpl());
972
973   float scale;
974   gfx::Point scroll;
975
976   ComputeScaleAndScrollForBlockRect(
977       point_in_root_frame, rect_to_zoom, touchPointPadding,
978       MinimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio, scale,
979       scroll);
980
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_;
985
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;
989
990   bool is_animating;
991
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);
999   } else {
1000     is_animating = StartPageScaleAnimation(scroll, false, scale,
1001                                            kDoubleTapZoomAnimationDuration);
1002   }
1003
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.
1008   if (is_animating) {
1009     double_tap_zoom_page_scale_factor_ = scale;
1010     double_tap_zoom_pending_ = true;
1011   }
1012 }
1013
1014 void WebViewImpl::ZoomToFindInPageRect(const gfx::Rect& rect_in_root_frame) {
1015   DCHECK(MainFrameImpl());
1016
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),
1021           true);
1022
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.
1026     return;
1027   }
1028
1029   float scale;
1030   gfx::Point scroll;
1031
1032   ComputeScaleAndScrollForBlockRect(rect_in_root_frame.origin(), block_bounds,
1033                                     nonUserInitiatedPointPadding,
1034                                     MinimumPageScaleFactor(), scale, scroll);
1035
1036   StartPageScaleAnimation(scroll, false, scale, kFindInPageAnimationDuration);
1037 }
1038
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
1047   // not run.
1048   GetPage()->GetContextMenuController().ClearContextMenu();
1049
1050   {
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);
1063   }
1064 }
1065 #else
1066 WebInputEventResult WebViewImpl::SendContextMenuEvent() {
1067   return WebInputEventResult::kNotHandled;
1068 }
1069 #endif
1070
1071 WebPagePopupImpl* WebViewImpl::OpenPagePopup(PagePopupClient* client) {
1072   DCHECK(client);
1073
1074   // This guarantees there is never more than 1 PagePopup active at a time.
1075   CancelPagePopup();
1076   DCHECK(!page_popup_);
1077
1078   LocalFrame* opener_frame = client->OwnerElement().GetDocument().GetFrame();
1079   WebLocalFrameImpl* web_opener_frame =
1080       WebLocalFrameImpl::FromFrame(opener_frame);
1081
1082   mojo::PendingAssociatedRemote<mojom::blink::Widget> widget;
1083   mojo::PendingAssociatedReceiver<mojom::blink::Widget> widget_receiver =
1084       widget.InitWithNewEndpointAndPassReceiver();
1085
1086   mojo::PendingAssociatedRemote<mojom::blink::WidgetHost> widget_host;
1087   mojo::PendingAssociatedReceiver<mojom::blink::WidgetHost>
1088       widget_host_receiver = widget_host.InitWithNewEndpointAndPassReceiver();
1089
1090   mojo::PendingAssociatedRemote<mojom::blink::PopupWidgetHost>
1091       popup_widget_host;
1092   mojo::PendingAssociatedReceiver<mojom::blink::PopupWidgetHost>
1093       popup_widget_host_receiver =
1094           popup_widget_host.InitWithNewEndpointAndPassReceiver();
1095
1096   opener_frame->GetLocalFrameHostRemote().CreateNewPopupWidget(
1097       std::move(popup_widget_host_receiver), std::move(widget_host_receiver),
1098       std::move(widget));
1099   WebFrameWidgetImpl* opener_widget = web_opener_frame->LocalRootFrameWidget();
1100
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();
1112 }
1113
1114 void WebViewImpl::CancelPagePopup() {
1115   if (page_popup_)
1116     page_popup_->Cancel();
1117 }
1118
1119 void WebViewImpl::ClosePagePopup(PagePopup* popup) {
1120   DCHECK(popup);
1121   auto* popup_impl = To<WebPagePopupImpl>(popup);
1122   DCHECK_EQ(page_popup_.get(), popup_impl);
1123   if (page_popup_.get() != popup_impl)
1124     return;
1125   page_popup_->ClosePopup();
1126 }
1127
1128 void WebViewImpl::CleanupPagePopup() {
1129   page_popup_ = nullptr;
1130   DisablePopupMouseWheelEventListener();
1131 }
1132
1133 void WebViewImpl::UpdatePagePopup() {
1134   if (page_popup_)
1135     page_popup_->Update();
1136 }
1137
1138 void WebViewImpl::EnablePopupMouseWheelEventListener(
1139     WebLocalFrameImpl* local_root) {
1140   DCHECK(!popup_mouse_wheel_event_listener_);
1141   Document* document = local_root->GetDocument();
1142   DCHECK(document);
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;
1150 }
1151
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();
1158   DCHECK(document);
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(),
1163                                 false);
1164   local_root_with_empty_mouse_wheel_listener_ = nullptr;
1165 }
1166
1167 LocalDOMWindow* WebViewImpl::PagePopupWindow() const {
1168   return page_popup_ ? page_popup_->Window() : nullptr;
1169 }
1170
1171 Frame* WebViewImpl::FocusedCoreFrame() const {
1172   Page* page = page_.Get();
1173   return page ? page->GetFocusController().FocusedOrMainFrame() : nullptr;
1174 }
1175
1176 // WebWidget ------------------------------------------------------------------
1177
1178 void WebViewImpl::Close() {
1179   // Closership is a single relationship, so only 1 call to Close() should
1180   // occur.
1181   CHECK(page_);
1182   DCHECK(AllInstances().Contains(this));
1183   AllInstances().erase(this);
1184
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.
1187   CancelPagePopup();
1188
1189   // Invalidate any weak ptrs as we are starting to shutdown.
1190   weak_ptr_factory_.InvalidateWeakPtrs();
1191   receiver_.reset();
1192
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
1195   // frame tree.
1196   page_->WillBeDestroyed();
1197   page_.Clear();
1198
1199   if (web_view_client_)
1200     web_view_client_->OnDestruct();
1201
1202   // Reset the delegate to prevent notifications being sent as we're being
1203   // deleted.
1204   web_view_client_ = nullptr;
1205
1206   for (auto& observer : observers_)
1207     observer.WebViewDestroyed();
1208
1209   Release();  // Balances a reference acquired in WebView::Create
1210 }
1211
1212 gfx::Size WebViewImpl::Size() {
1213   return size_;
1214 }
1215
1216 void WebViewImpl::ResizeVisualViewport(const gfx::Size& new_size) {
1217   GetPage()->GetVisualViewport().SetSize(new_size);
1218   GetPage()->GetVisualViewport().ClampToBoundaries();
1219 }
1220
1221 void WebViewImpl::DidFirstVisuallyNonEmptyPaint() {
1222   DCHECK(MainFrameImpl());
1223   local_main_frame_host_remote_->DidFirstVisuallyNonEmptyPaint();
1224 }
1225
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()));
1237   }
1238
1239   GetPageScaleConstraintsSet().DidChangeInitialContainingBlockSize(icb_size);
1240
1241   UpdatePageDefinedViewportConstraints(MainFrameImpl()
1242                                            ->GetFrame()
1243                                            ->GetDocument()
1244                                            ->GetViewportData()
1245                                            .GetViewportDescription());
1246   UpdateMainFrameLayoutSize();
1247
1248   GetPage()->GetVisualViewport().SetSize(visible_viewport_size);
1249
1250   if (MainFrameImpl()->GetFrameView()) {
1251     if (!MainFrameImpl()->GetFrameView()->NeedsLayout())
1252       resize_viewport_anchor_->ResizeFrameView(MainFrameSize());
1253   }
1254
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();
1259 }
1260
1261 void WebViewImpl::UpdateBrowserControlsConstraint(
1262     cc::BrowserControlsState constraint) {
1263   cc::BrowserControlsState old_permitted_state =
1264       GetBrowserControls().PermittedState();
1265
1266   GetBrowserControls().UpdateConstraintsAndState(
1267       constraint, cc::BrowserControlsState::kBoth);
1268
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
1272   // changed.
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());
1278   }
1279 }
1280
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.
1285   //
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.
1290   //
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())
1297     return;
1298
1299   WebFrameWidgetImpl* widget = main_frame->LocalRootFrameWidget();
1300   widget->SetBrowserControlsShownRatio(GetBrowserControls().TopShownRatio(),
1301                                        GetBrowserControls().BottomShownRatio());
1302   widget->SetBrowserControlsParams(GetBrowserControls().Params());
1303
1304   VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
1305   DCHECK(visual_viewport.IsActiveViewport());
1306
1307   {
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_);
1314
1315     visual_viewport.SetBrowserControlsAdjustment(
1316         GetBrowserControls().UnreportedSizeAdjustment());
1317   }
1318 }
1319
1320 #if BUILDFLAG(IS_TIZEN)
1321 void WebViewImpl::PauseScheduledTasks() {
1322   if (!MainFrameImpl())
1323     return;
1324
1325   if (Page* page = GetPage()) {
1326     page->SetIsSuspended(true);
1327     page->SetPaused(true);
1328   }
1329
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);
1335 #endif
1336 }
1337
1338 void WebViewImpl::UnpauseScheduledTasks() {
1339   if (!MainFrameImpl())
1340     return;
1341   Page* page = GetPage();
1342   if (!page)
1343     return;
1344 #if BUILDFLAG(IS_TIZEN_TV)
1345   // If floating video window existed and not current page, need to prevent
1346   // media resume
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);
1353     } else {
1354       page->NotifyViewResumedByTabSwitching(false);
1355     }
1356   }
1357   MainFrameImpl()->FrameWidgetImpl()->SetCompositorVisible(true);
1358 #endif
1359
1360   page->SetIsSuspended(false);
1361   page->SetPaused(false);
1362 }
1363 #endif
1364
1365 BrowserControls& WebViewImpl::GetBrowserControls() {
1366   return GetPage()->GetBrowserControls();
1367 }
1368
1369 void WebViewImpl::ResizeViewWhileAnchored(
1370     cc::BrowserControlsParams params,
1371     const gfx::Size& visible_viewport_size) {
1372   DCHECK(MainFrameImpl());
1373
1374   bool old_viewport_shrink = GetBrowserControls().ShrinkViewport();
1375
1376   GetBrowserControls().SetParams(params);
1377
1378   if (old_viewport_shrink != GetBrowserControls().ShrinkViewport())
1379     MainFrameImpl()->GetFrameView()->DynamicViewportUnitsChanged();
1380
1381   {
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();
1390     }
1391   }
1392
1393   fullscreen_controller_->UpdateSize();
1394
1395   if (!scoped_defer_main_frame_update_) {
1396     // Page scale constraints may need to be updated; running layout now will
1397     // do that.
1398     MainFrameWidget()->UpdateLifecycle(WebLifecycleUpdate::kLayout,
1399                                        DocumentUpdateReason::kSizeChange);
1400   }
1401 }
1402
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(
1409       new_size, new_size,
1410       {top_controls_height, GetBrowserControls().TopMinHeight(),
1411        bottom_controls_height, GetBrowserControls().BottomMinHeight(),
1412        GetBrowserControls().AnimateHeightChanges(),
1413        browser_controls_shrink_layout});
1414 }
1415
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);
1424     return;
1425   }
1426
1427   if (size_ == main_frame_widget_size &&
1428       GetPage()->GetVisualViewport().Size() == visible_viewport_size &&
1429       GetBrowserControls().Params() == browser_controls_params)
1430     return;
1431
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);
1441     return;
1442   }
1443
1444   WebLocalFrameImpl* main_frame = MainFrameImpl();
1445   if (!main_frame)
1446     return;
1447
1448   LocalFrameView* view = main_frame->GetFrameView();
1449   if (!view)
1450     return;
1451
1452   VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
1453
1454   bool is_rotation =
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;
1460
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);
1473   } else {
1474     DCHECK(visual_viewport.IsActiveViewport());
1475     ResizeViewportAnchor::ResizeScope resize_scope(*resize_viewport_anchor_);
1476     ResizeViewWhileAnchored(browser_controls_params, visible_viewport_size);
1477   }
1478
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();
1485 }
1486
1487 void WebViewImpl::Resize(const gfx::Size& new_size) {
1488   if (should_auto_resize_ || size_ == new_size)
1489     return;
1490
1491   ResizeWithBrowserControls(new_size, GetBrowserControls().TopHeight(),
1492                             GetBrowserControls().BottomHeight(),
1493                             GetBrowserControls().ShrinkViewport());
1494 }
1495
1496 void WebViewImpl::SetScreenOrientationOverrideForTesting(
1497     absl::optional<display::mojom::blink::ScreenOrientation> orientation) {
1498   screen_orientation_override_ = orientation;
1499
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());
1506       }
1507     }
1508   }
1509 }
1510
1511 void WebViewImpl::SetWindowRectSynchronouslyForTesting(
1512     const gfx::Rect& new_window_rect) {
1513   web_widget_->SetWindowRectSynchronouslyForTesting(new_window_rect);
1514 }
1515
1516 absl::optional<display::mojom::blink::ScreenOrientation>
1517 WebViewImpl::ScreenOrientationOverride() {
1518   return screen_orientation_override_;
1519 }
1520
1521 void WebViewImpl::DidEnterFullscreen() {
1522   fullscreen_controller_->DidEnterFullscreen();
1523 }
1524
1525 void WebViewImpl::DidExitFullscreen() {
1526   fullscreen_controller_->DidExitFullscreen();
1527 }
1528
1529 void WebViewImpl::SetMainFrameViewWidget(WebFrameWidgetImpl* widget) {
1530   DCHECK(!widget || widget->ForMainFrame());
1531   web_widget_ = widget;
1532 }
1533
1534 void WebViewImpl::SetMouseOverURL(const KURL& url) {
1535   mouse_over_url_ = url;
1536   UpdateTargetURL(mouse_over_url_, focus_url_);
1537 }
1538
1539 void WebViewImpl::SetKeyboardFocusURL(const KURL& url) {
1540   focus_url_ = url;
1541   UpdateTargetURL(focus_url_, mouse_over_url_);
1542 }
1543
1544 WebFrameWidgetImpl* WebViewImpl::MainFrameViewWidget() {
1545   return web_widget_;
1546 }
1547
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());
1554
1555   if (rect.IsEmpty())
1556     return;
1557
1558   LocalFrameView& main_view = *MainFrameImpl()->GetFrame()->View();
1559   // TODO(crbug.com/1442088): Investigate the reason.
1560   if (!main_view.GetLayoutView()
1561            ->FirstFragment()
1562            .HasLocalBorderBoxProperties()) {
1563     return;
1564   }
1565   DCHECK_EQ(main_view.GetLayoutView()->GetDocument().Lifecycle().GetState(),
1566             DocumentLifecycle::kPaintClean);
1567
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()
1575                                      ->FirstFragment()
1576                                      .LocalBorderBoxProperties()
1577                                      .Unalias());
1578 }
1579
1580 // static
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,
1588                     settings);
1589   ApplyFontsFromMap(prefs.serif_font_family_map, SetSerifFontFamilyWrapper,
1590                     settings);
1591   ApplyFontsFromMap(prefs.sans_serif_font_family_map,
1592                     SetSansSerifFontFamilyWrapper, settings);
1593   ApplyFontsFromMap(prefs.cursive_font_family_map, SetCursiveFontFamilyWrapper,
1594                     settings);
1595   ApplyFontsFromMap(prefs.fantasy_font_family_map, SetFantasyFontFamilyWrapper,
1596                     settings);
1597   ApplyFontsFromMap(prefs.math_font_family_map, SetMathFontFamilyWrapper,
1598                     settings);
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);
1629
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);
1637
1638   settings->SetWebGL1Enabled(prefs.webgl1_enabled);
1639   settings->SetWebGL2Enabled(prefs.webgl2_enabled);
1640
1641   // Enable WebGL errors to the JS console if requested.
1642   settings->SetWebGLErrorsToConsoleEnabled(
1643       prefs.webgl_errors_to_console_enabled);
1644
1645   settings->SetHideScrollbars(prefs.hide_scrollbars);
1646
1647   RuntimeEnabledFeatures::SetWebKitScrollbarStylingEnabled(
1648       prefs.enable_webkit_scrollbar_styling);
1649
1650   // Enable gpu-accelerated 2d canvas if requested on the command line.
1651   RuntimeEnabledFeatures::SetAccelerated2dCanvasEnabled(
1652       prefs.accelerated_2d_canvas_enabled);
1653
1654   RuntimeEnabledFeatures::SetCanvas2dLayersEnabled(
1655       prefs.canvas_2d_layers_enabled);
1656
1657   // Disable antialiasing for 2d canvas if requested on the command line.
1658   settings->SetAntialiased2dCanvasEnabled(
1659       !prefs.antialiased_2d_canvas_disabled);
1660
1661   // Disable antialiasing of clips for 2d canvas if requested on the command
1662   // line.
1663   settings->SetAntialiasedClips2dCanvasEnabled(
1664       prefs.antialiased_clips_2d_canvas_enabled);
1665
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);
1669
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);
1676
1677   settings->SetStrictlyBlockBlockableMixedContent(
1678       prefs.strictly_block_blockable_mixed_content);
1679
1680   settings->SetStrictMixedContentCheckingForPlugin(
1681       prefs.block_mixed_plugin_content);
1682
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);
1695
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);
1706
1707   settings->SetEditingBehavior(prefs.editing_behavior);
1708
1709   settings->SetSupportsMultipleWindows(prefs.supports_multiple_windows);
1710
1711   settings->SetMainFrameClipsContent(!prefs.record_whole_document);
1712
1713   RuntimeEnabledFeatures::SetStylusHandwritingEnabled(
1714       prefs.stylus_handwriting_enabled);
1715
1716   settings->SetSmartInsertDeleteEnabled(prefs.smart_insert_delete_enabled);
1717
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);
1724
1725   settings->SetSelectionIncludesAltImageText(true);
1726
1727   RuntimeEnabledFeatures::SetFakeNoAllocDirectCallForTestingEnabled(
1728       prefs.fake_no_alloc_direct_call_for_testing_enabled);
1729
1730   settings->SetV8CacheOptions(prefs.v8_cache_options);
1731
1732   settings->SetImageAnimationPolicy(prefs.animation_policy);
1733
1734   settings->SetPresentationRequiresUserGesture(
1735       prefs.user_gesture_required_for_presentation);
1736
1737   if (prefs.text_tracks_enabled) {
1738     settings->SetTextTrackKindUserPreference(
1739         WebSettings::TextTrackKindUserPreference::kCaptions);
1740   } else {
1741     settings->SetTextTrackKindUserPreference(
1742         WebSettings::TextTrackKindUserPreference::kDefault);
1743   }
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));
1763
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);
1768
1769   // Needs to happen before SetIgnoreViewportTagScaleLimits below.
1770   web_view->SetDefaultPageScaleLimits(prefs.default_minimum_page_scale_factor,
1771                                       prefs.default_maximum_page_scale_factor);
1772
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));
1779
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);
1786 #endif
1787
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);
1796 #endif
1797
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);
1808   }
1809 #endif
1810
1811 #if BUILDFLAG(IS_TIZEN)
1812   settings->SetLinkEffectEnabled(prefs.link_effect_enabled);
1813 #endif
1814
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);
1848
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)
1865
1866 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
1867   RuntimeEnabledFeatures::SetWebAuthEnabled(!prefs.disable_webauthn);
1868 #endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
1869
1870   settings->SetForceDarkModeEnabled(prefs.force_dark_mode_enabled);
1871
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);
1883
1884   settings->SetMainFrameResizesAreOrientationChanges(
1885       prefs.main_frame_resizes_are_orientation_changes);
1886
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);
1891
1892   settings->SetHideDownloadUI(prefs.hide_download_ui);
1893
1894   settings->SetPresentationReceiver(prefs.presentation_receiver);
1895
1896   settings->SetMediaControlsEnabled(prefs.media_controls_enabled);
1897
1898   settings->SetLowPriorityIframesThreshold(
1899       static_cast<blink::WebEffectiveConnectionType>(
1900           prefs.low_priority_iframes_threshold));
1901
1902   settings->SetPictureInPictureEnabled(prefs.picture_in_picture_enabled &&
1903                                        ::features::UseSurfaceLayerForVideo());
1904
1905   settings->SetLazyLoadEnabled(prefs.lazy_load_enabled);
1906   settings->SetPreferredColorScheme(prefs.preferred_color_scheme);
1907   settings->SetPreferredContrast(prefs.preferred_contrast);
1908
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);
1913
1914 #if defined(TIZEN_VIDEO_HOLE)
1915   settings->SetVideoHoleEnabled(prefs.video_hole_enabled);
1916 #endif
1917
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));
1922   }
1923 #endif
1924
1925 #if BUILDFLAG(IS_MAC)
1926   web_view_impl->SetMaximumLegibleScale(
1927       prefs.default_maximum_page_scale_factor);
1928 #endif
1929
1930 #if BUILDFLAG(IS_WIN)
1931   RuntimeEnabledFeatures::SetMiddleClickAutoscrollEnabled(true);
1932 #endif
1933
1934   RuntimeEnabledFeatures::SetTranslateServiceEnabled(
1935       prefs.translate_service_available);
1936
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()
1943               ->GetSettings()
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());
1957     }
1958   }
1959 #endif
1960
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);
1965   }
1966 }
1967
1968 void WebViewImpl::ThemeChanged() {
1969   if (auto* page = GetPage())
1970     page->InvalidatePaint();
1971 }
1972
1973 void WebViewImpl::EnterFullscreen(LocalFrame& frame,
1974                                   const FullscreenOptions* options,
1975                                   FullscreenRequestType request_type) {
1976   fullscreen_controller_->EnterFullscreen(frame, options, request_type);
1977 }
1978
1979 void WebViewImpl::ExitFullscreen(LocalFrame& frame) {
1980   fullscreen_controller_->ExitFullscreen(frame);
1981 }
1982
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);
1989 }
1990
1991 bool WebViewImpl::HasHorizontalScrollbar() {
1992   return MainFrameImpl()
1993       ->GetFrameView()
1994       ->LayoutViewport()
1995       ->HorizontalScrollbar();
1996 }
1997
1998 bool WebViewImpl::HasVerticalScrollbar() {
1999   return MainFrameImpl()->GetFrameView()->LayoutViewport()->VerticalScrollbar();
2000 }
2001
2002 void WebViewImpl::SetPageFocus(bool enable) {
2003   page_->GetFocusController().SetFocused(enable);
2004   if (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()
2010                          .IsNone()) {
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());
2025         }
2026       }
2027 #if BUILDFLAG(IS_TIZEN_TV)
2028       // Trigger auto show IME when webview focus in
2029       if (IsHbbTV()) {
2030         if (MainFrameImpl() && MainFrameImpl()->FrameWidgetImpl()) {
2031           MainFrameImpl()
2032               ->FrameWidgetImpl()
2033               ->DidUpdateTextOfFocusedElementByNonUserInput();
2034         }
2035       }
2036
2037       if (element) {
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();
2043         if (cache)
2044           cache->HandleFocusedUIElementChanged(0, element);
2045       } else {
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";
2050           GetPage()
2051               ->GetSpatialNavigationController()
2052               .HandleSpatialNavigationDirection(
2053                   SpatialNavigationDirection::kDown);
2054         }
2055       }
2056 #endif
2057     }
2058   } else {
2059     CancelPagePopup();
2060
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);
2074
2075         focused_frame->GetInputMethodController().FinishComposingText(
2076             InputMethodController::kKeepSelection);
2077       }
2078     }
2079   }
2080 }
2081
2082 // WebView --------------------------------------------------------------------
2083
2084 WebSettingsImpl* WebViewImpl::SettingsImpl() {
2085   if (!web_settings_) {
2086     web_settings_ = std::make_unique<WebSettingsImpl>(
2087         &page_->GetSettings(), dev_tools_emulator_.Get());
2088   }
2089   DCHECK(web_settings_);
2090   return web_settings_.get();
2091 }
2092
2093 WebSettings* WebViewImpl::GetSettings() {
2094   return SettingsImpl();
2095 }
2096
2097 WebString WebViewImpl::PageEncoding() const {
2098   if (!page_)
2099     return WebString();
2100
2101   auto* main_frame = DynamicTo<LocalFrame>(page_->MainFrame());
2102   if (!main_frame)
2103     return WebString();
2104
2105   // FIXME: Is this check needed?
2106   if (!main_frame->GetDocument()->Loader())
2107     return WebString();
2108
2109   return main_frame->GetDocument()->EncodingName();
2110 }
2111
2112 WebFrame* WebViewImpl::MainFrame() {
2113   Page* page = page_.Get();
2114   return WebFrame::FromCoreFrame(page ? page->MainFrame() : nullptr);
2115 }
2116
2117 const WebFrame* WebViewImpl::MainFrame() const {
2118   Page* page = page_.Get();
2119   return WebFrame::FromCoreFrame(page ? page->MainFrame() : nullptr);
2120 }
2121
2122 WebLocalFrameImpl* WebViewImpl::MainFrameImpl() const {
2123   Page* page = page_.Get();
2124   if (!page)
2125     return nullptr;
2126   return WebLocalFrameImpl::FromFrame(DynamicTo<LocalFrame>(page->MainFrame()));
2127 }
2128
2129 std::string WebViewImpl::GetNullFrameReasonForBug1139104() const {
2130   Page* page = page_.Get();
2131   if (!page)
2132     return "WebViewImpl::page";
2133   if (!page->MainFrame())
2134     return "WebViewImpl::page->MainFrame";
2135   LocalFrame* local_frame = DynamicTo<LocalFrame>(page->MainFrame());
2136   if (!local_frame)
2137     return "WebViewImpl::local_frame";
2138   return WebLocalFrameImpl::GetNullFrameReasonForBug1139104(local_frame);
2139 }
2140
2141 void WebViewImpl::DidAttachLocalMainFrame() {
2142   DCHECK(MainFrameImpl());
2143   DCHECK(!remote_main_frame_host_remote_);
2144
2145   LocalFrame* local_frame = MainFrameImpl()->GetFrame();
2146   local_frame->WasAttachedAsLocalMainFrame();
2147
2148   local_frame->GetRemoteNavigationAssociatedInterfaces()->GetInterface(
2149       local_main_frame_host_remote_.BindNewEndpointAndPassReceiver(
2150           GetPage()
2151               ->GetPageScheduler()
2152               ->GetAgentGroupScheduler()
2153               .DefaultTaskRunner()));
2154
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();
2168   }
2169
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
2178     // document.
2179     if (local_frame->GetDocument()->IsActive())
2180       local_frame->View()->InitializeRootScroller();
2181   }
2182 }
2183
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.
2197
2198   RemoteFrame* remote_frame = DynamicTo<RemoteFrame>(GetPage()->MainFrame());
2199   remote_frame->WasAttachedAsRemoteMainFrame(std::move(main_frame));
2200
2201   remote_main_frame_host_remote_.Bind(std::move(main_frame_host));
2202
2203   auto& viewport = GetPage()->GetVisualViewport();
2204   DCHECK(!viewport.IsActiveViewport());
2205   viewport.Reset();
2206 }
2207
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();
2213 }
2214
2215 void WebViewImpl::DidDetachRemoteMainFrame() {
2216   remote_main_frame_host_remote_.reset();
2217 }
2218
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));
2225 }
2226
2227 void WebViewImpl::SetFocusedFrame(WebFrame* frame) {
2228   if (!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);
2233     return;
2234   }
2235   LocalFrame* core_frame = To<WebLocalFrameImpl>(frame)->GetFrame();
2236   core_frame->GetPage()->GetFocusController().SetFocusedFrame(core_frame);
2237 }
2238
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);
2246
2247   // Zoom if:
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;
2256
2257   // Reconstruct the editable element's absolute rect from the caret-relative
2258   // location.
2259   gfx::RectF editable_rect_in_root_frame =
2260       scroll_into_view_util::FocusedEditableBoundsFromParams(
2261           caret_rect_in_root_frame, params);
2262
2263   DCHECK(!editable_rect_in_root_frame.IsEmpty());
2264
2265   float scale;
2266   gfx::Point scroll;
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);
2272
2273   if (need_animation) {
2274     StartPageScaleAnimation(scroll, false, scale,
2275                             kScrollAndScaleAnimationDuration);
2276   }
2277 }
2278
2279 void WebViewImpl::SmoothScroll(int target_x,
2280                                int target_y,
2281                                base::TimeDelta duration) {
2282   gfx::Point target_position(target_x, target_y);
2283   StartPageScaleAnimation(target_position, false, PageScaleFactor(), duration);
2284 }
2285
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,
2290     float& new_scale,
2291     gfx::Point& new_scroll_position,
2292     bool& need_animation) {
2293   VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
2294
2295   TopDocumentRootScrollerController& controller =
2296       GetPage()->GlobalRootScrollerController();
2297   Node* root_scroller = controller.GlobalRootScroller();
2298
2299   gfx::Rect element_bounds_in_content;
2300   gfx::Rect caret_bounds_in_content;
2301
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();
2308
2309     element_bounds_in_content = element_bounds_in_root_frame;
2310     caret_bounds_in_content = caret_bounds_in_root_frame;
2311
2312     element_bounds_in_content.Offset(gfx::ToFlooredVector2d(offset));
2313     caret_bounds_in_content.Offset(gfx::ToFlooredVector2d(offset));
2314   } else {
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);
2321   }
2322
2323   if (!zoom_into_legible_scale) {
2324     new_scale = PageScaleFactor();
2325   } else {
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());
2339   }
2340   const float delta_scale = new_scale / PageScaleFactor();
2341
2342   need_animation = false;
2343
2344   // If we are at less than the target zoom level, zoom in.
2345   if (delta_scale > minScaleChangeToTriggerZoom)
2346     need_animation = true;
2347   else
2348     new_scale = PageScaleFactor();
2349
2350   ScrollableArea* root_viewport =
2351       MainFrameImpl()->GetFrame()->View()->GetScrollableArea();
2352
2353   // If the caret is offscreen, then animate.
2354   if (!root_viewport->VisibleContentRect().Contains(caret_bounds_in_content))
2355     need_animation = true;
2356
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;
2365
2366   if (!need_animation)
2367     return;
2368
2369   gfx::SizeF target_viewport_size(visual_viewport.Size());
2370   target_viewport_size.Scale(1 / new_scale);
2371
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
2378     // onscreen.
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));
2385   } else {
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()));
2392   }
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()) /
2398             2);
2399   } else {
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()));
2406   }
2407
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));
2413 }
2414
2415 void WebViewImpl::AdvanceFocus(bool reverse) {
2416   GetPage()->GetFocusController().AdvanceFocus(
2417       reverse ? mojom::blink::FocusType::kBackward
2418               : mojom::blink::FocusType::kForward);
2419 }
2420
2421 double WebViewImpl::ZoomLevel() {
2422   return zoom_level_;
2423 }
2424
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);
2433       }
2434     }
2435   }
2436
2437   for (Frame* child = frame->Tree().FirstChild(); child;
2438        child = child->Tree().NextSibling())
2439     PropagateZoomFactorToLocalFrameRoots(child, zoom_factor);
2440 }
2441
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_;
2448   else
2449     zoom_level_ = zoom_level;
2450
2451   float zoom_factor =
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_);
2460
2461       zoom_factor *= compositor_device_scale_factor_override_;
2462     } else {
2463       page_->SetInspectorDeviceScaleFactorOverride(1.0f);
2464       zoom_factor *= zoom_factor_for_device_scale_factor_;
2465     }
2466   }
2467   PropagateZoomFactorToLocalFrameRoots(page_->MainFrame(), zoom_factor);
2468
2469   if (old_zoom_level != zoom_level_) {
2470     for (auto& observer : observers_)
2471       observer.OnZoomLevelChanged();
2472     CancelPagePopup();
2473   }
2474
2475   return zoom_level_;
2476 }
2477
2478 float WebViewImpl::PageScaleFactor() const {
2479   if (!GetPage())
2480     return 1;
2481
2482   return GetPage()->GetVisualViewport().Scale();
2483 }
2484
2485 float WebViewImpl::ClampPageScaleFactorToLimits(float scale_factor) const {
2486   return GetPageScaleConstraintsSet().FinalConstraints().ClampToConstraints(
2487       scale_factor);
2488 }
2489
2490 void WebViewImpl::SetVisualViewportOffset(const gfx::PointF& offset) {
2491   DCHECK(GetPage());
2492   GetPage()->GetVisualViewport().SetLocation(offset);
2493 }
2494
2495 gfx::PointF WebViewImpl::VisualViewportOffset() const {
2496   DCHECK(GetPage());
2497   return GetPage()->GetVisualViewport().VisibleRect().origin();
2498 }
2499
2500 gfx::SizeF WebViewImpl::VisualViewportSize() const {
2501   DCHECK(GetPage());
2502   return GetPage()->GetVisualViewport().VisibleRect().size();
2503 }
2504
2505 void WebViewImpl::SetPageScaleFactorAndLocation(float scale_factor,
2506                                                 bool is_pinch_gesture_active,
2507                                                 const gfx::PointF& location) {
2508   DCHECK(GetPage());
2509
2510   GetPage()->GetVisualViewport().SetScaleAndLocation(
2511       ClampPageScaleFactorToLimits(scale_factor), is_pinch_gesture_active,
2512       location);
2513 }
2514
2515 void WebViewImpl::SetPageScaleFactor(float scale_factor) {
2516   DCHECK(GetPage());
2517   DCHECK(MainFrameImpl());
2518
2519   if (LocalFrame* frame = MainFrameImpl()->GetFrame()) {
2520     frame->SetScaleFactor(scale_factor);
2521   }
2522 }
2523
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_);
2531 }
2532
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);
2544 }
2545
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();
2555 }
2556
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) {
2562   if (!old_state)
2563     return false;
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;
2571 }
2572
2573 void WebViewImpl::SetPageLifecycleStateInternal(
2574     mojom::blink::PageLifecycleStatePtr new_state,
2575     mojom::blink::PageRestoreParamsPtr page_restore_params) {
2576   Page* page = GetPage();
2577   if (!page)
2578     return;
2579   auto& old_state = page->GetPageLifecycleState();
2580   TRACE_EVENT2("navigation", "WebViewImpl::SetPageLifecycleStateInternal",
2581                "old_state", old_state, "new_state", new_state);
2582
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`.
2590   bool hiding_page =
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);
2596   } else {
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.
2600     hiding_page &=
2601         (old_state->visibility == mojom::blink::PageVisibilityState::kVisible);
2602   }
2603   bool showing_page =
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;
2616
2617   if (dispatching_pagehide) {
2618     RemoveFocusAndTextInputState();
2619   }
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);
2627   }
2628   if (hiding_page) {
2629     SetVisibilityState(new_state->visibility, /*is_initial_state=*/false);
2630   }
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);
2635   }
2636
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();
2642       }
2643     }
2644
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);
2648   }
2649
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);
2657   }
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);
2664   }
2665   if (showing_page) {
2666     SetVisibilityState(new_state->visibility, /*is_initial_state=*/false);
2667   }
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();
2682       }
2683     }
2684
2685     DispatchPersistedPageshow(page_restore_params->navigation_start);
2686
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);
2693
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();
2701           }
2702         }
2703       }
2704     }
2705   }
2706
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();
2712
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));
2716
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();
2721     }
2722   }
2723
2724   UpdateViewTransitionState(restoring_from_bfcache, storing_in_bfcache,
2725                             page_restore_params);
2726
2727   if (RuntimeEnabledFeatures::PageRevealEventEnabled()) {
2728     if (restoring_from_bfcache) {
2729       if (auto* main_frame = DynamicTo<LocalFrame>(GetPage()->MainFrame())) {
2730         main_frame->GetDocument()->EnqueuePageRevealEvent();
2731       }
2732     }
2733   }
2734 }
2735
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);
2745
2746   if (!MainFrame()->IsWebLocalFrame()) {
2747     return;
2748   }
2749   LocalFrame* local_frame = To<LocalFrame>(GetPage()->MainFrame());
2750   DCHECK(local_frame);
2751
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));
2758     }
2759   }
2760
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);
2769     }
2770   }
2771 }
2772
2773 void WebViewImpl::ReportActiveSchedulerTrackedFeatures() {
2774   Page* page = GetPage();
2775   if (!page)
2776     return;
2777
2778   for (Frame* frame = page->MainFrame(); frame;
2779        frame = frame->Tree().TraverseNext()) {
2780     if (!frame->IsLocalFrame())
2781       continue;
2782     auto* local_frame = DynamicTo<LocalFrame>(frame);
2783     if (!local_frame->GetFrameScheduler())
2784       continue;
2785     local_frame->GetFrameScheduler()->ReportActiveSchedulerTrackedFeatures();
2786   }
2787 }
2788
2789 void WebViewImpl::AudioStateChanged(bool is_audio_playing) {
2790   GetPage()->GetPageScheduler()->AudioStateChanged(is_audio_playing);
2791 }
2792
2793 void WebViewImpl::RemoveFocusAndTextInputState() {
2794   auto& focus_controller = GetPage()->GetFocusController();
2795   auto* focused_frame = focus_controller.FocusedFrame();
2796   if (!focused_frame)
2797     return;
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();
2808   }
2809 }
2810
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(
2821           persisted
2822               ? PageTransitionEventPersistence::kPageTransitionEventPersisted
2823               : PageTransitionEventPersistence::
2824                     kPageTransitionEventNotPersisted);
2825     }
2826   }
2827 }
2828
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();
2836       if (document) {
2837         PaintTiming::From(*document).OnRestoredFromBackForwardCache();
2838         InteractiveDetector::From(*document)->OnRestoredFromBackForwardCache();
2839       }
2840       DocumentLoader* loader = local_frame->Loader().GetDocumentLoader();
2841       if (loader) {
2842         loader->GetTiming().SetBackForwardCacheRestoreNavigationStart(
2843             navigation_start);
2844       }
2845     }
2846     if (frame->DomWindow() && frame->DomWindow()->IsLocalDOMWindow()) {
2847       auto pageshow_start_time = base::TimeTicks::Now();
2848       LocalDOMWindow* window = frame->DomWindow()->ToLocalDOMWindow();
2849
2850       window->DispatchPersistedPageshowEvent(navigation_start);
2851
2852       if (RuntimeEnabledFeatures::NavigationIdEnabled(window)) {
2853         auto pageshow_end_time = base::TimeTicks::Now();
2854
2855         WindowPerformance* performance =
2856             DOMWindowPerformance::performance(*window);
2857         DCHECK(performance);
2858
2859         performance->AddBackForwardCacheRestoration(
2860             navigation_start, pageshow_start_time, pageshow_end_time);
2861       }
2862       if (frame->IsOutermostMainFrame()) {
2863         UMA_HISTOGRAM_BOOLEAN(
2864             "BackForwardCache.MainFrameHasPageshowListenersOnRestore",
2865             window->HasEventListeners(event_type_names::kPageshow));
2866       }
2867     }
2868   }
2869 }
2870
2871 void WebViewImpl::HookBackForwardCacheEviction(bool hook) {
2872   DCHECK(GetPage());
2873   for (Frame* frame = GetPage()->MainFrame(); frame;
2874        frame = frame->Tree().TraverseNext()) {
2875     auto* local_frame = DynamicTo<LocalFrame>(frame);
2876     if (!local_frame)
2877       continue;
2878     if (hook)
2879       local_frame->HookBackForwardCacheEviction();
2880     else
2881       local_frame->RemoveBackForwardCacheEviction();
2882   }
2883 }
2884
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();
2891 }
2892
2893 void WebViewImpl::DisableAutoResizeMode() {
2894   should_auto_resize_ = false;
2895   ConfigureAutoResizeMode();
2896 }
2897
2898 bool WebViewImpl::AutoResizeMode() {
2899   return should_auto_resize_;
2900 }
2901
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));
2906 }
2907
2908 void WebViewImpl::DisableAutoResizeForTesting(
2909     const gfx::Size& new_window_size) {
2910   if (!should_auto_resize_)
2911     return;
2912   DisableAutoResizeMode();
2913
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));
2918   }
2919 }
2920
2921 void WebViewImpl::SetDefaultPageScaleLimits(float min_scale, float max_scale) {
2922   dev_tools_emulator_->SetDefaultPageScaleLimits(min_scale, max_scale);
2923 }
2924
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;
2930
2931   if (constraints == GetPageScaleConstraintsSet().UserAgentConstraints())
2932     return;
2933
2934   GetPageScaleConstraintsSet().SetNeedsReset(true);
2935   GetPage()->SetUserAgentPageScaleConstraints(constraints);
2936 }
2937
2938 void WebViewImpl::SetMaximumLegibleScale(float maximum_legible_scale) {
2939   maximum_legible_scale_ = maximum_legible_scale;
2940 }
2941
2942 void WebViewImpl::SetIgnoreViewportTagScaleLimits(bool ignore) {
2943   PageScaleConstraints constraints =
2944       GetPageScaleConstraintsSet().UserAgentConstraints();
2945   if (ignore) {
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;
2952     }
2953     constraints.maximum_scale =
2954         GetPageScaleConstraintsSet().DefaultConstraints().maximum_scale;
2955   } else {
2956     if (!RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) {
2957       constraints.minimum_scale = -1;
2958     }
2959     constraints.maximum_scale = -1;
2960   }
2961   GetPage()->SetUserAgentPageScaleConstraints(constraints);
2962 }
2963
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());
2968 }
2969
2970 PageScaleConstraintsSet& WebViewImpl::GetPageScaleConstraintsSet() const {
2971   return GetPage()->GetPageScaleConstraintsSet();
2972 }
2973
2974 void WebViewImpl::RefreshPageScaleFactor() {
2975   if (!MainFrame() || !GetPage() || !GetPage()->MainFrame() ||
2976       !GetPage()->MainFrame()->IsLocalFrame() ||
2977       !GetPage()->DeprecatedLocalMainFrame()->View())
2978     return;
2979   UpdatePageDefinedViewportConstraints(MainFrameImpl()
2980                                            ->GetFrame()
2981                                            ->GetDocument()
2982                                            ->GetViewportData()
2983                                            .GetViewportDescription());
2984   GetPageScaleConstraintsSet().ComputeFinalConstraints();
2985
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);
2992   }
2993   SetPageScaleFactor(new_page_scale_factor);
2994
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());
3003   }
3004 }
3005
3006 void WebViewImpl::UpdatePageDefinedViewportConstraints(
3007     const ViewportDescription& description) {
3008   if (!GetPage() || (!size_.width() && !size_.height()))
3009     return;
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
3013   // instead.
3014   if (!GetPage()->MainFrame()->IsLocalFrame())
3015     return;
3016
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();
3023
3024     frame_host.SetVirtualKeyboardMode(virtual_keyboard_mode_);
3025   }
3026
3027   if (!GetSettings()->ViewportEnabled()) {
3028     GetPageScaleConstraintsSet().ClearPageDefinedConstraints();
3029     UpdateMainFrameLayoutSize();
3030     return;
3031   }
3032
3033   Document* document = GetPage()->DeprecatedLocalMainFrame()->GetDocument();
3034
3035   Length default_min_width =
3036       document->GetViewportData().ViewportDefaultMinWidth();
3037   if (default_min_width.IsAuto())
3038     default_min_width = Length::ExtendToZoom();
3039
3040   float old_initial_scale =
3041       GetPageScaleConstraintsSet().PageDefinedConstraints().initial_scale;
3042
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;
3048 #endif
3049
3050   GetPageScaleConstraintsSet().UpdatePageDefinedConstraints(description,
3051                                                             default_min_width);
3052
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 ==
3059              1.0f))
3060       SetInitialPageScaleOverride(-1);
3061   }
3062
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;
3078 #endif
3079
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();
3084   }
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();
3090     }
3091   }
3092 #endif
3093
3094   if (does_composite_) {
3095     MainFrameImpl()->FrameWidgetImpl()->UpdateViewportDescription(description);
3096   }
3097
3098   UpdateMainFrameLayoutSize();
3099 }
3100
3101 void WebViewImpl::UpdateMainFrameLayoutSize() {
3102   if (should_auto_resize_ || !MainFrameImpl())
3103     return;
3104
3105   LocalFrameView* view = MainFrameImpl()->GetFrameView();
3106   if (!view)
3107     return;
3108
3109   gfx::Size layout_size = size_;
3110
3111   if (GetSettings()->ViewportEnabled())
3112     layout_size = GetPageScaleConstraintsSet().GetLayoutSize();
3113
3114   if (GetPage()->GetSettings().GetForceZeroLayoutHeight())
3115     layout_size.set_height(0);
3116
3117   view->SetLayoutSize(layout_size);
3118 }
3119
3120 gfx::Size WebViewImpl::ContentsSize() const {
3121   if (!GetPage()->MainFrame()->IsLocalFrame())
3122     return gfx::Size();
3123   auto* layout_view =
3124       GetPage()->DeprecatedLocalMainFrame()->ContentLayoutObject();
3125   if (!layout_view)
3126     return gfx::Size();
3127   return ToPixelSnappedRect(layout_view->DocumentRect()).size();
3128 }
3129
3130 gfx::Size WebViewImpl::ContentsPreferredMinimumSize() {
3131   DCHECK(page_->MainFrame()->IsLocalFrame());
3132
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())
3137     return gfx::Size();
3138
3139   // The preferred size requires an up-to-date layout tree.
3140   DCHECK(!document->NeedsLayoutTreeUpdate() &&
3141          !document->View()->NeedsLayout());
3142
3143   // Needed for computing MinPreferredWidth.
3144   FontCachePurgePreventer fontCachePurgePreventer;
3145   // Already accounts for zoom.
3146   int width_scaled = document->GetLayoutView()->ComputeMinimumWidth().Round();
3147   int height_scaled =
3148       document->documentElement()->GetLayoutBox()->ScrollHeight().Round();
3149   return gfx::Size(width_scaled, height_scaled);
3150 }
3151
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|
3155   // message.
3156   if (!send_preferred_size_changes_ || !MainFrameImpl())
3157     return;
3158
3159   if (!needs_preferred_size_update_)
3160     return;
3161   needs_preferred_size_update_ = false;
3162
3163   gfx::Size size_in_dips =
3164       MainFrameImpl()->LocalRootFrameWidget()->BlinkSpaceToFlooredDIPs(
3165           gfx::Size(ContentsPreferredMinimumSize()));
3166
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);
3170   }
3171 }
3172
3173 void WebViewImpl::EnablePreferredSizeChangedMode() {
3174   if (send_preferred_size_changes_)
3175     return;
3176   send_preferred_size_changes_ = true;
3177   needs_preferred_size_update_ = true;
3178
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);
3184   }
3185
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();
3190 }
3191
3192 void WebViewImpl::Focus() {
3193   if (GetPage()->MainFrame()->IsLocalFrame()) {
3194     DCHECK(local_main_frame_host_remote_);
3195     local_main_frame_host_remote_->FocusPage();
3196   } else {
3197     DCHECK(remote_main_frame_host_remote_);
3198     remote_main_frame_host_remote_->FocusPage();
3199   }
3200 }
3201
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);
3206   } else {
3207     DCHECK(remote_main_frame_host_remote_);
3208     remote_main_frame_host_remote_->TakeFocus(reverse);
3209   }
3210 }
3211
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)));
3234
3235   MainFrameDevToolsAgentImpl()->DidShowNewWindow();
3236 }
3237
3238 void WebViewImpl::DidShowCreatedWindow() {
3239   web_widget_->AckPendingWindowRect();
3240 }
3241
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));
3247 }
3248
3249 void WebViewImpl::DidAccessInitialMainDocument() {
3250   DCHECK(local_main_frame_host_remote_);
3251   local_main_frame_host_remote_->DidAccessInitialMainDocument();
3252 }
3253
3254 void WebViewImpl::SetResizable(bool resizable) {
3255   DCHECK(local_main_frame_host_remote_);
3256   local_main_frame_host_remote_->SetResizable(resizable);
3257 }
3258
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_)
3263     return;
3264
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;
3273   } else {
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;
3281   }
3282 }
3283
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)));
3292   } else {
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)));
3297   }
3298 }
3299
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_);
3304
3305   target_url_status_ = TARGET_NONE;
3306 }
3307
3308 float WebViewImpl::DefaultMinimumPageScaleFactor() const {
3309   return GetPageScaleConstraintsSet().DefaultConstraints().minimum_scale;
3310 }
3311
3312 float WebViewImpl::DefaultMaximumPageScaleFactor() const {
3313   return GetPageScaleConstraintsSet().DefaultConstraints().maximum_scale;
3314 }
3315
3316 float WebViewImpl::MinimumPageScaleFactor() const {
3317   return GetPageScaleConstraintsSet().FinalConstraints().minimum_scale;
3318 }
3319
3320 float WebViewImpl::MaximumPageScaleFactor() const {
3321   return GetPageScaleConstraintsSet().FinalConstraints().maximum_scale;
3322 }
3323
3324 void WebViewImpl::ResetScaleStateImmediately() {
3325   GetPageScaleConstraintsSet().SetNeedsReset(true);
3326 }
3327
3328 void WebViewImpl::ResetScrollAndScaleState() {
3329   GetPage()->GetVisualViewport().Reset();
3330
3331   auto* main_local_frame = DynamicTo<LocalFrame>(GetPage()->MainFrame());
3332   if (!main_local_frame)
3333     return;
3334
3335   if (LocalFrameView* frame_view = main_local_frame->View()) {
3336     ScrollableArea* scrollable_area = frame_view->LayoutViewport();
3337
3338     if (!scrollable_area->GetScrollOffset().IsZero()) {
3339       scrollable_area->SetScrollOffset(ScrollOffset(),
3340                                        mojom::blink::ScrollType::kProgrammatic);
3341     }
3342   }
3343
3344   if (Document* document = main_local_frame->GetDocument()) {
3345     if (DocumentLoader* loader = document->Loader()) {
3346       if (HistoryItem* item = loader->GetHistoryItem())
3347         item->ClearViewState();
3348     }
3349   }
3350
3351   GetPageScaleConstraintsSet().SetNeedsReset(true);
3352 }
3353
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. --
3358   // eseidel.
3359   if (MainFrameImpl()->GetFrameView()) {
3360     // Enqueues the resize event.
3361     MainFrameImpl()->GetFrame()->GetDocument()->EnqueueResizeEvent();
3362   }
3363
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());
3370   }
3371 }
3372
3373 void WebViewImpl::ConfigureAutoResizeMode() {
3374   if (!MainFrameImpl() || !MainFrameImpl()->GetFrame() ||
3375       !MainFrameImpl()->GetFrame()->View())
3376     return;
3377
3378   if (should_auto_resize_) {
3379     MainFrameImpl()->GetFrame()->View()->EnableAutoSizeMode(min_auto_size_,
3380                                                             max_auto_size_);
3381   } else {
3382     MainFrameImpl()->GetFrame()->View()->DisableAutoSizeMode();
3383   }
3384 }
3385
3386 void WebViewImpl::SetCompositorDeviceScaleFactorOverride(
3387     float device_scale_factor) {
3388   if (compositor_device_scale_factor_override_ == device_scale_factor)
3389     return;
3390   compositor_device_scale_factor_override_ = device_scale_factor;
3391   if (zoom_factor_for_device_scale_factor_) {
3392     SetZoomLevel(ZoomLevel());
3393     return;
3394   }
3395 }
3396
3397 void WebViewImpl::SetDeviceEmulationTransform(const gfx::Transform& transform) {
3398   if (transform == device_emulation_transform_)
3399     return;
3400   device_emulation_transform_ = transform;
3401   UpdateDeviceEmulationTransform();
3402 }
3403
3404 gfx::Transform WebViewImpl::GetDeviceEmulationTransform() const {
3405   return device_emulation_transform_;
3406 }
3407
3408 void WebViewImpl::EnableDeviceEmulation(const DeviceEmulationParams& params) {
3409   web_widget_->EnableDeviceEmulation(params);
3410 }
3411
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);
3417 }
3418
3419 void WebViewImpl::DisableDeviceEmulation() {
3420   web_widget_->DisableDeviceEmulation();
3421 }
3422
3423 void WebViewImpl::DeactivateDevToolsTransform() {
3424   dev_tools_emulator_->DisableDeviceEmulation();
3425   SetDeviceEmulationTransform(gfx::Transform());
3426 }
3427
3428 void WebViewImpl::PerformCustomContextMenuAction(unsigned action) {
3429   if (page_) {
3430     page_->GetContextMenuController().CustomContextMenuItemSelected(action);
3431   }
3432 }
3433
3434 void WebViewImpl::DidCloseContextMenu() {
3435   LocalFrame* frame = page_->GetFocusController().FocusedFrame();
3436   if (frame)
3437     frame->Selection().SetCaretBlinkingSuspended(false);
3438 }
3439
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();
3444   if (!page)
3445     return BaseBackgroundColor().Rgb();
3446   if (auto* main_local_frame = DynamicTo<LocalFrame>(page->MainFrame())) {
3447     LocalFrameView* view = main_local_frame->View();
3448     if (view)
3449       return view->DocumentBackgroundColor().Rgb();
3450   }
3451   return BaseBackgroundColor().Rgb();
3452 }
3453
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());
3462   }
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;
3467 }
3468
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)
3472     return;
3473   page_base_background_color_ = new_color;
3474   UpdateBaseBackgroundColor();
3475 }
3476
3477 void WebViewImpl::SetBaseBackgroundColorOverrideTransparent(
3478     bool override_to_transparent) {
3479   DCHECK(does_composite_);
3480   if (override_base_background_color_to_transparent_ == override_to_transparent)
3481     return;
3482   override_base_background_color_to_transparent_ = override_to_transparent;
3483   UpdateBaseBackgroundColor();
3484 }
3485
3486 void WebViewImpl::SetBaseBackgroundColorOverrideForInspector(
3487     absl::optional<SkColor> optional_color) {
3488   if (base_background_color_override_for_inspector_ == optional_color)
3489     return;
3490   base_background_color_override_for_inspector_ = optional_color;
3491   UpdateBaseBackgroundColor();
3492 }
3493
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);
3500   }
3501
3502   Color color = BaseBackgroundColor();
3503   if (auto* local_frame = DynamicTo<LocalFrame>(page_->MainFrame())) {
3504     LocalFrameView* view = local_frame->View();
3505     view->UpdateBaseBackgroundColorRecursively(color);
3506   }
3507 }
3508
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);
3531 #else
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
3543 // complete.
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));
3549   }
3550 #endif  // (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) &&
3551         // !BUILDFLAG(IS_ANDROID)
3552 #endif  // BUILDFLAG(IS_WIN)
3553 #endif  // !BUILDFLAG(IS_MAC)
3554 }
3555
3556 void WebViewImpl::ActivatePrerenderedPage(
3557     mojom::blink::PrerenderPageActivationParamsPtr
3558         prerender_page_activation_params,
3559     ActivatePrerenderedPageCallback callback) {
3560   TRACE_EVENT0("navigation", "WebViewImpl::ActivatePrerenderedPage");
3561
3562   // From here all new documents will have prerendering false.
3563   GetPage()->SetIsPrerendering(false);
3564
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
3568   // complicated.
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();
3573   }
3574   if (main_frame_document) {
3575     RecordPrerenderActivationSignalDelay();
3576   }
3577
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());
3583       }
3584     }
3585   }
3586
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);
3595
3596   if (main_frame_document) {
3597     main_frame_document->ActivateForPrerendering(
3598         *prerender_page_activation_params);
3599     prerender_page_activation_params->view_transition_state.reset();
3600   }
3601
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);
3608   }
3609
3610   std::move(callback).Run();
3611 }
3612
3613 void WebViewImpl::SetInsidePortal(bool inside_portal) {
3614   GetPage()->SetInsidePortal(inside_portal);
3615
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.
3619   if (web_widget_)
3620     web_widget_->SetIsNestedMainFrameWidget(inside_portal);
3621 }
3622
3623 void WebViewImpl::RegisterRendererPreferenceWatcher(
3624     CrossVariantMojoRemote<mojom::RendererPreferenceWatcherInterfaceBase>
3625         watcher) {
3626   renderer_preference_watchers_.Add(std::move(watcher));
3627 }
3628
3629 void WebViewImpl::SetRendererPreferences(
3630     const RendererPreferences& preferences) {
3631   UpdateRendererPreferences(preferences);
3632 }
3633
3634 const RendererPreferences& WebViewImpl::GetRendererPreferences() const {
3635   return renderer_preferences_;
3636 }
3637
3638 void WebViewImpl::UpdateRendererPreferences(
3639     const RendererPreferences& preferences) {
3640   std::string old_accept_languages = renderer_preferences_.accept_languages;
3641   renderer_preferences_ = preferences;
3642
3643   for (auto& watcher : renderer_preference_watchers_)
3644     watcher->NotifyUpdate(renderer_preferences_);
3645
3646   WebThemeEngineHelper::DidUpdateRendererPreferences(preferences);
3647   UpdateFontRenderingFromRendererPrefs();
3648
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));
3654
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);
3661 #endif
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);
3666     ThemeChanged();
3667   }
3668 #endif
3669
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);
3675   }
3676 #endif
3677
3678   if (old_accept_languages != renderer_preferences_.accept_languages)
3679     AcceptLanguagesChanged();
3680
3681   GetSettings()->SetCaretBrowsingEnabled(
3682       renderer_preferences_.caret_browsing_enabled);
3683
3684 #if BUILDFLAG(IS_OZONE)
3685   GetSettings()->SetSelectionClipboardBufferAvailable(
3686       renderer_preferences_.selection_clipboard_buffer_available);
3687 #endif  // BUILDFLAG(IS_OZONE)
3688
3689   SetExplicitlyAllowedPorts(
3690       renderer_preferences_.explicitly_allowed_network_ports);
3691 }
3692
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);
3699
3700   history_list_offset_ = history_offset;
3701   history_list_length_ = history_length;
3702 }
3703
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;
3709     return;
3710   }
3711
3712   SetHistoryOffsetAndLength(history_offset, *history_length);
3713 }
3714
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;
3721 }
3722
3723 int32_t WebViewImpl::HistoryBackListCount() const {
3724   return std::max(history_list_offset_, 0);
3725 }
3726
3727 int32_t WebViewImpl::HistoryForwardListCount() const {
3728   return history_list_length_ - HistoryBackListCount() - 1;
3729 }
3730
3731 void WebViewImpl::SetWebPreferences(
3732     const web_pref::WebPreferences& preferences) {
3733   UpdateWebPreferences(preferences);
3734 }
3735
3736 const web_pref::WebPreferences& WebViewImpl::GetWebPreferences() {
3737   return web_preferences_;
3738 }
3739
3740 void WebViewImpl::UpdateWebPreferences(
3741     const blink::web_pref::WebPreferences& preferences) {
3742   web_preferences_ = preferences;
3743
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;
3758
3759     // Insecure content should not be allowed in a fenced frame.
3760     web_preferences_.allow_running_insecure_content = false;
3761
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;
3767 #endif
3768   }
3769
3770   if (MainFrameImpl()) {
3771     MainFrameImpl()->FrameWidgetImpl()->SetPrefersReducedMotion(
3772         web_preferences_.prefers_reduced_motion);
3773   }
3774
3775   ApplyWebPreferences(web_preferences_, this);
3776   ApplyCommandLineToSettings(SettingsImpl());
3777 }
3778
3779 #if BUILDFLAG(IS_TIZEN)
3780 void WebViewImpl::EnterDragState() {
3781   if (MainFrameImpl())
3782     MainFrameImpl()->EnterDragState();
3783 }
3784 #endif
3785
3786 void WebViewImpl::AddObserver(WebViewObserver* observer) {
3787   observers_.AddObserver(observer);
3788 }
3789
3790 void WebViewImpl::RemoveObserver(WebViewObserver* observer) {
3791   observers_.RemoveObserver(observer);
3792 }
3793
3794 #if BUILDFLAG(IS_TIZEN_TV)
3795 bool WebViewImpl::IsHitScrollbar() {
3796   const LocalFrame* frame =
3797       DynamicTo<LocalFrame>(page_->GetFocusController().FocusedOrMainFrame());
3798   if (!frame)
3799     return false;
3800   return frame->GetEventHandler().PressedScrollbar();
3801 }
3802
3803 bool WebViewImpl::IsMouseDownEventSwallowed() {
3804   if (!MainFrameImpl() || !MainFrameImpl()->GetFrame())
3805     return false;
3806   return MainFrameImpl()
3807       ->GetFrame()
3808       ->GetEventHandler()
3809       .MousePressEventSwallowed();
3810 }
3811
3812 void WebViewImpl::SetFloatVideoWindowState(bool enable) {
3813   if (!GetPage())
3814     return;
3815
3816   LOG(INFO) << __FUNCTION__ << " enable : " << enable;
3817   GetPage()->SetFloatVideoWindowState(enable);
3818 }
3819 #endif
3820
3821 void WebViewImpl::SetIsActive(bool active) {
3822   if (GetPage())
3823     GetPage()->GetFocusController().SetActive(active);
3824 }
3825
3826 bool WebViewImpl::IsActive() const {
3827   return GetPage() ? GetPage()->GetFocusController().IsActive() : false;
3828 }
3829
3830 void WebViewImpl::SetWindowFeatures(const WebWindowFeatures& features) {
3831   page_->SetWindowFeatures(features);
3832 }
3833
3834 void WebViewImpl::SetOpenedByDOM() {
3835   page_->SetOpenedByDOM();
3836 }
3837
3838 void WebViewImpl::DidCommitLoad(bool is_new_navigation,
3839                                 bool is_navigation_within_page) {
3840   if (!is_navigation_within_page) {
3841     if (web_widget_)
3842       web_widget_->ResetMeaningfulLayoutStateForMainFrame();
3843
3844     if (is_new_navigation)
3845       GetPageScaleConstraintsSet().SetNeedsReset(true);
3846   }
3847
3848   // Give the visual viewport's scroll layer its initial size.
3849   GetPage()->GetVisualViewport().MainFrameDidChangeSize();
3850 }
3851
3852 void WebViewImpl::DidCommitCompositorFrameForLocalMainFrame() {
3853   for (auto& observer : observers_)
3854     observer.DidCommitCompositorFrame();
3855 }
3856
3857 void WebViewImpl::ResizeAfterLayout() {
3858   DCHECK(MainFrameImpl());
3859
3860   if (!web_view_client_)
3861     return;
3862
3863   if (should_auto_resize_) {
3864     LocalFrameView* view = MainFrameImpl()->GetFrame()->View();
3865     gfx::Size frame_size = view->Size();
3866     if (frame_size != size_) {
3867       size_ = frame_size;
3868
3869       GetPage()->GetVisualViewport().SetSize(size_);
3870       GetPageScaleConstraintsSet().DidChangeInitialContainingBlockSize(size_);
3871
3872       web_view_client_->DidAutoResize(size_);
3873       web_widget_->DidAutoResize(size_);
3874       SendResizeEventForMainFrame();
3875     }
3876   }
3877
3878   if (does_composite_ && GetPageScaleConstraintsSet().ConstraintsDirty())
3879     RefreshPageScaleFactor();
3880
3881   resize_viewport_anchor_->ResizeFrameView(MainFrameSize());
3882 }
3883
3884 void WebViewImpl::MainFrameLayoutUpdated() {
3885   DCHECK(MainFrameImpl());
3886   if (!web_view_client_)
3887     return;
3888
3889   for (auto& observer : observers_)
3890     observer.DidUpdateMainFrameLayout();
3891   needs_preferred_size_update_ = true;
3892 }
3893
3894 void WebViewImpl::DidChangeContentsSize() {
3895   auto* local_frame = DynamicTo<LocalFrame>(GetPage()->MainFrame());
3896   if (!local_frame)
3897     return;
3898
3899   LocalFrameView* view = local_frame->View();
3900
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();
3906   }
3907
3908   GetPageScaleConstraintsSet().DidChangeContentsSize(
3909       ContentsSize(), vertical_scrollbar_width, PageScaleFactor());
3910 }
3911
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_);
3918
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());
3927
3928   local_main_frame_host_remote_->ScaleFactorChanged(viewport.Scale());
3929
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
3933     // instead.
3934     if (MainFrameImpl()->IsOutermostMainFrame()) {
3935       gfx::Transform device_emulation_transform =
3936           dev_tools_emulator_->OutermostMainFrameScrollOrScaleChanged();
3937       SetDeviceEmulationTransform(device_emulation_transform);
3938     }
3939   }
3940 }
3941
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);
3949   }
3950 }
3951
3952 void WebViewImpl::TextAutosizerPageInfoChanged(
3953     const mojom::blink::TextAutosizerPageInfo& page_info) {
3954   DCHECK(MainFrameImpl());
3955   local_main_frame_host_remote_->TextAutosizerPageInfoChanged(
3956       page_info.Clone());
3957 }
3958
3959 void WebViewImpl::SetBackgroundColorOverrideForFullscreenController(
3960     absl::optional<SkColor> optional_color) {
3961   DCHECK(does_composite_);
3962
3963   background_color_override_for_fullscreen_controller_ = optional_color;
3964   if (MainFrameImpl()) {
3965     MainFrameImpl()->FrameWidgetImpl()->SetBackgroundColor(BackgroundColor());
3966   }
3967 }
3968
3969 void WebViewImpl::SetZoomFactorOverride(float zoom_factor) {
3970   zoom_factor_override_ = zoom_factor;
3971   SetZoomLevel(ZoomLevel());
3972 }
3973
3974 Element* WebViewImpl::FocusedElement() const {
3975   LocalFrame* frame = page_->GetFocusController().FocusedFrame();
3976   if (!frame)
3977     return nullptr;
3978
3979   Document* document = frame->GetDocument();
3980   if (!document)
3981     return nullptr;
3982
3983   return document->FocusedElement();
3984 }
3985
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());
3990   if (!main_frame)
3991     return HitTestResult();
3992
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();
4001
4002   WebGestureEvent scaled_event =
4003       TransformWebGestureEvent(MainFrameImpl()->GetFrameView(), tap_event);
4004
4005   HitTestResult result =
4006       main_frame->GetEventHandler()
4007           .HitTestResultForGestureEvent(
4008               scaled_event, HitTestRequest::kReadOnly | HitTestRequest::kActive)
4009           .GetHitTestResult();
4010
4011   result.SetToShadowHostIfInUAShadowRoot();
4012   return result;
4013 }
4014
4015 void WebViewImpl::SetTabsToLinks(bool enable) {
4016   tabs_to_links_ = enable;
4017 }
4018
4019 bool WebViewImpl::TabsToLinks() const {
4020   return tabs_to_links_;
4021 }
4022
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);
4030     return;
4031   }
4032   if (root_layer_exists) {
4033     if (!device_emulation_transform_.IsIdentity())
4034       UpdateDeviceEmulationTransform();
4035   } else {
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
4039     // them.
4040     //
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();
4045   }
4046 }
4047
4048 void WebViewImpl::InvalidateContainer() {
4049   // This is only for non-composited WebViewPlugin.
4050   if (!does_composite_ && web_view_client_)
4051     web_view_client_->InvalidateContainer();
4052 }
4053
4054 void WebViewImpl::ApplyViewportChanges(const ApplyViewportChangesArgs& args) {
4055   // TODO(https://crbug.com/1160652): Figure out if Page is null.
4056   CHECK(page_);
4057
4058   VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
4059   DCHECK(visual_viewport.IsActiveViewport());
4060
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());
4067
4068   GetBrowserControls().SetShownRatio(
4069       GetBrowserControls().TopShownRatio() + args.top_controls_delta,
4070       GetBrowserControls().BottomShownRatio() + args.bottom_controls_delta);
4071
4072   SetPageScaleFactorAndLocation(PageScaleFactor() * args.page_scale_delta,
4073                                 args.is_pinch_gesture_active,
4074                                 visual_viewport_offset);
4075
4076   if (args.page_scale_delta != 1) {
4077     double_tap_zoom_pending_ = false;
4078   }
4079
4080   elastic_overscroll_ += args.elastic_overscroll_delta;
4081   UpdateBrowserControlsConstraint(args.browser_controls_constraint);
4082
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();
4087   }
4088 }
4089
4090 Node* WebViewImpl::FindNodeFromScrollableCompositorElementId(
4091     cc::ElementId element_id) const {
4092   if (!GetPage())
4093     return nullptr;
4094
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();
4100   }
4101
4102   if (!GetPage()->GetScrollingCoordinator())
4103     return nullptr;
4104   ScrollableArea* scrollable_area =
4105       GetPage()
4106           ->GetScrollingCoordinator()
4107           ->ScrollableAreaWithElementIdInAllLocalFrames(element_id);
4108   if (!scrollable_area || !scrollable_area->GetLayoutBox())
4109     return nullptr;
4110
4111   return scrollable_area->GetLayoutBox()->GetNode();
4112 }
4113
4114 void WebViewImpl::UpdateDeviceEmulationTransform() {
4115   if (GetPage()->GetVisualViewport().IsActiveViewport())
4116     GetPage()->GetVisualViewport().SetNeedsPaintPropertyUpdate();
4117
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();
4125
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();
4130   }
4131 }
4132
4133 PageScheduler* WebViewImpl::Scheduler() const {
4134   DCHECK(GetPage());
4135   return GetPage()->GetPageScheduler();
4136 }
4137
4138 void WebViewImpl::SetVisibilityState(
4139     mojom::blink::PageVisibilityState visibility_state,
4140     bool is_initial_state) {
4141   DCHECK(GetPage());
4142   GetPage()->SetVisibilityState(visibility_state, is_initial_state);
4143   // Do not throttle if the page should be painting.
4144   bool is_visible =
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;
4151   }
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);
4157   }
4158 }
4159
4160 mojom::blink::PageVisibilityState WebViewImpl::GetVisibilityState() {
4161   DCHECK(GetPage());
4162   return GetPage()->GetVisibilityState();
4163 }
4164
4165 LocalFrame* WebViewImpl::FocusedLocalFrameInWidget() const {
4166   if (!MainFrameImpl())
4167     return nullptr;
4168
4169   auto* focused_frame = To<LocalFrame>(FocusedCoreFrame());
4170   if (focused_frame->LocalFrameRoot() != MainFrameImpl()->GetFrame())
4171     return nullptr;
4172   return focused_frame;
4173 }
4174
4175 void WebViewImpl::SetPageFrozen(bool frozen) {
4176   Scheduler()->SetPageFrozen(frozen);
4177 }
4178
4179 WebFrameWidget* WebViewImpl::MainFrameWidget() {
4180   return web_widget_;
4181 }
4182
4183 void WebViewImpl::AddAutoplayFlags(int32_t value) {
4184   page_->AddAutoplayFlags(value);
4185 }
4186
4187 void WebViewImpl::ClearAutoplayFlags() {
4188   page_->ClearAutoplayFlags();
4189 }
4190
4191 int32_t WebViewImpl::AutoplayFlagsForTest() {
4192   return page_->AutoplayFlags();
4193 }
4194
4195 gfx::Size WebViewImpl::GetPreferredSizeForTest() {
4196   return preferred_size_in_dips_;
4197 }
4198
4199 void WebViewImpl::StopDeferringMainFrameUpdate() {
4200   scoped_defer_main_frame_update_ = nullptr;
4201 }
4202
4203 void WebViewImpl::SetDeviceColorSpaceForTesting(
4204     const gfx::ColorSpace& color_space) {
4205   web_widget_->SetDeviceColorSpaceForTesting(color_space);
4206 }
4207
4208 const SessionStorageNamespaceId& WebViewImpl::GetSessionStorageNamespaceId() {
4209   CHECK(!session_storage_namespace_id_.empty());
4210   return session_storage_namespace_id_;
4211 }
4212
4213 bool WebViewImpl::IsFencedFrameRoot() const {
4214   return GetPage()->IsMainFrameFencedFrameRoot();
4215 }
4216
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)));
4225 }
4226
4227 void WebViewImpl::CreateRemoteMainFrame(
4228     const RemoteFrameToken& frame_token,
4229     const absl::optional<FrameToken>& opener_frame_token,
4230     mojom::blink::FrameReplicationStatePtr replicated_state,
4231     bool is_loading,
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.
4245
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));
4251 }
4252
4253 scheduler::WebAgentGroupScheduler& WebViewImpl::GetWebAgentGroupScheduler() {
4254   return web_agent_group_scheduler_;
4255 }
4256
4257 void WebViewImpl::UpdatePageBrowsingContextGroup(
4258     const BrowsingContextGroupInfo& browsing_context_group_info) {
4259   Page* page = GetPage();
4260   CHECK(page);
4261
4262   page->UpdateBrowsingContextGroup(browsing_context_group_info);
4263 }
4264
4265 void WebViewImpl::SetPageAttributionSupport(
4266     network::mojom::AttributionSupport support) {
4267   Page* page = GetPage();
4268   CHECK(page);
4269
4270   page->SetAttributionSupport(support);
4271 }
4272
4273 #if BUILDFLAG(IS_EFL)
4274 bool WebViewImpl::PaintSoftBitmap(SkCanvas* canvas, const gfx::Rect& rect) {
4275   if (rect.IsEmpty())
4276     return false;
4277
4278   if (!MainFrameImpl() || !MainFrameImpl()->GetFrameView())
4279     return false;
4280
4281   LocalFrameView* view = MainFrameImpl()->GetFrameView();
4282   view->UpdateAllLifecyclePhases(DocumentUpdateReason::kOverlay);
4283
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;
4288   {
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);
4298 #endif
4299     AffineTransform transform;
4300     transform.Scale(scale_factor);
4301     transform.Translate(static_cast<float>(-dirty_rect.x()),
4302                         static_cast<float>(-dirty_rect.y()));
4303
4304     // FIXME: Use the page-background color to clear instead for half
4305     // loaded pages.
4306     SkColor color = SkColorSetARGB(0xff, 0xff, 0xff, 0xff);
4307     canvas->clear(color);
4308     view->PaintOutsideOfLifecycle(context, PaintFlag::kOmitCompositingInfo,
4309                                   CullRect(dirty_rect));
4310   }
4311   builder.EndRecording().Playback(canvas);
4312   return true;
4313 }
4314
4315 bool WebViewImpl::HasAcceleratedCanvasWithinViewport() const {
4316   if (!MainFrameImpl() || !MainFrameImpl()->GetFrameView())
4317     return false;
4318
4319   Document* document = MainFrameImpl()->GetFrame()->GetDocument();
4320   if (!document)
4321     return false;
4322
4323   StaticElementList* canvas_elements =
4324       document->QuerySelectorAll(AtomicString("canvas"), ASSERT_NO_EXCEPTION);
4325   if (!canvas_elements)
4326     return false;
4327
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())) {
4333       return true;
4334     }
4335   }
4336
4337   return false;
4338 }
4339
4340 gfx::Rect WebViewImpl::CurrentSelectionRect() const {
4341   if (!GetPage())
4342     return gfx::Rect();
4343
4344   LocalFrame* frame = DynamicTo<LocalFrame>(
4345       GetPage()->GetFocusController().FocusedOrMainFrame());
4346   if (!frame)
4347     return gfx::Rect();
4348
4349   FrameSelection& selection = frame->Selection();
4350   if (!selection.ComputeVisibleSelectionInDOMTreeDeprecated().IsRange())
4351     return gfx::Rect();
4352
4353   Range* range = CreateRange(frame->Selection()
4354                                  .ComputeVisibleSelectionInDOMTreeDeprecated()
4355                                  .ToNormalizedEphemeralRange());
4356   if (!range)
4357     return gfx::Rect();
4358
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);
4367 }
4368
4369 void WebViewImpl::SetLongPollingGlobalTimeout(uint64_t timeout) {
4370   if (!GetPage())
4371     return;
4372   GetPage()->SetLongPollingGlobalTimeout(timeout);
4373 }
4374
4375 void WebViewImpl::ScrollFocusedNodeIntoView() {
4376   if (Element* element = FocusedElement())
4377     element->scrollIntoViewIfNeeded(true /*centerIfNeeded*/);
4378 }
4379
4380 bool WebViewImpl::FiltersInSelectElement(WebView::TraverseFocusThrough filter) {
4381   return static_cast<bool>((char)filter &
4382                            (char)WebView::TraverseFocusThrough::SelectElement);
4383 }
4384
4385 bool WebViewImpl::FiltersInEditableElement(
4386     WebView::TraverseFocusThrough filter) {
4387   return static_cast<bool>(
4388       (char)filter & (char)WebView::TraverseFocusThrough::EditableElement);
4389 }
4390
4391 bool WebViewImpl::IsFormNavigationTextInput(Element& element) const {
4392   if (element.HasTagName(html_names::kInputTag) &&
4393       DynamicTo<HTMLInputElement>(element)->IsReadOnly()) {
4394     return false;
4395   }
4396 #if !defined(EWK_BRINGUP)  // FIXME: m114 bringup
4397   LayoutObject* renderer = element.GetLayoutObject();
4398   return renderer &&
4399          (IsEditable(element) || renderer->IsTextControlIncludingNG());
4400 #else
4401   return false;
4402 #endif
4403 }
4404
4405 bool WebViewImpl::IsSelectElement(const Element& element) const {
4406   return element.GetLayoutObject() &&
4407          element.HasTagName(html_names::kSelectTag);
4408 }
4409
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)
4415               : gfx::Rect());
4416 }
4417
4418 bool WebViewImpl::PerformClickOnElement(Element& element) {
4419   if (gfx::Rect() == GetElementBounds(element))
4420     return false;
4421
4422   // Set focus to false to compare it with focusedElement of document.
4423   element.Focus();
4424
4425   Element* focus_element = FocusedElement();
4426
4427   if (!focus_element || focus_element != &element)
4428     return false;
4429
4430   // SimulatedClickCreationScope::kFromAccessibility simulates MouseUpDown
4431   // Events
4432   focus_element->DispatchSimulatedClick(
4433       nullptr, SimulatedClickCreationScope::kFromAccessibility);
4434
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));
4441   }
4442
4443   return true;
4444 }
4445
4446 Element* WebViewImpl::NextTextOrSelectElement(Element* element,
4447                                               TraverseFocusThrough filter) {
4448   if (!element)
4449     return 0;
4450
4451   Element* next_element = element;
4452
4453   if (next_element->IsFrameOwnerElement()) {
4454     HTMLFrameOwnerElement& htmlFrameOwnerElement =
4455         *DynamicTo<HTMLFrameOwnerElement>(next_element);
4456
4457     // Checks if the frame is empty or not.
4458     if (!htmlFrameOwnerElement.ContentFrame())
4459       return 0;
4460
4461     Document* owner_document = htmlFrameOwnerElement.contentDocument();
4462     if (!owner_document || !(next_element = owner_document->body()))
4463       return 0;
4464
4465     // Checks if content editable flag on body has set.
4466     if (IsEditable(*next_element) && FiltersInEditableElement(filter))
4467       return next_element;
4468   }
4469
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;
4474
4475       next_element = NextTextOrSelectElement(next_element, filter);
4476       if (!next_element) {
4477         next_element = frame_owner_element;
4478         continue;
4479       }
4480     }
4481     if (FiltersInSelectElement(filter) && IsSelectElement(*next_element))
4482       break;
4483   }
4484
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);
4492     }
4493   }
4494
4495   return next_element;
4496 }
4497
4498 Element* WebViewImpl::PreviousTextOrSelectElement(Element* element,
4499                                                   TraverseFocusThrough filter) {
4500   if (!element)
4501     return 0;
4502
4503   Element* previous_element = element;
4504
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())
4510       return 0;
4511
4512     Document* owner_document = htmlFrameOwnerElement.contentDocument();
4513     if (!owner_document)
4514       return 0;
4515
4516     previous_element = owner_document->lastElementChild();
4517     while (previous_element && ElementTraversal::FirstWithin(*previous_element))
4518       previous_element = previous_element->lastElementChild();
4519
4520     if (!previous_element)
4521       return 0;
4522
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;
4529     }
4530   }
4531
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;
4536
4537       previous_element = PreviousTextOrSelectElement(previous_element, filter);
4538       if (!previous_element) {
4539         previous_element = frame_owner_element;
4540         continue;
4541       }
4542     }
4543
4544     if (!previous_element->IsFocusable())
4545       continue;
4546
4547     if (FiltersInEditableElement(filter) &&
4548         IsFormNavigationTextInput(*previous_element)) {
4549       break;
4550     }
4551
4552     if (FiltersInSelectElement(filter) && IsSelectElement(*previous_element))
4553       break;
4554   }
4555
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()),
4563         filter);
4564   }
4565
4566   return previous_element;
4567 }
4568
4569 bool WebViewImpl::MoveFocusToNext(TraverseFocusThrough filter) {
4570   Element* focus_element = FocusedElement();
4571   if (!focus_element || (!IsFormNavigationTextInput(*focus_element) &&
4572                          !IsSelectElement(*focus_element))) {
4573     return false;
4574   }
4575
4576   Element* next_element = NextTextOrSelectElement(focus_element, filter);
4577   if (!next_element)
4578     return false;
4579
4580   // Scroll the element into center of screen.
4581   next_element->scrollIntoViewIfNeeded(true /*centerIfNeeded*/);
4582
4583   bool handled = PerformClickOnElement(*next_element);
4584
4585   if (FocusedFrame() && IsFormNavigationTextInput(*next_element))
4586     FocusedFrame()->ExecuteCommand(WebString::FromUTF8("MoveToEndOfDocument"));
4587
4588   return handled;
4589 }
4590
4591 bool WebViewImpl::MoveFocusToPrevious(TraverseFocusThrough filter) {
4592   Element* focus_element = FocusedElement();
4593
4594   if (!focus_element || (!IsFormNavigationTextInput(*focus_element) &&
4595                          !IsSelectElement(*focus_element))) {
4596     return false;
4597   }
4598
4599   Element* previous_element =
4600       PreviousTextOrSelectElement(focus_element, filter);
4601   if (!previous_element)
4602     return false;
4603
4604   // Scroll the element into center of screen.
4605   previous_element->scrollIntoViewIfNeeded(true /*centerIfNeeded*/);
4606
4607   bool handled = PerformClickOnElement(*previous_element);
4608
4609   if (FocusedFrame() && IsFormNavigationTextInput(*previous_element))
4610     FocusedFrame()->ExecuteCommand(WebString::FromUTF8("MoveToEndOfDocument"));
4611
4612   return handled;
4613 }
4614
4615 void WebViewImpl::SetScrollOffset(float x, float y) {
4616   if (auto* focused_frame = FocusedFrame())
4617     focused_frame->SetScrollOffset(gfx::PointF(x, y));
4618 }
4619
4620 #if BUILDFLAG(IS_TIZEN_TV)
4621 void WebViewImpl::SuspendNetworkLoading() {
4622   if (!GetPage())
4623     return;
4624
4625   GetPage()->SetDefersLoading(true);
4626 }
4627
4628 void WebViewImpl::ResumeNetworkLoading() {
4629   if (!GetPage())
4630     return;
4631
4632   GetPage()->SetDefersLoading(false);
4633 }
4634 #endif  // IS_TIZEN_TV
4635 #endif  // IS_EFL
4636
4637 #if defined(TIZEN_VIDEO_HOLE)
4638 bool WebViewImpl::IsVideoHoleForRender() const {
4639   return GetPage()->GetSettings().GetVideoHoleEnabled();
4640 }
4641 #endif
4642
4643 #if BUILDFLAG(IS_TIZEN_TV)
4644 bool WebViewImpl::EdgeScrollBy(const ScrollOffset& scroll_offset,
4645                                const gfx::Point& mouse_point) {
4646   if (!MainFrameImpl())
4647     return false;
4648   const LocalFrameView* view = MainFrameImpl()->GetFrameView();
4649   if (!view)
4650     return false;
4651
4652   LayoutView* const layout_view = view->GetLayoutView();
4653   if (!layout_view)
4654     return false;
4655
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);
4661
4662   layout_view->HitTest(location, result);
4663
4664   const LocalFrame* frame = result.InnerNodeFrame();
4665   if (!frame) {
4666     frame = DynamicTo<LocalFrame>(
4667         page_->GetFocusController().FocusedOrMainFrame());
4668   }
4669
4670   return frame->GetEventHandler().ScrollWithMultiplier(scroll_offset,
4671                                                        result.InnerNode());
4672 }
4673
4674 void WebViewImpl::SetTranslatedURL(const WebString url) {
4675   if (!MainFrameImpl())
4676     return;
4677
4678   for (const Frame* frame = MainFrameImpl()->GetFrame(); frame;
4679        frame = frame->Tree().TraverseNext()) {
4680     Document* document = To<LocalFrame>(frame)->GetDocument();
4681     DCHECK(document);
4682     document->SetTranslatedURL(url);
4683   }
4684 }
4685
4686 void WebViewImpl::SetParentalRatingResult(const WebString& url, bool is_pass) {
4687   if (!MainFrameImpl()){
4688     LOG(ERROR) << "no main frame.";
4689     return;
4690   }
4691
4692   for (const Frame* frame = MainFrameImpl()->GetFrame(); frame;
4693        frame = frame->Tree().TraverseNext()) {
4694     Document* document = To<LocalFrame>(frame)->GetDocument();
4695     DCHECK(document);
4696     document->SetParentalRatingResult(url, is_pass);
4697   }
4698 }
4699
4700 bool WebViewImpl::IsVideoPlaying() const {
4701   if (!MainFrameImpl()){
4702     LOG(ERROR) << "no main frame.";
4703     return false;
4704   }
4705
4706   for (const Frame* frame = MainFrameImpl()->GetFrame(); frame;
4707        frame = frame->Tree().TraverseNext()) {
4708     Document* document = To<LocalFrame>(frame)->GetDocument();
4709     DCHECK(document);
4710     if (document->IsVideoPlaying())
4711       return true;
4712   }
4713   return false;
4714 }
4715 void WebViewImpl::SetPreferTextLang(const WebString& lang) {
4716   if (!MainFrameImpl()) {
4717     LOG(ERROR) << "no main frame.";
4718     return;
4719   }
4720
4721   for (const Frame* frame = MainFrameImpl()->GetFrame(); frame;
4722        frame = frame->Tree().TraverseNext()) {
4723     Document* document = To<LocalFrame>(frame)->GetDocument();
4724     DCHECK(document);
4725     document->SetPreferTextLang(lang);
4726   }
4727 }
4728 #endif
4729
4730 }  // namespace blink