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/auto_reset.h"
37 #include "base/memory/scoped_refptr.h"
38 #include "base/metrics/histogram_macros.h"
39 #include "base/time/time.h"
40 #include "build/build_config.h"
41 #include "cc/layers/picture_layer.h"
42 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
43 #include "third_party/blink/public/common/features.h"
44 #include "third_party/blink/public/common/input/web_input_event.h"
45 #include "third_party/blink/public/common/input/web_menu_source_type.h"
46 #include "third_party/blink/public/common/page/page_zoom.h"
47 #include "third_party/blink/public/mojom/input/focus_type.mojom-blink.h"
48 #include "third_party/blink/public/platform/interface_registry.h"
49 #include "third_party/blink/public/platform/web_text_autosizer_page_info.h"
50 #include "third_party/blink/public/platform/web_text_input_info.h"
51 #include "third_party/blink/public/platform/web_url_request.h"
52 #include "third_party/blink/public/platform/web_vector.h"
53 #include "third_party/blink/public/web/web_autofill_client.h"
54 #include "third_party/blink/public/web/web_console_message.h"
55 #include "third_party/blink/public/web/web_element.h"
56 #include "third_party/blink/public/web/web_frame.h"
57 #include "third_party/blink/public/web/web_hit_test_result.h"
58 #include "third_party/blink/public/web/web_input_element.h"
59 #include "third_party/blink/public/web/web_local_frame_client.h"
60 #include "third_party/blink/public/web/web_meaningful_layout.h"
61 #include "third_party/blink/public/web/web_node.h"
62 #include "third_party/blink/public/web/web_plugin.h"
63 #include "third_party/blink/public/web/web_range.h"
64 #include "third_party/blink/public/web/web_view_client.h"
65 #include "third_party/blink/public/web/web_widget_client.h"
66 #include "third_party/blink/public/web/web_window_features.h"
67 #include "third_party/blink/renderer/core/clipboard/data_object.h"
68 #include "third_party/blink/renderer/core/core_initializer.h"
69 #include "third_party/blink/renderer/core/css_value_keywords.h"
70 #include "third_party/blink/renderer/core/dom/context_features_client_impl.h"
71 #include "third_party/blink/renderer/core/dom/document.h"
72 #include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
73 #include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
74 #include "third_party/blink/renderer/core/dom/text.h"
75 #include "third_party/blink/renderer/core/editing/editing_utilities.h"
76 #include "third_party/blink/renderer/core/editing/editor.h"
77 #include "third_party/blink/renderer/core/editing/ephemeral_range.h"
78 #include "third_party/blink/renderer/core/editing/frame_selection.h"
79 #include "third_party/blink/renderer/core/editing/ime/input_method_controller.h"
80 #include "third_party/blink/renderer/core/editing/iterators/text_iterator.h"
81 #include "third_party/blink/renderer/core/editing/selection_template.h"
82 #include "third_party/blink/renderer/core/editing/serializers/html_interchange.h"
83 #include "third_party/blink/renderer/core/editing/serializers/serialization.h"
84 #include "third_party/blink/renderer/core/events/current_input_event.h"
85 #include "third_party/blink/renderer/core/events/keyboard_event.h"
86 #include "third_party/blink/renderer/core/events/ui_event_with_key_state.h"
87 #include "third_party/blink/renderer/core/events/web_input_event_conversion.h"
88 #include "third_party/blink/renderer/core/events/wheel_event.h"
89 #include "third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h"
90 #include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
91 #include "third_party/blink/renderer/core/exported/web_remote_frame_impl.h"
92 #include "third_party/blink/renderer/core/exported/web_settings_impl.h"
93 #include "third_party/blink/renderer/core/frame/browser_controls.h"
94 #include "third_party/blink/renderer/core/frame/event_handler_registry.h"
95 #include "third_party/blink/renderer/core/frame/fullscreen_controller.h"
96 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
97 #include "third_party/blink/renderer/core/frame/local_frame.h"
98 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
99 #include "third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h"
100 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
101 #include "third_party/blink/renderer/core/frame/page_scale_constraints_set.h"
102 #include "third_party/blink/renderer/core/frame/remote_frame.h"
103 #include "third_party/blink/renderer/core/frame/resize_viewport_anchor.h"
104 #include "third_party/blink/renderer/core/frame/rotation_viewport_anchor.h"
105 #include "third_party/blink/renderer/core/frame/settings.h"
106 #include "third_party/blink/renderer/core/frame/viewport_data.h"
107 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
108 #include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
109 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
110 #include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
111 #include "third_party/blink/renderer/core/html/forms/html_text_area_element.h"
112 #include "third_party/blink/renderer/core/html/html_plugin_element.h"
113 #include "third_party/blink/renderer/core/html/plugin_document.h"
114 #include "third_party/blink/renderer/core/html_names.h"
115 #include "third_party/blink/renderer/core/input/context_menu_allowed_scope.h"
116 #include "third_party/blink/renderer/core/input/event_handler.h"
117 #include "third_party/blink/renderer/core/input/touch_action_util.h"
118 #include "third_party/blink/renderer/core/inspector/dev_tools_emulator.h"
119 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
120 #include "third_party/blink/renderer/core/layout/layout_view.h"
121 #include "third_party/blink/renderer/core/layout/text_autosizer.h"
122 #include "third_party/blink/renderer/core/loader/document_loader.h"
123 #include "third_party/blink/renderer/core/loader/frame_load_request.h"
124 #include "third_party/blink/renderer/core/loader/frame_loader.h"
125 #include "third_party/blink/renderer/core/loader/frame_loader_state_machine.h"
126 #include "third_party/blink/renderer/core/loader/interactive_detector.h"
127 #include "third_party/blink/renderer/core/loader/prerenderer_client.h"
128 #include "third_party/blink/renderer/core/page/chrome_client_impl.h"
129 #include "third_party/blink/renderer/core/page/context_menu_controller.h"
130 #include "third_party/blink/renderer/core/page/context_menu_provider.h"
131 #include "third_party/blink/renderer/core/page/focus_controller.h"
132 #include "third_party/blink/renderer/core/page/frame_tree.h"
133 #include "third_party/blink/renderer/core/page/link_highlight.h"
134 #include "third_party/blink/renderer/core/page/page.h"
135 #include "third_party/blink/renderer/core/page/page_popup_client.h"
136 #include "third_party/blink/renderer/core/page/pointer_lock_controller.h"
137 #include "third_party/blink/renderer/core/page/scrolling/fragment_anchor.h"
138 #include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
139 #include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
140 #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
141 #include "third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h"
142 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
143 #include "third_party/blink/renderer/core/paint/paint_timing_detector.h"
144 #include "third_party/blink/renderer/core/probe/core_probes.h"
145 #include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
146 #include "third_party/blink/renderer/core/timing/dom_window_performance.h"
147 #include "third_party/blink/renderer/core/timing/window_performance.h"
148 #include "third_party/blink/renderer/platform/fonts/font_cache.h"
149 #include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h"
150 #include "third_party/blink/renderer/platform/graphics/image.h"
151 #include "third_party/blink/renderer/platform/graphics/paint/cull_rect.h"
152 #include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h"
153 #include "third_party/blink/renderer/platform/image-decoders/image_decoder.h"
154 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
155 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
156 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
157 #include "third_party/blink/renderer/platform/keyboard_codes.h"
158 #include "third_party/blink/renderer/platform/loader/fetch/unique_identifier.h"
159 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
160 #include "third_party/blink/renderer/platform/scheduler/public/page_lifecycle_state.h"
161 #include "third_party/blink/renderer/platform/scheduler/public/page_scheduler.h"
162 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
163 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
164 #include "third_party/blink/renderer/platform/widget/widget_base.h"
165 
166 #include "ui/gfx/skia_util.h"
167 
168 // Get rid of WTF's pow define so we can use std::pow.
169 #undef pow
170 #include <cmath>  // for std::pow
171 
172 // The following constants control parameters for automated scaling of webpages
173 // (such as due to a double tap gesture or find in page etc.). These are
174 // experimentally determined.
175 static const int touchPointPadding = 32;
176 static const int nonUserInitiatedPointPadding = 11;
177 static const float minScaleDifference = 0.01f;
178 static const float doubleTapZoomContentDefaultMargin = 5;
179 static const float doubleTapZoomContentMinimumMargin = 2;
180 static constexpr base::TimeDelta kDoubleTapZoomAnimationDuration =
181     base::TimeDelta::FromMilliseconds(250);
182 static const float doubleTapZoomAlreadyLegibleRatio = 1.2f;
183 
184 static constexpr base::TimeDelta kFindInPageAnimationDuration;
185 
186 // Constants for viewport anchoring on resize.
187 static const float viewportAnchorCoordX = 0.5f;
188 static const float viewportAnchorCoordY = 0;
189 
190 // Constants for zooming in on a focused text field.
191 static constexpr base::TimeDelta kScrollAndScaleAnimationDuration =
192     base::TimeDelta::FromMicroseconds(200);
193 static const int minReadableCaretHeight = 16;
194 static const int minReadableCaretHeightForTextArea = 13;
195 static const float minScaleChangeToTriggerZoom = 1.5f;
196 static const float leftBoxRatio = 0.3f;
197 static const int caretPadding = 10;
198 
199 namespace blink {
200 
201 // Historically, these values came from Webkit in
202 // WebKitLegacy/mac/WebView/WebView.mm (named MinimumZoomMultiplier and
203 // MaximumZoomMultiplier there).
204 const double WebView::kMinTextSizeMultiplier = 0.5;
205 const double WebView::kMaxTextSizeMultiplier = 3.0;
206 
207 // static
AllInstances()208 HashSet<WebViewImpl*>& WebViewImpl::AllInstances() {
209   DEFINE_STATIC_LOCAL(HashSet<WebViewImpl*>, all_instances, ());
210   return all_instances;
211 }
212 
213 static bool g_should_use_external_popup_menus = false;
214 
SetUseExternalPopupMenus(bool use_external_popup_menus)215 void WebView::SetUseExternalPopupMenus(bool use_external_popup_menus) {
216   g_should_use_external_popup_menus = use_external_popup_menus;
217 }
218 
UseExternalPopupMenus()219 bool WebViewImpl::UseExternalPopupMenus() {
220   return g_should_use_external_popup_menus;
221 }
222 
223 namespace {
224 
225 class EmptyEventListener final : public NativeEventListener {
226  public:
Invoke(ExecutionContext * execution_context,Event *)227   void Invoke(ExecutionContext* execution_context, Event*) override {}
228 };
229 
230 }  // namespace
231 
232 // WebView ----------------------------------------------------------------
233 
Create(WebViewClient * client,bool is_hidden,bool compositing_enabled,WebView * opener,mojo::ScopedInterfaceEndpointHandle page_handle)234 WebView* WebView::Create(WebViewClient* client,
235                          bool is_hidden,
236                          bool compositing_enabled,
237                          WebView* opener,
238                          mojo::ScopedInterfaceEndpointHandle page_handle) {
239   return WebViewImpl::Create(client, is_hidden, compositing_enabled,
240                              static_cast<WebViewImpl*>(opener),
241                              std::move(page_handle));
242 }
243 
Create(WebViewClient * client,bool is_hidden,bool compositing_enabled,WebViewImpl * opener,mojo::ScopedInterfaceEndpointHandle page_handle)244 WebViewImpl* WebViewImpl::Create(
245     WebViewClient* client,
246     bool is_hidden,
247     bool compositing_enabled,
248     WebViewImpl* opener,
249     mojo::ScopedInterfaceEndpointHandle page_handle) {
250   // Take a self-reference for WebViewImpl that is released by calling Close(),
251   // then return a raw pointer to the caller.
252   auto web_view = base::AdoptRef(new WebViewImpl(
253       client, is_hidden, compositing_enabled, opener, std::move(page_handle)));
254   web_view->AddRef();
255   return web_view.get();
256 }
257 
UpdateVisitedLinkState(uint64_t link_hash)258 void WebView::UpdateVisitedLinkState(uint64_t link_hash) {
259   Page::VisitedStateChanged(link_hash);
260 }
261 
ResetVisitedLinkState(bool invalidate_visited_link_hashes)262 void WebView::ResetVisitedLinkState(bool invalidate_visited_link_hashes) {
263   Page::AllVisitedStateChanged(invalidate_visited_link_hashes);
264 }
265 
SetPrerendererClient(WebPrerendererClient * prerenderer_client)266 void WebViewImpl::SetPrerendererClient(
267     WebPrerendererClient* prerenderer_client) {
268   DCHECK(AsView().page);
269   ProvidePrerendererClientTo(*AsView().page,
270                              MakeGarbageCollected<PrerendererClient>(
271                                  *AsView().page, prerenderer_client));
272 }
273 
WebViewImpl(WebViewClient * client,bool is_hidden,bool does_composite,WebViewImpl * opener,mojo::ScopedInterfaceEndpointHandle page_handle)274 WebViewImpl::WebViewImpl(WebViewClient* client,
275                          bool is_hidden,
276                          bool does_composite,
277                          WebViewImpl* opener,
278                          mojo::ScopedInterfaceEndpointHandle page_handle)
279     : as_view_(client),
280       chrome_client_(MakeGarbageCollected<ChromeClientImpl>(this)),
281       minimum_zoom_level_(PageZoomFactorToZoomLevel(kMinimumPageZoomFactor)),
282       maximum_zoom_level_(PageZoomFactorToZoomLevel(kMaximumPageZoomFactor)),
283       does_composite_(does_composite),
284       fullscreen_controller_(std::make_unique<FullscreenController>(this)),
285       receiver_(this,
286                 mojo::PendingAssociatedReceiver<mojom::blink::PageBroadcast>(
287                     std::move(page_handle))) {
288   if (!AsView().client) {
289     DCHECK(!does_composite_);
290   }
291   Page::PageClients page_clients;
292   page_clients.chrome_client = chrome_client_.Get();
293 
294   AsView().page =
295       Page::CreateOrdinary(page_clients, opener ? opener->GetPage() : nullptr);
296   CoreInitializer::GetInstance().ProvideModulesToPage(*AsView().page,
297                                                       AsView().client);
298   SetVisibilityState(
299       is_hidden ? PageVisibilityState::kHidden : PageVisibilityState::kVisible,
300       /*is_initial_state=*/true);
301 
302   // When not compositing, keep the Page in the loop so that it will paint all
303   // content into the root layer, as multiple layers can only be used when
304   // compositing them together later.
305   if (does_composite_)
306     AsView().page->GetSettings().SetAcceleratedCompositingEnabled(true);
307 
308   dev_tools_emulator_ = MakeGarbageCollected<DevToolsEmulator>(this);
309 
310   AllInstances().insert(this);
311 
312   resize_viewport_anchor_ =
313       MakeGarbageCollected<ResizeViewportAnchor>(*AsView().page);
314 }
315 
~WebViewImpl()316 WebViewImpl::~WebViewImpl() {
317   DCHECK(!AsView().page);
318 }
319 
MainFrameDevToolsAgentImpl()320 WebDevToolsAgentImpl* WebViewImpl::MainFrameDevToolsAgentImpl() {
321   WebLocalFrameImpl* main_frame = MainFrameImpl();
322   return main_frame ? main_frame->DevToolsAgentImpl() : nullptr;
323 }
324 
TabKeyCyclesThroughElements() const325 bool WebViewImpl::TabKeyCyclesThroughElements() const {
326   DCHECK(AsView().page);
327   return AsView().page->TabKeyCyclesThroughElements();
328 }
329 
SetTabKeyCyclesThroughElements(bool value)330 void WebViewImpl::SetTabKeyCyclesThroughElements(bool value) {
331   if (AsView().page)
332     AsView().page->SetTabKeyCyclesThroughElements(value);
333 }
334 
HandleMouseLeave(LocalFrame & main_frame,const WebMouseEvent & event)335 void WebViewImpl::HandleMouseLeave(LocalFrame& main_frame,
336                                    const WebMouseEvent& event) {
337   AsView().client->SetMouseOverURL(WebURL());
338   PageWidgetEventHandler::HandleMouseLeave(main_frame, event);
339 }
340 
HandleMouseDown(LocalFrame & main_frame,const WebMouseEvent & event)341 void WebViewImpl::HandleMouseDown(LocalFrame& main_frame,
342                                   const WebMouseEvent& event) {
343   // If there is a popup open, close it as the user is clicking on the page
344   // (outside of the popup). We also save it so we can prevent a click on an
345   // element from immediately reopening the same popup.
346   //
347   // The popup would not be destroyed in this stack normally as it is owned by
348   // closership from the RenderWidget, which is owned by the browser via the
349   // Close IPC. However if a nested message loop were to happen then the browser
350   // close of the RenderWidget and WebPagePopupImpl could feasibly occur inside
351   // this method, so holding a reference here ensures we can use the
352   // |page_popup| even if it is closed.
353   scoped_refptr<WebPagePopupImpl> page_popup;
354   if (event.button == WebMouseEvent::Button::kLeft) {
355     page_popup = page_popup_;
356     CancelPagePopup();
357     DCHECK(!page_popup_);
358   }
359 
360   // Take capture on a mouse down on a plugin so we can send it mouse events.
361   // If the hit node is a plugin but a scrollbar is over it don't start mouse
362   // capture because it will interfere with the scrollbar receiving events.
363   if (event.button == WebMouseEvent::Button::kLeft) {
364     HitTestLocation location(main_frame.View()->ConvertFromRootFrame(
365         FloatPoint(event.PositionInWidget())));
366     HitTestResult result(
367         main_frame.GetEventHandler().HitTestResultAtLocation(location));
368     result.SetToShadowHostIfInRestrictedShadowRoot();
369     Node* hit_node = result.InnerNodeOrImageMapImage();
370     auto* html_element = DynamicTo<HTMLElement>(hit_node);
371     if (!result.GetScrollbar() && hit_node && hit_node->GetLayoutObject() &&
372         hit_node->GetLayoutObject()->IsEmbeddedObject() && html_element &&
373         html_element->IsPluginElement()) {
374       mouse_capture_element_ = To<HTMLPlugInElement>(hit_node);
375       main_frame.Client()->SetMouseCapture(true);
376       TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("input", "capturing mouse",
377                                         TRACE_ID_LOCAL(this));
378     }
379   }
380 
381   PageWidgetEventHandler::HandleMouseDown(main_frame, event);
382 
383   if (page_popup_ && page_popup &&
384       page_popup_->HasSamePopupClient(page_popup.get())) {
385     // That click triggered a page popup that is the same as the one we just
386     // closed.  It needs to be closed.
387     CancelPagePopup();
388   }
389 
390   // Dispatch the contextmenu event regardless of if the click was swallowed.
391   if (!GetPage()->GetSettings().GetShowContextMenuOnMouseUp()) {
392 #if defined(OS_MACOSX)
393     if (event.button == WebMouseEvent::Button::kRight ||
394         (event.button == WebMouseEvent::Button::kLeft &&
395          event.GetModifiers() & WebMouseEvent::kControlKey))
396       MouseContextMenu(event);
397 #else
398     if (event.button == WebMouseEvent::Button::kRight)
399       MouseContextMenu(event);
400 #endif
401   }
402 }
403 
SetDisplayMode(blink::mojom::DisplayMode mode)404 void WebViewImpl::SetDisplayMode(blink::mojom::DisplayMode mode) {
405   display_mode_ = mode;
406   if (!MainFrameImpl() || !MainFrameImpl()->GetFrameView())
407     return;
408 
409   MainFrameImpl()->GetFrameView()->SetDisplayMode(mode);
410 }
411 
MouseContextMenu(const WebMouseEvent & event)412 void WebViewImpl::MouseContextMenu(const WebMouseEvent& event) {
413   if (!MainFrameImpl() || !MainFrameImpl()->GetFrameView())
414     return;
415 
416   AsView().page->GetContextMenuController().ClearContextMenu();
417 
418   WebMouseEvent transformed_event =
419       TransformWebMouseEvent(MainFrameImpl()->GetFrameView(), event);
420   transformed_event.menu_source_type = kMenuSourceMouse;
421   PhysicalOffset position_in_root_frame = PhysicalOffset::FromFloatPointRound(
422       FloatPoint(transformed_event.PositionInRootFrame()));
423 
424   // Find the right target frame. See issue 1186900.
425   HitTestResult result = HitTestResultForRootFramePos(position_in_root_frame);
426   Frame* target_frame;
427   if (result.InnerNodeOrImageMapImage())
428     target_frame = result.InnerNodeOrImageMapImage()->GetDocument().GetFrame();
429   else
430     target_frame = AsView().page->GetFocusController().FocusedOrMainFrame();
431 
432   auto* target_local_frame = DynamicTo<LocalFrame>(target_frame);
433   if (!target_local_frame)
434     return;
435 
436   {
437     ContextMenuAllowedScope scope;
438     target_local_frame->GetEventHandler().SendContextMenuEvent(
439         transformed_event);
440   }
441   // Actually showing the context menu is handled by the ContextMenuController
442   // implementation...
443 }
444 
HandleMouseUp(LocalFrame & main_frame,const WebMouseEvent & event)445 WebInputEventResult WebViewImpl::HandleMouseUp(LocalFrame& main_frame,
446                                                const WebMouseEvent& event) {
447   WebInputEventResult result =
448       PageWidgetEventHandler::HandleMouseUp(main_frame, event);
449 
450   if (GetPage()->GetSettings().GetShowContextMenuOnMouseUp()) {
451     // Dispatch the contextmenu event regardless of if the click was swallowed.
452     // On Mac/Linux, we handle it on mouse down, not up.
453     if (event.button == WebMouseEvent::Button::kRight)
454       MouseContextMenu(event);
455   }
456   return result;
457 }
458 
HandleMouseWheel(LocalFrame & main_frame,const WebMouseWheelEvent & event)459 WebInputEventResult WebViewImpl::HandleMouseWheel(
460     LocalFrame& main_frame,
461     const WebMouseWheelEvent& event) {
462   CancelPagePopup();
463   return PageWidgetEventHandler::HandleMouseWheel(main_frame, event);
464 }
465 
HandleGestureEvent(const WebGestureEvent & event)466 WebInputEventResult WebViewImpl::HandleGestureEvent(
467     const WebGestureEvent& event) {
468   if (!AsView().client || !AsView().client->CanHandleGestureEvent()) {
469     return WebInputEventResult::kNotHandled;
470   }
471 
472   WebInputEventResult event_result = WebInputEventResult::kNotHandled;
473   bool event_cancelled = false;  // for disambiguation
474 
475   // Fling events are not sent to the renderer.
476   CHECK(event.GetType() != WebInputEvent::kGestureFlingStart);
477   CHECK(event.GetType() != WebInputEvent::kGestureFlingCancel);
478 
479   WebGestureEvent scaled_event =
480       TransformWebGestureEvent(MainFrameImpl()->GetFrameView(), event);
481 
482   // Special handling for double tap and scroll events as we don't want to
483   // hit test for them.
484   switch (event.GetType()) {
485     case WebInputEvent::kGestureDoubleTap:
486       if (web_settings_->DoubleTapToZoomEnabled() &&
487           MinimumPageScaleFactor() != MaximumPageScaleFactor()) {
488         if (auto* main_frame = MainFrameImpl()) {
489           IntPoint pos_in_root_frame =
490               FlooredIntPoint(scaled_event.PositionInRootFrame());
491           WebRect block_bounds =
492               main_frame->FrameWidgetImpl()->ComputeBlockBound(
493                   pos_in_root_frame, false);
494           AnimateDoubleTapZoom(pos_in_root_frame, block_bounds);
495         }
496       }
497       event_result = WebInputEventResult::kHandledSystem;
498       MainFrameImpl()->FrameWidgetImpl()->Client()->DidHandleGestureEvent(
499           event, event_cancelled);
500       return event_result;
501     case WebInputEvent::kGestureScrollBegin:
502     case WebInputEvent::kGestureScrollEnd:
503     case WebInputEvent::kGestureScrollUpdate:
504       // Scrolling-related gesture events invoke EventHandler recursively for
505       // each frame down the chain, doing a single-frame hit-test per frame.
506       // This matches handleWheelEvent.  Perhaps we could simplify things by
507       // rewriting scroll handling to work inner frame out, and then unify with
508       // other gesture events.
509       event_result = MainFrameImpl()
510                          ->GetFrame()
511                          ->GetEventHandler()
512                          .HandleGestureScrollEvent(scaled_event);
513       MainFrameImpl()->FrameWidgetImpl()->Client()->DidHandleGestureEvent(
514           event, event_cancelled);
515       return event_result;
516     default:
517       break;
518   }
519 
520   // Hit test across all frames and do touch adjustment as necessary for the
521   // event type.
522   GestureEventWithHitTestResults targeted_event =
523       AsView()
524           .page->DeprecatedLocalMainFrame()
525           ->GetEventHandler()
526           .TargetGestureEvent(scaled_event);
527 
528   // Handle link highlighting outside the main switch to avoid getting lost in
529   // the complicated set of cases handled below.
530   switch (event.GetType()) {
531     case WebInputEvent::kGestureShowPress:
532       // Queue a highlight animation, then hand off to regular handler.
533       EnableTapHighlightAtPoint(targeted_event);
534       break;
535     case WebInputEvent::kGestureTapCancel:
536     case WebInputEvent::kGestureTap:
537     case WebInputEvent::kGestureLongPress:
538       GetPage()->GetLinkHighlight().StartHighlightAnimationIfNeeded();
539       break;
540     default:
541       break;
542   }
543 
544   switch (event.GetType()) {
545     case WebInputEvent::kGestureTap: {
546       {
547         ContextMenuAllowedScope scope;
548         event_result =
549             MainFrameImpl()->GetFrame()->GetEventHandler().HandleGestureEvent(
550                 targeted_event);
551       }
552 
553       if (page_popup_ && last_hidden_page_popup_ &&
554           page_popup_->HasSamePopupClient(last_hidden_page_popup_.get())) {
555         // The tap triggered a page popup that is the same as the one we just
556         // closed. It needs to be closed.
557         CancelPagePopup();
558       }
559       // Don't have this value persist outside of a single tap gesture, plus
560       // we're done with it now.
561       last_hidden_page_popup_ = nullptr;
562       break;
563     }
564     case WebInputEvent::kGestureTwoFingerTap:
565     case WebInputEvent::kGestureLongPress:
566     case WebInputEvent::kGestureLongTap: {
567       if (!MainFrameImpl() || !MainFrameImpl()->GetFrameView())
568         break;
569 
570       if (event.GetType() == WebInputEvent::kGestureLongTap &&
571           !MainFrameImpl()
572                ->GetFrame()
573                ->GetEventHandler()
574                .LongTapShouldInvokeContextMenu())
575         break;
576 
577       AsView().page->GetContextMenuController().ClearContextMenu();
578       {
579         ContextMenuAllowedScope scope;
580         event_result =
581             MainFrameImpl()->GetFrame()->GetEventHandler().HandleGestureEvent(
582                 targeted_event);
583       }
584 
585       break;
586     }
587     case WebInputEvent::kGestureTapDown: {
588       // Touch pinch zoom and scroll on the page (outside of a popup) must hide
589       // the popup. In case of a touch scroll or pinch zoom, this function is
590       // called with GestureTapDown rather than a GSB/GSU/GSE or GPB/GPU/GPE.
591       // When we close a popup because of a GestureTapDown, we also save it so
592       // we can prevent the following GestureTap from immediately reopening the
593       // same popup.
594       // This value should not persist outside of a gesture, so is cleared by
595       // GestureTap (where it is used) and by GestureCancel.
596       last_hidden_page_popup_ = page_popup_;
597       CancelPagePopup();
598       DCHECK(!page_popup_);
599       event_result =
600           MainFrameImpl()->GetFrame()->GetEventHandler().HandleGestureEvent(
601               targeted_event);
602       break;
603     }
604     case WebInputEvent::kGestureTapCancel: {
605       // Don't have this value persist outside of a single tap gesture.
606       last_hidden_page_popup_ = nullptr;
607       event_result =
608           MainFrameImpl()->GetFrame()->GetEventHandler().HandleGestureEvent(
609               targeted_event);
610       break;
611     }
612     case WebInputEvent::kGestureShowPress: {
613       event_result =
614           MainFrameImpl()->GetFrame()->GetEventHandler().HandleGestureEvent(
615               targeted_event);
616       break;
617     }
618     case WebInputEvent::kGestureTapUnconfirmed: {
619       event_result =
620           MainFrameImpl()->GetFrame()->GetEventHandler().HandleGestureEvent(
621               targeted_event);
622       break;
623     }
624     default: { NOTREACHED(); }
625   }
626   MainFrameImpl()->FrameWidgetImpl()->Client()->DidHandleGestureEvent(
627       event, event_cancelled);
628   return event_result;
629 }
630 
StartPageScaleAnimation(const IntPoint & target_position,bool use_anchor,float new_scale,base::TimeDelta duration)631 bool WebViewImpl::StartPageScaleAnimation(const IntPoint& target_position,
632                                           bool use_anchor,
633                                           float new_scale,
634                                           base::TimeDelta duration) {
635   // PageScaleFactor is a property of the main frame only, and only exists when
636   // compositing.
637   DCHECK(MainFrameImpl());
638   DCHECK(does_composite_);
639 
640   VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
641   gfx::Point clamped_point = target_position;
642   if (!use_anchor) {
643     clamped_point =
644         visual_viewport.ClampDocumentOffsetAtScale(target_position, new_scale);
645     if (duration.is_zero()) {
646       SetPageScaleFactor(new_scale);
647 
648       LocalFrameView* view = MainFrameImpl()->GetFrameView();
649       if (view && view->GetScrollableArea()) {
650         view->GetScrollableArea()->SetScrollOffset(
651             ScrollOffset(clamped_point.x(), clamped_point.y()),
652             mojom::blink::ScrollType::kProgrammatic);
653       }
654 
655       return false;
656     }
657   }
658   if (use_anchor && new_scale == PageScaleFactor())
659     return false;
660 
661   if (enable_fake_page_scale_animation_for_testing_) {
662     fake_page_scale_animation_target_position_ = target_position;
663     fake_page_scale_animation_use_anchor_ = use_anchor;
664     fake_page_scale_animation_page_scale_factor_ = new_scale;
665   } else {
666     MainFrameImpl()->FrameWidgetImpl()->StartPageScaleAnimation(
667         static_cast<gfx::Vector2d>(target_position), use_anchor, new_scale,
668         duration);
669   }
670   return true;
671 }
672 
EnableFakePageScaleAnimationForTesting(bool enable)673 void WebViewImpl::EnableFakePageScaleAnimationForTesting(bool enable) {
674   enable_fake_page_scale_animation_for_testing_ = enable;
675   fake_page_scale_animation_target_position_ = IntPoint();
676   fake_page_scale_animation_use_anchor_ = false;
677   fake_page_scale_animation_page_scale_factor_ = 0;
678 }
679 
AcceptLanguagesChanged()680 void WebViewImpl::AcceptLanguagesChanged() {
681   if (AsView().client)
682     FontCache::AcceptLanguagesChanged(AsView().client->AcceptLanguages());
683 
684   if (!GetPage())
685     return;
686 
687   GetPage()->AcceptLanguagesChanged();
688 }
689 
HandleKeyEvent(const WebKeyboardEvent & event)690 WebInputEventResult WebViewImpl::HandleKeyEvent(const WebKeyboardEvent& event) {
691   DCHECK((event.GetType() == WebInputEvent::kRawKeyDown) ||
692          (event.GetType() == WebInputEvent::kKeyDown) ||
693          (event.GetType() == WebInputEvent::kKeyUp));
694   TRACE_EVENT2("input", "WebViewImpl::handleKeyEvent", "type",
695                WebInputEvent::GetName(event.GetType()), "text",
696                String(event.text).Utf8());
697 
698   // Please refer to the comments explaining |suppress_next_keypress_event_|.
699   //
700   // |suppress_next_keypress_event_| is set if the KeyDown is handled by
701   // Webkit. A keyDown event is typically associated with a keyPress(char)
702   // event and a keyUp event. We reset this flag here as this is a new keyDown
703   // event.
704   suppress_next_keypress_event_ = false;
705 
706   // If there is a popup, it should be the one processing the event, not the
707   // page.
708   if (page_popup_) {
709     page_popup_->HandleKeyEvent(event);
710     // We need to ignore the next Char event after this otherwise pressing
711     // enter when selecting an item in the popup will go to the page.
712     if (WebInputEvent::kRawKeyDown == event.GetType())
713       suppress_next_keypress_event_ = true;
714     return WebInputEventResult::kHandledSystem;
715   }
716 
717   Frame* focused_frame = FocusedCoreFrame();
718   auto* focused_local_frame = DynamicTo<LocalFrame>(focused_frame);
719   if (!focused_local_frame)
720     return WebInputEventResult::kNotHandled;
721 
722   WebInputEventResult result =
723       focused_local_frame->GetEventHandler().KeyEvent(event);
724   if (result != WebInputEventResult::kNotHandled) {
725     if (WebInputEvent::kRawKeyDown == event.GetType()) {
726       // Suppress the next keypress event unless the focused node is a plugin
727       // node.  (Flash needs these keypress events to handle non-US keyboards.)
728       Element* element = FocusedElement();
729       if (element && element->GetLayoutObject() &&
730           element->GetLayoutObject()->IsEmbeddedObject()) {
731         if (event.windows_key_code == VKEY_TAB) {
732           // If the plugin supports keyboard focus then we should not send a tab
733           // keypress event.
734           WebPluginContainerImpl* plugin_view =
735               ToLayoutEmbeddedContent(element->GetLayoutObject())->Plugin();
736           if (plugin_view && plugin_view->SupportsKeyboardFocus()) {
737             suppress_next_keypress_event_ = true;
738           }
739         }
740       } else {
741         suppress_next_keypress_event_ = true;
742       }
743     }
744     return result;
745   }
746 
747 #if !defined(OS_MACOSX)
748   const WebInputEvent::Type kContextMenuKeyTriggeringEventType =
749 #if defined(OS_WIN)
750       WebInputEvent::kKeyUp;
751 #else
752       WebInputEvent::kRawKeyDown;
753 #endif
754   const WebInputEvent::Type kShiftF10TriggeringEventType =
755       WebInputEvent::kRawKeyDown;
756 
757   bool is_unmodified_menu_key =
758       !(event.GetModifiers() & WebInputEvent::kInputModifiers) &&
759       event.windows_key_code == VKEY_APPS;
760   bool is_shift_f10 = (event.GetModifiers() & WebInputEvent::kInputModifiers) ==
761                           WebInputEvent::kShiftKey &&
762                       event.windows_key_code == VKEY_F10;
763   if ((is_unmodified_menu_key &&
764        event.GetType() == kContextMenuKeyTriggeringEventType) ||
765       (is_shift_f10 && event.GetType() == kShiftF10TriggeringEventType)) {
766     SendContextMenuEvent();
767     return WebInputEventResult::kHandledSystem;
768   }
769 #endif  // !defined(OS_MACOSX)
770 
771   return WebInputEventResult::kNotHandled;
772 }
773 
HandleCharEvent(const WebKeyboardEvent & event)774 WebInputEventResult WebViewImpl::HandleCharEvent(
775     const WebKeyboardEvent& event) {
776   DCHECK_EQ(event.GetType(), WebInputEvent::kChar);
777   TRACE_EVENT1("input", "WebViewImpl::handleCharEvent", "text",
778                String(event.text).Utf8());
779 
780   // Please refer to the comments explaining |suppress_next_keypress_event_|
781   // |suppress_next_keypress_event_| is set if the KeyDown is
782   // handled by Webkit. A keyDown event is typically associated with a
783   // keyPress(char) event and a keyUp event. We reset this flag here as it
784   // only applies to the current keyPress event.
785   bool suppress = suppress_next_keypress_event_;
786   suppress_next_keypress_event_ = false;
787 
788   // If there is a popup, it should be the one processing the event, not the
789   // page.
790   if (page_popup_)
791     return page_popup_->HandleKeyEvent(event);
792 
793   auto* frame = To<LocalFrame>(FocusedCoreFrame());
794   if (!frame) {
795     return suppress ? WebInputEventResult::kHandledSuppressed
796                     : WebInputEventResult::kNotHandled;
797   }
798 
799   EventHandler& handler = frame->GetEventHandler();
800 
801   if (!event.IsCharacterKey())
802     return WebInputEventResult::kHandledSuppressed;
803 
804   // Accesskeys are triggered by char events and can't be suppressed.
805   if (handler.HandleAccessKey(event))
806     return WebInputEventResult::kHandledSystem;
807 
808   // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to
809   // the eventHandler::keyEvent. We mimic this behavior on all platforms since
810   // for now we are converting other platform's key events to windows key
811   // events.
812   if (event.is_system_key)
813     return WebInputEventResult::kNotHandled;
814 
815   if (suppress)
816     return WebInputEventResult::kHandledSuppressed;
817 
818   WebInputEventResult result = handler.KeyEvent(event);
819   if (result != WebInputEventResult::kNotHandled)
820     return result;
821 
822   return WebInputEventResult::kNotHandled;
823 }
824 
WidenRectWithinPageBounds(const WebRect & source,int target_margin,int minimum_margin)825 WebRect WebViewImpl::WidenRectWithinPageBounds(const WebRect& source,
826                                                int target_margin,
827                                                int minimum_margin) {
828   // Caller should guarantee that the main frame exists and is local.
829   DCHECK(MainFrame());
830   DCHECK(MainFrame()->IsWebLocalFrame());
831   WebSize max_size = MainFrame()->ToWebLocalFrame()->DocumentSize();
832   IntSize scroll_offset = MainFrame()->ToWebLocalFrame()->GetScrollOffset();
833 
834   int left_margin = target_margin;
835   int right_margin = target_margin;
836 
837   const int absolute_source_x = source.x + scroll_offset.Width();
838   if (left_margin > absolute_source_x) {
839     left_margin = absolute_source_x;
840     right_margin = std::max(left_margin, minimum_margin);
841   }
842 
843   const int maximum_right_margin =
844       max_size.width - (source.width + absolute_source_x);
845   if (right_margin > maximum_right_margin) {
846     right_margin = maximum_right_margin;
847     left_margin = std::min(left_margin, std::max(right_margin, minimum_margin));
848   }
849 
850   const int new_width = source.width + left_margin + right_margin;
851   const int new_x = source.x - left_margin;
852 
853   DCHECK_GE(new_width, 0);
854   DCHECK_LE(scroll_offset.Width() + new_x + new_width, max_size.width);
855 
856   return WebRect(new_x, source.y, new_width, source.height);
857 }
858 
MaximumLegiblePageScale() const859 float WebViewImpl::MaximumLegiblePageScale() const {
860   // Pages should be as legible as on desktop when at dpi scale, so no
861   // need to zoom in further when automatically determining zoom level
862   // (after double tap, find in page, etc), though the user should still
863   // be allowed to manually pinch zoom in further if they desire.
864   if (GetPage()) {
865     return maximum_legible_scale_ *
866            GetPage()->GetSettings().GetAccessibilityFontScaleFactor();
867   }
868   return maximum_legible_scale_;
869 }
870 
ComputeScaleAndScrollForBlockRect(const gfx::Point & hit_point_in_root_frame,const WebRect & block_rect_in_root_frame,float padding,float default_scale_when_already_legible,float & scale,IntPoint & scroll)871 void WebViewImpl::ComputeScaleAndScrollForBlockRect(
872     const gfx::Point& hit_point_in_root_frame,
873     const WebRect& block_rect_in_root_frame,
874     float padding,
875     float default_scale_when_already_legible,
876     float& scale,
877     IntPoint& scroll) {
878   scale = PageScaleFactor();
879   scroll = IntPoint();
880 
881   WebRect rect = block_rect_in_root_frame;
882 
883   if (!rect.IsEmpty()) {
884     float default_margin = doubleTapZoomContentDefaultMargin;
885     float minimum_margin = doubleTapZoomContentMinimumMargin;
886     // We want the margins to have the same physical size, which means we
887     // need to express them in post-scale size. To do that we'd need to know
888     // the scale we're scaling to, but that depends on the margins. Instead
889     // we express them as a fraction of the target rectangle: this will be
890     // correct if we end up fully zooming to it, and won't matter if we
891     // don't.
892     rect = WidenRectWithinPageBounds(
893         rect, static_cast<int>(default_margin * rect.width / size_.width),
894         static_cast<int>(minimum_margin * rect.width / size_.width));
895     // Fit block to screen, respecting limits.
896     scale = static_cast<float>(size_.width) / rect.width;
897     scale = std::min(scale, MaximumLegiblePageScale());
898     if (PageScaleFactor() < default_scale_when_already_legible)
899       scale = std::max(scale, default_scale_when_already_legible);
900     scale = ClampPageScaleFactorToLimits(scale);
901   }
902 
903   // FIXME: If this is being called for auto zoom during find in page,
904   // then if the user manually zooms in it'd be nice to preserve the
905   // relative increase in zoom they caused (if they zoom out then it's ok
906   // to zoom them back in again). This isn't compatible with our current
907   // double-tap zoom strategy (fitting the containing block to the screen)
908   // though.
909 
910   float screen_width = size_.width / scale;
911   float screen_height = size_.height / scale;
912 
913   // Scroll to vertically align the block.
914   if (rect.height < screen_height) {
915     // Vertically center short blocks.
916     rect.y -= 0.5 * (screen_height - rect.height);
917   } else {
918     // Ensure position we're zooming to (+ padding) isn't off the bottom of
919     // the screen.
920     rect.y = std::max<float>(
921         rect.y, hit_point_in_root_frame.y() + padding - screen_height);
922   }  // Otherwise top align the block.
923 
924   // Do the same thing for horizontal alignment.
925   if (rect.width < screen_width) {
926     rect.x -= 0.5 * (screen_width - rect.width);
927   } else {
928     rect.x = std::max<float>(
929         rect.x, hit_point_in_root_frame.x() + padding - screen_width);
930   }
931   scroll.SetX(rect.x);
932   scroll.SetY(rect.y);
933 
934   scale = ClampPageScaleFactorToLimits(scale);
935   scroll = MainFrameImpl()->GetFrameView()->RootFrameToDocument(scroll);
936   scroll =
937       GetPage()->GetVisualViewport().ClampDocumentOffsetAtScale(scroll, scale);
938 }
939 
FindCursorDefiningAncestor(Node * node,LocalFrame * frame)940 static Node* FindCursorDefiningAncestor(Node* node, LocalFrame* frame) {
941   // Go up the tree to find the node that defines a mouse cursor style
942   while (node) {
943     if (node->GetLayoutObject()) {
944       ECursor cursor = node->GetLayoutObject()->Style()->Cursor();
945       if (cursor != ECursor::kAuto ||
946           frame->GetEventHandler().UseHandCursor(node, node->IsLink()))
947         break;
948     }
949     node = LayoutTreeBuilderTraversal::Parent(*node);
950   }
951 
952   return node;
953 }
954 
ShowsHandCursor(Node * node,LocalFrame * frame)955 static bool ShowsHandCursor(Node* node, LocalFrame* frame) {
956   if (!node || !node->GetLayoutObject())
957     return false;
958 
959   ECursor cursor = node->GetLayoutObject()->Style()->Cursor();
960   return cursor == ECursor::kPointer ||
961          (cursor == ECursor::kAuto &&
962           frame->GetEventHandler().UseHandCursor(node, node->IsLink()));
963 }
964 
965 // This is for tap (link) highlight and is tested in
966 // link_highlight_impl_test.cc.
BestTapNode(const GestureEventWithHitTestResults & targeted_tap_event)967 Node* WebViewImpl::BestTapNode(
968     const GestureEventWithHitTestResults& targeted_tap_event) {
969   TRACE_EVENT0("input", "WebViewImpl::bestTapNode");
970 
971   Page* page = AsView().page.Get();
972   if (!page || !page->MainFrame())
973     return nullptr;
974 
975   Node* best_touch_node = targeted_tap_event.GetHitTestResult().InnerNode();
976   if (!best_touch_node)
977     return nullptr;
978 
979   // We might hit something like an image map that has no layoutObject on it
980   // Walk up the tree until we have a node with an attached layoutObject
981   while (!best_touch_node->GetLayoutObject()) {
982     best_touch_node = LayoutTreeBuilderTraversal::Parent(*best_touch_node);
983     if (!best_touch_node)
984       return nullptr;
985   }
986 
987   // Editable nodes should not be highlighted (e.g., <input>)
988   if (HasEditableStyle(*best_touch_node))
989     return nullptr;
990 
991   Node* cursor_defining_ancestor = FindCursorDefiningAncestor(
992       best_touch_node, page->DeprecatedLocalMainFrame());
993   // We show a highlight on tap only when the current node shows a hand cursor
994   if (!cursor_defining_ancestor ||
995       !ShowsHandCursor(cursor_defining_ancestor,
996                        page->DeprecatedLocalMainFrame())) {
997     return nullptr;
998   }
999 
1000   // We should pick the largest enclosing node with hand cursor set. We do this
1001   // by first jumping up to cursorDefiningAncestor (which is already known to
1002   // have hand cursor set). Then we locate the next cursor-defining ancestor up
1003   // in the the tree and repeat the jumps as long as the node has hand cursor
1004   // set.
1005   do {
1006     best_touch_node = cursor_defining_ancestor;
1007     cursor_defining_ancestor = FindCursorDefiningAncestor(
1008         LayoutTreeBuilderTraversal::Parent(*best_touch_node),
1009         page->DeprecatedLocalMainFrame());
1010   } while (cursor_defining_ancestor &&
1011            ShowsHandCursor(cursor_defining_ancestor,
1012                            page->DeprecatedLocalMainFrame()));
1013 
1014   // This happens in cases like:
1015   // <div style="display: contents; cursor: pointer">Text</div>.
1016   // The text node inherits cursor: pointer and the div doesn't have a
1017   // LayoutObject, so |best_touch_node| is the text node here. We should not
1018   // return the text node because it can't have touch actions.
1019   if (best_touch_node->IsTextNode())
1020     return nullptr;
1021 
1022   return best_touch_node;
1023 }
1024 
EnableTapHighlightAtPoint(const GestureEventWithHitTestResults & targeted_tap_event)1025 void WebViewImpl::EnableTapHighlightAtPoint(
1026     const GestureEventWithHitTestResults& targeted_tap_event) {
1027   Node* touch_node = BestTapNode(targeted_tap_event);
1028   GetPage()->GetLinkHighlight().SetTapHighlight(touch_node);
1029   UpdateLifecycle(WebLifecycleUpdate::kAll,
1030                   DocumentUpdateReason::kTapHighlight);
1031 }
1032 
AnimateDoubleTapZoom(const gfx::Point & point_in_root_frame,const WebRect & rect_to_zoom)1033 void WebViewImpl::AnimateDoubleTapZoom(const gfx::Point& point_in_root_frame,
1034                                        const WebRect& rect_to_zoom) {
1035   DCHECK(MainFrameImpl());
1036 
1037   float scale;
1038   IntPoint scroll;
1039 
1040   ComputeScaleAndScrollForBlockRect(
1041       point_in_root_frame, rect_to_zoom, touchPointPadding,
1042       MinimumPageScaleFactor() * doubleTapZoomAlreadyLegibleRatio, scale,
1043       scroll);
1044 
1045   bool still_at_previous_double_tap_scale =
1046       (PageScaleFactor() == double_tap_zoom_page_scale_factor_ &&
1047        double_tap_zoom_page_scale_factor_ != MinimumPageScaleFactor()) ||
1048       double_tap_zoom_pending_;
1049 
1050   bool scale_unchanged = fabs(PageScaleFactor() - scale) < minScaleDifference;
1051   bool should_zoom_out = rect_to_zoom.IsEmpty() || scale_unchanged ||
1052                          still_at_previous_double_tap_scale;
1053 
1054   bool is_animating;
1055 
1056   if (should_zoom_out) {
1057     scale = MinimumPageScaleFactor();
1058     IntPoint target_position =
1059         MainFrameImpl()->GetFrameView()->RootFrameToDocument(
1060             IntPoint(point_in_root_frame.x(), point_in_root_frame.y()));
1061     is_animating = StartPageScaleAnimation(target_position, true, scale,
1062                                            kDoubleTapZoomAnimationDuration);
1063   } else {
1064     is_animating = StartPageScaleAnimation(scroll, false, scale,
1065                                            kDoubleTapZoomAnimationDuration);
1066   }
1067 
1068   // TODO(dglazkov): The only reason why we're using isAnimating and not just
1069   // checking for layer_tree_view_->HasPendingPageScaleAnimation() is because of
1070   // fake page scale animation plumbing for testing, which doesn't actually
1071   // initiate a page scale animation.
1072   if (is_animating) {
1073     double_tap_zoom_page_scale_factor_ = scale;
1074     double_tap_zoom_pending_ = true;
1075   }
1076 }
1077 
ZoomToFindInPageRect(const WebRect & rect_in_root_frame)1078 void WebViewImpl::ZoomToFindInPageRect(const WebRect& rect_in_root_frame) {
1079   DCHECK(MainFrameImpl());
1080 
1081   WebRect block_bounds = MainFrameImpl()->FrameWidgetImpl()->ComputeBlockBound(
1082       gfx::Point(rect_in_root_frame.x + rect_in_root_frame.width / 2,
1083                  rect_in_root_frame.y + rect_in_root_frame.height / 2),
1084       true);
1085 
1086   if (block_bounds.IsEmpty()) {
1087     // Keep current scale (no need to scroll as x,y will normally already
1088     // be visible). FIXME: Revisit this if it isn't always true.
1089     return;
1090   }
1091 
1092   float scale;
1093   IntPoint scroll;
1094 
1095   ComputeScaleAndScrollForBlockRect(
1096       gfx::Point(rect_in_root_frame.x, rect_in_root_frame.y), block_bounds,
1097       nonUserInitiatedPointPadding, MinimumPageScaleFactor(), scale, scroll);
1098 
1099   StartPageScaleAnimation(scroll, false, scale, kFindInPageAnimationDuration);
1100 }
1101 
1102 #if !defined(OS_MACOSX)
1103 // Mac has no way to open a context menu based on a keyboard event.
SendContextMenuEvent()1104 WebInputEventResult WebViewImpl::SendContextMenuEvent() {
1105   // The contextMenuController() holds onto the last context menu that was
1106   // popped up on the page until a new one is created. We need to clear
1107   // this menu before propagating the event through the DOM so that we can
1108   // detect if we create a new menu for this event, since we won't create
1109   // a new menu if the DOM swallows the event and the defaultEventHandler does
1110   // not run.
1111   GetPage()->GetContextMenuController().ClearContextMenu();
1112 
1113   {
1114     ContextMenuAllowedScope scope;
1115     Frame* focused_frame = GetPage()->GetFocusController().FocusedOrMainFrame();
1116     auto* focused_local_frame = DynamicTo<LocalFrame>(focused_frame);
1117     if (!focused_local_frame)
1118       return WebInputEventResult::kNotHandled;
1119     // Firefox reveal focus based on "keydown" event but not "contextmenu"
1120     // event, we match FF.
1121     if (Element* focused_element =
1122             focused_local_frame->GetDocument()->FocusedElement())
1123       focused_element->scrollIntoViewIfNeeded();
1124     return focused_local_frame->GetEventHandler().ShowNonLocatedContextMenu(
1125         nullptr, kMenuSourceKeyboard);
1126   }
1127 }
1128 #else
SendContextMenuEvent()1129 WebInputEventResult WebViewImpl::SendContextMenuEvent() {
1130   return WebInputEventResult::kNotHandled;
1131 }
1132 #endif
1133 
ShowContextMenuForElement(WebElement element)1134 void WebViewImpl::ShowContextMenuForElement(WebElement element) {
1135   if (!GetPage())
1136     return;
1137 
1138   GetPage()->GetContextMenuController().ClearContextMenu();
1139   {
1140     ContextMenuAllowedScope scope;
1141     if (LocalFrame* focused_frame = To<LocalFrame>(
1142             GetPage()->GetFocusController().FocusedOrMainFrame())) {
1143       focused_frame->GetEventHandler().ShowNonLocatedContextMenu(
1144           element.Unwrap<Element>());
1145     }
1146   }
1147 }
1148 
OpenPagePopup(PagePopupClient * client)1149 WebPagePopupImpl* WebViewImpl::OpenPagePopup(PagePopupClient* client) {
1150   DCHECK(client);
1151 
1152   // This guarantees there is never more than 1 PagePopup active at a time.
1153   CancelPagePopup();
1154   DCHECK(!page_popup_);
1155 
1156   WebLocalFrameImpl* frame = WebLocalFrameImpl::FromFrame(
1157       client->OwnerElement().GetDocument().GetFrame()->LocalFrameRoot());
1158   WebPagePopup* popup_widget = AsView().client->CreatePopup(frame);
1159   // CreatePopup returns nullptr if this renderer process is about to die.
1160   if (!popup_widget)
1161     return nullptr;
1162   page_popup_ = To<WebPagePopupImpl>(popup_widget);
1163   page_popup_->Initialize(this, client);
1164   EnablePopupMouseWheelEventListener(frame);
1165   return page_popup_.get();
1166 }
1167 
CancelPagePopup()1168 void WebViewImpl::CancelPagePopup() {
1169   if (page_popup_)
1170     page_popup_->Cancel();
1171 }
1172 
ClosePagePopup(PagePopup * popup)1173 void WebViewImpl::ClosePagePopup(PagePopup* popup) {
1174   DCHECK(popup);
1175   auto* popup_impl = To<WebPagePopupImpl>(popup);
1176   DCHECK_EQ(page_popup_.get(), popup_impl);
1177   if (page_popup_.get() != popup_impl)
1178     return;
1179   page_popup_->ClosePopup();
1180 }
1181 
CleanupPagePopup()1182 void WebViewImpl::CleanupPagePopup() {
1183   page_popup_ = nullptr;
1184   DisablePopupMouseWheelEventListener();
1185 }
1186 
EnablePopupMouseWheelEventListener(WebLocalFrameImpl * local_root)1187 void WebViewImpl::EnablePopupMouseWheelEventListener(
1188     WebLocalFrameImpl* local_root) {
1189   DCHECK(!popup_mouse_wheel_event_listener_);
1190   Document* document = local_root->GetDocument();
1191   DCHECK(document);
1192   // We register an empty event listener, EmptyEventListener, so that mouse
1193   // wheel events get sent to the WebView.
1194   popup_mouse_wheel_event_listener_ =
1195       MakeGarbageCollected<EmptyEventListener>();
1196   document->addEventListener(event_type_names::kMousewheel,
1197                              popup_mouse_wheel_event_listener_, false);
1198   local_root_with_empty_mouse_wheel_listener_ = local_root;
1199 }
1200 
DisablePopupMouseWheelEventListener()1201 void WebViewImpl::DisablePopupMouseWheelEventListener() {
1202   // TODO(kenrb): Concerns the same as in enablePopupMouseWheelEventListener.
1203   // See https://crbug.com/566130
1204   DCHECK(popup_mouse_wheel_event_listener_);
1205   Document* document =
1206       local_root_with_empty_mouse_wheel_listener_->GetDocument();
1207   DCHECK(document);
1208   // Document may have already removed the event listener, for instance, due
1209   // to a navigation, but remove it anyway.
1210   document->removeEventListener(event_type_names::kMousewheel,
1211                                 popup_mouse_wheel_event_listener_.Release(),
1212                                 false);
1213   local_root_with_empty_mouse_wheel_listener_ = nullptr;
1214 }
1215 
PagePopupWindow() const1216 LocalDOMWindow* WebViewImpl::PagePopupWindow() const {
1217   return page_popup_ ? page_popup_->Window() : nullptr;
1218 }
1219 
FocusedCoreFrame() const1220 Frame* WebViewImpl::FocusedCoreFrame() const {
1221   Page* page = AsView().page.Get();
1222   return page ? page->GetFocusController().FocusedOrMainFrame() : nullptr;
1223 }
1224 
1225 // WebWidget ------------------------------------------------------------------
1226 
Close()1227 void WebViewImpl::Close() {
1228   // Closership is a single relationship, so only 1 call to Close() should
1229   // occur.
1230   CHECK(AsView().page);
1231   DCHECK(AllInstances().Contains(this));
1232   AllInstances().erase(this);
1233 
1234   // Initiate shutdown for the entire frameset.  This will cause a lot of
1235   // notifications to be sent. This will detach all frames in this WebView's
1236   // frame tree.
1237   AsView().page->WillBeDestroyed();
1238 
1239   // TODO(bokan): Temporary debugging added to diagnose
1240   // https://crbug.com/992315. Somehow we're synchronously calling
1241   // WebViewImpl::Close while handling an input event.
1242   CHECK(!debug_inside_input_handling_);
1243   AsView().page.Clear();
1244 
1245   // Reset the delegate to prevent notifications being sent as we're being
1246   // deleted.
1247   AsView().client = nullptr;
1248 
1249   Release();  // Balances a reference acquired in WebView::Create
1250 }
1251 
Size()1252 WebSize WebViewImpl::Size() {
1253   return size_;
1254 }
1255 
ResizeVisualViewport(const WebSize & new_size)1256 void WebViewImpl::ResizeVisualViewport(const WebSize& new_size) {
1257   GetPage()->GetVisualViewport().SetSize(new_size);
1258   GetPage()->GetVisualViewport().ClampToBoundaries();
1259 }
1260 
UpdateICBAndResizeViewport(const IntSize & visible_viewport_size)1261 void WebViewImpl::UpdateICBAndResizeViewport(
1262     const IntSize& visible_viewport_size) {
1263   // We'll keep the initial containing block size from changing when the top
1264   // controls hide so that the ICB will always be the same size as the
1265   // viewport with the browser controls shown.
1266   IntSize icb_size = size_;
1267   if (GetBrowserControls().PermittedState() ==
1268           cc::BrowserControlsState::kBoth &&
1269       !GetBrowserControls().ShrinkViewport()) {
1270     icb_size.Expand(0, -(GetBrowserControls().TotalHeight() -
1271                          GetBrowserControls().TotalMinHeight()));
1272   }
1273 
1274   GetPageScaleConstraintsSet().DidChangeInitialContainingBlockSize(icb_size);
1275 
1276   UpdatePageDefinedViewportConstraints(MainFrameImpl()
1277                                            ->GetFrame()
1278                                            ->GetDocument()
1279                                            ->GetViewportData()
1280                                            .GetViewportDescription());
1281   UpdateMainFrameLayoutSize();
1282 
1283   GetPage()->GetVisualViewport().SetSize(visible_viewport_size);
1284 
1285   if (MainFrameImpl()->GetFrameView()) {
1286     MainFrameImpl()->GetFrameView()->SetInitialViewportSize(icb_size);
1287     if (!MainFrameImpl()->GetFrameView()->NeedsLayout())
1288       resize_viewport_anchor_->ResizeFrameView(MainFrameSize());
1289   }
1290 
1291   // The boundaries are not properly established until after the frame view is
1292   // also resized, as demonstrated by
1293   // VisualViewportTest.TestBrowserControlsAdjustmentAndResize.
1294   GetPage()->GetVisualViewport().ClampToBoundaries();
1295 }
1296 
UpdateBrowserControlsConstraint(cc::BrowserControlsState constraint)1297 void WebViewImpl::UpdateBrowserControlsConstraint(
1298     cc::BrowserControlsState constraint) {
1299   cc::BrowserControlsState old_permitted_state =
1300       GetBrowserControls().PermittedState();
1301 
1302   GetBrowserControls().UpdateConstraintsAndState(
1303       constraint, cc::BrowserControlsState::kBoth);
1304 
1305   // If the controls are going from a locked hidden to unlocked state, or vice
1306   // versa, the ICB size needs to change but we can't rely on getting a
1307   // WebViewImpl::resize since the top controls shown state may not have
1308   // changed.
1309   if ((old_permitted_state == cc::BrowserControlsState::kHidden &&
1310        constraint == cc::BrowserControlsState::kBoth) ||
1311       (old_permitted_state == cc::BrowserControlsState::kBoth &&
1312        constraint == cc::BrowserControlsState::kHidden)) {
1313     UpdateICBAndResizeViewport(GetPage()->GetVisualViewport().Size());
1314   }
1315 }
1316 
DidUpdateBrowserControls()1317 void WebViewImpl::DidUpdateBrowserControls() {
1318   // BrowserControls are a feature whereby the browser can introduce an
1319   // interactable element [e.g. search box] that grows/shrinks in height as the
1320   // user scrolls the web contents.
1321   //
1322   // This method is called by the BrowserControls class to let the compositor
1323   // know that the browser controls have been updated. This is only relevant if
1324   // the main frame is local because BrowserControls only affects the main
1325   // frame's viewport, and are only affected by main frame scrolling.
1326   //
1327   // The relevant state is stored on the BrowserControls object even if the main
1328   // frame is remote. If the main frame becomes local, the state will be
1329   // restored by the first commit, since the state is checked in every call to
1330   // ApplyScrollAndScale().
1331   WebLocalFrameImpl* main_frame = MainFrameImpl();
1332   if (!main_frame)
1333     return;
1334 
1335   WebFrameWidgetBase* widget = main_frame->LocalRootFrameWidget();
1336   widget->SetBrowserControlsShownRatio(GetBrowserControls().TopShownRatio(),
1337                                        GetBrowserControls().BottomShownRatio());
1338   widget->SetBrowserControlsParams(GetBrowserControls().Params());
1339 
1340   VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
1341 
1342   {
1343     // This object will save the current visual viewport offset w.r.t. the
1344     // document and restore it when the object goes out of scope. It's
1345     // needed since the browser controls adjustment will change the maximum
1346     // scroll offset and we may need to reposition them to keep the user's
1347     // apparent position unchanged.
1348     ResizeViewportAnchor::ResizeScope resize_scope(*resize_viewport_anchor_);
1349 
1350     visual_viewport.SetBrowserControlsAdjustment(
1351         GetBrowserControls().UnreportedSizeAdjustment());
1352   }
1353 }
1354 
GetBrowserControls()1355 BrowserControls& WebViewImpl::GetBrowserControls() {
1356   return GetPage()->GetBrowserControls();
1357 }
1358 
ResizeViewWhileAnchored(cc::BrowserControlsParams params,const IntSize & visible_viewport_size)1359 void WebViewImpl::ResizeViewWhileAnchored(
1360     cc::BrowserControlsParams params,
1361     const IntSize& visible_viewport_size) {
1362   DCHECK(MainFrameImpl());
1363 
1364   GetBrowserControls().SetParams(params);
1365 
1366   {
1367     // Avoids unnecessary invalidations while various bits of state in
1368     // TextAutosizer are updated.
1369     TextAutosizer::DeferUpdatePageInfo defer_update_page_info(GetPage());
1370     LocalFrameView* frame_view = MainFrameImpl()->GetFrameView();
1371     IntSize old_size = frame_view->Size();
1372     UpdateICBAndResizeViewport(visible_viewport_size);
1373     IntSize new_size = frame_view->Size();
1374     frame_view->MarkViewportConstrainedObjectsForLayout(
1375         old_size.Width() != new_size.Width(),
1376         old_size.Height() != new_size.Height());
1377   }
1378 
1379   fullscreen_controller_->UpdateSize();
1380 
1381   // Update lifecycle phases immediately to recalculate the minimum scale limit
1382   // for rotation anchoring, and to make sure that no lifecycle states are
1383   // stale if this WebView is embedded in another one.
1384   UpdateLifecycle(WebLifecycleUpdate::kAll, DocumentUpdateReason::kSizeChange);
1385 }
1386 
ResizeWithBrowserControls(const WebSize & new_size,float top_controls_height,float bottom_controls_height,bool browser_controls_shrink_layout)1387 void WebViewImpl::ResizeWithBrowserControls(
1388     const WebSize& new_size,
1389     float top_controls_height,
1390     float bottom_controls_height,
1391     bool browser_controls_shrink_layout) {
1392   ResizeWithBrowserControls(
1393       new_size, new_size,
1394       {top_controls_height, GetBrowserControls().TopMinHeight(),
1395        bottom_controls_height, GetBrowserControls().BottomMinHeight(),
1396        GetBrowserControls().AnimateHeightChanges(),
1397        browser_controls_shrink_layout});
1398 }
1399 
ResizeWithBrowserControls(const WebSize & main_frame_widget_size,const WebSize & visible_viewport_size,cc::BrowserControlsParams browser_controls_params)1400 void WebViewImpl::ResizeWithBrowserControls(
1401     const WebSize& main_frame_widget_size,
1402     const WebSize& visible_viewport_size,
1403     cc::BrowserControlsParams browser_controls_params) {
1404   if (should_auto_resize_) {
1405     // When auto-resizing only the viewport size comes from the browser, while
1406     // the widget size is determined in the renderer.
1407     ResizeVisualViewport(visible_viewport_size);
1408     return;
1409   }
1410 
1411   if (size_ == main_frame_widget_size &&
1412       GetPage()->GetVisualViewport().Size() == IntSize(visible_viewport_size) &&
1413       GetBrowserControls().Params() == browser_controls_params)
1414     return;
1415 
1416   if (GetPage()->MainFrame() && !GetPage()->MainFrame()->IsLocalFrame()) {
1417     // Viewport resize for a remote main frame does not require any
1418     // particular action, but the state needs to reflect the correct size
1419     // so that it can be used for initialization if the main frame gets
1420     // swapped to a LocalFrame at a later time.
1421     size_ = main_frame_widget_size;
1422     GetPageScaleConstraintsSet().DidChangeInitialContainingBlockSize(size_);
1423     GetPage()->GetVisualViewport().SetSize(size_);
1424     GetPage()->GetBrowserControls().SetParams(browser_controls_params);
1425     return;
1426   }
1427 
1428   WebLocalFrameImpl* main_frame = MainFrameImpl();
1429   if (!main_frame)
1430     return;
1431 
1432   LocalFrameView* view = main_frame->GetFrameView();
1433   if (!view)
1434     return;
1435 
1436   VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
1437 
1438   bool is_rotation =
1439       GetPage()->GetSettings().GetMainFrameResizesAreOrientationChanges() &&
1440       size_.width && ContentsSize().Width() &&
1441       main_frame_widget_size.width != size_.width &&
1442       !fullscreen_controller_->IsFullscreenOrTransitioning();
1443   size_ = main_frame_widget_size;
1444 
1445   FloatSize viewport_anchor_coords(viewportAnchorCoordX, viewportAnchorCoordY);
1446   if (is_rotation) {
1447     RotationViewportAnchor anchor(*view, visual_viewport,
1448                                   viewport_anchor_coords,
1449                                   GetPageScaleConstraintsSet());
1450     ResizeViewWhileAnchored(browser_controls_params, visible_viewport_size);
1451   } else {
1452     ResizeViewportAnchor::ResizeScope resize_scope(*resize_viewport_anchor_);
1453     ResizeViewWhileAnchored(browser_controls_params, visible_viewport_size);
1454   }
1455   SendResizeEventForMainFrame();
1456 }
1457 
Resize(const WebSize & new_size)1458 void WebViewImpl::Resize(const WebSize& new_size) {
1459   if (should_auto_resize_ || size_ == new_size)
1460     return;
1461 
1462   ResizeWithBrowserControls(new_size, GetBrowserControls().TopHeight(),
1463                             GetBrowserControls().BottomHeight(),
1464                             GetBrowserControls().ShrinkViewport());
1465 }
1466 
GetSize()1467 WebSize WebViewImpl::GetSize() {
1468   return size_;
1469 }
1470 
DidEnterFullscreen()1471 void WebViewImpl::DidEnterFullscreen() {
1472   fullscreen_controller_->DidEnterFullscreen();
1473 }
1474 
DidExitFullscreen()1475 void WebViewImpl::DidExitFullscreen() {
1476   fullscreen_controller_->DidExitFullscreen();
1477 }
1478 
SetMainFrameWidgetBase(WebFrameWidgetBase * widget)1479 void WebViewImpl::SetMainFrameWidgetBase(WebFrameWidgetBase* widget) {
1480   web_widget_ = widget;
1481 }
1482 
MainFrameWidgetBase()1483 WebFrameWidgetBase* WebViewImpl::MainFrameWidgetBase() {
1484   return web_widget_;
1485 }
1486 
SetSuppressFrameRequestsWorkaroundFor704763Only(bool suppress_frame_requests)1487 void WebViewImpl::SetSuppressFrameRequestsWorkaroundFor704763Only(
1488     bool suppress_frame_requests) {
1489   AsView().page->Animator().SetSuppressFrameRequestsWorkaroundFor704763Only(
1490       suppress_frame_requests);
1491 }
BeginFrame(base::TimeTicks last_frame_time)1492 void WebViewImpl::BeginFrame(base::TimeTicks last_frame_time) {
1493   TRACE_EVENT1("blink", "WebViewImpl::beginFrame", "frameTime",
1494                last_frame_time);
1495   DCHECK(!last_frame_time.is_null());
1496 
1497   if (!MainFrameImpl())
1498     return;
1499 
1500   MainFrameImpl()
1501       ->GetFrame()
1502       ->GetEventHandler()
1503       .RecomputeMouseHoverStateIfNeeded();
1504 
1505   if (LocalFrameView* view = MainFrameImpl()->GetFrameView()) {
1506     if (FragmentAnchor* anchor = view->GetFragmentAnchor())
1507       anchor->PerformPreRafActions();
1508   }
1509 
1510   DocumentLifecycle::AllowThrottlingScope throttling_scope(
1511       MainFrameImpl()->GetFrame()->GetDocument()->Lifecycle());
1512 
1513   base::Optional<LocalFrameUkmAggregator::ScopedUkmHierarchicalTimer> ukm_timer;
1514   if (WidgetBase::ShouldRecordBeginMainFrameMetrics()) {
1515     ukm_timer.emplace(MainFrameImpl()
1516                           ->GetFrame()
1517                           ->View()
1518                           ->EnsureUkmAggregator()
1519                           .GetScopedTimer(LocalFrameUkmAggregator::kAnimate));
1520   }
1521   PageWidgetDelegate::Animate(*AsView().page, last_frame_time);
1522 }
1523 
DidBeginFrame()1524 void WebViewImpl::DidBeginFrame() {
1525   if (!MainFrameImpl() || !MainFrameImpl()->GetFrame())
1526     return;
1527   if (Document* document = MainFrameImpl()->GetFrame()->GetDocument()) {
1528     DocumentLifecycle::AllowThrottlingScope throttling_scope(
1529         document->Lifecycle());
1530     PageWidgetDelegate::DidBeginFrame(*MainFrameImpl()->GetFrame());
1531   }
1532 }
1533 
BeginUpdateLayers()1534 void WebViewImpl::BeginUpdateLayers() {
1535   if (MainFrameImpl())
1536     update_layers_start_time_.emplace(base::TimeTicks::Now());
1537 }
1538 
EndUpdateLayers()1539 void WebViewImpl::EndUpdateLayers() {
1540   if (MainFrameImpl()) {
1541     DCHECK(update_layers_start_time_);
1542     MainFrameImpl()->GetFrame()->View()->EnsureUkmAggregator().RecordSample(
1543         LocalFrameUkmAggregator::kUpdateLayers,
1544         update_layers_start_time_.value(), base::TimeTicks::Now());
1545     probe::LayerTreeDidChange(MainFrameImpl()->GetFrame());
1546   }
1547   update_layers_start_time_.reset();
1548 }
1549 
BeginCommitCompositorFrame()1550 void WebViewImpl::BeginCommitCompositorFrame() {
1551   if (MainFrameImpl()) {
1552     commit_compositor_frame_start_time_.emplace(base::TimeTicks::Now());
1553   }
1554 }
1555 
EndCommitCompositorFrame(base::TimeTicks commit_start_time)1556 void WebViewImpl::EndCommitCompositorFrame(base::TimeTicks commit_start_time) {
1557   // Some tests call this without ever beginning a frame.
1558   if (MainFrameImpl() && commit_compositor_frame_start_time_) {
1559     MainFrameImpl()
1560         ->GetFrame()
1561         ->View()
1562         ->EnsureUkmAggregator()
1563         .RecordImplCompositorSample(commit_compositor_frame_start_time_.value(),
1564                                     commit_start_time, base::TimeTicks::Now());
1565   }
1566   commit_compositor_frame_start_time_.reset();
1567 }
1568 
RecordStartOfFrameMetrics()1569 void WebViewImpl::RecordStartOfFrameMetrics() {
1570   if (!MainFrameImpl())
1571     return;
1572 
1573   MainFrameImpl()->GetFrame()->View()->EnsureUkmAggregator().BeginMainFrame();
1574 }
1575 
RecordEndOfFrameMetrics(base::TimeTicks frame_begin_time,cc::ActiveFrameSequenceTrackers trackers)1576 void WebViewImpl::RecordEndOfFrameMetrics(
1577     base::TimeTicks frame_begin_time,
1578     cc::ActiveFrameSequenceTrackers trackers) {
1579   if (!MainFrameImpl())
1580     return;
1581 
1582   MainFrameImpl()
1583       ->GetFrame()
1584       ->View()
1585       ->EnsureUkmAggregator()
1586       .RecordEndOfFrameMetrics(frame_begin_time, base::TimeTicks::Now(),
1587                                trackers);
1588 }
1589 
1590 std::unique_ptr<cc::BeginMainFrameMetrics>
GetBeginMainFrameMetrics()1591 WebViewImpl::GetBeginMainFrameMetrics() {
1592   if (!MainFrameImpl())
1593     return nullptr;
1594 
1595   return MainFrameImpl()
1596       ->GetFrame()
1597       ->View()
1598       ->EnsureUkmAggregator()
1599       .GetBeginMainFrameMetrics();
1600 }
1601 
UpdateLifecycle(WebLifecycleUpdate requested_update,DocumentUpdateReason reason)1602 void WebViewImpl::UpdateLifecycle(WebLifecycleUpdate requested_update,
1603                                   DocumentUpdateReason reason) {
1604   TRACE_EVENT0("blink", "WebViewImpl::updateAllLifecyclePhases");
1605   if (!MainFrameImpl())
1606     return;
1607 
1608   DocumentLifecycle::AllowThrottlingScope throttling_scope(
1609       MainFrameImpl()->GetFrame()->GetDocument()->Lifecycle());
1610 
1611   PageWidgetDelegate::UpdateLifecycle(
1612       *AsView().page, *MainFrameImpl()->GetFrame(), requested_update, reason);
1613   if (requested_update != WebLifecycleUpdate::kAll)
1614     return;
1615 
1616   // There is no background color for non-composited WebViews (eg printing).
1617   if (does_composite_) {
1618     MainFrameImpl()->FrameWidgetImpl()->SetBackgroundColor(BackgroundColor());
1619   }
1620 
1621   if (LocalFrameView* view = MainFrameImpl()->GetFrameView()) {
1622     LocalFrame* frame = MainFrameImpl()->GetFrame();
1623     WebWidgetClient* client =
1624         WebLocalFrameImpl::FromFrame(frame)->FrameWidgetImpl()->Client();
1625 
1626     if (should_dispatch_first_visually_non_empty_layout_ &&
1627         view->IsVisuallyNonEmpty()) {
1628       should_dispatch_first_visually_non_empty_layout_ = false;
1629       // TODO(esprehn): Move users of this callback to something
1630       // better, the heuristic for "visually non-empty" is bad.
1631       client->DidMeaningfulLayout(WebMeaningfulLayout::kVisuallyNonEmpty);
1632     }
1633 
1634     if (should_dispatch_first_layout_after_finished_parsing_ &&
1635         frame->GetDocument()->HasFinishedParsing()) {
1636       should_dispatch_first_layout_after_finished_parsing_ = false;
1637       client->DidMeaningfulLayout(WebMeaningfulLayout::kFinishedParsing);
1638     }
1639 
1640     if (should_dispatch_first_layout_after_finished_loading_ &&
1641         frame->GetDocument()->IsLoadCompleted()) {
1642       should_dispatch_first_layout_after_finished_loading_ = false;
1643       client->DidMeaningfulLayout(WebMeaningfulLayout::kFinishedLoading);
1644     }
1645   }
1646 }
1647 
PaintContent(cc::PaintCanvas * canvas,const gfx::Rect & rect)1648 void WebViewImpl::PaintContent(cc::PaintCanvas* canvas, const gfx::Rect& rect) {
1649   // This should only be used when compositing is not being used for this
1650   // WebView, and it is painting into the recording of its parent.
1651   DCHECK(!does_composite_);
1652   // Non-composited WebViews always have a local main frame.
1653   DCHECK(MainFrameImpl());
1654 
1655   if (rect.IsEmpty())
1656     return;
1657 
1658   LocalFrameView& main_view = *MainFrameImpl()->GetFrame()->View();
1659   DCHECK(main_view.GetLayoutView()->GetDocument().Lifecycle().GetState() ==
1660          DocumentLifecycle::kPaintClean);
1661 
1662   PaintRecordBuilder builder;
1663   main_view.PaintOutsideOfLifecycle(builder.Context(), kGlobalPaintNormalPhase,
1664                                     CullRect(IntRect(rect)));
1665   // Don't bother to save/restore here as the caller is expecting the canvas
1666   // to be modified and take care of it.
1667   canvas->clipRect(gfx::RectToSkRect(rect));
1668   builder.EndRecording(
1669       *canvas,
1670       main_view.GetLayoutView()->FirstFragment().LocalBorderBoxProperties());
1671 }
1672 
ThemeChanged()1673 void WebViewImpl::ThemeChanged() {
1674   if (!GetPage())
1675     return;
1676   if (!GetPage()->MainFrame()->IsLocalFrame())
1677     return;
1678   LocalFrameView* view = GetPage()->DeprecatedLocalMainFrame()->View();
1679 
1680   WebRect damaged_rect(0, 0, size_.width, size_.height);
1681   view->InvalidateRect(damaged_rect);
1682 }
1683 
EnterFullscreen(LocalFrame & frame,const FullscreenOptions * options,bool for_cross_process_descendant)1684 void WebViewImpl::EnterFullscreen(LocalFrame& frame,
1685                                   const FullscreenOptions* options,
1686                                   bool for_cross_process_descendant) {
1687   fullscreen_controller_->EnterFullscreen(frame, options,
1688                                           for_cross_process_descendant);
1689 }
1690 
ExitFullscreen(LocalFrame & frame)1691 void WebViewImpl::ExitFullscreen(LocalFrame& frame) {
1692   fullscreen_controller_->ExitFullscreen(frame);
1693 }
1694 
FullscreenElementChanged(Element * old_element,Element * new_element)1695 void WebViewImpl::FullscreenElementChanged(Element* old_element,
1696                                            Element* new_element) {
1697   fullscreen_controller_->FullscreenElementChanged(old_element, new_element);
1698 }
1699 
HasHorizontalScrollbar()1700 bool WebViewImpl::HasHorizontalScrollbar() {
1701   return MainFrameImpl()
1702       ->GetFrameView()
1703       ->LayoutViewport()
1704       ->HorizontalScrollbar();
1705 }
1706 
HasVerticalScrollbar()1707 bool WebViewImpl::HasVerticalScrollbar() {
1708   return MainFrameImpl()->GetFrameView()->LayoutViewport()->VerticalScrollbar();
1709 }
1710 
DispatchBufferedTouchEvents()1711 WebInputEventResult WebViewImpl::DispatchBufferedTouchEvents() {
1712   if (!MainFrameImpl())
1713     return WebInputEventResult::kNotHandled;
1714   if (WebDevToolsAgentImpl* devtools = MainFrameDevToolsAgentImpl())
1715     devtools->DispatchBufferedTouchEvents();
1716   return MainFrameImpl()
1717       ->GetFrame()
1718       ->GetEventHandler()
1719       .DispatchBufferedTouchEvents();
1720 }
1721 
HandleInputEvent(const WebCoalescedInputEvent & coalesced_event)1722 WebInputEventResult WebViewImpl::HandleInputEvent(
1723     const WebCoalescedInputEvent& coalesced_event) {
1724   // TODO(bokan): Temporary debugging added to diagnose
1725   // https://crbug.com/992315. Somehow we're synchronously calling
1726   // WebViewImpl::Close while handling an input event.
1727   base::AutoReset<bool> inside_input_handling(&debug_inside_input_handling_,
1728                                               true);
1729 
1730   const WebInputEvent& input_event = coalesced_event.Event();
1731   // TODO(dcheng): The fact that this is getting called when there is no local
1732   // main frame is problematic and probably indicates a bug in the input event
1733   // routing code.
1734   if (!MainFrameImpl())
1735     return WebInputEventResult::kNotHandled;
1736   DCHECK(!WebInputEvent::IsTouchEventType(input_event.GetType()));
1737 
1738   GetPage()->GetVisualViewport().StartTrackingPinchStats();
1739 
1740   TRACE_EVENT1("input,rail", "WebViewImpl::handleInputEvent", "type",
1741                WebInputEvent::GetName(input_event.GetType()));
1742 
1743   // If a drag-and-drop operation is in progress, ignore input events except
1744   // PointerCancel.
1745   if (MainFrameImpl()->FrameWidgetImpl()->DoingDragAndDrop() &&
1746       input_event.GetType() != WebInputEvent::kPointerCancel)
1747     return WebInputEventResult::kHandledSuppressed;
1748 
1749   if (WebDevToolsAgentImpl* devtools = MainFrameDevToolsAgentImpl()) {
1750     auto result = devtools->HandleInputEvent(input_event);
1751     if (result != WebInputEventResult::kNotHandled)
1752       return result;
1753   }
1754 
1755   // Report the event to be NOT processed by WebKit, so that the browser can
1756   // handle it appropriately.
1757   if (WebFrameWidgetBase::IgnoreInputEvents())
1758     return WebInputEventResult::kNotHandled;
1759 
1760   base::AutoReset<const WebInputEvent*> current_event_change(
1761       &CurrentInputEvent::current_input_event_, &input_event);
1762   UIEventWithKeyState::ClearNewTabModifierSetFromIsolatedWorld();
1763 
1764   bool is_pointer_locked = false;
1765   if (WebFrameWidgetBase* widget = MainFrameImpl()->FrameWidgetImpl()) {
1766     if (WebWidgetClient* client = widget->Client())
1767       is_pointer_locked = client->IsPointerLocked();
1768   }
1769 
1770   if (is_pointer_locked &&
1771       WebInputEvent::IsMouseEventType(input_event.GetType())) {
1772     MainFrameImpl()->FrameWidgetImpl()->PointerLockMouseEvent(coalesced_event);
1773     return WebInputEventResult::kHandledSystem;
1774   }
1775 
1776   Document& main_frame_document = *MainFrameImpl()->GetFrame()->GetDocument();
1777 
1778   if (input_event.GetType() != WebInputEvent::kMouseMove) {
1779     FirstMeaningfulPaintDetector::From(main_frame_document).NotifyInputEvent();
1780   }
1781 
1782   if (input_event.GetType() != WebInputEvent::kMouseMove &&
1783       input_event.GetType() != WebInputEvent::kMouseEnter &&
1784       input_event.GetType() != WebInputEvent::kMouseLeave) {
1785     InteractiveDetector* interactive_detector(
1786         InteractiveDetector::From(main_frame_document));
1787     if (interactive_detector) {
1788       interactive_detector->OnInvalidatingInputEvent(input_event.TimeStamp());
1789     }
1790   }
1791 
1792   // Notify the focus frame of the input. Note that the other frames are not
1793   // notified as input is only handled by the focused frame.
1794   Frame* frame = FocusedCoreFrame();
1795   if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
1796     if (local_frame->View() && local_frame->View()
1797                                    ->GetPaintTimingDetector()
1798                                    .NeedToNotifyInputOrScroll()) {
1799       local_frame->View()->GetPaintTimingDetector().NotifyInputEvent(
1800           input_event.GetType());
1801     }
1802   }
1803 
1804   // Skip the pointerrawupdate for mouse capture case.
1805   if (mouse_capture_element_ &&
1806       input_event.GetType() == WebInputEvent::kPointerRawUpdate)
1807     return WebInputEventResult::kHandledSystem;
1808 
1809   if (mouse_capture_element_ &&
1810       WebInputEvent::IsMouseEventType(input_event.GetType()))
1811     return HandleCapturedMouseEvent(coalesced_event);
1812 
1813   // FIXME: This should take in the intended frame, not the local frame
1814   // root.
1815   return PageWidgetDelegate::HandleInputEvent(*this, coalesced_event,
1816                                               MainFrameImpl()->GetFrame());
1817 }
1818 
HandleCapturedMouseEvent(const WebCoalescedInputEvent & coalesced_event)1819 WebInputEventResult WebViewImpl::HandleCapturedMouseEvent(
1820     const WebCoalescedInputEvent& coalesced_event) {
1821   const WebInputEvent& input_event = coalesced_event.Event();
1822   TRACE_EVENT1("input", "captured mouse event", "type", input_event.GetType());
1823   // Save |mouse_capture_element_| since |MouseCaptureLost()| will clear it.
1824   HTMLPlugInElement* element = mouse_capture_element_;
1825 
1826   // Not all platforms call mouseCaptureLost() directly.
1827   if (input_event.GetType() == WebInputEvent::kMouseUp)
1828     MouseCaptureLost();
1829 
1830   AtomicString event_type;
1831   switch (input_event.GetType()) {
1832     case WebInputEvent::kMouseEnter:
1833       event_type = event_type_names::kMouseover;
1834       break;
1835     case WebInputEvent::kMouseMove:
1836       event_type = event_type_names::kMousemove;
1837       break;
1838     case WebInputEvent::kPointerRawUpdate:
1839       // There will be no mouse event for rawupdate events.
1840       event_type = event_type_names::kPointerrawupdate;
1841       break;
1842     case WebInputEvent::kMouseLeave:
1843       event_type = event_type_names::kMouseout;
1844       break;
1845     case WebInputEvent::kMouseDown:
1846       event_type = event_type_names::kMousedown;
1847       LocalFrame::NotifyUserActivation(element->GetDocument().GetFrame());
1848       break;
1849     case WebInputEvent::kMouseUp:
1850       event_type = event_type_names::kMouseup;
1851       break;
1852     default:
1853       NOTREACHED();
1854   }
1855 
1856   WebMouseEvent transformed_event =
1857       TransformWebMouseEvent(MainFrameImpl()->GetFrameView(),
1858                              static_cast<const WebMouseEvent&>(input_event));
1859   if (LocalFrame* frame = element->GetDocument().GetFrame()) {
1860     frame->GetEventHandler().HandleTargetedMouseEvent(
1861         element, transformed_event, event_type,
1862         TransformWebMouseEventVector(
1863             MainFrameImpl()->GetFrameView(),
1864             coalesced_event.GetCoalescedEventsPointers()),
1865         TransformWebMouseEventVector(
1866             MainFrameImpl()->GetFrameView(),
1867             coalesced_event.GetPredictedEventsPointers()));
1868   }
1869   return WebInputEventResult::kHandledSystem;
1870 }
1871 
SetCursorVisibilityState(bool is_visible)1872 void WebViewImpl::SetCursorVisibilityState(bool is_visible) {
1873   if (AsView().page)
1874     AsView().page->SetIsCursorVisible(is_visible);
1875 }
1876 
OnFallbackCursorModeToggled(bool is_on)1877 void WebViewImpl::OnFallbackCursorModeToggled(bool is_on) {
1878   DCHECK(MainFrameImpl());
1879   MainFrameImpl()->GetFrame()->GetEventHandler().SetIsFallbackCursorModeOn(
1880       is_on);
1881 }
1882 
MouseCaptureLost()1883 void WebViewImpl::MouseCaptureLost() {
1884   TRACE_EVENT_NESTABLE_ASYNC_END0("input", "capturing mouse",
1885                                   TRACE_ID_LOCAL(this));
1886   mouse_capture_element_ = nullptr;
1887   if (AsView().page->DeprecatedLocalMainFrame())
1888     AsView().page->DeprecatedLocalMainFrame()->Client()->SetMouseCapture(false);
1889 }
1890 
SetFocus(bool enable)1891 void WebViewImpl::SetFocus(bool enable) {
1892   if (enable)
1893     AsView().page->GetFocusController().SetActive(true);
1894   AsView().page->GetFocusController().SetFocused(enable);
1895   if (enable) {
1896     LocalFrame* focused_frame =
1897         AsView().page->GetFocusController().FocusedFrame();
1898     if (focused_frame) {
1899       Element* element = focused_frame->GetDocument()->FocusedElement();
1900       if (element && focused_frame->Selection()
1901                          .ComputeVisibleSelectionInDOMTreeDeprecated()
1902                          .IsNone()) {
1903         // If the selection was cleared while the WebView was not
1904         // focused, then the focus element shows with a focus ring but
1905         // no caret and does respond to keyboard inputs.
1906         focused_frame->GetDocument()->UpdateStyleAndLayoutTree();
1907         if (element->IsTextControl()) {
1908           element->UpdateFocusAppearance(SelectionBehaviorOnFocus::kRestore);
1909         } else if (HasEditableStyle(*element)) {
1910           // updateFocusAppearance() selects all the text of
1911           // contentseditable DIVs. So we set the selection explicitly
1912           // instead. Note that this has the side effect of moving the
1913           // caret back to the beginning of the text.
1914           Position position(element, 0);
1915           focused_frame->Selection().SetSelectionAndEndTyping(
1916               SelectionInDOMTree::Builder().Collapse(position).Build());
1917         }
1918       }
1919     }
1920     ime_accept_events_ = true;
1921   } else {
1922     CancelPagePopup();
1923 
1924     // Clear focus on the currently focused frame if any.
1925     if (!AsView().page)
1926       return;
1927 
1928     LocalFrame* frame = DynamicTo<LocalFrame>(AsView().page->MainFrame());
1929     if (!frame)
1930       return;
1931 
1932     LocalFrame* focused_frame = FocusedLocalFrameInWidget();
1933     if (focused_frame) {
1934       // Finish an ongoing composition to delete the composition node.
1935       if (focused_frame->GetInputMethodController().HasComposition()) {
1936         // TODO(editing-dev): The use of
1937         // UpdateStyleAndLayout needs to be audited.
1938         // See http://crbug.com/590369 for more details.
1939         focused_frame->GetDocument()->UpdateStyleAndLayout(
1940             DocumentUpdateReason::kFocus);
1941 
1942         focused_frame->GetInputMethodController().FinishComposingText(
1943             InputMethodController::kKeepSelection);
1944       }
1945       ime_accept_events_ = false;
1946     }
1947   }
1948 }
1949 
SelectionBounds(WebRect & anchor_web,WebRect & focus_web) const1950 bool WebViewImpl::SelectionBounds(WebRect& anchor_web,
1951                                   WebRect& focus_web) const {
1952   const Frame* frame = FocusedCoreFrame();
1953   const auto* local_frame = DynamicTo<LocalFrame>(frame);
1954   if (!local_frame)
1955     return false;
1956 
1957   LocalFrameView* frame_view = local_frame->View();
1958   if (!frame_view)
1959     return false;
1960 
1961   IntRect anchor;
1962   IntRect focus;
1963   if (!local_frame->Selection().ComputeAbsoluteBounds(anchor, focus))
1964     return false;
1965 
1966   VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
1967   anchor_web = visual_viewport.RootFrameToViewport(
1968       frame_view->ConvertToRootFrame(anchor));
1969   focus_web = visual_viewport.RootFrameToViewport(
1970       frame_view->ConvertToRootFrame(focus));
1971   return true;
1972 }
1973 
DidAcquirePointerLock()1974 void WebViewImpl::DidAcquirePointerLock() {
1975   if (MainFrameImpl())
1976     MainFrameImpl()->FrameWidget()->DidAcquirePointerLock();
1977 }
1978 
DidNotAcquirePointerLock()1979 void WebViewImpl::DidNotAcquirePointerLock() {
1980   if (MainFrameImpl())
1981     MainFrameImpl()->FrameWidget()->DidNotAcquirePointerLock();
1982 }
1983 
DidLosePointerLock()1984 void WebViewImpl::DidLosePointerLock() {
1985   // Make sure that the main frame wasn't swapped-out when the pointer lock is
1986   // lost. There's a race that can happen when a pointer lock is requested, but
1987   // the browser swaps out the main frame while the pointer lock request is in
1988   // progress. This won't be needed once the main frame is refactored to not use
1989   // the WebViewImpl as its WebWidget.
1990   if (MainFrameImpl())
1991     MainFrameImpl()->FrameWidget()->DidLosePointerLock();
1992 }
1993 
1994 // WebView --------------------------------------------------------------------
1995 
SettingsImpl()1996 WebSettingsImpl* WebViewImpl::SettingsImpl() {
1997   if (!web_settings_) {
1998     web_settings_ = std::make_unique<WebSettingsImpl>(
1999         &AsView().page->GetSettings(), dev_tools_emulator_.Get());
2000   }
2001   DCHECK(web_settings_);
2002   return web_settings_.get();
2003 }
2004 
GetSettings()2005 WebSettings* WebViewImpl::GetSettings() {
2006   return SettingsImpl();
2007 }
2008 
PageEncoding() const2009 WebString WebViewImpl::PageEncoding() const {
2010   if (!AsView().page)
2011     return WebString();
2012 
2013   auto* main_frame = DynamicTo<LocalFrame>(AsView().page->MainFrame());
2014   if (!main_frame)
2015     return WebString();
2016 
2017   // FIXME: Is this check needed?
2018   if (!main_frame->GetDocument()->Loader())
2019     return WebString();
2020 
2021   return main_frame->GetDocument()->EncodingName();
2022 }
2023 
MainFrame()2024 WebFrame* WebViewImpl::MainFrame() {
2025   Page* page = AsView().page.Get();
2026   return WebFrame::FromFrame(page ? page->MainFrame() : nullptr);
2027 }
2028 
MainFrameImpl() const2029 WebLocalFrameImpl* WebViewImpl::MainFrameImpl() const {
2030   Page* page = AsView().page.Get();
2031   if (!page)
2032     return nullptr;
2033   return WebLocalFrameImpl::FromFrame(DynamicTo<LocalFrame>(page->MainFrame()));
2034 }
2035 
DidAttachLocalMainFrame()2036 void WebViewImpl::DidAttachLocalMainFrame() {
2037   DCHECK(MainFrameImpl());
2038 
2039   LocalFrame* local_frame = MainFrameImpl()->GetFrame();
2040   local_frame->WasAttachedAsLocalMainFrame();
2041 
2042   local_frame->GetRemoteNavigationAssociatedInterfaces()->GetInterface(
2043       local_main_frame_host_remote_.BindNewEndpointAndPassReceiver());
2044 
2045   if (does_composite_) {
2046     WebWidgetClient* widget_client =
2047         MainFrameImpl()->FrameWidgetImpl()->Client();
2048     // When attaching a local main frame, set up any state on the compositor.
2049     MainFrameImpl()->FrameWidgetImpl()->SetBackgroundColor(BackgroundColor());
2050     auto& viewport = GetPage()->GetVisualViewport();
2051     widget_client->SetPageScaleStateAndLimits(
2052         viewport.Scale(), viewport.IsPinchGestureActive(),
2053         MinimumPageScaleFactor(), MaximumPageScaleFactor());
2054     // Prevent main frame updates while the main frame is loading until enough
2055     // progress is made and BeginMainFrames are explicitly asked for.
2056     scoped_defer_main_frame_update_ =
2057         MainFrameImpl()->FrameWidgetImpl()->DeferMainFrameUpdate();
2058   }
2059 }
2060 
DidDetachLocalMainFrame()2061 void WebViewImpl::DidDetachLocalMainFrame() {
2062   // The WebWidgetClient that generated the |scoped_defer_main_frame_update_|
2063   // for a local main frame is going away.
2064   scoped_defer_main_frame_update_ = nullptr;
2065   local_main_frame_host_remote_.reset();
2066 }
2067 
FocusedFrame()2068 WebLocalFrame* WebViewImpl::FocusedFrame() {
2069   Frame* frame = FocusedCoreFrame();
2070   // TODO(yabinh): focusedCoreFrame() should always return a local frame, and
2071   // the following check should be unnecessary.
2072   // See crbug.com/625068
2073   return WebLocalFrameImpl::FromFrame(DynamicTo<LocalFrame>(frame));
2074 }
2075 
SetFocusedFrame(WebFrame * frame)2076 void WebViewImpl::SetFocusedFrame(WebFrame* frame) {
2077   if (!frame) {
2078     // Clears the focused frame if any.
2079     Frame* focused_frame = FocusedCoreFrame();
2080     if (auto* focused_local_frame = DynamicTo<LocalFrame>(focused_frame))
2081       focused_local_frame->Selection().SetFrameIsFocused(false);
2082     return;
2083   }
2084   LocalFrame* core_frame = To<WebLocalFrameImpl>(frame)->GetFrame();
2085   core_frame->GetPage()->GetFocusController().SetFocusedFrame(core_frame);
2086 }
2087 
SetInitialFocus(bool reverse)2088 void WebViewImpl::SetInitialFocus(bool reverse) {
2089   if (!AsView().page)
2090     return;
2091   Frame* frame = GetPage()->GetFocusController().FocusedOrMainFrame();
2092   if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
2093     if (Document* document = local_frame->GetDocument())
2094       document->ClearFocusedElement();
2095   }
2096   GetPage()->GetFocusController().SetInitialFocus(
2097       reverse ? mojom::blink::FocusType::kBackward
2098               : mojom::blink::FocusType::kForward);
2099 }
2100 
2101 // TODO(dglazkov): Remove and replace with Node:hasEditableStyle.
2102 // http://crbug.com/612560
IsElementEditable(const Element * element)2103 static bool IsElementEditable(const Element* element) {
2104   element->GetDocument().UpdateStyleAndLayoutTree();
2105   if (HasEditableStyle(*element))
2106     return true;
2107 
2108   if (auto* text_control = ToTextControlOrNull(element)) {
2109     if (!text_control->IsDisabledOrReadOnly())
2110       return true;
2111   }
2112 
2113   return EqualIgnoringASCIICase(
2114       element->FastGetAttribute(html_names::kRoleAttr), "textbox");
2115 }
2116 
ScrollFocusedEditableElementIntoView()2117 bool WebViewImpl::ScrollFocusedEditableElementIntoView() {
2118   DCHECK(MainFrameImpl());
2119   LocalFrameView* main_frame_view = MainFrameImpl()->GetFrame()->View();
2120   if (!main_frame_view)
2121     return false;
2122 
2123   Element* element = FocusedElement();
2124   if (!element || !IsElementEditable(element))
2125     return false;
2126 
2127   element->GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kSelection);
2128 
2129   LayoutObject* layout_object = element->GetLayoutObject();
2130   if (!layout_object)
2131     return false;
2132 
2133   // Since the page has been resized, the layout may have changed. The page
2134   // scale animation started by ZoomAndScrollToFocusedEditableRect will scroll
2135   // only the visual and layout viewports. We'll call ScrollRectToVisible with
2136   // the stop_at_main_frame_layout_viewport param to ensure the element is
2137   // actually visible in the page.
2138   auto params = ScrollAlignment::CreateScrollIntoViewParams(
2139       ScrollAlignment::CenterIfNeeded(), ScrollAlignment::CenterIfNeeded(),
2140       mojom::blink::ScrollType::kProgrammatic, false,
2141       mojom::blink::ScrollBehavior::kInstant);
2142   params->stop_at_main_frame_layout_viewport = true;
2143   layout_object->ScrollRectToVisible(
2144       PhysicalRect(layout_object->AbsoluteBoundingBoxRect()),
2145       std::move(params));
2146 
2147   ZoomAndScrollToFocusedEditableElementRect(
2148       main_frame_view->RootFrameToDocument(
2149           element->GetDocument().View()->ConvertToRootFrame(
2150               layout_object->AbsoluteBoundingBoxRect())),
2151       main_frame_view->RootFrameToDocument(
2152           element->GetDocument().View()->ConvertToRootFrame(
2153               element->GetDocument()
2154                   .GetFrame()
2155                   ->Selection()
2156                   .ComputeRectToScroll(kDoNotRevealExtent))),
2157       ShouldZoomToLegibleScale(*element));
2158 
2159   return true;
2160 }
2161 
ShouldZoomToLegibleScale(const Element & element)2162 bool WebViewImpl::ShouldZoomToLegibleScale(const Element& element) {
2163   bool zoom_into_legible_scale =
2164       web_settings_->AutoZoomFocusedNodeToLegibleScale() &&
2165       !GetPage()->GetVisualViewport().ShouldDisableDesktopWorkarounds();
2166 
2167   if (zoom_into_legible_scale) {
2168     // When deciding whether to zoom in on a focused text box, we should
2169     // decide not to zoom in if the user won't be able to zoom out. e.g if the
2170     // textbox is within a touch-action: none container the user can't zoom
2171     // back out.
2172     TouchAction action =
2173         touch_action_util::ComputeEffectiveTouchAction(element);
2174     if (!(static_cast<int>(action) & static_cast<int>(TouchAction::kPinchZoom)))
2175       zoom_into_legible_scale = false;
2176   }
2177 
2178   return zoom_into_legible_scale;
2179 }
2180 
ZoomAndScrollToFocusedEditableElementRect(const WebRect & element_bounds_in_document,const WebRect & caret_bounds_in_document,bool zoom_into_legible_scale)2181 void WebViewImpl::ZoomAndScrollToFocusedEditableElementRect(
2182     const WebRect& element_bounds_in_document,
2183     const WebRect& caret_bounds_in_document,
2184     bool zoom_into_legible_scale) {
2185   float scale;
2186   IntPoint scroll;
2187   bool need_animation = false;
2188   ComputeScaleAndScrollForEditableElementRects(
2189       element_bounds_in_document, caret_bounds_in_document,
2190       zoom_into_legible_scale, scale, scroll, need_animation);
2191   if (need_animation) {
2192     StartPageScaleAnimation(scroll, false, scale,
2193                             kScrollAndScaleAnimationDuration);
2194   }
2195 }
2196 
SmoothScroll(int target_x,int target_y,base::TimeDelta duration)2197 void WebViewImpl::SmoothScroll(int target_x,
2198                                int target_y,
2199                                base::TimeDelta duration) {
2200   IntPoint target_position(target_x, target_y);
2201   StartPageScaleAnimation(target_position, false, PageScaleFactor(), duration);
2202 }
2203 
ComputeScaleAndScrollForEditableElementRects(const IntRect & element_bounds_in_document,const IntRect & caret_bounds_in_document,bool zoom_into_legible_scale,float & new_scale,IntPoint & new_scroll,bool & need_animation)2204 void WebViewImpl::ComputeScaleAndScrollForEditableElementRects(
2205     const IntRect& element_bounds_in_document,
2206     const IntRect& caret_bounds_in_document,
2207     bool zoom_into_legible_scale,
2208     float& new_scale,
2209     IntPoint& new_scroll,
2210     bool& need_animation) {
2211   VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
2212 
2213   TopDocumentRootScrollerController& controller =
2214       GetPage()->GlobalRootScrollerController();
2215   Node* root_scroller = controller.GlobalRootScroller();
2216 
2217   IntRect element_bounds_in_content = element_bounds_in_document;
2218   IntRect caret_bounds_in_content = caret_bounds_in_document;
2219 
2220   // If the page has a non-default root scroller then we need to scroll that
2221   // rather than the "real" viewport. However, the given coordinates are in the
2222   // real viewport's document space rather than the root scroller's so we
2223   // perform the conversion here.  TODO(bokan): Convert this function to take
2224   // coordinates in absolute/root-frame coordinates to make this more
2225   // consistent. https://crbug.com/931447.
2226   if (root_scroller != MainFrameImpl()->GetFrame()->GetDocument() &&
2227       controller.RootScrollerArea()) {
2228     ScrollOffset offset = controller.RootScrollerArea()->GetScrollOffset();
2229     element_bounds_in_content.Move(FlooredIntSize(offset));
2230     caret_bounds_in_content.Move(FlooredIntSize(offset));
2231   }
2232 
2233   if (!zoom_into_legible_scale) {
2234     new_scale = PageScaleFactor();
2235   } else {
2236     // Pick a scale which is reasonably readable. This is the scale at which
2237     // the caret height will become minReadableCaretHeightForNode (adjusted
2238     // for dpi and font scale factor).
2239     const int min_readable_caret_height_for_node =
2240         (element_bounds_in_content.Height() >=
2241                  2 * caret_bounds_in_content.Height()
2242              ? minReadableCaretHeightForTextArea
2243              : minReadableCaretHeight) *
2244         MainFrameImpl()->GetFrame()->PageZoomFactor();
2245     new_scale = ClampPageScaleFactorToLimits(
2246         MaximumLegiblePageScale() * min_readable_caret_height_for_node /
2247         caret_bounds_in_content.Height());
2248     new_scale = std::max(new_scale, PageScaleFactor());
2249   }
2250   const float delta_scale = new_scale / PageScaleFactor();
2251 
2252   need_animation = false;
2253 
2254   // If we are at less than the target zoom level, zoom in.
2255   if (delta_scale > minScaleChangeToTriggerZoom)
2256     need_animation = true;
2257   else
2258     new_scale = PageScaleFactor();
2259 
2260   ScrollableArea* root_viewport =
2261       MainFrameImpl()->GetFrame()->View()->GetScrollableArea();
2262 
2263   // If the caret is offscreen, then animate.
2264   if (!root_viewport->VisibleContentRect().Contains(caret_bounds_in_content))
2265     need_animation = true;
2266 
2267   // If the box is partially offscreen and it's possible to bring it fully
2268   // onscreen, then animate.
2269   if (visual_viewport.VisibleRect().Width() >=
2270           element_bounds_in_content.Width() &&
2271       visual_viewport.VisibleRect().Height() >=
2272           element_bounds_in_content.Height() &&
2273       !root_viewport->VisibleContentRect().Contains(element_bounds_in_content))
2274     need_animation = true;
2275 
2276   if (!need_animation)
2277     return;
2278 
2279   FloatSize target_viewport_size(visual_viewport.Size());
2280   target_viewport_size.Scale(1 / new_scale);
2281 
2282   if (element_bounds_in_content.Width() <= target_viewport_size.Width()) {
2283     // Field is narrower than screen. Try to leave padding on left so field's
2284     // label is visible, but it's more important to ensure entire field is
2285     // onscreen.
2286     int ideal_left_padding = target_viewport_size.Width() * leftBoxRatio;
2287     int max_left_padding_keeping_box_onscreen =
2288         target_viewport_size.Width() - element_bounds_in_content.Width();
2289     new_scroll.SetX(element_bounds_in_content.X() -
2290                     std::min<int>(ideal_left_padding,
2291                                   max_left_padding_keeping_box_onscreen));
2292   } else {
2293     // Field is wider than screen. Try to left-align field, unless caret would
2294     // be offscreen, in which case right-align the caret.
2295     new_scroll.SetX(std::max<int>(
2296         element_bounds_in_content.X(),
2297         caret_bounds_in_content.X() + caret_bounds_in_content.Width() +
2298             caretPadding - target_viewport_size.Width()));
2299   }
2300   if (element_bounds_in_content.Height() <= target_viewport_size.Height()) {
2301     // Field is shorter than screen. Vertically center it.
2302     new_scroll.SetY(
2303         element_bounds_in_content.Y() -
2304         (target_viewport_size.Height() - element_bounds_in_content.Height()) /
2305             2);
2306   } else {
2307     // Field is taller than screen. Try to top align field, unless caret would
2308     // be offscreen, in which case bottom-align the caret.
2309     new_scroll.SetY(std::max<int>(
2310         element_bounds_in_content.Y(),
2311         caret_bounds_in_content.Y() + caret_bounds_in_content.Height() +
2312             caretPadding - target_viewport_size.Height()));
2313   }
2314 }
2315 
AdvanceFocus(bool reverse)2316 void WebViewImpl::AdvanceFocus(bool reverse) {
2317   GetPage()->GetFocusController().AdvanceFocus(
2318       reverse ? mojom::blink::FocusType::kBackward
2319               : mojom::blink::FocusType::kForward);
2320 }
2321 
AdvanceFocusAcrossFrames(mojom::blink::FocusType type,WebRemoteFrame * from,WebLocalFrame * to)2322 void WebViewImpl::AdvanceFocusAcrossFrames(mojom::blink::FocusType type,
2323                                            WebRemoteFrame* from,
2324                                            WebLocalFrame* to) {
2325   // TODO(alexmos): Pass in proper with sourceCapabilities.
2326   GetPage()->GetFocusController().AdvanceFocusAcrossFrames(
2327       type, To<WebRemoteFrameImpl>(from)->GetFrame(),
2328       To<WebLocalFrameImpl>(to)->GetFrame());
2329 }
2330 
ZoomLevel()2331 double WebViewImpl::ZoomLevel() {
2332   return zoom_level_;
2333 }
2334 
PropagateZoomFactorToLocalFrameRoots(Frame * frame,float zoom_factor)2335 void WebViewImpl::PropagateZoomFactorToLocalFrameRoots(Frame* frame,
2336                                                        float zoom_factor) {
2337   auto* local_frame = DynamicTo<LocalFrame>(frame);
2338   if (local_frame && local_frame->IsLocalRoot()) {
2339     if (Document* document = local_frame->GetDocument()) {
2340       auto* plugin_document = DynamicTo<PluginDocument>(document);
2341       if (!plugin_document || !plugin_document->GetPluginView()) {
2342         local_frame->SetPageZoomFactor(zoom_factor);
2343       }
2344     }
2345   }
2346 
2347   for (Frame* child = frame->Tree().FirstChild(); child;
2348        child = child->Tree().NextSibling())
2349     PropagateZoomFactorToLocalFrameRoots(child, zoom_factor);
2350 }
2351 
SetZoomLevel(double zoom_level)2352 double WebViewImpl::SetZoomLevel(double zoom_level) {
2353   if (zoom_level < minimum_zoom_level_)
2354     zoom_level_ = minimum_zoom_level_;
2355   else if (zoom_level > maximum_zoom_level_)
2356     zoom_level_ = maximum_zoom_level_;
2357   else
2358     zoom_level_ = zoom_level;
2359 
2360   float zoom_factor =
2361       zoom_factor_override_
2362           ? zoom_factor_override_
2363           : static_cast<float>(PageZoomLevelToZoomFactor(zoom_level_));
2364   if (zoom_factor_for_device_scale_factor_) {
2365     if (compositor_device_scale_factor_override_) {
2366       // Adjust the page's DSF so that DevicePixelRatio becomes
2367       // |zoom_factor_for_device_scale_factor_|.
2368       AsView().page->SetDeviceScaleFactorDeprecated(
2369           zoom_factor_for_device_scale_factor_ /
2370           compositor_device_scale_factor_override_);
2371       zoom_factor *= compositor_device_scale_factor_override_;
2372     } else {
2373       AsView().page->SetDeviceScaleFactorDeprecated(1.f);
2374       zoom_factor *= zoom_factor_for_device_scale_factor_;
2375     }
2376   }
2377   PropagateZoomFactorToLocalFrameRoots(AsView().page->MainFrame(), zoom_factor);
2378 
2379   return zoom_level_;
2380 }
2381 
TextZoomFactor()2382 float WebViewImpl::TextZoomFactor() {
2383   return MainFrameImpl()->GetFrame()->TextZoomFactor();
2384 }
2385 
SetTextZoomFactor(float text_zoom_factor)2386 float WebViewImpl::SetTextZoomFactor(float text_zoom_factor) {
2387   LocalFrame* frame = MainFrameImpl()->GetFrame();
2388   if (frame->GetWebPluginContainer())
2389     return 1;
2390 
2391   frame->SetTextZoomFactor(text_zoom_factor);
2392 
2393   return text_zoom_factor;
2394 }
2395 
PageScaleFactor() const2396 float WebViewImpl::PageScaleFactor() const {
2397   if (!GetPage())
2398     return 1;
2399 
2400   return GetPage()->GetVisualViewport().Scale();
2401 }
2402 
ClampPageScaleFactorToLimits(float scale_factor) const2403 float WebViewImpl::ClampPageScaleFactorToLimits(float scale_factor) const {
2404   return GetPageScaleConstraintsSet().FinalConstraints().ClampToConstraints(
2405       scale_factor);
2406 }
2407 
SetVisualViewportOffset(const gfx::PointF & offset)2408 void WebViewImpl::SetVisualViewportOffset(const gfx::PointF& offset) {
2409   DCHECK(GetPage());
2410   GetPage()->GetVisualViewport().SetLocation(FloatPoint(offset));
2411 }
2412 
VisualViewportOffset() const2413 gfx::PointF WebViewImpl::VisualViewportOffset() const {
2414   DCHECK(GetPage());
2415   return GetPage()->GetVisualViewport().VisibleRect().Location();
2416 }
2417 
VisualViewportSize() const2418 gfx::SizeF WebViewImpl::VisualViewportSize() const {
2419   DCHECK(GetPage());
2420   return gfx::SizeF(GetPage()->GetVisualViewport().VisibleRect().Size());
2421 }
2422 
SetPageScaleFactorAndLocation(float scale_factor,bool is_pinch_gesture_active,const FloatPoint & location)2423 void WebViewImpl::SetPageScaleFactorAndLocation(float scale_factor,
2424                                                 bool is_pinch_gesture_active,
2425                                                 const FloatPoint& location) {
2426   DCHECK(GetPage());
2427 
2428   GetPage()->GetVisualViewport().SetScaleAndLocation(
2429       ClampPageScaleFactorToLimits(scale_factor), is_pinch_gesture_active,
2430       location);
2431 }
2432 
SetPageScaleFactor(float scale_factor)2433 void WebViewImpl::SetPageScaleFactor(float scale_factor) {
2434   DCHECK(GetPage());
2435   DCHECK(MainFrameImpl());
2436 
2437   MainFrameImpl()->GetFrame()->SetScaleFactor(scale_factor);
2438 }
2439 
SetDeviceScaleFactor(float scale_factor)2440 void WebViewImpl::SetDeviceScaleFactor(float scale_factor) {
2441   if (!GetPage())
2442     return;
2443 
2444   if (GetPage()->DeviceScaleFactorDeprecated() == scale_factor)
2445     return;
2446 
2447   GetPage()->SetDeviceScaleFactorDeprecated(scale_factor);
2448 }
2449 
SetZoomFactorForDeviceScaleFactor(float zoom_factor_for_device_scale_factor)2450 void WebViewImpl::SetZoomFactorForDeviceScaleFactor(
2451     float zoom_factor_for_device_scale_factor) {
2452   DCHECK(does_composite_);
2453   // We can't early-return here if these are already equal, because we may
2454   // need to propagate the correct zoom factor to newly navigated frames.
2455   zoom_factor_for_device_scale_factor_ = zoom_factor_for_device_scale_factor;
2456   SetZoomLevel(zoom_level_);
2457 }
2458 
SetPageLifecycleState(mojom::blink::PageLifecycleStatePtr state,SetPageLifecycleStateCallback callback)2459 void WebViewImpl::SetPageLifecycleState(
2460     mojom::blink::PageLifecycleStatePtr state,
2461     SetPageLifecycleStateCallback callback) {
2462   Page* page = GetPage();
2463   if (!page)
2464     return;
2465   Scheduler()->SetPageFrozen(state->is_frozen);
2466 
2467   // Tell the browser that the freezing or resuming was successful.
2468   std::move(callback).Run();
2469 }
2470 
EnableAutoResizeMode(const WebSize & min_size,const WebSize & max_size)2471 void WebViewImpl::EnableAutoResizeMode(const WebSize& min_size,
2472                                        const WebSize& max_size) {
2473   should_auto_resize_ = true;
2474   min_auto_size_ = min_size;
2475   max_auto_size_ = max_size;
2476   ConfigureAutoResizeMode();
2477 }
2478 
DisableAutoResizeMode()2479 void WebViewImpl::DisableAutoResizeMode() {
2480   should_auto_resize_ = false;
2481   ConfigureAutoResizeMode();
2482 }
2483 
SetDefaultPageScaleLimits(float min_scale,float max_scale)2484 void WebViewImpl::SetDefaultPageScaleLimits(float min_scale, float max_scale) {
2485   GetPage()->SetDefaultPageScaleLimits(min_scale, max_scale);
2486 }
2487 
SetInitialPageScaleOverride(float initial_page_scale_factor_override)2488 void WebViewImpl::SetInitialPageScaleOverride(
2489     float initial_page_scale_factor_override) {
2490   PageScaleConstraints constraints =
2491       GetPageScaleConstraintsSet().UserAgentConstraints();
2492   constraints.initial_scale = initial_page_scale_factor_override;
2493 
2494   if (constraints == GetPageScaleConstraintsSet().UserAgentConstraints())
2495     return;
2496 
2497   GetPageScaleConstraintsSet().SetNeedsReset(true);
2498   GetPage()->SetUserAgentPageScaleConstraints(constraints);
2499 }
2500 
SetMaximumLegibleScale(float maximum_legible_scale)2501 void WebViewImpl::SetMaximumLegibleScale(float maximum_legible_scale) {
2502   maximum_legible_scale_ = maximum_legible_scale;
2503 }
2504 
SetIgnoreViewportTagScaleLimits(bool ignore)2505 void WebViewImpl::SetIgnoreViewportTagScaleLimits(bool ignore) {
2506   PageScaleConstraints constraints =
2507       GetPageScaleConstraintsSet().UserAgentConstraints();
2508   if (ignore) {
2509     // Don't ignore the minimum limits in touchless mode to prevent wide
2510     // loading elements from causing us to zoom pages out beyond their layout
2511     // which is fairly common.
2512     if (!RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) {
2513       constraints.minimum_scale =
2514           GetPageScaleConstraintsSet().DefaultConstraints().minimum_scale;
2515     }
2516     constraints.maximum_scale =
2517         GetPageScaleConstraintsSet().DefaultConstraints().maximum_scale;
2518   } else {
2519     if (!RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) {
2520       constraints.minimum_scale = -1;
2521     }
2522     constraints.maximum_scale = -1;
2523   }
2524   GetPage()->SetUserAgentPageScaleConstraints(constraints);
2525 }
2526 
MainFrameSize()2527 IntSize WebViewImpl::MainFrameSize() {
2528   // The frame size should match the viewport size at minimum scale, since the
2529   // viewport must always be contained by the frame.
2530   FloatSize frame_size(size_);
2531   frame_size.Scale(1 / MinimumPageScaleFactor());
2532   return ExpandedIntSize(frame_size);
2533 }
2534 
GetPageScaleConstraintsSet() const2535 PageScaleConstraintsSet& WebViewImpl::GetPageScaleConstraintsSet() const {
2536   return GetPage()->GetPageScaleConstraintsSet();
2537 }
2538 
RefreshPageScaleFactor()2539 void WebViewImpl::RefreshPageScaleFactor() {
2540   if (!MainFrame() || !GetPage() || !GetPage()->MainFrame() ||
2541       !GetPage()->MainFrame()->IsLocalFrame() ||
2542       !GetPage()->DeprecatedLocalMainFrame()->View())
2543     return;
2544   UpdatePageDefinedViewportConstraints(MainFrameImpl()
2545                                            ->GetFrame()
2546                                            ->GetDocument()
2547                                            ->GetViewportData()
2548                                            .GetViewportDescription());
2549   GetPageScaleConstraintsSet().ComputeFinalConstraints();
2550 
2551   float new_page_scale_factor = PageScaleFactor();
2552   if (GetPageScaleConstraintsSet().NeedsReset() &&
2553       GetPageScaleConstraintsSet().FinalConstraints().initial_scale != -1) {
2554     new_page_scale_factor =
2555         GetPageScaleConstraintsSet().FinalConstraints().initial_scale;
2556     GetPageScaleConstraintsSet().SetNeedsReset(false);
2557   }
2558   SetPageScaleFactor(new_page_scale_factor);
2559 
2560   // The constraints may have changed above which affects the page scale limits,
2561   // so we must update those even though SetPageScaleFactor() may do the same if
2562   // the scale factor is changed.
2563   if (does_composite_) {
2564     auto& viewport = GetPage()->GetVisualViewport();
2565     MainFrameImpl()->FrameWidgetImpl()->Client()->SetPageScaleStateAndLimits(
2566         viewport.Scale(), viewport.IsPinchGestureActive(),
2567         MinimumPageScaleFactor(), MaximumPageScaleFactor());
2568   }
2569 }
2570 
UpdatePageDefinedViewportConstraints(const ViewportDescription & description)2571 void WebViewImpl::UpdatePageDefinedViewportConstraints(
2572     const ViewportDescription& description) {
2573   if (!GetPage() || (!size_.width && !size_.height))
2574     return;
2575   // The viewport is a property of the main frame and its widget, so ignore it
2576   // when the main frame is remote.
2577   // TODO(danakj): Remove calls to this method from ChromeClient and DCHECK this
2578   // instead.
2579   if (!GetPage()->MainFrame()->IsLocalFrame())
2580     return;
2581 
2582   if (!GetSettings()->ViewportEnabled()) {
2583     GetPageScaleConstraintsSet().ClearPageDefinedConstraints();
2584     UpdateMainFrameLayoutSize();
2585     return;
2586   }
2587 
2588   Document* document = GetPage()->DeprecatedLocalMainFrame()->GetDocument();
2589 
2590   Length default_min_width =
2591       document->GetViewportData().ViewportDefaultMinWidth();
2592   if (default_min_width.IsAuto())
2593     default_min_width = Length::ExtendToZoom();
2594 
2595   float old_initial_scale =
2596       GetPageScaleConstraintsSet().PageDefinedConstraints().initial_scale;
2597   GetPageScaleConstraintsSet().UpdatePageDefinedConstraints(description,
2598                                                             default_min_width);
2599 
2600   if (SettingsImpl()->ClobberUserAgentInitialScaleQuirk() &&
2601       GetPageScaleConstraintsSet().UserAgentConstraints().initial_scale != -1 &&
2602       GetPageScaleConstraintsSet().UserAgentConstraints().initial_scale *
2603               DeviceScaleFactor() <=
2604           1) {
2605     if (description.max_width == Length::DeviceWidth() ||
2606         (description.max_width.IsAuto() &&
2607          GetPageScaleConstraintsSet().PageDefinedConstraints().initial_scale ==
2608              1.0f))
2609       SetInitialPageScaleOverride(-1);
2610   }
2611 
2612   Settings& page_settings = GetPage()->GetSettings();
2613   GetPageScaleConstraintsSet().AdjustForAndroidWebViewQuirks(
2614       description, default_min_width.IntValue(), DeviceScaleFactor(),
2615       SettingsImpl()->SupportDeprecatedTargetDensityDPI(),
2616       page_settings.GetWideViewportQuirkEnabled(),
2617       page_settings.GetUseWideViewport(),
2618       page_settings.GetLoadWithOverviewMode(),
2619       SettingsImpl()->ViewportMetaNonUserScalableQuirk());
2620   float new_initial_scale =
2621       GetPageScaleConstraintsSet().PageDefinedConstraints().initial_scale;
2622   if (old_initial_scale != new_initial_scale && new_initial_scale != -1) {
2623     GetPageScaleConstraintsSet().SetNeedsReset(true);
2624     if (MainFrameImpl() && MainFrameImpl()->GetFrameView())
2625       MainFrameImpl()->GetFrameView()->SetNeedsLayout();
2626   }
2627 
2628   UpdateMainFrameLayoutSize();
2629 }
2630 
SetTextAutosizerPageInfo(const WebTextAutosizerPageInfo & page_info)2631 void WebViewImpl::SetTextAutosizerPageInfo(
2632     const WebTextAutosizerPageInfo& page_info) {
2633   Frame* root_frame = GetPage()->MainFrame();
2634   DCHECK(root_frame->IsRemoteFrame());
2635   if (page_info == GetPage()->TextAutosizerPageInfo())
2636     return;
2637 
2638   GetPage()->SetTextAutosizerPageInfo(page_info);
2639   TextAutosizer::UpdatePageInfoInAllFrames(root_frame);
2640 }
2641 
UpdateMainFrameLayoutSize()2642 void WebViewImpl::UpdateMainFrameLayoutSize() {
2643   if (should_auto_resize_ || !MainFrameImpl())
2644     return;
2645 
2646   LocalFrameView* view = MainFrameImpl()->GetFrameView();
2647   if (!view)
2648     return;
2649 
2650   WebSize layout_size = size_;
2651 
2652   if (GetSettings()->ViewportEnabled())
2653     layout_size = GetPageScaleConstraintsSet().GetLayoutSize();
2654 
2655   if (GetPage()->GetSettings().GetForceZeroLayoutHeight())
2656     layout_size.height = 0;
2657 
2658   view->SetLayoutSize(layout_size);
2659 }
2660 
ContentsSize() const2661 IntSize WebViewImpl::ContentsSize() const {
2662   if (!GetPage()->MainFrame()->IsLocalFrame())
2663     return IntSize();
2664   auto* layout_view =
2665       GetPage()->DeprecatedLocalMainFrame()->ContentLayoutObject();
2666   if (!layout_view)
2667     return IntSize();
2668   return PixelSnappedIntRect(layout_view->DocumentRect()).Size();
2669 }
2670 
ContentsPreferredMinimumSize()2671 WebSize WebViewImpl::ContentsPreferredMinimumSize() {
2672   DCHECK(AsView().page->MainFrame()->IsLocalFrame());
2673 
2674   auto* main_local_frame = DynamicTo<LocalFrame>(AsView().page->MainFrame());
2675   Document* document = main_local_frame->GetDocument();
2676   if (!document || !document->GetLayoutView() || !document->documentElement() ||
2677       !document->documentElement()->GetLayoutBox())
2678     return WebSize();
2679 
2680   // The preferred size requires an up-to-date layout tree.
2681   DCHECK(!document->NeedsLayoutTreeUpdate() &&
2682          !document->View()->NeedsLayout());
2683 
2684   // Needed for computing MinPreferredWidth.
2685   FontCachePurgePreventer fontCachePurgePreventer;
2686   int width_scaled = document->GetLayoutView()
2687                          ->PreferredLogicalWidths()
2688                          .min_size.Round();  // Already accounts for zoom.
2689   int height_scaled =
2690       document->documentElement()->GetLayoutBox()->ScrollHeight().Round();
2691   return IntSize(width_scaled, height_scaled);
2692 }
2693 
UpdatePreferredSize()2694 void WebViewImpl::UpdatePreferredSize() {
2695   // We don't always want to send the change messages over IPC, only if we've
2696   // been put in that mode by getting a |ViewMsg_EnablePreferredSizeChangedMode|
2697   // message.
2698   if (!send_preferred_size_changes_ || !MainFrameImpl())
2699     return;
2700 
2701   if (!needs_preferred_size_update_)
2702     return;
2703   needs_preferred_size_update_ = false;
2704 
2705   WebSize web_size = ContentsPreferredMinimumSize();
2706   WebRect web_rect(0, 0, web_size.width, web_size.height);
2707   MainFrameImpl()->LocalRootFrameWidget()->Client()->ConvertViewportToWindow(
2708       &web_rect);
2709   WebSize size(web_rect.width, web_rect.height);
2710 
2711   if (size != preferred_size_) {
2712     preferred_size_ = size;
2713     local_main_frame_host_remote_->ContentsPreferredSizeChanged(
2714         gfx::Size(size));
2715   }
2716 }
2717 
EnablePreferredSizeChangedMode()2718 void WebViewImpl::EnablePreferredSizeChangedMode() {
2719   if (send_preferred_size_changes_)
2720     return;
2721   send_preferred_size_changes_ = true;
2722   needs_preferred_size_update_ = true;
2723 
2724   // We need to ensure |UpdatePreferredSize| gets called. If a layout is needed,
2725   // force an update here which will call |DidUpdateMainFrameLayout|.
2726   if (MainFrameWidget()) {
2727     MainFrameWidget()->UpdateLifecycle(WebLifecycleUpdate::kLayout,
2728                                        DocumentUpdateReason::kSizeChange);
2729   }
2730 
2731   // If a layout was not needed, |DidUpdateMainFrameLayout| will not be called.
2732   // We explicitly update the preferred size here to ensure the preferred size
2733   // notification is sent.
2734   UpdatePreferredSize();
2735 }
2736 
DefaultMinimumPageScaleFactor() const2737 float WebViewImpl::DefaultMinimumPageScaleFactor() const {
2738   return GetPageScaleConstraintsSet().DefaultConstraints().minimum_scale;
2739 }
2740 
DefaultMaximumPageScaleFactor() const2741 float WebViewImpl::DefaultMaximumPageScaleFactor() const {
2742   return GetPageScaleConstraintsSet().DefaultConstraints().maximum_scale;
2743 }
2744 
MinimumPageScaleFactor() const2745 float WebViewImpl::MinimumPageScaleFactor() const {
2746   return GetPageScaleConstraintsSet().FinalConstraints().minimum_scale;
2747 }
2748 
MaximumPageScaleFactor() const2749 float WebViewImpl::MaximumPageScaleFactor() const {
2750   return GetPageScaleConstraintsSet().FinalConstraints().maximum_scale;
2751 }
2752 
ResetScaleStateImmediately()2753 void WebViewImpl::ResetScaleStateImmediately() {
2754   GetPageScaleConstraintsSet().SetNeedsReset(true);
2755 }
2756 
ResetScrollAndScaleState()2757 void WebViewImpl::ResetScrollAndScaleState() {
2758   GetPage()->GetVisualViewport().Reset();
2759 
2760   auto* main_local_frame = DynamicTo<LocalFrame>(GetPage()->MainFrame());
2761   if (!main_local_frame)
2762     return;
2763 
2764   if (LocalFrameView* frame_view = main_local_frame->View()) {
2765     ScrollableArea* scrollable_area = frame_view->LayoutViewport();
2766 
2767     if (!scrollable_area->GetScrollOffset().IsZero()) {
2768       scrollable_area->SetScrollOffset(ScrollOffset(),
2769                                        mojom::blink::ScrollType::kProgrammatic);
2770     }
2771   }
2772 
2773   if (Document* document = main_local_frame->GetDocument()) {
2774     if (DocumentLoader* loader = document->Loader()) {
2775       if (HistoryItem* item = loader->GetHistoryItem())
2776         item->ClearViewState();
2777     }
2778   }
2779 
2780   GetPageScaleConstraintsSet().SetNeedsReset(true);
2781 }
2782 
AudioStateChanged(bool is_audio_playing)2783 void WebViewImpl::AudioStateChanged(bool is_audio_playing) {
2784   GetPage()->GetPageScheduler()->AudioStateChanged(is_audio_playing);
2785 }
2786 
HitTestResultAt(const gfx::Point & point)2787 WebHitTestResult WebViewImpl::HitTestResultAt(const gfx::Point& point) {
2788   return CoreHitTestResultAt(point);
2789 }
2790 
CoreHitTestResultAt(const gfx::Point & point_in_viewport)2791 HitTestResult WebViewImpl::CoreHitTestResultAt(
2792     const gfx::Point& point_in_viewport) {
2793   // TODO(crbug.com/843128): When we do async hit-testing, we might try to do
2794   // hit-testing when the local main frame is not valid anymore. Look into if we
2795   // can avoid getting here earlier in the pipeline.
2796   if (!MainFrameImpl() || !MainFrameImpl()->GetFrameView())
2797     return HitTestResult();
2798 
2799   DocumentLifecycle::AllowThrottlingScope throttling_scope(
2800       MainFrameImpl()->GetFrame()->GetDocument()->Lifecycle());
2801   LocalFrameView* view = MainFrameImpl()->GetFrameView();
2802   PhysicalOffset point_in_root_frame =
2803       view->ViewportToFrame(PhysicalOffset(IntPoint(point_in_viewport)));
2804   return HitTestResultForRootFramePos(point_in_root_frame);
2805 }
2806 
SendResizeEventForMainFrame()2807 void WebViewImpl::SendResizeEventForMainFrame() {
2808   // FIXME: This is wrong. The LocalFrameView is responsible sending a
2809   // resizeEvent as part of layout. Layout is also responsible for sending
2810   // invalidations to the embedder. This method and all callers may be wrong. --
2811   // eseidel.
2812   if (MainFrameImpl()->GetFrameView()) {
2813     // Enqueues the resize event.
2814     MainFrameImpl()->GetFrame()->GetDocument()->EnqueueResizeEvent();
2815   }
2816 
2817   // A resized main frame can change the page scale limits.
2818   if (does_composite_) {
2819     auto& viewport = GetPage()->GetVisualViewport();
2820     MainFrameImpl()->FrameWidgetImpl()->Client()->SetPageScaleStateAndLimits(
2821         viewport.Scale(), viewport.IsPinchGestureActive(),
2822         MinimumPageScaleFactor(), MaximumPageScaleFactor());
2823   }
2824 }
2825 
ConfigureAutoResizeMode()2826 void WebViewImpl::ConfigureAutoResizeMode() {
2827   if (!MainFrameImpl() || !MainFrameImpl()->GetFrame() ||
2828       !MainFrameImpl()->GetFrame()->View())
2829     return;
2830 
2831   if (should_auto_resize_) {
2832     MainFrameImpl()->GetFrame()->View()->EnableAutoSizeMode(min_auto_size_,
2833                                                             max_auto_size_);
2834   } else {
2835     MainFrameImpl()->GetFrame()->View()->DisableAutoSizeMode();
2836   }
2837 }
2838 
CreateUniqueIdentifierForRequest()2839 uint64_t WebViewImpl::CreateUniqueIdentifierForRequest() {
2840   return CreateUniqueIdentifier();
2841 }
2842 
SetCompositorDeviceScaleFactorOverride(float device_scale_factor)2843 void WebViewImpl::SetCompositorDeviceScaleFactorOverride(
2844     float device_scale_factor) {
2845   if (compositor_device_scale_factor_override_ == device_scale_factor)
2846     return;
2847   compositor_device_scale_factor_override_ = device_scale_factor;
2848   if (zoom_factor_for_device_scale_factor_) {
2849     SetZoomLevel(ZoomLevel());
2850     return;
2851   }
2852 }
2853 
SetDeviceEmulationTransform(const TransformationMatrix & transform)2854 void WebViewImpl::SetDeviceEmulationTransform(
2855     const TransformationMatrix& transform) {
2856   if (transform == device_emulation_transform_)
2857     return;
2858   device_emulation_transform_ = transform;
2859   UpdateDeviceEmulationTransform();
2860 }
2861 
GetDeviceEmulationTransform() const2862 TransformationMatrix WebViewImpl::GetDeviceEmulationTransform() const {
2863   return device_emulation_transform_;
2864 }
2865 
EnableDeviceEmulation(const WebDeviceEmulationParams & params)2866 void WebViewImpl::EnableDeviceEmulation(
2867     const WebDeviceEmulationParams& params) {
2868   TransformationMatrix device_emulation_transform =
2869       dev_tools_emulator_->EnableDeviceEmulation(params);
2870   SetDeviceEmulationTransform(device_emulation_transform);
2871 }
2872 
DisableDeviceEmulation()2873 void WebViewImpl::DisableDeviceEmulation() {
2874   dev_tools_emulator_->DisableDeviceEmulation();
2875   SetDeviceEmulationTransform(TransformationMatrix());
2876 }
2877 
PerformCustomContextMenuAction(unsigned action)2878 void WebViewImpl::PerformCustomContextMenuAction(unsigned action) {
2879   if (AsView().page) {
2880     AsView().page->GetContextMenuController().CustomContextMenuItemSelected(
2881         action);
2882   }
2883 }
2884 
ShowContextMenu(WebMenuSourceType source_type)2885 void WebViewImpl::ShowContextMenu(WebMenuSourceType source_type) {
2886   if (!MainFrameImpl())
2887     return;
2888 
2889   // If MainFrameImpl() is non-null, then FrameWidget() will also be non-null.
2890   DCHECK(MainFrameImpl()->FrameWidget());
2891   MainFrameImpl()->FrameWidget()->ShowContextMenu(source_type);
2892 }
2893 
GetURLForDebugTrace()2894 WebURL WebViewImpl::GetURLForDebugTrace() {
2895   WebFrame* main_frame = MainFrame();
2896   if (main_frame->IsWebLocalFrame())
2897     return main_frame->ToWebLocalFrame()->GetDocument().Url();
2898   return {};
2899 }
2900 
DidCloseContextMenu()2901 void WebViewImpl::DidCloseContextMenu() {
2902   LocalFrame* frame = AsView().page->GetFocusController().FocusedFrame();
2903   if (frame)
2904     frame->Selection().SetCaretBlinkingSuspended(false);
2905 }
2906 
GetActiveWebInputMethodController() const2907 WebInputMethodController* WebViewImpl::GetActiveWebInputMethodController()
2908     const {
2909   WebLocalFrameImpl* local_frame =
2910       WebLocalFrameImpl::FromFrame(FocusedLocalFrameInWidget());
2911   return local_frame ? local_frame->GetInputMethodController() : nullptr;
2912 }
2913 
BackgroundColor() const2914 SkColor WebViewImpl::BackgroundColor() const {
2915   if (background_color_override_enabled_)
2916     return background_color_override_;
2917   Page* page = AsView().page.Get();
2918   if (!page)
2919     return BaseBackgroundColor().Rgb();
2920   if (auto* main_local_frame = DynamicTo<LocalFrame>(page->MainFrame())) {
2921     LocalFrameView* view = main_local_frame->View();
2922     if (view)
2923       return view->DocumentBackgroundColor().Rgb();
2924   }
2925   return BaseBackgroundColor().Rgb();
2926 }
2927 
BaseBackgroundColor() const2928 Color WebViewImpl::BaseBackgroundColor() const {
2929   return base_background_color_override_enabled_
2930              ? base_background_color_override_
2931              : base_background_color_;
2932 }
2933 
SetBaseBackgroundColor(SkColor color)2934 void WebViewImpl::SetBaseBackgroundColor(SkColor color) {
2935   if (base_background_color_ == color)
2936     return;
2937 
2938   base_background_color_ = color;
2939   UpdateBaseBackgroundColor();
2940 }
2941 
SetBaseBackgroundColorOverride(SkColor color)2942 void WebViewImpl::SetBaseBackgroundColorOverride(SkColor color) {
2943   if (base_background_color_override_enabled_ &&
2944       base_background_color_override_ == color) {
2945     return;
2946   }
2947 
2948   base_background_color_override_enabled_ = true;
2949   base_background_color_override_ = color;
2950   if (MainFrameImpl()) {
2951     // Force lifecycle update to ensure we're good to call
2952     // LocalFrameView::setBaseBackgroundColor().
2953     MainFrameImpl()
2954         ->GetFrame()
2955         ->View()
2956         ->UpdateLifecycleToCompositingCleanPlusScrolling(
2957             DocumentUpdateReason::kBaseColor);
2958   }
2959   UpdateBaseBackgroundColor();
2960 }
2961 
ClearBaseBackgroundColorOverride()2962 void WebViewImpl::ClearBaseBackgroundColorOverride() {
2963   if (!base_background_color_override_enabled_)
2964     return;
2965 
2966   base_background_color_override_enabled_ = false;
2967   if (MainFrameImpl()) {
2968     // Force lifecycle update to ensure we're good to call
2969     // LocalFrameView::setBaseBackgroundColor().
2970     MainFrameImpl()
2971         ->GetFrame()
2972         ->View()
2973         ->UpdateLifecycleToCompositingCleanPlusScrolling(
2974             DocumentUpdateReason::kBaseColor);
2975   }
2976   UpdateBaseBackgroundColor();
2977 }
2978 
UpdateBaseBackgroundColor()2979 void WebViewImpl::UpdateBaseBackgroundColor() {
2980   Color color = BaseBackgroundColor();
2981   if (auto* local_frame = DynamicTo<LocalFrame>(AsView().page->MainFrame())) {
2982     LocalFrameView* view = local_frame->View();
2983     view->UpdateBaseBackgroundColorRecursively(color);
2984   }
2985 }
2986 
SetInsidePortal(bool inside_portal)2987 void WebViewImpl::SetInsidePortal(bool inside_portal) {
2988   GetPage()->SetInsidePortal(inside_portal);
2989 }
2990 
SetIsActive(bool active)2991 void WebViewImpl::SetIsActive(bool active) {
2992   if (GetPage())
2993     GetPage()->GetFocusController().SetActive(active);
2994 }
2995 
IsActive() const2996 bool WebViewImpl::IsActive() const {
2997   return GetPage() ? GetPage()->GetFocusController().IsActive() : false;
2998 }
2999 
SetDomainRelaxationForbidden(bool forbidden,const WebString & scheme)3000 void WebViewImpl::SetDomainRelaxationForbidden(bool forbidden,
3001                                                const WebString& scheme) {
3002   SchemeRegistry::SetDomainRelaxationForbiddenForURLScheme(forbidden,
3003                                                            String(scheme));
3004 }
3005 
SetWindowFeatures(const WebWindowFeatures & features)3006 void WebViewImpl::SetWindowFeatures(const WebWindowFeatures& features) {
3007   AsView().page->SetWindowFeatures(features);
3008 }
3009 
SetOpenedByDOM()3010 void WebViewImpl::SetOpenedByDOM() {
3011   AsView().page->SetOpenedByDOM();
3012 }
3013 
DidCommitLoad(bool is_new_navigation,bool is_navigation_within_page)3014 void WebViewImpl::DidCommitLoad(bool is_new_navigation,
3015                                 bool is_navigation_within_page) {
3016   if (!is_navigation_within_page) {
3017     should_dispatch_first_visually_non_empty_layout_ = true;
3018     should_dispatch_first_layout_after_finished_parsing_ = true;
3019     should_dispatch_first_layout_after_finished_loading_ = true;
3020 
3021     if (is_new_navigation)
3022       GetPageScaleConstraintsSet().SetNeedsReset(true);
3023   }
3024 
3025   // Give the visual viewport's scroll layer its initial size.
3026   GetPage()->GetVisualViewport().MainFrameDidChangeSize();
3027 }
3028 
ResizeAfterLayout()3029 void WebViewImpl::ResizeAfterLayout() {
3030   DCHECK(MainFrameImpl());
3031 
3032   if (!AsView().client || !AsView().client->CanUpdateLayout())
3033     return;
3034 
3035   if (should_auto_resize_) {
3036     LocalFrameView* view = MainFrameImpl()->GetFrame()->View();
3037     WebSize frame_size = view->Size();
3038     if (frame_size != size_) {
3039       size_ = frame_size;
3040 
3041       GetPage()->GetVisualViewport().SetSize(size_);
3042       GetPageScaleConstraintsSet().DidChangeInitialContainingBlockSize(size_);
3043       view->SetInitialViewportSize(size_);
3044 
3045       AsView().client->DidAutoResize(size_);
3046       SendResizeEventForMainFrame();
3047     }
3048   }
3049 
3050   if (does_composite_ && GetPageScaleConstraintsSet().ConstraintsDirty())
3051     RefreshPageScaleFactor();
3052 
3053   resize_viewport_anchor_->ResizeFrameView(MainFrameSize());
3054 }
3055 
MainFrameLayoutUpdated()3056 void WebViewImpl::MainFrameLayoutUpdated() {
3057   DCHECK(MainFrameImpl());
3058   if (!AsView().client)
3059     return;
3060 
3061   AsView().client->DidUpdateMainFrameLayout();
3062   needs_preferred_size_update_ = true;
3063 }
3064 
DidChangeContentsSize()3065 void WebViewImpl::DidChangeContentsSize() {
3066   auto* local_frame = DynamicTo<LocalFrame>(GetPage()->MainFrame());
3067   if (!local_frame)
3068     return;
3069 
3070   LocalFrameView* view = local_frame->View();
3071 
3072   int vertical_scrollbar_width = 0;
3073   if (view && view->LayoutViewport()) {
3074     Scrollbar* vertical_scrollbar = view->LayoutViewport()->VerticalScrollbar();
3075     if (vertical_scrollbar && !vertical_scrollbar->IsOverlayScrollbar())
3076       vertical_scrollbar_width = vertical_scrollbar->Width();
3077   }
3078 
3079   GetPageScaleConstraintsSet().DidChangeContentsSize(
3080       ContentsSize(), vertical_scrollbar_width, PageScaleFactor());
3081 }
3082 
PageScaleFactorChanged()3083 void WebViewImpl::PageScaleFactorChanged() {
3084   // This is called from the VisualViewport which only is used to control the
3085   // page scale/scroll viewport for a local main frame, and only when
3086   // compositing as PageScaleFactor doesn't exist otherwise.
3087   DCHECK(MainFrameImpl());
3088   DCHECK(does_composite_);
3089 
3090   GetPageScaleConstraintsSet().SetNeedsReset(false);
3091   // Set up the compositor and inform the browser of the PageScaleFactor,
3092   // which is tracked per-view.
3093   auto& viewport = GetPage()->GetVisualViewport();
3094   MainFrameImpl()->FrameWidgetImpl()->Client()->SetPageScaleStateAndLimits(
3095       viewport.Scale(), viewport.IsPinchGestureActive(),
3096       MinimumPageScaleFactor(), MaximumPageScaleFactor());
3097 
3098   local_main_frame_host_remote_->ScaleFactorChanged(viewport.Scale());
3099 
3100   if (dev_tools_emulator_->HasViewportOverride()) {
3101     TransformationMatrix device_emulation_transform =
3102         dev_tools_emulator_->MainFrameScrollOrScaleChanged();
3103     SetDeviceEmulationTransform(device_emulation_transform);
3104   }
3105 }
3106 
MainFrameScrollOffsetChanged()3107 void WebViewImpl::MainFrameScrollOffsetChanged() {
3108   DCHECK(MainFrameImpl());
3109   if (dev_tools_emulator_->HasViewportOverride()) {
3110     TransformationMatrix device_emulation_transform =
3111         dev_tools_emulator_->MainFrameScrollOrScaleChanged();
3112     SetDeviceEmulationTransform(device_emulation_transform);
3113   }
3114 }
3115 
SetBackgroundColorOverride(SkColor color)3116 void WebViewImpl::SetBackgroundColorOverride(SkColor color) {
3117   DCHECK(does_composite_);
3118 
3119   background_color_override_enabled_ = true;
3120   background_color_override_ = color;
3121   if (MainFrameImpl()) {
3122     MainFrameImpl()->FrameWidgetImpl()->SetBackgroundColor(BackgroundColor());
3123   }
3124 }
3125 
ClearBackgroundColorOverride()3126 void WebViewImpl::ClearBackgroundColorOverride() {
3127   DCHECK(does_composite_);
3128 
3129   background_color_override_enabled_ = false;
3130   if (MainFrameImpl()) {
3131     MainFrameImpl()->FrameWidgetImpl()->SetBackgroundColor(BackgroundColor());
3132   }
3133 }
3134 
SetZoomFactorOverride(float zoom_factor)3135 void WebViewImpl::SetZoomFactorOverride(float zoom_factor) {
3136   zoom_factor_override_ = zoom_factor;
3137   SetZoomLevel(ZoomLevel());
3138 }
3139 
SetMainFrameOverlayColor(SkColor color)3140 void WebViewImpl::SetMainFrameOverlayColor(SkColor color) {
3141   DCHECK(AsView().page->MainFrame());
3142   if (auto* local_frame = DynamicTo<LocalFrame>(AsView().page->MainFrame()))
3143     local_frame->SetMainFrameColorOverlay(color);
3144 }
3145 
FocusedElement() const3146 Element* WebViewImpl::FocusedElement() const {
3147   LocalFrame* frame = AsView().page->GetFocusController().FocusedFrame();
3148   if (!frame)
3149     return nullptr;
3150 
3151   Document* document = frame->GetDocument();
3152   if (!document)
3153     return nullptr;
3154 
3155   return document->FocusedElement();
3156 }
3157 
HitTestResultForRootFramePos(const PhysicalOffset & pos_in_root_frame)3158 HitTestResult WebViewImpl::HitTestResultForRootFramePos(
3159     const PhysicalOffset& pos_in_root_frame) {
3160   auto* main_frame = DynamicTo<LocalFrame>(AsView().page->MainFrame());
3161   if (!main_frame)
3162     return HitTestResult();
3163   HitTestLocation location(
3164       main_frame->View()->ConvertFromRootFrame(pos_in_root_frame));
3165   HitTestResult result = main_frame->GetEventHandler().HitTestResultAtLocation(
3166       location, HitTestRequest::kReadOnly | HitTestRequest::kActive);
3167   result.SetToShadowHostIfInRestrictedShadowRoot();
3168   return result;
3169 }
3170 
HitTestResultForTap(const gfx::Point & tap_point_window_pos,const WebSize & tap_area)3171 WebHitTestResult WebViewImpl::HitTestResultForTap(
3172     const gfx::Point& tap_point_window_pos,
3173     const WebSize& tap_area) {
3174   auto* main_frame = DynamicTo<LocalFrame>(AsView().page->MainFrame());
3175   if (!main_frame)
3176     return HitTestResult();
3177 
3178   WebGestureEvent tap_event(WebInputEvent::kGestureTap,
3179                             WebInputEvent::kNoModifiers, base::TimeTicks::Now(),
3180                             WebGestureDevice::kTouchscreen);
3181   // GestureTap is only ever from a touchscreen.
3182   tap_event.SetPositionInWidget(FloatPoint(IntPoint(tap_point_window_pos)));
3183   tap_event.data.tap.tap_count = 1;
3184   tap_event.data.tap.width = tap_area.width;
3185   tap_event.data.tap.height = tap_area.height;
3186 
3187   WebGestureEvent scaled_event =
3188       TransformWebGestureEvent(MainFrameImpl()->GetFrameView(), tap_event);
3189 
3190   HitTestResult result =
3191       main_frame->GetEventHandler()
3192           .HitTestResultForGestureEvent(
3193               scaled_event, HitTestRequest::kReadOnly | HitTestRequest::kActive)
3194           .GetHitTestResult();
3195 
3196   result.SetToShadowHostIfInRestrictedShadowRoot();
3197   return result;
3198 }
3199 
SetTabsToLinks(bool enable)3200 void WebViewImpl::SetTabsToLinks(bool enable) {
3201   tabs_to_links_ = enable;
3202 }
3203 
TabsToLinks() const3204 bool WebViewImpl::TabsToLinks() const {
3205   return tabs_to_links_;
3206 }
3207 
DidChangeRootLayer(bool root_layer_exists)3208 void WebViewImpl::DidChangeRootLayer(bool root_layer_exists) {
3209   if (!MainFrameImpl()) {
3210     DCHECK(!root_layer_exists);
3211     return;
3212   }
3213   if (root_layer_exists) {
3214     UpdateDeviceEmulationTransform();
3215   } else {
3216     // When the document in an already-attached main frame is being replaced by
3217     // a navigation then DidChangeRootLayer(false) will be called. Since we are
3218     // navigating, defer BeginMainFrames until the new document is ready for
3219     // them.
3220     //
3221     // TODO(crbug.com/936696): This should not be needed once we always swap
3222     // frames when swapping documents.
3223     scoped_defer_main_frame_update_ =
3224         MainFrameImpl()->FrameWidgetImpl()->DeferMainFrameUpdate();
3225   }
3226 }
3227 
InvalidateRect(const IntRect & rect)3228 void WebViewImpl::InvalidateRect(const IntRect& rect) {
3229   // This is only for WebViewPlugin.
3230   if (!does_composite_ && AsView().client)
3231     AsView().client->DidInvalidateRect(rect);
3232 }
3233 
ApplyViewportChanges(const ApplyViewportChangesArgs & args)3234 void WebViewImpl::ApplyViewportChanges(const ApplyViewportChangesArgs& args) {
3235   VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
3236 
3237   // Store the desired offsets the visual viewport before setting the top
3238   // controls ratio since doing so will change the bounds and move the
3239   // viewports to keep the offsets valid. The compositor may have already
3240   // done that so we don't want to double apply the deltas here.
3241   FloatPoint visual_viewport_offset = visual_viewport.VisibleRect().Location();
3242   visual_viewport_offset.Move(args.inner_delta.x(), args.inner_delta.y());
3243 
3244   GetBrowserControls().SetShownRatio(
3245       GetBrowserControls().TopShownRatio() + args.top_controls_delta,
3246       GetBrowserControls().BottomShownRatio() + args.bottom_controls_delta);
3247 
3248   SetPageScaleFactorAndLocation(PageScaleFactor() * args.page_scale_delta,
3249                                 args.is_pinch_gesture_active,
3250                                 visual_viewport_offset);
3251 
3252   if (args.page_scale_delta != 1) {
3253     double_tap_zoom_pending_ = false;
3254     visual_viewport.UserDidChangeScale();
3255   }
3256 
3257   elastic_overscroll_ += FloatSize(args.elastic_overscroll_delta.x(),
3258                                    args.elastic_overscroll_delta.y());
3259   UpdateBrowserControlsConstraint(args.browser_controls_constraint);
3260 
3261   if (args.scroll_gesture_did_end)
3262     MainFrameImpl()->GetFrame()->GetEventHandler().MarkHoverStateDirty();
3263 }
3264 
RecordManipulationTypeCounts(cc::ManipulationInfo info)3265 void WebViewImpl::RecordManipulationTypeCounts(cc::ManipulationInfo info) {
3266   if (!MainFrameImpl())
3267     return;
3268 
3269   if ((info & cc::kManipulationInfoHasScrolledByWheel) ==
3270       cc::kManipulationInfoHasScrolledByWheel) {
3271     UseCounter::Count(MainFrameImpl()->GetDocument(),
3272                       WebFeature::kScrollByWheel);
3273   }
3274   if ((info & cc::kManipulationInfoHasScrolledByTouch) ==
3275       cc::kManipulationInfoHasScrolledByTouch) {
3276     UseCounter::Count(MainFrameImpl()->GetDocument(),
3277                       WebFeature::kScrollByTouch);
3278   }
3279   if ((info & cc::kManipulationInfoHasPinchZoomed) ==
3280       cc::kManipulationInfoHasPinchZoomed) {
3281     UseCounter::Count(MainFrameImpl()->GetDocument(), WebFeature::kPinchZoom);
3282   }
3283   if ((info & cc::kManipulationInfoHasScrolledByPrecisionTouchPad) ==
3284       cc::kManipulationInfoHasScrolledByPrecisionTouchPad) {
3285     UseCounter::Count(MainFrameImpl()->GetDocument(),
3286                       WebFeature::kScrollByPrecisionTouchPad);
3287   }
3288 }
3289 
FindNodeFromScrollableCompositorElementId(cc::ElementId element_id) const3290 Node* WebViewImpl::FindNodeFromScrollableCompositorElementId(
3291     cc::ElementId element_id) const {
3292   if (!GetPage())
3293     return nullptr;
3294 
3295   if (element_id == GetPage()->GetVisualViewport().GetScrollElementId()) {
3296     // Return the Document in this case since the window.visualViewport DOM
3297     // object is not a node.
3298     if (MainFrameImpl())
3299       return MainFrameImpl()->GetDocument();
3300   }
3301 
3302   if (!GetPage()->GetScrollingCoordinator())
3303     return nullptr;
3304   ScrollableArea* scrollable_area =
3305       GetPage()
3306           ->GetScrollingCoordinator()
3307           ->ScrollableAreaWithElementIdInAllLocalFrames(element_id);
3308   if (!scrollable_area || !scrollable_area->GetLayoutBox())
3309     return nullptr;
3310 
3311   return scrollable_area->GetLayoutBox()->GetNode();
3312 }
3313 
SendOverscrollEventFromImplSide(const gfx::Vector2dF & overscroll_delta,cc::ElementId scroll_latched_element_id)3314 void WebViewImpl::SendOverscrollEventFromImplSide(
3315     const gfx::Vector2dF& overscroll_delta,
3316     cc::ElementId scroll_latched_element_id) {
3317   if (!RuntimeEnabledFeatures::OverscrollCustomizationEnabled())
3318     return;
3319 
3320   DCHECK(!overscroll_delta.IsZero());
3321   Node* target_node =
3322       FindNodeFromScrollableCompositorElementId(scroll_latched_element_id);
3323   if (target_node) {
3324     target_node->GetDocument().EnqueueOverscrollEventForNode(
3325         target_node, overscroll_delta.x(), overscroll_delta.y());
3326   }
3327 }
3328 
SendScrollEndEventFromImplSide(cc::ElementId scroll_latched_element_id)3329 void WebViewImpl::SendScrollEndEventFromImplSide(
3330     cc::ElementId scroll_latched_element_id) {
3331   if (!RuntimeEnabledFeatures::OverscrollCustomizationEnabled())
3332     return;
3333 
3334   Node* target_node =
3335       FindNodeFromScrollableCompositorElementId(scroll_latched_element_id);
3336   if (target_node)
3337     target_node->GetDocument().EnqueueScrollEndEventForNode(target_node);
3338 }
3339 
UpdateDeviceEmulationTransform()3340 void WebViewImpl::UpdateDeviceEmulationTransform() {
3341   GetPage()->GetVisualViewport().SetNeedsPaintPropertyUpdate();
3342 
3343   if (MainFrameImpl()) {
3344     // When the device emulation transform is updated, to avoid incorrect
3345     // scales and fuzzy raster from the compositor, force all content to
3346     // pick ideal raster scales.
3347     // TODO(wjmaclean): This is only done on the main frame's widget currently,
3348     // it should update all local frames.
3349     MainFrameImpl()->FrameWidgetImpl()->SetNeedsRecalculateRasterScales();
3350   }
3351 }
3352 
Scheduler() const3353 PageScheduler* WebViewImpl::Scheduler() const {
3354   DCHECK(GetPage());
3355   return GetPage()->GetPageScheduler();
3356 }
3357 
SetVisibilityState(PageVisibilityState visibility_state,bool is_initial_state)3358 void WebViewImpl::SetVisibilityState(PageVisibilityState visibility_state,
3359                                      bool is_initial_state) {
3360   DCHECK(GetPage());
3361   GetPage()->SetVisibilityState(visibility_state, is_initial_state);
3362   GetPage()->GetPageScheduler()->SetPageVisible(visibility_state ==
3363                                                 PageVisibilityState::kVisible);
3364 }
3365 
GetVisibilityState()3366 PageVisibilityState WebViewImpl::GetVisibilityState() {
3367   DCHECK(GetPage());
3368   return GetPage()->GetVisibilityState();
3369 }
3370 
ForceNextWebGLContextCreationToFail()3371 void WebViewImpl::ForceNextWebGLContextCreationToFail() {
3372   CoreInitializer::GetInstance().ForceNextWebGLContextCreationToFail();
3373 }
3374 
ForceNextDrawingBufferCreationToFail()3375 void WebViewImpl::ForceNextDrawingBufferCreationToFail() {
3376   DrawingBuffer::ForceNextDrawingBufferCreationToFail();
3377 }
3378 
DeviceScaleFactor() const3379 float WebViewImpl::DeviceScaleFactor() const {
3380   // TODO(oshima): Investigate if this should return the ScreenInfo's scale
3381   // factor rather than page's scale factor, which can be 1 in use-zoom-for-dsf
3382   // mode.
3383   if (!GetPage())
3384     return 1;
3385 
3386   return GetPage()->DeviceScaleFactorDeprecated();
3387 }
3388 
FocusedLocalFrameInWidget() const3389 LocalFrame* WebViewImpl::FocusedLocalFrameInWidget() const {
3390   if (!MainFrameImpl())
3391     return nullptr;
3392 
3393   auto* focused_frame = To<LocalFrame>(FocusedCoreFrame());
3394   if (focused_frame->LocalFrameRoot() != MainFrameImpl()->GetFrame())
3395     return nullptr;
3396   return focused_frame;
3397 }
3398 
FocusedLocalFrameAvailableForIme() const3399 LocalFrame* WebViewImpl::FocusedLocalFrameAvailableForIme() const {
3400   return ime_accept_events_ ? FocusedLocalFrameInWidget() : nullptr;
3401 }
3402 
SetPageFrozen(bool frozen)3403 void WebViewImpl::SetPageFrozen(bool frozen) {
3404   Scheduler()->SetPageFrozen(frozen);
3405 }
3406 
PutPageIntoBackForwardCache()3407 void WebViewImpl::PutPageIntoBackForwardCache() {
3408   SetVisibilityState(PageVisibilityState::kHidden, /*is_initial_state=*/false);
3409 
3410   Page* page = AsView().page;
3411   if (page) {
3412     for (Frame* frame = page->MainFrame(); frame;
3413          frame = frame->Tree().TraverseNext()) {
3414       if (frame->DomWindow() && frame->DomWindow()->IsLocalDOMWindow()) {
3415         frame->DomWindow()->ToLocalDOMWindow()->DispatchPagehideEvent(
3416             PageTransitionEventPersistence::kPageTransitionEventPersisted);
3417       }
3418     }
3419   }
3420 
3421   // Freeze the page.
3422   Scheduler()->SetPageFrozen(/*frozen =*/true);
3423   // Hook eviction.
3424   if (page) {
3425     for (Frame* frame = page->MainFrame(); frame;
3426          frame = frame->Tree().TraverseNext()) {
3427       auto* local_frame = DynamicTo<LocalFrame>(frame);
3428       if (!local_frame)
3429         continue;
3430       local_frame->HookBackForwardCacheEviction();
3431     }
3432   }
3433 }
3434 
RestorePageFromBackForwardCache(base::TimeTicks navigation_start)3435 void WebViewImpl::RestorePageFromBackForwardCache(
3436     base::TimeTicks navigation_start) {
3437   // Unhook eviction.
3438   Page* page = AsView().page;
3439   if (page) {
3440     for (Frame* frame = page->MainFrame(); frame;
3441          frame = frame->Tree().TraverseNext()) {
3442       auto* local_frame = DynamicTo<LocalFrame>(frame);
3443       if (!local_frame)
3444         continue;
3445       local_frame->RemoveBackForwardCacheEviction();
3446     }
3447   }
3448 
3449   // Resume the page.
3450   Scheduler()->SetPageFrozen(/*frozen =*/false);
3451   if (page) {
3452     for (Frame* frame = page->MainFrame(); frame;
3453          frame = frame->Tree().TraverseNext()) {
3454       if (frame->DomWindow() && frame->DomWindow()->IsLocalDOMWindow()) {
3455         frame->DomWindow()->ToLocalDOMWindow()->DispatchPersistedPageshowEvent(
3456             navigation_start);
3457         if (frame->IsMainFrame()) {
3458           UMA_HISTOGRAM_BOOLEAN(
3459               "BackForwardCache.MainFrameHasPageshowListenersOnRestore",
3460               frame->DomWindow()->ToLocalDOMWindow()->HasEventListeners(
3461                   event_type_names::kPageshow));
3462         }
3463       }
3464     }
3465   }
3466   SetVisibilityState(PageVisibilityState::kVisible, /*is_initial_state=*/false);
3467 }
3468 
MainFrameWidget()3469 WebFrameWidget* WebViewImpl::MainFrameWidget() {
3470   return web_widget_;
3471 }
3472 
AddAutoplayFlags(int32_t value)3473 void WebViewImpl::AddAutoplayFlags(int32_t value) {
3474   AsView().page->AddAutoplayFlags(value);
3475 }
3476 
ClearAutoplayFlags()3477 void WebViewImpl::ClearAutoplayFlags() {
3478   AsView().page->ClearAutoplayFlags();
3479 }
3480 
AutoplayFlagsForTest()3481 int32_t WebViewImpl::AutoplayFlagsForTest() {
3482   return AsView().page->AutoplayFlags();
3483 }
3484 
GetPreferredSizeForTest()3485 WebSize WebViewImpl::GetPreferredSizeForTest() {
3486   return preferred_size_;
3487 }
3488 
StopDeferringMainFrameUpdate()3489 void WebViewImpl::StopDeferringMainFrameUpdate() {
3490   DCHECK(MainFrameImpl());
3491   scoped_defer_main_frame_update_ = nullptr;
3492 }
3493 
3494 }  // namespace blink
3495