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