2 * Copyright (C) 2014 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
36 #include "base/auto_reset.h"
37 #include "base/debug/crash_logging.h"
38 #include "base/debug/dump_without_crashing.h"
39 #include "base/functional/callback_helpers.h"
40 #include "base/functional/function_ref.h"
41 #include "base/metrics/histogram_macros.h"
42 #include "base/numerics/safe_conversions.h"
43 #include "base/task/single_thread_task_runner.h"
44 #include "base/time/time.h"
45 #include "build/build_config.h"
46 #include "cc/animation/animation_host.h"
47 #include "cc/base/features.h"
48 #include "cc/trees/compositor_commit_data.h"
49 #include "cc/trees/layer_tree_host.h"
50 #include "cc/trees/swap_promise.h"
51 #include "cc/trees/ukm_manager.h"
52 #include "third_party/blink/public/common/features.h"
53 #include "third_party/blink/public/mojom/frame/intrinsic_sizing_info.mojom-blink.h"
54 #include "third_party/blink/public/mojom/input/input_handler.mojom-blink.h"
55 #include "third_party/blink/public/mojom/input/touch_event.mojom-blink.h"
56 #include "third_party/blink/public/platform/platform.h"
57 #include "third_party/blink/public/web/web_autofill_client.h"
58 #include "third_party/blink/public/web/web_local_frame.h"
59 #include "third_party/blink/public/web/web_local_frame_client.h"
60 #include "third_party/blink/public/web/web_non_composited_widget_client.h"
61 #include "third_party/blink/public/web/web_performance_metrics_for_reporting.h"
62 #include "third_party/blink/public/web/web_plugin.h"
63 #include "third_party/blink/public/web/web_settings.h"
64 #include "third_party/blink/public/web/web_view_client.h"
65 #include "third_party/blink/renderer/core/content_capture/content_capture_manager.h"
66 #include "third_party/blink/renderer/core/core_initializer.h"
67 #include "third_party/blink/renderer/core/dom/element.h"
68 #include "third_party/blink/renderer/core/dom/focus_params.h"
69 #include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
70 #include "third_party/blink/renderer/core/editing/editing_utilities.h"
71 #include "third_party/blink/renderer/core/editing/ephemeral_range.h"
72 #include "third_party/blink/renderer/core/editing/frame_selection.h"
73 #include "third_party/blink/renderer/core/editing/ime/edit_context.h"
74 #include "third_party/blink/renderer/core/editing/ime/input_method_controller.h"
75 #include "third_party/blink/renderer/core/editing/ime/stylus_writing_gesture.h"
76 #include "third_party/blink/renderer/core/editing/selection_template.h"
77 #include "third_party/blink/renderer/core/events/current_input_event.h"
78 #include "third_party/blink/renderer/core/events/pointer_event_factory.h"
79 #include "third_party/blink/renderer/core/events/web_input_event_conversion.h"
80 #include "third_party/blink/renderer/core/events/wheel_event.h"
81 #include "third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h"
82 #include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
83 #include "third_party/blink/renderer/core/exported/web_settings_impl.h"
84 #include "third_party/blink/renderer/core/exported/web_view_impl.h"
85 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
86 #include "third_party/blink/renderer/core/frame/local_frame_ukm_aggregator.h"
87 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
88 #include "third_party/blink/renderer/core/frame/remote_frame_client.h"
89 #include "third_party/blink/renderer/core/frame/screen.h"
90 #include "third_party/blink/renderer/core/frame/screen_metrics_emulator.h"
91 #include "third_party/blink/renderer/core/frame/settings.h"
92 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
93 #include "third_party/blink/renderer/core/frame/web_feature.h"
94 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
95 #include "third_party/blink/renderer/core/html/fenced_frame/document_fenced_frames.h"
96 #include "third_party/blink/renderer/core/html/fenced_frame/html_fenced_frame_element.h"
97 #include "third_party/blink/renderer/core/html/forms/text_control_element.h"
98 #include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
99 #include "third_party/blink/renderer/core/html/html_plugin_element.h"
100 #include "third_party/blink/renderer/core/html/portal/document_portals.h"
101 #include "third_party/blink/renderer/core/html/portal/portal_contents.h"
102 #include "third_party/blink/renderer/core/input/context_menu_allowed_scope.h"
103 #include "third_party/blink/renderer/core/input/event_handler.h"
104 #include "third_party/blink/renderer/core/input/touch_action_util.h"
105 #include "third_party/blink/renderer/core/layout/hit_test_location.h"
106 #include "third_party/blink/renderer/core/layout/hit_test_request.h"
107 #include "third_party/blink/renderer/core/layout/layout_box.h"
108 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
109 #include "third_party/blink/renderer/core/layout/layout_object.h"
110 #include "third_party/blink/renderer/core/layout/layout_shift_tracker.h"
111 #include "third_party/blink/renderer/core/layout/layout_text.h"
112 #include "third_party/blink/renderer/core/loader/document_loader.h"
113 #include "third_party/blink/renderer/core/loader/interactive_detector.h"
114 #include "third_party/blink/renderer/core/page/context_menu_controller.h"
115 #include "third_party/blink/renderer/core/page/drag_actions.h"
116 #include "third_party/blink/renderer/core/page/drag_data.h"
117 #include "third_party/blink/renderer/core/page/focus_controller.h"
118 #include "third_party/blink/renderer/core/page/link_highlight.h"
119 #include "third_party/blink/renderer/core/page/page.h"
120 #include "third_party/blink/renderer/core/page/page_animator.h"
121 #include "third_party/blink/renderer/core/page/pointer_lock_controller.h"
122 #include "third_party/blink/renderer/core/page/scrolling/fragment_anchor.h"
123 #include "third_party/blink/renderer/core/page/validation_message_client.h"
124 #include "third_party/blink/renderer/core/page/viewport_description.h"
125 #include "third_party/blink/renderer/core/paint/timing/first_meaningful_paint_detector.h"
126 #include "third_party/blink/renderer/core/paint/timing/paint_timing_detector.h"
127 #include "third_party/blink/renderer/core/probe/core_probes.h"
128 #include "third_party/blink/renderer/core/scroll/scroll_into_view_util.h"
129 #include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
130 #include "third_party/blink/renderer/core/timing/dom_window_performance.h"
131 #include "third_party/blink/renderer/core/timing/window_performance.h"
132 #include "third_party/blink/renderer/core/view_transition/view_transition.h"
133 #include "third_party/blink/renderer/core/view_transition/view_transition_utils.h"
134 #include "third_party/blink/renderer/platform/graphics/animation_worklet_mutator_dispatcher_impl.h"
135 #include "third_party/blink/renderer/platform/graphics/compositor_mutator_client.h"
136 #include "third_party/blink/renderer/platform/graphics/paint_worklet_paint_dispatcher.h"
137 #include "third_party/blink/renderer/platform/heap/cross_thread_handle.h"
138 #include "third_party/blink/renderer/platform/heap/persistent.h"
139 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
140 #include "third_party/blink/renderer/platform/keyboard_codes.h"
141 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
142 #include "third_party/blink/renderer/platform/scheduler/public/non_main_thread.h"
143 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
144 #include "third_party/blink/renderer/platform/widget/input/main_thread_event_queue.h"
145 #include "third_party/blink/renderer/platform/widget/input/widget_input_handler_manager.h"
146 #include "third_party/blink/renderer/platform/widget/widget_base.h"
147 #include "third_party/blink/renderer/platform/wtf/cross_thread_copier_base.h"
148 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
149 #include "third_party/blink/renderer/platform/wtf/functional.h"
150 #include "ui/base/dragdrop/mojom/drag_drop_types.mojom-blink.h"
151 #include "ui/base/ui_base_types.h"
152 #include "ui/gfx/geometry/point_conversions.h"
154 #if BUILDFLAG(IS_MAC)
155 #include "third_party/blink/renderer/core/editing/substring_util.h"
156 #include "third_party/blink/renderer/platform/fonts/mac/attributed_string_type_converter.h"
157 #include "ui/base/mojom/attributed_string.mojom-blink.h"
158 #include "ui/gfx/geometry/point.h"
161 #if BUILDFLAG(IS_EFL)
162 #include "skia/ext/image_operations.h"
163 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
164 #include "third_party/blink/renderer/core/input_type_names.h"
170 struct CrossThreadCopier<blink::WebFrameWidgetImpl::PromiseCallbacks>
171 : public CrossThreadCopierByValuePassThrough<
172 blink::WebFrameWidgetImpl::PromiseCallbacks> {
173 STATIC_ONLY(CrossThreadCopier);
182 using ::ui::mojom::blink::DragOperation;
184 void ForEachLocalFrameControlledByWidget(
186 base::FunctionRef<void(WebLocalFrameImpl*)> callback) {
187 callback(WebLocalFrameImpl::FromFrame(frame));
188 for (Frame* child = frame->FirstChild(); child;
189 child = child->NextSibling()) {
190 if (auto* local_child = DynamicTo<LocalFrame>(child)) {
191 ForEachLocalFrameControlledByWidget(local_child, callback);
196 // Iterate the remote children that will be controlled by the widget. Skip over
197 // any RemoteFrames have have another LocalFrame root as their parent.
198 void ForEachRemoteFrameChildrenControlledByWidget(
200 base::FunctionRef<void(RemoteFrame*)> callback) {
201 for (Frame* child = frame->Tree().FirstChild(); child;
202 child = child->Tree().NextSibling()) {
203 if (auto* remote_frame = DynamicTo<RemoteFrame>(child)) {
204 callback(remote_frame);
205 ForEachRemoteFrameChildrenControlledByWidget(remote_frame, callback);
206 } else if (auto* local_frame = DynamicTo<LocalFrame>(child)) {
207 // If iteration arrives at a local root then don't descend as it will be
208 // controlled by another widget.
209 if (!local_frame->IsLocalRoot()) {
210 ForEachRemoteFrameChildrenControlledByWidget(local_frame, callback);
215 if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
216 if (Document* document = local_frame->GetDocument()) {
217 // Iterate on any portals owned by a local frame.
218 if (auto* portals = DocumentPortals::Get(*document)) {
219 for (PortalContents* portal : portals->GetPortals()) {
220 if (RemoteFrame* remote_frame = portal->GetFrame())
221 callback(remote_frame);
224 // Iterate on any fenced frames owned by a local frame.
225 if (auto* fenced_frames = DocumentFencedFrames::Get(*document)) {
226 for (HTMLFencedFrameElement* fenced_frame :
227 fenced_frames->GetFencedFrames()) {
228 callback(To<RemoteFrame>(fenced_frame->ContentFrame()));
235 viz::FrameSinkId GetRemoteFrameSinkId(const HitTestResult& result) {
236 Node* node = result.InnerNode();
237 auto* frame_owner = DynamicTo<HTMLFrameOwnerElement>(node);
238 if (!frame_owner || !frame_owner->ContentFrame() ||
239 !frame_owner->ContentFrame()->IsRemoteFrame())
240 return viz::FrameSinkId();
242 RemoteFrame* remote_frame = To<RemoteFrame>(frame_owner->ContentFrame());
243 if (remote_frame->IsIgnoredForHitTest())
244 return viz::FrameSinkId();
245 LayoutObject* object = node->GetLayoutObject();
247 if (!object->IsBox())
248 return viz::FrameSinkId();
250 PhysicalOffset local_point(ToRoundedPoint(result.LocalPoint()));
251 if (!To<LayoutBox>(object)->ComputedCSSContentBoxRect().Contains(local_point))
252 return viz::FrameSinkId();
254 return remote_frame->GetFrameSinkId();
257 bool IsElementNotNullAndEditable(Element* element) {
261 if (IsEditable(*element))
264 auto* text_control = ToTextControlOrNull(element);
265 if (text_control && !text_control->IsDisabledOrReadOnly())
268 if (EqualIgnoringASCIICase(element->FastGetAttribute(html_names::kRoleAttr),
276 bool& InputDisabledPerBrowsingContextGroup(
277 const base::UnguessableToken& token) {
278 using BrowsingContextGroupMap = std::map<base::UnguessableToken, bool>;
279 DEFINE_STATIC_LOCAL(BrowsingContextGroupMap, values, ());
280 return values[token];
285 // WebFrameWidget ------------------------------------------------------------
287 bool WebFrameWidgetImpl::ignore_input_events_ = false;
290 void WebFrameWidgetImpl::SetIgnoreInputEvents(
291 const base::UnguessableToken& browsing_context_group_token,
293 if (base::FeatureList::IsEnabled(
294 features::kPausePagesPerBrowsingContextGroup)) {
295 CHECK_NE(InputDisabledPerBrowsingContextGroup(browsing_context_group_token),
297 InputDisabledPerBrowsingContextGroup(browsing_context_group_token) = value;
299 CHECK_NE(ignore_input_events_, value);
300 ignore_input_events_ = value;
305 bool WebFrameWidgetImpl::IgnoreInputEvents(
306 const base::UnguessableToken& browsing_context_group_token) {
307 if (base::FeatureList::IsEnabled(
308 features::kPausePagesPerBrowsingContextGroup)) {
309 return InputDisabledPerBrowsingContextGroup(browsing_context_group_token);
311 return ignore_input_events_;
315 WebFrameWidgetImpl::WebFrameWidgetImpl(
316 base::PassKey<WebLocalFrame>,
317 CrossVariantMojoAssociatedRemote<mojom::blink::FrameWidgetHostInterfaceBase>
319 CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
321 CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
323 CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
325 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
326 const viz::FrameSinkId& frame_sink_id,
328 bool never_composited,
329 bool is_for_child_local_root,
330 bool is_for_nested_main_frame,
331 bool is_for_scalable_page)
332 : widget_base_(std::make_unique<WidgetBase>(
333 /*widget_base_client=*/this,
334 std::move(widget_host),
339 /*is_embedded=*/is_for_child_local_root || is_for_nested_main_frame,
340 is_for_scalable_page)),
341 frame_sink_id_(frame_sink_id),
342 is_for_child_local_root_(is_for_child_local_root),
343 is_for_scalable_page_(is_for_scalable_page) {
345 if (is_for_nested_main_frame)
346 main_data().is_for_nested_main_frame = is_for_nested_main_frame;
347 frame_widget_host_.Bind(std::move(frame_widget_host), task_runner);
348 receiver_.Bind(std::move(frame_widget), task_runner);
351 WebFrameWidgetImpl::~WebFrameWidgetImpl() {
352 // Ensure that Close is called and we aren't releasing |widget_base_| in the
354 // TODO(crbug.com/1139104): This CHECK can be changed to a DCHECK once
355 // the issue is solved.
356 CHECK(!widget_base_);
359 void WebFrameWidgetImpl::BindLocalRoot(WebLocalFrame& local_root) {
360 local_root_ = To<WebLocalFrameImpl>(local_root);
361 CHECK(local_root_ && local_root_->GetFrame());
362 if (RuntimeEnabledFeatures::LongAnimationFrameMonitoringEnabled(
363 local_root_->GetFrame()->DomWindow()) &&
365 animation_frame_timing_monitor_ =
366 MakeGarbageCollected<AnimationFrameTimingMonitor>(
367 *this, local_root_->GetFrame()->GetProbeSink());
371 bool WebFrameWidgetImpl::ForTopMostMainFrame() const {
372 return ForMainFrame() && !main_data().is_for_nested_main_frame;
375 void WebFrameWidgetImpl::SetIsNestedMainFrameWidget(bool is_nested) {
376 main_data().is_for_nested_main_frame = is_nested;
379 void WebFrameWidgetImpl::Close() {
380 // TODO(bokan): This seems wrong since the page may have other still-active
381 // frame widgets. See also: https://crbug.com/1344531.
382 GetPage()->WillStopCompositing();
384 if (ForMainFrame()) {
385 // Closing the WebFrameWidgetImpl happens in response to the local main
386 // frame being detached from the Page/WebViewImpl.
387 View()->SetMainFrameViewWidget(nullptr);
390 if (animation_frame_timing_monitor_) {
391 animation_frame_timing_monitor_->Shutdown();
392 animation_frame_timing_monitor_.Clear();
395 mutator_dispatcher_ = nullptr;
396 local_root_ = nullptr;
397 widget_base_->Shutdown();
398 widget_base_.reset();
399 // These WeakPtrs must be invalidated for WidgetInputHandlerManager at the
400 // same time as the WidgetBase is.
401 input_handler_weak_ptr_factory_.InvalidateWeakPtrs();
403 input_target_receiver_.reset();
406 WebLocalFrame* WebFrameWidgetImpl::LocalRoot() const {
407 return local_root_.Get();
410 bool WebFrameWidgetImpl::RequestedMainFramePending() {
411 return View() && View()->does_composite() && LayerTreeHost() &&
412 LayerTreeHost()->RequestedMainFramePending();
415 ukm::UkmRecorder* WebFrameWidgetImpl::MainFrameUkmRecorder() {
417 if (!local_root_->IsOutermostMainFrame()) {
421 if (!local_root_->GetFrame() || !local_root_->GetFrame()->DomWindow()) {
425 return local_root_->GetFrame()->DomWindow()->UkmRecorder();
427 ukm::SourceId WebFrameWidgetImpl::MainFrameUkmSourceId() {
429 if (!local_root_->IsOutermostMainFrame()) {
430 return ukm::kInvalidSourceId;
433 if (!local_root_->GetFrame() || !local_root_->GetFrame()->DomWindow()) {
434 return ukm::kInvalidSourceId;
437 return local_root_->GetFrame()->DomWindow()->UkmSourceID();
440 bool WebFrameWidgetImpl::IsMainFrameFullyLoaded() const {
442 if (!local_root_->IsOutermostMainFrame()) {
446 return local_root_->GetFrame() &&
447 local_root_->GetFrame()->Loader().GetDocumentLoader() &&
448 !local_root_->GetFrame()
456 gfx::Rect WebFrameWidgetImpl::ComputeBlockBound(
457 const gfx::Point& point_in_root_frame,
458 bool ignore_clipping) const {
459 HitTestLocation location(local_root_->GetFrameView()->ConvertFromRootFrame(
460 PhysicalOffset(point_in_root_frame)));
461 HitTestRequest::HitTestRequestType hit_type =
462 HitTestRequest::kReadOnly | HitTestRequest::kActive |
463 (ignore_clipping ? HitTestRequest::kIgnoreClipping : 0);
464 HitTestResult result =
465 local_root_->GetFrame()->GetEventHandler().HitTestResultAtLocation(
467 result.SetToShadowHostIfInUAShadowRoot();
469 Node* node = result.InnerNodeOrImageMapImage();
473 // Find the block type node based on the hit node.
474 // FIXME: This wants to walk flat tree with
475 // LayoutTreeBuilderTraversal::parent().
477 (!node->GetLayoutObject() || node->GetLayoutObject()->IsInline()))
478 node = LayoutTreeBuilderTraversal::Parent(*node);
480 // Return the bounding box in the root frame's coordinate space.
482 gfx::Rect absolute_rect =
483 node->GetLayoutObject()->AbsoluteBoundingBoxRect();
484 LocalFrame* frame = node->GetDocument().GetFrame();
485 return frame->View()->ConvertToRootFrame(absolute_rect);
490 void WebFrameWidgetImpl::DragTargetDragEnter(
491 const WebDragData& web_drag_data,
492 const gfx::PointF& point_in_viewport,
493 const gfx::PointF& screen_point,
494 DragOperationsMask operations_allowed,
495 uint32_t key_modifiers,
496 DragTargetDragEnterCallback callback) {
497 auto* target = local_root_->GetFrame()->DocumentAtPoint(
498 PhysicalOffset::FromPointFRound(ViewportToRootFrame(point_in_viewport)));
500 // Any execution context should do the work since no file should ever be
501 // created during drag events.
502 current_drag_data_ = DataObject::Create(
503 target ? target->GetExecutionContext() : nullptr, web_drag_data);
504 operations_allowed_ = operations_allowed;
506 DragTargetDragEnterOrOver(point_in_viewport, screen_point, kDragEnter,
509 std::move(callback).Run(drag_operation_.operation,
510 drag_operation_.document_is_handling_drag);
513 void WebFrameWidgetImpl::DragTargetDragOver(
514 const gfx::PointF& point_in_viewport,
515 const gfx::PointF& screen_point,
516 DragOperationsMask operations_allowed,
517 uint32_t key_modifiers,
518 DragTargetDragOverCallback callback) {
519 operations_allowed_ = operations_allowed;
521 DragTargetDragEnterOrOver(point_in_viewport, screen_point, kDragOver,
524 std::move(callback).Run(drag_operation_.operation,
525 drag_operation_.document_is_handling_drag);
528 void WebFrameWidgetImpl::DragTargetDragLeave(
529 const gfx::PointF& point_in_viewport,
530 const gfx::PointF& screen_point) {
531 base::ScopedClosureRunner runner(
532 WTF::BindOnce(&WebFrameWidgetImpl::CancelDrag, WrapWeakPersistent(this)));
533 if (ShouldIgnoreInputEvents() || !current_drag_data_) {
537 gfx::PointF point_in_root_frame(ViewportToRootFrame(point_in_viewport));
538 DragData drag_data(current_drag_data_.Get(), point_in_root_frame,
539 screen_point, operations_allowed_,
540 /*force_default_action=*/false);
542 GetPage()->GetDragController().DragExited(&drag_data,
543 *local_root_->GetFrame());
545 // FIXME: why is the drag scroll timer not stopped here?
548 void WebFrameWidgetImpl::DragTargetDrop(const WebDragData& web_drag_data,
549 const gfx::PointF& point_in_viewport,
550 const gfx::PointF& screen_point,
551 uint32_t key_modifiers,
552 base::OnceClosure callback) {
553 base::ScopedClosureRunner callback_runner(std::move(callback));
554 base::ScopedClosureRunner runner(
555 WTF::BindOnce(&WebFrameWidgetImpl::CancelDrag, WrapWeakPersistent(this)));
557 if (ShouldIgnoreInputEvents() || !current_drag_data_) {
561 auto* target = local_root_->GetFrame()->DocumentAtPoint(
562 PhysicalOffset::FromPointFRound(ViewportToRootFrame(point_in_viewport)));
564 current_drag_data_ = DataObject::Create(
565 target ? target->GetExecutionContext() : nullptr, web_drag_data);
567 // If this webview transitions from the "drop accepting" state to the "not
568 // accepting" state, then our IPC message reply indicating that may be in-
569 // flight, or else delayed by javascript processing in this webview. If a
570 // drop happens before our IPC reply has reached the browser process, then
571 // the browser forwards the drop to this webview. So only allow a drop to
572 // proceed if our webview drag operation state is not DragOperation::kNone.
574 if (drag_operation_.operation == DragOperation::kNone) {
575 // IPC RACE CONDITION: do not allow this drop.
576 DragTargetDragLeave(point_in_viewport, screen_point);
580 current_drag_data_->SetModifiers(key_modifiers);
581 DragData drag_data(current_drag_data_.Get(),
582 ViewportToRootFrame(point_in_viewport), screen_point,
583 operations_allowed_, web_drag_data.ForceDefaultAction());
584 GetPage()->GetDragController().PerformDrag(&drag_data,
585 *local_root_->GetFrame());
588 void WebFrameWidgetImpl::DragSourceEndedAt(const gfx::PointF& point_in_viewport,
589 const gfx::PointF& screen_point,
590 DragOperation operation,
591 base::OnceClosure callback) {
592 base::ScopedClosureRunner callback_runner(std::move(callback));
593 base::ScopedClosureRunner runner(
594 WTF::BindOnce(&WebFrameWidgetImpl::DragSourceSystemDragEnded,
595 WrapWeakPersistent(this)));
597 if (ShouldIgnoreInputEvents()) {
601 WebMouseEvent fake_mouse_move(
602 WebInputEvent::Type::kMouseMove,
603 GetPage()->GetVisualViewport().ViewportToRootFrame(point_in_viewport),
604 screen_point, WebPointerProperties::Button::kLeft, 0,
605 WebInputEvent::kNoModifiers, base::TimeTicks::Now());
606 fake_mouse_move.SetFrameScale(1);
607 local_root_->GetFrame()->GetEventHandler().DragSourceEndedAt(fake_mouse_move,
611 void WebFrameWidgetImpl::DragSourceSystemDragEnded() {
614 // It's possible for this to be false if the source stopped dragging at a
616 if (!doing_drag_and_drop_) {
619 GetPage()->GetDragController().DragEnded();
620 doing_drag_and_drop_ = false;
623 gfx::Rect WebFrameWidgetImpl::GetAbsoluteCaretBounds() {
624 LocalFrame* local_frame = GetPage()->GetFocusController().FocusedFrame();
626 auto& selection = local_frame->Selection();
627 if (selection.GetSelectionInDOMTree().IsCaret())
628 return selection.AbsoluteCaretBounds();
633 void WebFrameWidgetImpl::OnStartStylusWriting(
634 OnStartStylusWritingCallback callback) {
635 // Focus the stylus writable element for current touch sequence as we have
636 // detected writing has started.
637 LocalFrame* frame = LocalRootImpl()->GetFrame();
639 std::move(callback).Run(absl::nullopt, absl::nullopt);
643 Element* stylus_writable_element =
644 frame->GetEventHandler().CurrentTouchDownElement();
645 if (!stylus_writable_element) {
646 std::move(callback).Run(absl::nullopt, absl::nullopt);
650 if (auto* text_control = EnclosingTextControl(stylus_writable_element)) {
651 text_control->Focus(FocusParams(FocusTrigger::kUserGesture));
652 } else if (auto* html_element =
653 DynamicTo<HTMLElement>(stylus_writable_element)) {
654 html_element->Focus(FocusParams(FocusTrigger::kUserGesture));
656 Element* focused_element = FocusedElement();
657 // Since the element can change after it gets focused, we just verify if
658 // the focused element is editable to continue writing.
659 if (IsElementNotNullAndEditable(focused_element)) {
660 std::move(callback).Run(
661 focused_element->BoundsInWidget(),
662 frame->View()->FrameToViewport(GetAbsoluteCaretBounds()));
666 std::move(callback).Run(absl::nullopt, absl::nullopt);
669 void WebFrameWidgetImpl::HandleStylusWritingGestureAction(
670 mojom::blink::StylusWritingGestureDataPtr gesture_data,
671 HandleStylusWritingGestureActionCallback callback) {
672 LocalFrame* focused_frame = FocusedLocalFrameInWidget();
673 if (!focused_frame) {
674 std::move(callback).Run(mojom::blink::HandwritingGestureResult::kFailed);
677 mojom::blink::HandwritingGestureResult result =
678 StylusWritingGesture::ApplyGesture(focused_frame,
679 std::move(gesture_data));
680 std::move(callback).Run(result);
683 void WebFrameWidgetImpl::SetBackgroundOpaque(bool opaque) {
684 View()->SetBaseBackgroundColorOverrideTransparent(!opaque);
687 void WebFrameWidgetImpl::SetTextDirection(base::i18n::TextDirection direction) {
688 LocalFrame* focusedFrame = FocusedLocalFrameInWidget();
690 focusedFrame->SetTextDirection(direction);
693 void WebFrameWidgetImpl::SetInheritedEffectiveTouchActionForSubFrame(
694 TouchAction touch_action) {
695 DCHECK(ForSubframe());
696 LocalRootImpl()->GetFrame()->SetInheritedEffectiveTouchAction(touch_action);
699 void WebFrameWidgetImpl::UpdateRenderThrottlingStatusForSubFrame(
701 bool subtree_throttled,
702 bool display_locked) {
703 DCHECK(ForSubframe());
704 // TODO(szager,vmpstr): The parent render process currently rolls up
705 // display_locked into the value of subtree throttled here; display_locked
706 // should be maintained as a separate bit and transmitted between render
708 LocalRootImpl()->GetFrameView()->UpdateRenderThrottlingStatus(
709 is_throttled, subtree_throttled, display_locked, /*recurse=*/true);
712 #if BUILDFLAG(IS_MAC)
713 void WebFrameWidgetImpl::GetStringAtPoint(const gfx::Point& point_in_local_root,
714 GetStringAtPointCallback callback) {
715 gfx::Point baseline_point;
716 ui::mojom::blink::AttributedStringPtr attributed_string = nullptr;
717 base::apple::ScopedCFTypeRef<CFAttributedStringRef> string =
718 SubstringUtil::AttributedWordAtPoint(this, point_in_local_root,
721 attributed_string = ui::mojom::blink::AttributedString::From(string.get());
724 std::move(callback).Run(std::move(attributed_string), baseline_point);
728 void WebFrameWidgetImpl::BindWidgetCompositor(
729 mojo::PendingReceiver<mojom::blink::WidgetCompositor> receiver) {
730 widget_base_->BindWidgetCompositor(std::move(receiver));
733 void WebFrameWidgetImpl::BindInputTargetClient(
734 mojo::PendingReceiver<viz::mojom::blink::InputTargetClient> receiver) {
735 DCHECK(!input_target_receiver_.is_bound());
736 input_target_receiver_.Bind(
738 local_root_->GetTaskRunner(TaskType::kInternalInputBlocking));
741 void WebFrameWidgetImpl::FrameSinkIdAt(const gfx::PointF& point,
742 const uint64_t trace_id,
743 FrameSinkIdAtCallback callback) {
744 TRACE_EVENT_WITH_FLOW1("viz,benchmark", "Event.Pipeline",
745 TRACE_ID_GLOBAL(trace_id),
746 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
747 "step", "FrameSinkIdAt");
749 gfx::PointF local_point;
750 viz::FrameSinkId id = GetFrameSinkIdAtPoint(point, &local_point);
751 std::move(callback).Run(id, local_point);
754 viz::FrameSinkId WebFrameWidgetImpl::GetFrameSinkIdAtPoint(
755 const gfx::PointF& point_in_dips,
756 gfx::PointF* local_point_in_dips) {
757 HitTestResult result =
758 CoreHitTestResultAt(widget_base_->DIPsToBlinkSpace(point_in_dips));
760 Node* result_node = result.InnerNode();
761 *local_point_in_dips = gfx::PointF(point_in_dips);
763 // TODO(crbug.com/797828): When the node is null the caller may
764 // need to do extra checks. Like maybe update the layout and then
765 // call the hit-testing API. Either way it might be better to have
766 // a DCHECK for the node rather than a null check here.
768 return frame_sink_id_;
771 viz::FrameSinkId remote_frame_sink_id = GetRemoteFrameSinkId(result);
772 if (remote_frame_sink_id.is_valid()) {
773 gfx::PointF local_point(result.LocalPoint());
774 LayoutObject* object = result_node->GetLayoutObject();
775 if (auto* box = DynamicTo<LayoutBox>(object))
776 local_point -= gfx::Vector2dF(box->PhysicalContentBoxOffset());
778 *local_point_in_dips = widget_base_->BlinkSpaceToDIPs(local_point);
779 return remote_frame_sink_id;
782 // Return the FrameSinkId for the current widget if the point did not hit
783 // test to a remote frame, or the point is outside of the remote frame's
784 // content box, or the remote frame doesn't have a valid FrameSinkId yet.
785 return frame_sink_id_;
788 gfx::RectF WebFrameWidgetImpl::BlinkSpaceToDIPs(const gfx::RectF& rect) {
789 return widget_base_->BlinkSpaceToDIPs(rect);
792 gfx::Rect WebFrameWidgetImpl::BlinkSpaceToEnclosedDIPs(const gfx::Rect& rect) {
793 return widget_base_->BlinkSpaceToEnclosedDIPs(rect);
796 gfx::Size WebFrameWidgetImpl::BlinkSpaceToFlooredDIPs(const gfx::Size& size) {
797 return widget_base_->BlinkSpaceToFlooredDIPs(size);
800 gfx::RectF WebFrameWidgetImpl::DIPsToBlinkSpace(const gfx::RectF& rect) {
801 return widget_base_->DIPsToBlinkSpace(rect);
804 gfx::PointF WebFrameWidgetImpl::DIPsToBlinkSpace(const gfx::PointF& point) {
805 return widget_base_->DIPsToBlinkSpace(point);
808 gfx::Point WebFrameWidgetImpl::DIPsToRoundedBlinkSpace(
809 const gfx::Point& point) {
810 return widget_base_->DIPsToRoundedBlinkSpace(point);
813 float WebFrameWidgetImpl::DIPsToBlinkSpace(float scalar) {
814 return widget_base_->DIPsToBlinkSpace(scalar);
817 gfx::Size WebFrameWidgetImpl::DIPsToCeiledBlinkSpace(const gfx::Size& size) {
818 return widget_base_->DIPsToCeiledBlinkSpace(size);
821 void WebFrameWidgetImpl::SetActive(bool active) {
822 View()->SetIsActive(active);
825 WebInputEventResult WebFrameWidgetImpl::HandleKeyEvent(
826 const WebKeyboardEvent& event) {
827 DCHECK((event.GetType() == WebInputEvent::Type::kRawKeyDown) ||
828 (event.GetType() == WebInputEvent::Type::kKeyDown) ||
829 (event.GetType() == WebInputEvent::Type::kKeyUp));
831 // Please refer to the comments explaining the m_suppressNextKeypressEvent
833 // The m_suppressNextKeypressEvent is set if the KeyDown is handled by
834 // Webkit. A keyDown event is typically associated with a keyPress(char)
835 // event and a keyUp event. We reset this flag here as this is a new keyDown
837 suppress_next_keypress_event_ = false;
839 // If there is a popup open, it should be the one processing the event,
841 scoped_refptr<WebPagePopupImpl> page_popup = View()->GetPagePopup();
843 page_popup->HandleKeyEvent(event);
844 if (event.GetType() == WebInputEvent::Type::kRawKeyDown) {
845 suppress_next_keypress_event_ = true;
847 return WebInputEventResult::kHandledSystem;
850 auto* frame = DynamicTo<LocalFrame>(FocusedCoreFrame());
852 return WebInputEventResult::kNotHandled;
854 WebInputEventResult result = frame->GetEventHandler().KeyEvent(event);
855 // EventHandler may have detached the frame.
856 if (!LocalRootImpl())
859 if (result != WebInputEventResult::kNotHandled) {
860 if (WebInputEvent::Type::kRawKeyDown == event.GetType()) {
861 // Suppress the next keypress event unless the focused node is a plugin
862 // node. (Flash needs these keypress events to handle non-US keyboards.)
863 Element* element = FocusedElement();
864 if (element && element->GetLayoutObject() &&
865 element->GetLayoutObject()->IsEmbeddedObject()) {
866 if (event.windows_key_code == VKEY_TAB) {
867 // If the plugin supports keyboard focus then we should not send a tab
869 WebPluginContainerImpl* plugin_view =
870 To<LayoutEmbeddedContent>(element->GetLayoutObject())->Plugin();
871 if (plugin_view && plugin_view->SupportsKeyboardFocus()) {
872 suppress_next_keypress_event_ = true;
876 suppress_next_keypress_event_ = true;
882 #if !BUILDFLAG(IS_MAC)
883 const WebInputEvent::Type kContextMenuKeyTriggeringEventType =
884 #if BUILDFLAG(IS_WIN)
885 WebInputEvent::Type::kKeyUp;
887 WebInputEvent::Type::kRawKeyDown;
889 const WebInputEvent::Type kShiftF10TriggeringEventType =
890 WebInputEvent::Type::kRawKeyDown;
892 bool is_unmodified_menu_key =
893 !(event.GetModifiers() & WebInputEvent::kInputModifiers) &&
894 event.windows_key_code == VKEY_APPS;
895 bool is_shift_f10 = (event.GetModifiers() & WebInputEvent::kInputModifiers) ==
896 WebInputEvent::kShiftKey &&
897 event.windows_key_code == VKEY_F10;
898 if ((is_unmodified_menu_key &&
899 event.GetType() == kContextMenuKeyTriggeringEventType) ||
900 (is_shift_f10 && event.GetType() == kShiftF10TriggeringEventType)) {
901 View()->SendContextMenuEvent();
902 return WebInputEventResult::kHandledSystem;
904 #endif // !BUILDFLAG(IS_MAC)
906 return WebInputEventResult::kNotHandled;
909 void WebFrameWidgetImpl::HandleMouseDown(LocalFrame& local_root,
910 const WebMouseEvent& event) {
911 WebViewImpl* view_impl = View();
912 // If there is a popup open, close it as the user is clicking on the page
913 // (outside of the popup). We also save it so we can prevent a click on an
914 // element from immediately reopening the same popup.
915 scoped_refptr<WebPagePopupImpl> page_popup;
916 if (event.button == WebMouseEvent::Button::kLeft) {
917 page_popup = view_impl->GetPagePopup();
918 view_impl->CancelPagePopup();
921 // Take capture on a mouse down on a plugin so we can send it mouse events.
922 // If the hit node is a plugin but a scrollbar is over it don't start mouse
923 // capture because it will interfere with the scrollbar receiving events.
924 PhysicalOffset point(LayoutUnit(event.PositionInWidget().x()),
925 LayoutUnit(event.PositionInWidget().y()));
926 if (event.button == WebMouseEvent::Button::kLeft) {
927 HitTestLocation location(
928 LocalRootImpl()->GetFrameView()->ConvertFromRootFrame(point));
929 HitTestResult result(
930 LocalRootImpl()->GetFrame()->GetEventHandler().HitTestResultAtLocation(
932 result.SetToShadowHostIfInUAShadowRoot();
933 Node* hit_node = result.InnerNode();
934 auto* html_element = DynamicTo<HTMLElement>(hit_node);
935 if (!result.GetScrollbar() && hit_node && hit_node->GetLayoutObject() &&
936 hit_node->GetLayoutObject()->IsEmbeddedObject() && html_element &&
937 html_element->IsPluginElement()) {
938 mouse_capture_element_ = To<HTMLPlugInElement>(hit_node);
939 SetMouseCapture(true);
940 TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("input", "capturing mouse",
941 TRACE_ID_LOCAL(this));
945 WidgetEventHandler::HandleMouseDown(local_root, event);
946 // WidgetEventHandler may have detached the frame.
947 if (!LocalRootImpl())
950 if (view_impl->GetPagePopup() && page_popup &&
951 view_impl->GetPagePopup()->HasSamePopupClient(page_popup.get())) {
952 // That click triggered a page popup that is the same as the one we just
953 // closed. It needs to be closed.
954 view_impl->CancelPagePopup();
957 // Dispatch the contextmenu event regardless of if the click was swallowed.
958 if (!GetPage()->GetSettings().GetShowContextMenuOnMouseUp()) {
959 #if BUILDFLAG(IS_MAC)
960 if (event.button == WebMouseEvent::Button::kRight ||
961 (event.button == WebMouseEvent::Button::kLeft &&
962 event.GetModifiers() & WebMouseEvent::kControlKey))
963 MouseContextMenu(event);
965 if (event.button == WebMouseEvent::Button::kRight)
966 MouseContextMenu(event);
971 void WebFrameWidgetImpl::HandleMouseLeave(LocalFrame& local_root,
972 const WebMouseEvent& event) {
973 View()->SetMouseOverURL(WebURL());
974 WidgetEventHandler::HandleMouseLeave(local_root, event);
975 // WidgetEventHandler may have detached the frame.
978 void WebFrameWidgetImpl::MouseContextMenu(const WebMouseEvent& event) {
979 GetPage()->GetContextMenuController().ClearContextMenu();
981 WebMouseEvent transformed_event =
982 TransformWebMouseEvent(LocalRootImpl()->GetFrameView(), event);
983 transformed_event.menu_source_type = kMenuSourceMouse;
984 transformed_event.id = PointerEventFactory::kMouseId;
986 // Find the right target frame. See issue 1186900.
987 HitTestResult result =
988 HitTestResultForRootFramePos(transformed_event.PositionInRootFrame());
990 if (result.InnerNodeOrImageMapImage())
991 target_frame = result.InnerNodeOrImageMapImage()->GetDocument().GetFrame();
993 target_frame = GetPage()->GetFocusController().FocusedOrMainFrame();
995 // This will need to be changed to a nullptr check when focus control
996 // is refactored, at which point focusedOrMainFrame will never return a
998 // See https://crbug.com/341918.
999 LocalFrame* target_local_frame = DynamicTo<LocalFrame>(target_frame);
1000 if (!target_local_frame)
1004 ContextMenuAllowedScope scope;
1005 target_local_frame->GetEventHandler().SendContextMenuEvent(
1008 // Actually showing the context menu is handled by the ContextMenuClient
1009 // implementation...
1012 WebInputEventResult WebFrameWidgetImpl::HandleMouseUp(
1013 LocalFrame& local_root,
1014 const WebMouseEvent& event) {
1015 WebInputEventResult result =
1016 WidgetEventHandler::HandleMouseUp(local_root, event);
1017 // WidgetEventHandler may have detached the frame.
1018 if (!LocalRootImpl())
1021 if (GetPage()->GetSettings().GetShowContextMenuOnMouseUp()) {
1022 // Dispatch the contextmenu event regardless of if the click was swallowed.
1023 // On Mac/Linux, we handle it on mouse down, not up.
1024 if (event.button == WebMouseEvent::Button::kRight)
1025 MouseContextMenu(event);
1030 WebInputEventResult WebFrameWidgetImpl::HandleGestureEvent(
1031 const WebGestureEvent& event) {
1032 WebInputEventResult event_result = WebInputEventResult::kNotHandled;
1034 // Fling events are not sent to the renderer.
1035 CHECK(event.GetType() != WebInputEvent::Type::kGestureFlingStart);
1036 CHECK(event.GetType() != WebInputEvent::Type::kGestureFlingCancel);
1038 WebViewImpl* web_view = View();
1040 LocalFrame* frame = LocalRootImpl()->GetFrame();
1041 WebGestureEvent scaled_event = TransformWebGestureEvent(frame->View(), event);
1043 // Special handling for double tap and scroll events as we don't want to
1044 // hit test for them.
1045 switch (event.GetType()) {
1046 case WebInputEvent::Type::kGestureDoubleTap:
1047 if (web_view->SettingsImpl()->DoubleTapToZoomEnabled() &&
1048 web_view->MinimumPageScaleFactor() !=
1049 web_view->MaximumPageScaleFactor()) {
1050 gfx::Point pos_in_local_frame_root =
1051 gfx::ToFlooredPoint(scaled_event.PositionInRootFrame());
1052 auto block_bounds = ComputeBlockBound(pos_in_local_frame_root, false);
1054 if (ForMainFrame()) {
1055 web_view->AnimateDoubleTapZoom(pos_in_local_frame_root, block_bounds);
1057 // This sends the tap point and bounds to the main frame renderer via
1058 // the browser, where their coordinates will be transformed into the
1059 // main frame's coordinate space.
1060 GetAssociatedFrameWidgetHost()->AnimateDoubleTapZoomInMainFrame(
1061 pos_in_local_frame_root, block_bounds);
1064 event_result = WebInputEventResult::kHandledSystem;
1065 DidHandleGestureEvent(event);
1066 return event_result;
1067 case WebInputEvent::Type::kGestureScrollBegin:
1068 case WebInputEvent::Type::kGestureScrollEnd:
1069 case WebInputEvent::Type::kGestureScrollUpdate:
1070 // If we are getting any scroll toss close any page popup that is open.
1071 web_view->CancelPagePopup();
1073 // Scrolling-related gesture events invoke EventHandler recursively for
1074 // each frame down the chain, doing a single-frame hit-test per frame.
1075 // This matches handleWheelEvent. Perhaps we could simplify things by
1076 // rewriting scroll handling to work inner frame out, and then unify with
1077 // other gesture events.
1079 frame->GetEventHandler().HandleGestureScrollEvent(scaled_event);
1080 DidHandleGestureEvent(event);
1081 return event_result;
1086 // Hit test across all frames and do touch adjustment as necessary for the
1088 GestureEventWithHitTestResults targeted_event =
1089 frame->GetEventHandler().TargetGestureEvent(scaled_event);
1091 // Link highlight animations are only for the main frame.
1092 // TODO(bokan): This isn't intentional, see https://crbug.com/1344531.
1093 if (ForMainFrame()) {
1094 // Handle link highlighting outside the main switch to avoid getting lost in
1095 // the complicated set of cases handled below.
1096 switch (scaled_event.GetType()) {
1097 case WebInputEvent::Type::kGestureShowPress:
1098 // Queue a highlight animation, then hand off to regular handler.
1099 web_view->EnableTapHighlightAtPoint(targeted_event);
1101 case WebInputEvent::Type::kGestureShortPress:
1102 case WebInputEvent::Type::kGestureLongPress:
1103 case WebInputEvent::Type::kGestureTapCancel:
1104 case WebInputEvent::Type::kGestureTap:
1105 GetPage()->GetLinkHighlight().UpdateOpacityAndRequestAnimation();
1112 switch (scaled_event.GetType()) {
1113 case WebInputEvent::Type::kGestureTap: {
1114 #if BUILDFLAG(IS_EFL)
1115 if (web_view->SettingsImpl()->LinkEffectEnabled()) {
1116 HitTestResult result = targeted_event.GetHitTestResult();
1117 result.SetToShadowHostIfInUAShadowRoot();
1118 if (result.CanPlayLinkEffect()) {
1119 auto focused_frame = FocusedWebLocalFrameInWidget();
1120 if (focused_frame) {
1121 focused_frame->Client()->PlayLinkEffect();
1127 ContextMenuAllowedScope scope;
1129 frame->GetEventHandler().HandleGestureEvent(targeted_event);
1132 if (web_view->GetPagePopup() && last_hidden_page_popup_ &&
1133 web_view->GetPagePopup()->HasSamePopupClient(
1134 last_hidden_page_popup_.get())) {
1135 // The tap triggered a page popup that is the same as the one we just
1136 // closed. It needs to be closed.
1137 web_view->CancelPagePopup();
1139 // Don't have this value persist outside of a single tap gesture, plus
1140 // we're done with it now.
1141 last_hidden_page_popup_ = nullptr;
1144 case WebInputEvent::Type::kGestureTwoFingerTap:
1145 case WebInputEvent::Type::kGestureLongPress:
1146 case WebInputEvent::Type::kGestureLongTap:
1147 if (scaled_event.GetType() == WebInputEvent::Type::kGestureLongTap) {
1148 if (LocalFrame* inner_frame =
1149 targeted_event.GetHitTestResult().InnerNodeFrame()) {
1150 if (!inner_frame->GetEventHandler().LongTapShouldInvokeContextMenu())
1152 } else if (!frame->GetEventHandler().LongTapShouldInvokeContextMenu()) {
1157 GetPage()->GetContextMenuController().ClearContextMenu();
1159 ContextMenuAllowedScope scope;
1161 frame->GetEventHandler().HandleGestureEvent(targeted_event);
1165 case WebInputEvent::Type::kGestureTapDown:
1166 // Touch pinch zoom and scroll on the page (outside of a popup) must hide
1167 // the popup. In case of a touch scroll or pinch zoom, this function is
1168 // called with GestureTapDown rather than a GSB/GSU/GSE or GPB/GPU/GPE.
1169 // When we close a popup because of a GestureTapDown, we also save it so
1170 // we can prevent the following GestureTap from immediately reopening the
1172 // This value should not persist outside of a gesture, so is cleared by
1173 // GestureTap (where it is used) and by GestureCancel.
1174 last_hidden_page_popup_ = web_view->GetPagePopup();
1175 web_view->CancelPagePopup();
1177 frame->GetEventHandler().HandleGestureEvent(targeted_event);
1179 case WebInputEvent::Type::kGestureTapCancel:
1180 // Don't have this value persist outside of a single tap gesture.
1181 last_hidden_page_popup_ = nullptr;
1183 frame->GetEventHandler().HandleGestureEvent(targeted_event);
1185 case WebInputEvent::Type::kGestureShowPress:
1186 case WebInputEvent::Type::kGestureTapUnconfirmed:
1187 case WebInputEvent::Type::kGestureShortPress:
1189 frame->GetEventHandler().HandleGestureEvent(targeted_event);
1194 DidHandleGestureEvent(event);
1195 return event_result;
1198 WebInputEventResult WebFrameWidgetImpl::HandleMouseWheel(
1200 const WebMouseWheelEvent& event) {
1201 View()->CancelPagePopup();
1202 return WidgetEventHandler::HandleMouseWheel(frame, event);
1203 // WidgetEventHandler may have detached the frame.
1206 WebInputEventResult WebFrameWidgetImpl::HandleCharEvent(
1207 const WebKeyboardEvent& event) {
1208 DCHECK_EQ(event.GetType(), WebInputEvent::Type::kChar);
1210 // Please refer to the comments explaining the m_suppressNextKeypressEvent
1211 // member. The m_suppressNextKeypressEvent is set if the KeyDown is
1212 // handled by Webkit. A keyDown event is typically associated with a
1213 // keyPress(char) event and a keyUp event. We reset this flag here as it
1214 // only applies to the current keyPress event.
1215 bool suppress = suppress_next_keypress_event_;
1216 suppress_next_keypress_event_ = false;
1218 // If there is a popup open, it should be the one processing the event,
1220 scoped_refptr<WebPagePopupImpl> page_popup = View()->GetPagePopup();
1222 return page_popup->HandleKeyEvent(event);
1224 LocalFrame* frame = To<LocalFrame>(FocusedCoreFrame());
1226 return suppress ? WebInputEventResult::kHandledSuppressed
1227 : WebInputEventResult::kNotHandled;
1230 EventHandler& handler = frame->GetEventHandler();
1232 if (!event.IsCharacterKey())
1233 return WebInputEventResult::kHandledSuppressed;
1235 // Accesskeys are triggered by char events and can't be suppressed.
1236 // It is unclear whether a keypress should be dispatched as well
1238 if (handler.HandleAccessKey(event))
1239 return WebInputEventResult::kHandledSystem;
1241 // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to
1242 // the eventHandler::keyEvent. We mimic this behavior on all platforms since
1243 // for now we are converting other platform's key events to windows key
1245 if (event.is_system_key)
1246 return WebInputEventResult::kNotHandled;
1249 return WebInputEventResult::kHandledSuppressed;
1251 WebInputEventResult result = handler.KeyEvent(event);
1252 if (result != WebInputEventResult::kNotHandled)
1255 return WebInputEventResult::kNotHandled;
1258 void WebFrameWidgetImpl::CancelDrag() {
1259 drag_operation_ = DragController::Operation();
1260 current_drag_data_ = nullptr;
1263 void WebFrameWidgetImpl::StartDragging(LocalFrame* source_frame,
1264 const WebDragData& drag_data,
1265 DragOperationsMask operations_allowed,
1266 const SkBitmap& drag_image,
1267 const gfx::Vector2d& cursor_offset,
1268 const gfx::Rect& drag_obj_rect) {
1269 doing_drag_and_drop_ = true;
1270 if (drag_and_drop_disabled_) {
1271 DragSourceSystemDragEnded();
1275 gfx::Vector2d offset_in_dips =
1276 widget_base_->BlinkSpaceToFlooredDIPs(gfx::Point() + cursor_offset)
1277 .OffsetFromOrigin();
1278 gfx::Rect drag_obj_rect_in_dips =
1279 gfx::Rect(widget_base_->BlinkSpaceToFlooredDIPs(drag_obj_rect.origin()),
1280 widget_base_->BlinkSpaceToFlooredDIPs(drag_obj_rect.size()));
1281 source_frame->GetLocalFrameHostRemote().StartDragging(
1282 drag_data, operations_allowed, drag_image, offset_in_dips,
1283 drag_obj_rect_in_dips, possible_drag_event_info_.Clone());
1286 void WebFrameWidgetImpl::DragTargetDragEnterOrOver(
1287 const gfx::PointF& point_in_viewport,
1288 const gfx::PointF& screen_point,
1289 DragAction drag_action,
1290 uint32_t key_modifiers) {
1291 if (ShouldIgnoreInputEvents() || !current_drag_data_) {
1296 gfx::PointF point_in_root_frame = ViewportToRootFrame(point_in_viewport);
1298 current_drag_data_->SetModifiers(key_modifiers);
1299 DragData drag_data(current_drag_data_.Get(), point_in_root_frame,
1300 screen_point, operations_allowed_,
1301 /*force_default_action=*/false);
1303 drag_operation_ = GetPage()->GetDragController().DragEnteredOrUpdated(
1304 &drag_data, *local_root_->GetFrame());
1306 // Mask the drag operation against the drag source's allowed
1308 if (!(static_cast<int>(drag_operation_.operation) &
1309 drag_data.DraggingSourceOperationMask())) {
1310 drag_operation_ = DragController::Operation();
1314 void WebFrameWidgetImpl::SendOverscrollEventFromImplSide(
1315 const gfx::Vector2dF& overscroll_delta,
1316 cc::ElementId scroll_latched_element_id) {
1317 if (!RuntimeEnabledFeatures::OverscrollCustomizationEnabled())
1320 Node* target_node = View()->FindNodeFromScrollableCompositorElementId(
1321 scroll_latched_element_id);
1323 target_node->GetDocument().EnqueueOverscrollEventForNode(
1324 target_node, overscroll_delta.x(), overscroll_delta.y());
1328 void WebFrameWidgetImpl::SendScrollEndEventFromImplSide(
1329 bool affects_outer_viewport,
1330 cc::ElementId scroll_latched_element_id) {
1331 if (!RuntimeEnabledFeatures::ScrollEndEventsEnabled())
1334 Node* target_node = View()->FindNodeFromScrollableCompositorElementId(
1335 scroll_latched_element_id);
1336 bool target_is_root_scroller = false;
1337 if (View()->MainFrameImpl()) {
1338 Node* document_node = View()->MainFrameImpl()->GetDocument();
1339 if (target_node == document_node) {
1340 target_is_root_scroller = true;
1344 // Scrolls consumed entirely by the VisualViewport and not the
1345 // LayoutViewport should not trigger scrollends on the document. The
1346 // VisualViewport currently handles scroll but not scrollends. If that
1347 // changes, we should consider firing scrollend at the visualviewport
1348 // instead of simply bailing.
1349 if (affects_outer_viewport || !target_is_root_scroller) {
1350 target_node->GetDocument().EnqueueScrollEndEventForNode(target_node);
1355 void WebFrameWidgetImpl::UpdateCompositorScrollState(
1356 const cc::CompositorCommitData& commit_data) {
1357 if (WebDevToolsAgentImpl* devtools = LocalRootImpl()->DevToolsAgentImpl())
1358 devtools->SetPageIsScrolling(commit_data.is_scroll_active);
1360 RecordManipulationTypeCounts(commit_data.manipulation_info);
1362 if (commit_data.scroll_latched_element_id == cc::ElementId())
1365 if (!commit_data.overscroll_delta.IsZero()) {
1366 SendOverscrollEventFromImplSide(commit_data.overscroll_delta,
1367 commit_data.scroll_latched_element_id);
1370 // TODO(bokan): If a scroll ended and a new one began in the same Blink frame
1371 // (e.g. during a long running main thread task), this will erroneously
1372 // dispatch the scroll end to the latter (still-scrolling) element.
1373 // https://crbug.com/1116780.
1374 if (commit_data.scroll_end_data.scroll_gesture_did_end) {
1375 SendScrollEndEventFromImplSide(
1376 commit_data.scroll_end_data.gesture_affects_outer_viewport_scroll,
1377 commit_data.scroll_latched_element_id);
1381 WebInputMethodController*
1382 WebFrameWidgetImpl::GetActiveWebInputMethodController() const {
1383 WebLocalFrameImpl* local_frame =
1384 WebLocalFrameImpl::FromFrame(FocusedLocalFrameInWidget());
1385 return local_frame ? local_frame->GetInputMethodController() : nullptr;
1388 void WebFrameWidgetImpl::DisableDragAndDrop() {
1389 drag_and_drop_disabled_ = true;
1392 gfx::PointF WebFrameWidgetImpl::ViewportToRootFrame(
1393 const gfx::PointF& point_in_viewport) const {
1394 return GetPage()->GetVisualViewport().ViewportToRootFrame(point_in_viewport);
1397 WebViewImpl* WebFrameWidgetImpl::View() const {
1398 return local_root_->ViewImpl();
1401 Page* WebFrameWidgetImpl::GetPage() const {
1402 return View()->GetPage();
1405 mojom::blink::FrameWidgetHost*
1406 WebFrameWidgetImpl::GetAssociatedFrameWidgetHost() const {
1407 return frame_widget_host_.get();
1410 void WebFrameWidgetImpl::RequestDecode(
1411 const PaintImage& image,
1412 base::OnceCallback<void(bool)> callback) {
1413 widget_base_->LayerTreeHost()->QueueImageDecode(image, std::move(callback));
1416 void WebFrameWidgetImpl::Trace(Visitor* visitor) const {
1417 visitor->Trace(local_root_);
1418 visitor->Trace(current_drag_data_);
1419 visitor->Trace(frame_widget_host_);
1420 visitor->Trace(receiver_);
1421 visitor->Trace(input_target_receiver_);
1422 visitor->Trace(mouse_capture_element_);
1423 visitor->Trace(device_emulator_);
1424 visitor->Trace(animation_frame_timing_monitor_);
1427 #if BUILDFLAG(IS_TIZEN_TV)
1428 void WebFrameWidgetImpl::EdgeScrollBy(const gfx::Point& offset, const gfx::Point& mouse_position) {
1429 bool handled = false;
1430 WebViewImpl* webview = View();
1432 handled = webview->EdgeScrollBy(
1433 blink::ScrollOffset(offset.x(), offset.y()),
1434 gfx::Point(mouse_position.x(), mouse_position.y()));
1435 widget_base_->DidEdgeScrollBy(offset, handled);
1438 void WebFrameWidgetImpl::SetTranslatedURL(const WTF::String& url) {
1439 WebViewImpl* webview = View();
1442 webview->SetTranslatedURL(blink::WebString::FromUTF8(url.Ascii()));
1445 void WebFrameWidgetImpl::SetParentalRatingResult(const WTF::String& url,
1447 WebViewImpl* webview = View();
1449 LOG(ERROR) << "no webview.";
1452 webview->SetParentalRatingResult(blink::WebString::FromUTF8(url.Ascii()),
1456 bool WebFrameWidgetImpl::IsVideoPlaying() {
1457 WebViewImpl* webview = View();
1459 LOG(ERROR) << "no webview.";
1462 return webview->IsVideoPlaying();
1465 void WebFrameWidgetImpl::SetPreferSubtitleLang(const WTF::String lang_list) {
1466 WebViewImpl* webview = View();
1468 LOG(ERROR) << "no webview.";
1471 webview->SetPreferTextLang(lang_list);
1475 void WebFrameWidgetImpl::SetNeedsRecalculateRasterScales() {
1476 if (!View()->does_composite())
1478 widget_base_->LayerTreeHost()->SetNeedsRecalculateRasterScales();
1481 void WebFrameWidgetImpl::SetBackgroundColor(SkColor color) {
1482 if (!View()->does_composite())
1484 // TODO(crbug/1308932): Remove FromColor and make all SkColor4f.
1485 widget_base_->LayerTreeHost()->set_background_color(
1486 SkColor4f::FromColor(color));
1489 void WebFrameWidgetImpl::SetOverscrollBehavior(
1490 const cc::OverscrollBehavior& overscroll_behavior) {
1491 if (!View()->does_composite())
1493 widget_base_->LayerTreeHost()->SetOverscrollBehavior(overscroll_behavior);
1496 void WebFrameWidgetImpl::SetPrefersReducedMotion(bool prefers_reduced_motion) {
1497 if (!View()->does_composite())
1499 widget_base_->LayerTreeHost()->SetPrefersReducedMotion(
1500 prefers_reduced_motion);
1503 void WebFrameWidgetImpl::StartPageScaleAnimation(const gfx::Point& destination,
1505 float new_page_scale,
1506 base::TimeDelta duration) {
1507 widget_base_->LayerTreeHost()->StartPageScaleAnimation(
1508 destination, use_anchor, new_page_scale, duration);
1511 void WebFrameWidgetImpl::RequestBeginMainFrameNotExpected(bool request) {
1512 if (!View()->does_composite())
1514 widget_base_->LayerTreeHost()->RequestBeginMainFrameNotExpected(request);
1517 void WebFrameWidgetImpl::DidCommitAndDrawCompositorFrame() {
1518 ForEachLocalFrameControlledByWidget(
1519 local_root_->GetFrame(), [](WebLocalFrameImpl* local_frame) {
1520 local_frame->Client()->DidCommitAndDrawCompositorFrame();
1524 void WebFrameWidgetImpl::DidObserveFirstScrollDelay(
1525 base::TimeDelta first_scroll_delay,
1526 base::TimeTicks first_scroll_timestamp) {
1527 if (!local_root_ || !(local_root_->GetFrame()) ||
1528 !(local_root_->GetFrame()->GetDocument())) {
1531 InteractiveDetector* interactive_detector =
1532 InteractiveDetector::From(*(local_root_->GetFrame()->GetDocument()));
1533 if (interactive_detector) {
1534 interactive_detector->DidObserveFirstScrollDelay(first_scroll_delay,
1535 first_scroll_timestamp);
1539 void WebFrameWidgetImpl::WillBeginMainFrame() {
1540 if (animation_frame_timing_monitor_) {
1541 animation_frame_timing_monitor_->WillBeginMainFrame();
1545 bool WebFrameWidgetImpl::ShouldIgnoreInputEvents() {
1547 return IgnoreInputEvents(GetPage()->BrowsingContextGroupToken());
1550 std::unique_ptr<cc::LayerTreeFrameSink>
1551 WebFrameWidgetImpl::AllocateNewLayerTreeFrameSink() {
1555 void WebFrameWidgetImpl::ReportLongAnimationFrameTiming(
1556 AnimationFrameTimingInfo* timing_info) {
1557 WebSecurityOrigin root_origin = local_root_->GetSecurityOrigin();
1558 ForEachLocalFrameControlledByWidget(
1559 local_root_->GetFrame(), [&](WebLocalFrameImpl* local_frame) {
1560 if (local_frame == local_root_ ||
1561 !local_frame->GetSecurityOrigin().IsSameOriginWith(root_origin)) {
1562 DOMWindowPerformance::performance(
1563 *local_frame->GetFrame()->DomWindow())
1564 ->ReportLongAnimationFrameTiming(timing_info);
1569 void WebFrameWidgetImpl::ReportLongTaskTiming(base::TimeTicks start_time,
1570 base::TimeTicks end_time,
1571 ExecutionContext* task_context) {
1573 CHECK(local_root_->GetFrame());
1574 ForEachLocalFrameControlledByWidget(
1575 local_root_->GetFrame(), [&](WebLocalFrameImpl* local_frame) {
1576 CHECK(local_frame->GetFrame());
1577 CHECK(local_frame->GetFrame()->DomWindow());
1578 // Note: |task_context| could be the execution context of any same-agent
1580 DOMWindowPerformance::performance(*local_frame->GetFrame()->DomWindow())
1581 ->ReportLongTask(start_time, end_time, task_context,
1582 /*has_multiple_contexts=*/false);
1586 bool WebFrameWidgetImpl::ShouldReportLongAnimationFrameTiming() const {
1587 return widget_base_ && !IsHidden();
1589 void WebFrameWidgetImpl::OnTaskCompletedForFrame(
1590 base::TimeTicks start_time,
1591 base::TimeTicks end_time,
1592 base::TimeTicks desired_execution_time,
1593 LocalFrame* frame) {
1594 if (animation_frame_timing_monitor_) {
1595 animation_frame_timing_monitor_->OnTaskCompleted(
1596 start_time, end_time, desired_execution_time, frame);
1600 void WebFrameWidgetImpl::DidBeginMainFrame() {
1601 LocalFrame* root_frame = LocalRootImpl()->GetFrame();
1604 if (LocalFrameView* frame_view = root_frame->View())
1605 frame_view->RunPostLifecycleSteps();
1607 if (animation_frame_timing_monitor_) {
1608 animation_frame_timing_monitor_->DidBeginMainFrame();
1611 if (Page* page = root_frame->GetPage())
1612 page->Animator().PostAnimate();
1615 void WebFrameWidgetImpl::UpdateLifecycle(WebLifecycleUpdate requested_update,
1616 DocumentUpdateReason reason) {
1617 TRACE_EVENT0("blink", "WebFrameWidgetImpl::UpdateLifecycle");
1618 if (!LocalRootImpl())
1621 if (requested_update == WebLifecycleUpdate::kAll &&
1622 animation_frame_timing_monitor_) {
1623 animation_frame_timing_monitor_->WillPerformStyleAndLayoutCalculation();
1626 GetPage()->UpdateLifecycle(*LocalRootImpl()->GetFrame(), requested_update,
1628 if (requested_update != WebLifecycleUpdate::kAll)
1631 View()->UpdatePagePopup();
1633 // Meaningful layout events and background colors only apply to main frames.
1634 if (ForMainFrame()) {
1635 MainFrameData& data = main_data();
1637 // There is no background color for non-composited WebViews (eg
1639 if (View()->does_composite()) {
1640 SkColor background_color = View()->BackgroundColor();
1641 SetBackgroundColor(background_color);
1642 if (background_color != data.last_background_color) {
1643 LocalRootImpl()->GetFrame()->DidChangeBackgroundColor(
1644 SkColor4f::FromColor(background_color), false /* color_adjust */);
1645 data.last_background_color = background_color;
1649 if (LocalFrameView* view = LocalRootImpl()->GetFrameView()) {
1650 LocalFrame* frame = LocalRootImpl()->GetFrame();
1652 if (data.should_dispatch_first_visually_non_empty_layout &&
1653 view->IsVisuallyNonEmpty()) {
1654 data.should_dispatch_first_visually_non_empty_layout = false;
1655 // TODO(esprehn): Move users of this callback to something
1656 // better, the heuristic for "visually non-empty" is bad.
1657 DidMeaningfulLayout(WebMeaningfulLayout::kVisuallyNonEmpty);
1660 if (data.should_dispatch_first_layout_after_finished_parsing &&
1661 frame->GetDocument()->HasFinishedParsing()) {
1662 data.should_dispatch_first_layout_after_finished_parsing = false;
1663 DidMeaningfulLayout(WebMeaningfulLayout::kFinishedParsing);
1666 if (data.should_dispatch_first_layout_after_finished_loading &&
1667 frame->GetDocument()->IsLoadCompleted()) {
1668 data.should_dispatch_first_layout_after_finished_loading = false;
1669 DidMeaningfulLayout(WebMeaningfulLayout::kFinishedLoading);
1675 void WebFrameWidgetImpl::DidCompletePageScaleAnimation() {
1676 // Page scale animations only happen on the main frame.
1677 DCHECK(ForMainFrame());
1678 if (auto* focused_frame = View()->FocusedFrame()) {
1679 if (focused_frame->AutofillClient())
1680 focused_frame->AutofillClient()->DidCompleteFocusChangeInFrame();
1683 if (page_scale_animation_for_testing_callback_)
1684 std::move(page_scale_animation_for_testing_callback_).Run();
1687 void WebFrameWidgetImpl::ScheduleAnimation() {
1688 if (!View()->does_composite()) {
1689 non_composited_client_->ScheduleNonCompositedAnimation();
1693 if (widget_base_->WillBeDestroyed()) {
1697 widget_base_->LayerTreeHost()->SetNeedsAnimate();
1700 void WebFrameWidgetImpl::FocusChanged(mojom::blink::FocusState focus_state) {
1701 // TODO(crbug.com/689777): FocusChange events are only sent to the MainFrame
1702 // these maybe should goto the local root so that the rest of input messages
1703 // sent to those are preserved in order.
1704 DCHECK(ForMainFrame());
1705 View()->SetIsActive(focus_state == mojom::blink::FocusState::kFocused ||
1707 mojom::blink::FocusState::kNotFocusedAndActive);
1708 View()->SetPageFocus(focus_state == mojom::blink::FocusState::kFocused);
1711 bool WebFrameWidgetImpl::ShouldAckSyntheticInputImmediately() {
1712 // TODO(bokan): The RequestPresentation API appears not to function in VR. As
1713 // a short term workaround for https://crbug.com/940063, ACK input
1714 // immediately rather than using RequestPresentation.
1715 if (GetPage()->GetSettings().GetImmersiveModeEnabled())
1720 void WebFrameWidgetImpl::UpdateVisualProperties(
1721 const VisualProperties& visual_properties) {
1722 SetZoomLevel(visual_properties.zoom_level);
1724 // TODO(danakj): In order to synchronize updates between local roots, the
1725 // display mode should be propagated to RenderFrameProxies and down through
1726 // their RenderWidgetHosts to child WebFrameWidgetImpl via the
1727 // VisualProperties waterfall, instead of coming to each WebFrameWidgetImpl
1729 // https://developer.mozilla.org/en-US/docs/Web/CSS/@media/display-mode
1730 SetDisplayMode(visual_properties.display_mode);
1731 SetWindowShowState(visual_properties.window_show_state);
1732 SetResizable(visual_properties.resizable);
1734 if (ForMainFrame()) {
1736 visual_properties.auto_resize_enabled,
1737 visual_properties.min_size_for_auto_resize,
1738 visual_properties.max_size_for_auto_resize,
1739 visual_properties.screen_infos.current().device_scale_factor);
1742 bool capture_sequence_number_changed =
1743 visual_properties.capture_sequence_number !=
1744 last_capture_sequence_number_;
1745 if (capture_sequence_number_changed) {
1746 last_capture_sequence_number_ = visual_properties.capture_sequence_number;
1748 // Send the capture sequence number to RemoteFrames that are below the
1749 // local root for this widget.
1750 ForEachRemoteFrameControlledByWidget(
1751 [capture_sequence_number = visual_properties.capture_sequence_number](
1752 RemoteFrame* remote_frame) {
1753 remote_frame->UpdateCaptureSequenceNumber(capture_sequence_number);
1757 if (!View()->AutoResizeMode()) {
1758 // This needs to run before ApplyVisualPropertiesSizing below,
1759 // which updates the current set of screen_infos from visual properties.
1760 if (DidChangeFullscreenState(visual_properties)) {
1761 is_fullscreen_granted_ = visual_properties.is_fullscreen_granted;
1762 if (is_fullscreen_granted_)
1763 View()->DidEnterFullscreen();
1765 View()->DidExitFullscreen();
1769 gfx::Size old_visible_viewport_size_in_dips =
1770 widget_base_->VisibleViewportSizeInDIPs();
1771 ApplyVisualPropertiesSizing(visual_properties);
1773 if (old_visible_viewport_size_in_dips !=
1774 widget_base_->VisibleViewportSizeInDIPs()) {
1775 ForEachLocalFrameControlledByWidget(
1776 local_root_->GetFrame(),
1777 &WebLocalFrameImpl::ResetHasScrolledFocusedEditableIntoView);
1779 // Propagate changes down to child local root RenderWidgets and
1780 // BrowserPlugins in other frame trees/processes.
1781 ForEachRemoteFrameControlledByWidget(
1782 [visible_viewport_size = widget_base_->VisibleViewportSizeInDIPs()](
1783 RemoteFrame* remote_frame) {
1784 remote_frame->DidChangeVisibleViewportSize(visible_viewport_size);
1788 // All non-top-level Widgets (child local-root frames, Portals, GuestViews,
1789 // etc.) propagate and consume the page scale factor as "external", meaning
1790 // that it comes from the top level widget's page scale.
1791 if (!ForTopMostMainFrame()) {
1792 // The main frame controls the page scale factor, from blink. For other
1793 // frame widgets, the page scale from pinch zoom and compositing scale is
1794 // received from its parent as part of the visual properties here. While
1795 // blink doesn't need to know this page scale factor outside the main frame,
1796 // the compositor does in order to produce its output at the correct scale.
1797 float combined_scale_factor = visual_properties.page_scale_factor *
1798 visual_properties.compositing_scale_factor;
1799 widget_base_->LayerTreeHost()->SetExternalPageScaleFactor(
1800 combined_scale_factor, visual_properties.is_pinch_gesture_active);
1802 NotifyPageScaleFactorChanged(visual_properties.page_scale_factor,
1803 visual_properties.is_pinch_gesture_active);
1805 NotifyCompositingScaleFactorChanged(
1806 visual_properties.compositing_scale_factor);
1808 // Ensure the external scale factor in top-level widgets is reset as it may
1809 // be leftover from when a widget was nested and was promoted to top level
1810 // (e.g. portal activation).
1811 widget_base_->LayerTreeHost()->SetExternalPageScaleFactor(
1813 /*is_pinch_gesture_active=*/false);
1816 EventHandler& event_handler = local_root_->GetFrame()->GetEventHandler();
1817 if (event_handler.cursor_accessibility_scale_factor() !=
1818 visual_properties.cursor_accessibility_scale_factor) {
1819 ForEachLocalFrameControlledByWidget(
1820 local_root_->GetFrame(), [&](WebLocalFrameImpl* local_frame) {
1821 local_frame->GetFrame()
1823 .set_cursor_accessibility_scale_factor(
1824 visual_properties.cursor_accessibility_scale_factor);
1826 // Propagate changes down to any child RemoteFrames.
1827 ForEachRemoteFrameControlledByWidget(
1828 [scale_factor = visual_properties.cursor_accessibility_scale_factor](
1829 RemoteFrame* remote_frame) {
1830 remote_frame->CursorAccessibilityScaleFactorChanged(scale_factor);
1834 // TODO(crbug.com/939118): This code path where scroll_focused_node_into_view
1835 // is set is used only for WebView, crbug 939118 tracks fixing webviews to
1836 // not use scroll_focused_node_into_view.
1837 if (visual_properties.scroll_focused_node_into_view)
1838 ScrollFocusedEditableElementIntoView();
1841 void WebFrameWidgetImpl::ApplyVisualPropertiesSizing(
1842 const VisualProperties& visual_properties) {
1843 gfx::Rect new_compositor_viewport_pixel_rect =
1844 visual_properties.compositor_viewport_pixel_rect;
1845 if (ForMainFrame()) {
1847 widget_base_->DIPsToCeiledBlinkSpace(visual_properties.new_size)) {
1848 // Only hide popups when the size changes. Eg https://crbug.com/761908.
1849 View()->CancelPagePopup();
1852 if (auto* device_emulator = DeviceEmulator()) {
1853 device_emulator->UpdateVisualProperties(visual_properties);
1857 if (AutoResizeMode()) {
1858 new_compositor_viewport_pixel_rect = gfx::Rect(gfx::ScaleToCeiledSize(
1859 widget_base_->BlinkSpaceToFlooredDIPs(size_.value_or(gfx::Size())),
1860 visual_properties.screen_infos.current().device_scale_factor));
1864 SetWindowSegments(visual_properties.root_widget_window_segments);
1866 widget_base_->UpdateSurfaceAndScreenInfo(
1867 visual_properties.local_surface_id.value_or(viz::LocalSurfaceId()),
1868 new_compositor_viewport_pixel_rect, visual_properties.screen_infos);
1870 // Store this even when auto-resizing, it is the size of the full viewport
1871 // used for clipping, and this value is propagated down the Widget
1872 // hierarchy via the VisualProperties waterfall.
1873 widget_base_->SetVisibleViewportSizeInDIPs(
1874 visual_properties.visible_viewport_size);
1876 virtual_keyboard_resize_height_physical_px_ =
1877 visual_properties.virtual_keyboard_resize_height_physical_px;
1878 DCHECK(!virtual_keyboard_resize_height_physical_px_ || ForTopMostMainFrame());
1880 if (ForMainFrame()) {
1881 if (!AutoResizeMode()) {
1882 size_ = widget_base_->DIPsToCeiledBlinkSpace(visual_properties.new_size);
1884 View()->ResizeWithBrowserControls(
1886 widget_base_->DIPsToCeiledBlinkSpace(
1887 widget_base_->VisibleViewportSizeInDIPs()),
1888 visual_properties.browser_controls_params);
1891 #if !BUILDFLAG(IS_ANDROID)
1892 LocalRootImpl()->GetFrame()->UpdateWindowControlsOverlay(
1893 visual_properties.window_controls_overlay_rect);
1897 // Widgets in a WebView's frame tree without a local main frame
1898 // set the size of the WebView to be the |visible_viewport_size|, in order
1899 // to limit compositing in (out of process) child frames to what is visible.
1901 // Note that child frames in the same process/WebView frame tree as the
1902 // main frame do not do this in order to not clobber the source of truth in
1904 if (!View()->MainFrameImpl()) {
1905 View()->Resize(widget_base_->DIPsToCeiledBlinkSpace(
1906 widget_base_->VisibleViewportSizeInDIPs()));
1909 Resize(widget_base_->DIPsToCeiledBlinkSpace(visual_properties.new_size));
1913 bool WebFrameWidgetImpl::DidChangeFullscreenState(
1914 const VisualProperties& visual_properties) const {
1915 if (visual_properties.is_fullscreen_granted != is_fullscreen_granted_)
1917 // If changing fullscreen from one display to another, the fullscreen
1918 // granted state will not change, but we still need to resolve promises
1919 // by considering this a change.
1920 return visual_properties.is_fullscreen_granted &&
1921 widget_base_->screen_infos().current().display_id !=
1922 visual_properties.screen_infos.current().display_id;
1925 int WebFrameWidgetImpl::GetLayerTreeId() {
1926 if (!View()->does_composite())
1928 return widget_base_->LayerTreeHost()->GetId();
1931 const cc::LayerTreeSettings* WebFrameWidgetImpl::GetLayerTreeSettings() {
1932 if (!View()->does_composite()) {
1935 return &widget_base_->LayerTreeHost()->GetSettings();
1938 void WebFrameWidgetImpl::UpdateBrowserControlsState(
1939 cc::BrowserControlsState constraints,
1940 cc::BrowserControlsState current,
1942 DCHECK(View()->does_composite());
1943 widget_base_->LayerTreeHost()->UpdateBrowserControlsState(constraints,
1947 void WebFrameWidgetImpl::SetHaveScrollEventHandlers(bool has_handlers) {
1948 widget_base_->LayerTreeHost()->SetHaveScrollEventHandlers(has_handlers);
1951 void WebFrameWidgetImpl::SetEventListenerProperties(
1952 cc::EventListenerClass listener_class,
1953 cc::EventListenerProperties listener_properties) {
1954 widget_base_->LayerTreeHost()->SetEventListenerProperties(
1955 listener_class, listener_properties);
1957 if (listener_class == cc::EventListenerClass::kTouchStartOrMove ||
1958 listener_class == cc::EventListenerClass::kTouchEndOrCancel) {
1959 bool has_touch_handlers =
1960 EventListenerProperties(cc::EventListenerClass::kTouchStartOrMove) !=
1961 cc::EventListenerProperties::kNone ||
1962 EventListenerProperties(cc::EventListenerClass::kTouchEndOrCancel) !=
1963 cc::EventListenerProperties::kNone;
1964 if (!has_touch_handlers_ || *has_touch_handlers_ != has_touch_handlers) {
1965 has_touch_handlers_ = has_touch_handlers;
1967 widget_base_->WidgetScheduler()->SetHasTouchHandler(has_touch_handlers);
1968 // Set touch event consumers based on whether there are touch event
1969 // handlers or the page has hit testable scrollbars.
1970 auto touch_event_consumers = mojom::blink::TouchEventConsumers::New(
1971 has_touch_handlers, GetPage()->GetScrollbarTheme().AllowsHitTest());
1972 frame_widget_host_->SetHasTouchEventConsumers(
1973 std::move(touch_event_consumers));
1975 } else if (listener_class == cc::EventListenerClass::kPointerRawUpdate) {
1976 SetHasPointerRawUpdateEventHandlers(listener_properties !=
1977 cc::EventListenerProperties::kNone);
1981 cc::EventListenerProperties WebFrameWidgetImpl::EventListenerProperties(
1982 cc::EventListenerClass listener_class) const {
1983 return widget_base_->LayerTreeHost()->event_listener_properties(
1987 mojom::blink::DisplayMode WebFrameWidgetImpl::DisplayMode() const {
1988 return display_mode_;
1991 ui::WindowShowState WebFrameWidgetImpl::WindowShowState() const {
1992 return window_show_state_;
1995 bool WebFrameWidgetImpl::Resizable() const {
1999 const WebVector<gfx::Rect>& WebFrameWidgetImpl::WindowSegments() const {
2000 return window_segments_;
2003 bool WebFrameWidgetImpl::StartDeferringCommits(base::TimeDelta timeout,
2004 cc::PaintHoldingReason reason) {
2005 if (!View()->does_composite())
2007 return widget_base_->LayerTreeHost()->StartDeferringCommits(timeout, reason);
2010 void WebFrameWidgetImpl::StopDeferringCommits(
2011 cc::PaintHoldingCommitTrigger triggger) {
2012 if (!View()->does_composite())
2014 widget_base_->LayerTreeHost()->StopDeferringCommits(triggger);
2017 std::unique_ptr<cc::ScopedPauseRendering> WebFrameWidgetImpl::PauseRendering() {
2018 if (!View()->does_composite())
2020 return widget_base_->LayerTreeHost()->PauseRendering();
2023 absl::optional<int> WebFrameWidgetImpl::GetMaxRenderBufferBounds() const {
2024 if (!View()->does_composite()) {
2025 return absl::nullopt;
2027 return widget_base_->GetMaxRenderBufferBounds();
2030 std::unique_ptr<cc::ScopedDeferMainFrameUpdate>
2031 WebFrameWidgetImpl::DeferMainFrameUpdate() {
2032 return widget_base_->LayerTreeHost()->DeferMainFrameUpdate();
2035 void WebFrameWidgetImpl::SetBrowserControlsShownRatio(float top_ratio,
2036 float bottom_ratio) {
2037 widget_base_->LayerTreeHost()->SetBrowserControlsShownRatio(top_ratio,
2041 void WebFrameWidgetImpl::SetBrowserControlsParams(
2042 cc::BrowserControlsParams params) {
2043 widget_base_->LayerTreeHost()->SetBrowserControlsParams(params);
2046 void WebFrameWidgetImpl::SynchronouslyCompositeForTesting(
2047 base::TimeTicks frame_time) {
2048 widget_base_->LayerTreeHost()->CompositeForTest(frame_time, false,
2049 base::OnceClosure());
2052 void WebFrameWidgetImpl::SetDeviceColorSpaceForTesting(
2053 const gfx::ColorSpace& color_space) {
2054 DCHECK(ForMainFrame());
2055 // We are changing the device color space from the renderer, so allocate a
2056 // new viz::LocalSurfaceId to avoid surface invariants violations in tests.
2057 widget_base_->LayerTreeHost()->RequestNewLocalSurfaceId();
2059 display::ScreenInfos screen_infos = widget_base_->screen_infos();
2060 for (display::ScreenInfo& screen_info : screen_infos.screen_infos)
2061 screen_info.display_color_spaces = gfx::DisplayColorSpaces(color_space);
2062 widget_base_->UpdateScreenInfo(screen_infos);
2065 // TODO(665924): Remove direct dispatches of mouse events from
2066 // PointerLockController, instead passing them through EventHandler.
2067 void WebFrameWidgetImpl::PointerLockMouseEvent(
2068 const WebCoalescedInputEvent& coalesced_event) {
2069 const WebInputEvent& input_event = coalesced_event.Event();
2070 const WebMouseEvent& mouse_event =
2071 static_cast<const WebMouseEvent&>(input_event);
2072 WebMouseEvent transformed_event =
2073 TransformWebMouseEvent(local_root_->GetFrameView(), mouse_event);
2075 AtomicString event_type;
2076 switch (input_event.GetType()) {
2077 case WebInputEvent::Type::kMouseDown:
2078 event_type = event_type_names::kMousedown;
2079 if (!GetPage() || !GetPage()->GetPointerLockController().GetElement())
2081 LocalFrame::NotifyUserActivation(
2083 ->GetPointerLockController()
2087 mojom::blink::UserActivationNotificationType::kInteraction);
2089 case WebInputEvent::Type::kMouseUp:
2090 event_type = event_type_names::kMouseup;
2092 case WebInputEvent::Type::kMouseMove:
2093 event_type = event_type_names::kMousemove;
2095 case WebInputEvent::Type::kMouseEnter:
2096 case WebInputEvent::Type::kMouseLeave:
2097 case WebInputEvent::Type::kContextMenu:
2098 // These should not be normally dispatched but may be due to timing
2099 // because pointer lost messaging happens on separate mojo channel.
2102 NOTREACHED() << input_event.GetType();
2106 GetPage()->GetPointerLockController().DispatchLockedMouseEvent(
2108 TransformWebMouseEventVector(
2109 local_root_->GetFrameView(),
2110 coalesced_event.GetCoalescedEventsPointers()),
2111 TransformWebMouseEventVector(
2112 local_root_->GetFrameView(),
2113 coalesced_event.GetPredictedEventsPointers()),
2117 bool WebFrameWidgetImpl::IsPointerLocked() {
2119 return GetPage()->GetPointerLockController().IsPointerLocked();
2124 void WebFrameWidgetImpl::ShowContextMenu(
2125 ui::mojom::blink::MenuSourceType source_type,
2126 const gfx::Point& location) {
2127 host_context_menu_location_ = location;
2131 GetPage()->GetContextMenuController().ClearContextMenu();
2133 ContextMenuAllowedScope scope;
2134 if (LocalFrame* focused_frame =
2135 GetPage()->GetFocusController().FocusedFrame()) {
2136 focused_frame->GetEventHandler().ShowNonLocatedContextMenu(
2137 nullptr, static_cast<blink::WebMenuSourceType>(source_type));
2140 host_context_menu_location_.reset();
2143 void WebFrameWidgetImpl::SetViewportIntersection(
2144 mojom::blink::ViewportIntersectionStatePtr intersection_state,
2145 const absl::optional<VisualProperties>& visual_properties) {
2146 // Remote viewports are only applicable to local frames with remote ancestors.
2147 // TODO(https://crbug.com/1148960): Should this deal with portals?
2148 DCHECK(ForSubframe() || !LocalRootImpl()->GetFrame()->IsOutermostMainFrame());
2150 if (visual_properties.has_value())
2151 UpdateVisualProperties(visual_properties.value());
2152 ApplyViewportIntersection(std::move(intersection_state));
2155 void WebFrameWidgetImpl::ApplyViewportIntersectionForTesting(
2156 mojom::blink::ViewportIntersectionStatePtr intersection_state) {
2157 ApplyViewportIntersection(std::move(intersection_state));
2160 void WebFrameWidgetImpl::ApplyViewportIntersection(
2161 mojom::blink::ViewportIntersectionStatePtr intersection_state) {
2162 if (ForSubframe()) {
2163 // This information is propagated to LTH to define the region for filling
2164 // the on-screen text content.
2165 // TODO(khushalsagar) : This needs to also be done for main frames which are
2166 // embedded pages (see Frame::IsOutermostMainFrame()).
2167 child_data().compositor_visible_rect =
2168 intersection_state->compositor_visible_rect;
2169 widget_base_->LayerTreeHost()->SetVisualDeviceViewportIntersectionRect(
2170 intersection_state->compositor_visible_rect);
2172 LocalRootImpl()->GetFrame()->SetViewportIntersectionFromParent(
2173 *intersection_state);
2176 void WebFrameWidgetImpl::EnableDeviceEmulation(
2177 const DeviceEmulationParams& parameters) {
2178 // Device Emaulation is only supported for the main frame.
2179 DCHECK(ForMainFrame());
2180 if (!device_emulator_) {
2181 gfx::Size size_in_dips = widget_base_->BlinkSpaceToFlooredDIPs(Size());
2183 device_emulator_ = MakeGarbageCollected<ScreenMetricsEmulator>(
2184 this, widget_base_->screen_infos(), size_in_dips,
2185 widget_base_->VisibleViewportSizeInDIPs(),
2186 widget_base_->WidgetScreenRect(), widget_base_->WindowScreenRect());
2188 device_emulator_->ChangeEmulationParams(parameters);
2191 void WebFrameWidgetImpl::DisableDeviceEmulation() {
2192 if (!device_emulator_)
2194 device_emulator_->DisableAndApply();
2195 device_emulator_ = nullptr;
2198 void WebFrameWidgetImpl::SetIsInertForSubFrame(bool inert) {
2199 DCHECK(ForSubframe());
2200 LocalRootImpl()->GetFrame()->SetIsInert(inert);
2203 absl::optional<gfx::Point>
2204 WebFrameWidgetImpl::GetAndResetContextMenuLocation() {
2205 return std::move(host_context_menu_location_);
2208 void WebFrameWidgetImpl::SetZoomLevel(double zoom_level) {
2209 // Override the zoom level with the testing one if necessary.
2210 if (zoom_level_for_testing_ != -INFINITY)
2211 zoom_level = zoom_level_for_testing_;
2213 // Set the layout shift exclusion window for the zoom level change.
2214 if (View()->ZoomLevel() != zoom_level)
2215 NotifyZoomLevelChanged(LocalRootImpl()->GetFrame());
2217 View()->SetZoomLevel(zoom_level);
2219 // Part of the UpdateVisualProperties dance we send the zoom level to
2220 // RemoteFrames that are below the local root for this widget.
2221 ForEachRemoteFrameControlledByWidget([zoom_level](RemoteFrame* remote_frame) {
2222 remote_frame->ZoomLevelChanged(zoom_level);
2226 void WebFrameWidgetImpl::SetAutoResizeMode(bool auto_resize,
2227 const gfx::Size& min_window_size,
2228 const gfx::Size& max_window_size,
2229 float device_scale_factor) {
2230 // Auto resize only applies to main frames.
2231 DCHECK(ForMainFrame());
2234 View()->EnableAutoResizeMode(
2235 gfx::ScaleToCeiledSize(min_window_size, device_scale_factor),
2236 gfx::ScaleToCeiledSize(max_window_size, device_scale_factor));
2237 } else if (AutoResizeMode()) {
2238 View()->DisableAutoResizeMode();
2242 void WebFrameWidgetImpl::DidAutoResize(const gfx::Size& size) {
2243 DCHECK(ForMainFrame());
2244 gfx::Size size_in_dips = widget_base_->BlinkSpaceToFlooredDIPs(size);
2247 // TODO(ccameron): Note that this destroys any information differentiating
2248 // |size| from the compositor's viewport size.
2249 gfx::Rect size_with_dsf = gfx::Rect(gfx::ScaleToCeiledSize(
2250 gfx::Rect(size_in_dips).size(),
2251 widget_base_->GetScreenInfo().device_scale_factor));
2252 widget_base_->LayerTreeHost()->RequestNewLocalSurfaceId();
2253 widget_base_->UpdateCompositorViewportRect(size_with_dsf);
2256 LocalFrame* WebFrameWidgetImpl::FocusedLocalFrameInWidget() const {
2258 // WebFrameWidget is created in the call to CreateFrame. The corresponding
2259 // RenderWidget, however, might not swap in right away (InstallNewDocument()
2260 // will lead to it swapping in). During this interval local_root_ is nullptr
2261 // (see https://crbug.com/792345).
2265 LocalFrame* frame = GetPage()->GetFocusController().FocusedFrame();
2266 return (frame && frame->LocalFrameRoot() == local_root_->GetFrame())
2271 WebLocalFrameImpl* WebFrameWidgetImpl::FocusedWebLocalFrameInWidget() const {
2272 return WebLocalFrameImpl::FromFrame(FocusedLocalFrameInWidget());
2275 bool WebFrameWidgetImpl::ScrollFocusedEditableElementIntoView() {
2276 Element* element = FocusedElement();
2280 EditContext* edit_context = element->GetDocument()
2282 ->GetInputMethodController()
2283 .GetActiveEditContext();
2285 if (!WebElement(element).IsEditable() && !edit_context)
2288 element->GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kSelection);
2290 if (!element->GetLayoutObject())
2293 // The page scale animation started by ZoomAndScrollToFocusedEditableRect
2294 // will scroll only the visual and layout viewports. Call ScrollRectToVisible
2295 // first to ensure the editable is visible within the document (i.e. scroll
2296 // it into view in any subscrollers). By setting `for_focused_editable`,
2297 // ScrollRectToVisible will stop bubbling when it reaches the layout viewport
2298 // so that can be animated by the PageScaleAnimation.
2299 mojom::blink::ScrollIntoViewParamsPtr params =
2300 ScrollAlignment::CreateScrollIntoViewParams(
2301 ScrollAlignment::CenterIfNeeded(), ScrollAlignment::CenterIfNeeded(),
2302 mojom::blink::ScrollType::kProgrammatic,
2303 /*make_visible_in_visual_viewport=*/false,
2304 mojom::blink::ScrollBehavior::kInstant);
2305 params->for_focused_editable = mojom::blink::FocusedEditableParams::New();
2307 // When deciding whether to zoom in on a focused text box, we should
2308 // decide not to zoom in if the user won't be able to zoom out. e.g if the
2309 // textbox is within a touch-action: none container the user can't zoom
2311 TouchAction action = touch_action_util::ComputeEffectiveTouchAction(*element);
2312 params->for_focused_editable->can_zoom =
2313 static_cast<int>(action) & static_cast<int>(TouchAction::kPinchZoom);
2315 PhysicalRect absolute_element_bounds;
2316 PhysicalRect absolute_caret_bounds;
2319 gfx::Rect control_bounds_in_physical_pixels;
2320 gfx::Rect selection_bounds_in_physical_pixels;
2321 edit_context->GetLayoutBounds(&control_bounds_in_physical_pixels,
2322 &selection_bounds_in_physical_pixels);
2324 absolute_element_bounds = PhysicalRect(control_bounds_in_physical_pixels);
2325 absolute_caret_bounds = PhysicalRect(selection_bounds_in_physical_pixels);
2327 absolute_element_bounds =
2328 PhysicalRect(element->GetLayoutObject()->AbsoluteBoundingBoxRect());
2329 absolute_caret_bounds = PhysicalRect(
2330 element->GetDocument().GetFrame()->Selection().ComputeRectToScroll(
2334 gfx::Vector2dF editable_offset_from_caret(absolute_element_bounds.offset -
2335 absolute_caret_bounds.offset);
2336 gfx::SizeF editable_size(absolute_element_bounds.size);
2338 if (editable_size.IsEmpty()) {
2342 params->for_focused_editable->relative_location = editable_offset_from_caret;
2343 params->for_focused_editable->size = editable_size;
2345 scroll_into_view_util::ScrollRectToVisible(
2346 *element->GetLayoutObject(), absolute_caret_bounds, std::move(params));
2351 void WebFrameWidgetImpl::ResetMeaningfulLayoutStateForMainFrame() {
2352 MainFrameData& data = main_data();
2353 data.should_dispatch_first_visually_non_empty_layout = true;
2354 data.should_dispatch_first_layout_after_finished_parsing = true;
2355 data.should_dispatch_first_layout_after_finished_loading = true;
2356 data.last_background_color.reset();
2358 #if BUILDFLAG(IS_EFL)
2359 if (widget_base_ && widget_base_->LayerTreeHost())
2360 widget_base_->LayerTreeHost()->ResetMeaningfulLayoutStateForMainFrame();
2364 void WebFrameWidgetImpl::InitializeCompositing(
2365 const display::ScreenInfos& screen_infos,
2366 const cc::LayerTreeSettings* settings) {
2367 InitializeCompositingInternal(screen_infos, settings, nullptr);
2370 void WebFrameWidgetImpl::InitializeCompositingFromPreviousWidget(
2371 const display::ScreenInfos& screen_infos,
2372 const cc::LayerTreeSettings* settings,
2373 WebFrameWidget& previous_widget) {
2374 InitializeCompositingInternal(screen_infos, settings, &previous_widget);
2377 void WebFrameWidgetImpl::InitializeCompositingInternal(
2378 const display::ScreenInfos& screen_infos,
2379 const cc::LayerTreeSettings* settings,
2380 WebFrameWidget* previous_widget) {
2381 DCHECK(View()->does_composite());
2382 DCHECK(!non_composited_client_); // Assure only one initialize is called.
2383 widget_base_->InitializeCompositing(
2384 *GetPage()->GetPageScheduler(), screen_infos, settings,
2385 input_handler_weak_ptr_factory_.GetWeakPtr(),
2386 previous_widget ? static_cast<WebFrameWidgetImpl*>(previous_widget)
2387 ->widget_base_.get()
2390 probe::DidInitializeFrameWidget(local_root_->GetFrame());
2392 // TODO(bokan): This seems wrong. Page may host multiple FrameWidgets so this
2393 // will call DidInitializeCompositing once per FrameWidget. It probably makes
2394 // sense to move LinkHighlight from Page to WidgetBase so initialization is
2395 // per-widget. See also: https://crbug.com/1344531.
2396 GetPage()->DidInitializeCompositing(*AnimationHost());
2399 void WebFrameWidgetImpl::InitializeNonCompositing(
2400 WebNonCompositedWidgetClient* client) {
2401 DCHECK(!non_composited_client_);
2403 DCHECK(!View()->does_composite());
2404 widget_base_->InitializeNonCompositing();
2405 non_composited_client_ = client;
2408 void WebFrameWidgetImpl::SetCompositorVisible(bool visible) {
2409 widget_base_->SetCompositorVisible(visible);
2412 gfx::Size WebFrameWidgetImpl::Size() {
2413 return size_.value_or(gfx::Size());
2416 void WebFrameWidgetImpl::Resize(const gfx::Size& new_size) {
2417 if (size_ && *size_ == new_size)
2420 if (ForMainFrame()) {
2422 View()->Resize(new_size);
2426 if (child_data().did_suspend_parsing) {
2427 child_data().did_suspend_parsing = false;
2428 LocalRootImpl()->GetFrame()->Loader().GetDocumentLoader()->ResumeParser();
2431 LocalFrameView* view = LocalRootImpl()->GetFrameView();
2436 view->SetLayoutSize(*size_);
2437 view->Resize(*size_);
2440 void WebFrameWidgetImpl::OnCommitRequested() {
2441 // This can be called during shutdown, in which case local_root_ will be
2443 if (!LocalRootImpl() || !LocalRootImpl()->GetFrame()) {
2446 if (auto* view = LocalRootImpl()->GetFrame()->View())
2447 view->OnCommitRequested();
2450 void WebFrameWidgetImpl::BeginMainFrame(base::TimeTicks last_frame_time) {
2451 TRACE_EVENT1("blink", "WebFrameWidgetImpl::BeginMainFrame", "frameTime",
2453 DCHECK(!last_frame_time.is_null());
2454 CHECK(LocalRootImpl());
2456 // The last_frame_time is created in the compositor thread, it's the time when
2457 // the compositor is ready for a new frame and starts preparing it. For the
2458 // purpose of animation frame timing, this is the desired time to start
2459 // rendering, equivalent to the time when a work task is posted.
2460 if (animation_frame_timing_monitor_) {
2461 animation_frame_timing_monitor_->SetDesiredRenderStartTime(last_frame_time);
2464 // Dirty bit on MouseEventManager is not cleared in OOPIFs after scroll
2465 // or layout changes. Ensure the hover state is recomputed if necessary.
2469 .RecomputeMouseHoverStateIfNeeded();
2471 absl::optional<LocalFrameUkmAggregator::ScopedUkmHierarchicalTimer> ukm_timer;
2472 if (WidgetBase::ShouldRecordBeginMainFrameMetrics()) {
2474 LocalRootImpl()->GetFrame()->View()->GetUkmAggregator()->GetScopedTimer(
2475 LocalFrameUkmAggregator::kAnimate));
2478 GetPage()->Animate(last_frame_time);
2479 // Animate can cause the local frame to detach.
2480 if (!LocalRootImpl())
2483 GetPage()->GetValidationMessageClient().LayoutOverlay();
2486 void WebFrameWidgetImpl::BeginCommitCompositorFrame() {
2487 if (commit_compositor_frame_start_time_.has_value()) {
2488 next_commit_compositor_frame_start_time_.emplace(base::TimeTicks::Now());
2490 commit_compositor_frame_start_time_.emplace(base::TimeTicks::Now());
2492 GetPage()->GetChromeClient().WillCommitCompositorFrame();
2493 probe::LayerTreePainted(LocalRootImpl()->GetFrame());
2494 if (ForTopMostMainFrame()) {
2495 Document* doc = local_root_->GetFrame()->GetDocument();
2496 if (doc->GetSettings()->GetViewportMetaEnabled() &&
2497 !LayerTreeHost()->IsMobileOptimized()) {
2498 UseCounter::Count(doc, WebFeature::kTapDelayEnabled);
2501 if (ForMainFrame()) {
2502 View()->DidCommitCompositorFrameForLocalMainFrame();
2503 View()->UpdatePreferredSize();
2504 if (!View()->MainFrameImpl()) {
2505 // Trying to track down why the view's idea of the main frame varies
2506 // from LocalRootImpl's.
2507 // TODO(https://crbug.com/1139104): Remove this.
2508 std::string reason = View()->GetNullFrameReasonForBug1139104();
2509 DCHECK(false) << reason;
2510 SCOPED_CRASH_KEY_STRING32("Crbug1139104", "NullFrameReason", reason);
2511 base::debug::DumpWithoutCrashing();
2516 void WebFrameWidgetImpl::EndCommitCompositorFrame(
2517 base::TimeTicks commit_start_time,
2518 base::TimeTicks commit_finish_time) {
2519 DCHECK(commit_compositor_frame_start_time_.has_value());
2523 ->GetUkmAggregator()
2524 ->RecordImplCompositorSample(commit_compositor_frame_start_time_.value(),
2525 commit_start_time, commit_finish_time);
2526 commit_compositor_frame_start_time_ =
2527 next_commit_compositor_frame_start_time_;
2528 next_commit_compositor_frame_start_time_.reset();
2531 void WebFrameWidgetImpl::ApplyViewportChanges(
2532 const ApplyViewportChangesArgs& args) {
2533 // Viewport changes only change the outermost main frame. Technically a
2534 // portal has a viewport but it cannot produce changes from the compositor
2535 // until activated so this should be correct for portals too.
2536 if (!LocalRootImpl()->GetFrame()->IsOutermostMainFrame())
2539 WebViewImpl* web_view = View();
2540 // TODO(https://crbug.com/1160652): Figure out if View is null.
2541 CHECK(widget_base_);
2543 web_view->ApplyViewportChanges(args);
2546 void WebFrameWidgetImpl::RecordManipulationTypeCounts(
2547 cc::ManipulationInfo info) {
2548 // Manipulation counts are only recorded for the main frame.
2549 if (!ForMainFrame())
2552 if ((info & cc::kManipulationInfoWheel) == cc::kManipulationInfoWheel) {
2553 UseCounter::Count(LocalRootImpl()->GetDocument(),
2554 WebFeature::kScrollByWheel);
2556 if ((info & cc::kManipulationInfoTouch) == cc::kManipulationInfoTouch) {
2557 UseCounter::Count(LocalRootImpl()->GetDocument(),
2558 WebFeature::kScrollByTouch);
2560 if ((info & cc::kManipulationInfoPinchZoom) ==
2561 cc::kManipulationInfoPinchZoom) {
2562 UseCounter::Count(LocalRootImpl()->GetDocument(), WebFeature::kPinchZoom);
2564 if ((info & cc::kManipulationInfoPrecisionTouchPad) ==
2565 cc::kManipulationInfoPrecisionTouchPad) {
2566 UseCounter::Count(LocalRootImpl()->GetDocument(),
2567 WebFeature::kScrollByPrecisionTouchPad);
2571 void WebFrameWidgetImpl::RecordDispatchRafAlignedInputTime(
2572 base::TimeTicks raf_aligned_input_start_time) {
2573 if (LocalRootImpl()) {
2574 LocalRootImpl()->GetFrame()->View()->GetUkmAggregator()->RecordTimerSample(
2575 LocalFrameUkmAggregator::kHandleInputEvents,
2576 raf_aligned_input_start_time, base::TimeTicks::Now());
2580 void WebFrameWidgetImpl::SetSuppressFrameRequestsWorkaroundFor704763Only(
2581 bool suppress_frame_requests) {
2582 GetPage()->Animator().SetSuppressFrameRequestsWorkaroundFor704763Only(
2583 suppress_frame_requests);
2586 void WebFrameWidgetImpl::CountDroppedPointerDownForEventTiming(unsigned count) {
2587 if (!local_root_ || !(local_root_->GetFrame()) ||
2588 !(local_root_->GetFrame()->DomWindow())) {
2591 WindowPerformance* performance = DOMWindowPerformance::performance(
2592 *(local_root_->GetFrame()->DomWindow()));
2594 performance->eventCounts()->AddMultipleEvents(event_type_names::kPointerdown,
2596 // We only count dropped touchstart that can trigger pointerdown.
2597 performance->eventCounts()->AddMultipleEvents(event_type_names::kTouchstart,
2599 // TouchEnd will not be dropped. But in touch event model only touch starts
2600 // can set the target and after that the touch event always goes to that
2601 // target. So if a touchstart has been dropped, the following touchend will
2602 // not be dispatched. Meanwhile, the pointerup can be captured in the
2603 // pointer_event_manager.
2604 performance->eventCounts()->AddMultipleEvents(event_type_names::kTouchend,
2608 std::unique_ptr<cc::BeginMainFrameMetrics>
2609 WebFrameWidgetImpl::GetBeginMainFrameMetrics() {
2610 if (!LocalRootImpl())
2613 return LocalRootImpl()
2616 ->GetUkmAggregator()
2617 ->GetBeginMainFrameMetrics();
2620 std::unique_ptr<cc::WebVitalMetrics> WebFrameWidgetImpl::GetWebVitalMetrics() {
2621 if (!LocalRootImpl())
2624 // This class should be called at most once per commit.
2625 WebPerformanceMetricsForReporting perf =
2626 LocalRootImpl()->PerformanceMetricsForReporting();
2627 auto metrics = std::make_unique<cc::WebVitalMetrics>();
2628 if (perf.FirstInputDelay().has_value()) {
2629 metrics->first_input_delay = perf.FirstInputDelay().value();
2630 metrics->has_fid = true;
2633 base::TimeTicks start = perf.NavigationStartAsMonotonicTime();
2634 base::TimeTicks largest_contentful_paint =
2635 perf.LargestContentfulDetailsForMetrics().paint_time;
2636 if (largest_contentful_paint >= start) {
2637 metrics->largest_contentful_paint = largest_contentful_paint - start;
2638 metrics->has_lcp = true;
2641 double layout_shift = LocalRootImpl()
2644 ->GetLayoutShiftTracker()
2646 if (layout_shift > 0.f) {
2647 metrics->layout_shift = layout_shift;
2648 metrics->has_cls = true;
2651 if (!metrics->HasValue())
2657 void WebFrameWidgetImpl::BeginUpdateLayers() {
2658 if (LocalRootImpl())
2659 update_layers_start_time_.emplace(base::TimeTicks::Now());
2662 void WebFrameWidgetImpl::EndUpdateLayers() {
2663 if (LocalRootImpl()) {
2664 DCHECK(update_layers_start_time_);
2665 LocalRootImpl()->GetFrame()->View()->GetUkmAggregator()->RecordTimerSample(
2666 LocalFrameUkmAggregator::kUpdateLayers,
2667 update_layers_start_time_.value(), base::TimeTicks::Now());
2668 probe::LayerTreeDidChange(LocalRootImpl()->GetFrame());
2670 update_layers_start_time_.reset();
2673 void WebFrameWidgetImpl::RecordStartOfFrameMetrics() {
2674 if (!LocalRootImpl())
2677 LocalRootImpl()->GetFrame()->View()->GetUkmAggregator()->BeginMainFrame();
2680 void WebFrameWidgetImpl::RecordEndOfFrameMetrics(
2681 base::TimeTicks frame_begin_time,
2682 cc::ActiveFrameSequenceTrackers trackers) {
2683 if (!LocalRootImpl())
2685 Document* document = LocalRootImpl()->GetFrame()->GetDocument();
2690 ->GetUkmAggregator()
2691 ->RecordEndOfFrameMetrics(frame_begin_time, base::TimeTicks::Now(),
2692 trackers, document->UkmSourceID(),
2693 document->UkmRecorder());
2696 void WebFrameWidgetImpl::WillHandleGestureEvent(const WebGestureEvent& event,
2698 possible_drag_event_info_.source = ui::mojom::blink::DragEventSource::kTouch;
2699 possible_drag_event_info_.location =
2700 gfx::ToFlooredPoint(event.PositionInScreen());
2702 bool handle_as_cursor_control = false;
2703 switch (event.GetType()) {
2704 case WebInputEvent::Type::kGestureScrollBegin: {
2705 if (event.data.scroll_begin.cursor_control) {
2706 swipe_to_move_cursor_activated_ = true;
2707 handle_as_cursor_control = true;
2711 case WebInputEvent::Type::kGestureScrollUpdate: {
2712 if (swipe_to_move_cursor_activated_)
2713 handle_as_cursor_control = true;
2716 case WebInputEvent::Type::kGestureScrollEnd: {
2717 if (swipe_to_move_cursor_activated_) {
2718 swipe_to_move_cursor_activated_ = false;
2719 handle_as_cursor_control = true;
2726 // TODO(crbug.com/1140106): Place cursor for scroll begin other than just move
2728 if (handle_as_cursor_control) {
2729 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
2730 if (focused_frame) {
2731 gfx::Point base(event.PositionInWidget().x(),
2732 event.PositionInWidget().y());
2733 focused_frame->MoveCaretSelection(base);
2739 void WebFrameWidgetImpl::WillHandleMouseEvent(const WebMouseEvent& event) {
2740 possible_drag_event_info_.source = ui::mojom::blink::DragEventSource::kMouse;
2741 possible_drag_event_info_.location =
2742 gfx::Point(event.PositionInScreen().x(), event.PositionInScreen().y());
2745 void WebFrameWidgetImpl::ObserveGestureEventAndResult(
2746 const WebGestureEvent& gesture_event,
2747 const gfx::Vector2dF& unused_delta,
2748 const cc::OverscrollBehavior& overscroll_behavior,
2749 bool event_processed) {
2750 if (!widget_base_->LayerTreeHost()->GetSettings().enable_elastic_overscroll)
2753 cc::InputHandlerScrollResult scroll_result;
2754 scroll_result.did_scroll = event_processed;
2755 scroll_result.did_overscroll_root = !unused_delta.IsZero();
2756 scroll_result.unused_scroll_delta = unused_delta;
2757 scroll_result.overscroll_behavior = overscroll_behavior;
2759 widget_base_->widget_input_handler_manager()->ObserveGestureEventOnMainThread(
2760 gesture_event, scroll_result);
2763 void WebFrameWidgetImpl::DidHandleKeyEvent() {
2764 ClearEditCommands();
2767 WebTextInputType WebFrameWidgetImpl::GetTextInputType() {
2768 if (ShouldDispatchImeEventsToPlugin()) {
2769 return GetFocusedPluginContainer()->GetPluginTextInputType();
2772 WebInputMethodController* controller = GetActiveWebInputMethodController();
2774 return WebTextInputType::kWebTextInputTypeNone;
2775 return controller->TextInputType();
2778 void WebFrameWidgetImpl::SetCursorVisibilityState(bool is_visible) {
2779 GetPage()->SetIsCursorVisible(is_visible);
2782 void WebFrameWidgetImpl::ApplyViewportChangesForTesting(
2783 const ApplyViewportChangesArgs& args) {
2784 widget_base_->ApplyViewportChanges(args);
2787 void WebFrameWidgetImpl::SetDisplayMode(mojom::blink::DisplayMode mode) {
2788 if (mode != display_mode_) {
2789 display_mode_ = mode;
2790 LocalFrame* frame = LocalRootImpl()->GetFrame();
2791 frame->MediaQueryAffectingValueChangedForLocalSubtree(
2792 MediaValueChange::kOther);
2796 void WebFrameWidgetImpl::SetWindowShowState(ui::WindowShowState state) {
2797 if (state == window_show_state_) {
2801 window_show_state_ = state;
2802 LocalFrame* frame = LocalRootImpl()->GetFrame();
2803 frame->MediaQueryAffectingValueChangedForLocalSubtree(
2804 MediaValueChange::kOther);
2807 void WebFrameWidgetImpl::SetResizable(bool resizable) {
2808 if (resizable_ == resizable) {
2812 resizable_ = resizable;
2813 LocalFrame* frame = LocalRootImpl()->GetFrame();
2814 frame->MediaQueryAffectingValueChangedForLocalSubtree(
2815 MediaValueChange::kOther);
2818 void WebFrameWidgetImpl::SetWindowSegments(
2819 const std::vector<gfx::Rect>& window_segments_param) {
2820 WebVector<gfx::Rect> window_segments(window_segments_param);
2821 if (!window_segments_.Equals(window_segments)) {
2822 window_segments_ = window_segments;
2823 LocalFrame* frame = LocalRootImpl()->GetFrame();
2824 frame->WindowSegmentsChanged(window_segments_);
2826 ForEachRemoteFrameControlledByWidget(
2827 [&window_segments = window_segments_param](RemoteFrame* remote_frame) {
2828 remote_frame->DidChangeRootWindowSegments(window_segments);
2833 void WebFrameWidgetImpl::SetCursor(const ui::Cursor& cursor) {
2834 widget_base_->SetCursor(cursor);
2837 bool WebFrameWidgetImpl::HandlingInputEvent() {
2838 return widget_base_->input_handler().handling_input_event();
2841 void WebFrameWidgetImpl::SetHandlingInputEvent(bool handling) {
2842 widget_base_->input_handler().set_handling_input_event(handling);
2845 void WebFrameWidgetImpl::ProcessInputEventSynchronouslyForTesting(
2846 const WebCoalescedInputEvent& event,
2847 WidgetBaseInputHandler::HandledEventCallback callback) {
2848 widget_base_->input_handler().HandleInputEvent(event, nullptr,
2849 std::move(callback));
2852 void WebFrameWidgetImpl::ProcessInputEventSynchronouslyForTesting(
2853 const WebCoalescedInputEvent& event) {
2854 ProcessInputEventSynchronouslyForTesting(event, base::DoNothing());
2857 WebInputEventResult WebFrameWidgetImpl::DispatchBufferedTouchEvents() {
2858 CHECK(LocalRootImpl());
2860 if (WebDevToolsAgentImpl* devtools = LocalRootImpl()->DevToolsAgentImpl())
2861 devtools->DispatchBufferedTouchEvents();
2863 return LocalRootImpl()
2866 .DispatchBufferedTouchEvents();
2869 WebInputEventResult WebFrameWidgetImpl::HandleInputEvent(
2870 const WebCoalescedInputEvent& coalesced_event) {
2871 const WebInputEvent& input_event = coalesced_event.Event();
2872 TRACE_EVENT1("input,rail", "WebFrameWidgetImpl::HandleInputEvent", "type",
2873 WebInputEvent::GetName(input_event.GetType()));
2874 DCHECK(!WebInputEvent::IsTouchEventType(input_event.GetType()));
2875 CHECK(LocalRootImpl());
2877 // Clients shouldn't be dispatching events to a provisional frame but this
2878 // can happen. Ensure that event handling can assume we're in a committed
2880 if (IsProvisional())
2881 return WebInputEventResult::kHandledSuppressed;
2883 // If a drag-and-drop operation is in progress, ignore input events except
2884 // PointerCancel and GestureLongPress.
2885 if (doing_drag_and_drop_ &&
2886 input_event.GetType() != WebInputEvent::Type::kPointerCancel &&
2887 input_event.GetType() != WebInputEvent::Type::kGestureLongPress) {
2888 return WebInputEventResult::kHandledSuppressed;
2891 // Don't handle events once we've started shutting down or when the page is in
2894 GetPage()->GetPageLifecycleState()->is_in_back_forward_cache) {
2895 return WebInputEventResult::kNotHandled;
2898 if (WebDevToolsAgentImpl* devtools = LocalRootImpl()->DevToolsAgentImpl()) {
2899 auto result = devtools->HandleInputEvent(input_event);
2900 if (result != WebInputEventResult::kNotHandled)
2904 // Report the event to be NOT processed by WebKit, so that the browser can
2905 // handle it appropriately.
2906 if (ShouldIgnoreInputEvents()) {
2907 return WebInputEventResult::kNotHandled;
2910 base::AutoReset<const WebInputEvent*> current_event_change(
2911 &CurrentInputEvent::current_input_event_, &input_event);
2912 UIEventWithKeyState::ClearNewTabModifierSetFromIsolatedWorld();
2914 if (GetPage()->GetPointerLockController().IsPointerLocked() &&
2915 WebInputEvent::IsMouseEventType(input_event.GetType())) {
2916 PointerLockMouseEvent(coalesced_event);
2917 return WebInputEventResult::kHandledSystem;
2920 /// These metrics are only captured for the main frame.
2921 if (ForMainFrame()) {
2922 Document& main_frame_document = *LocalRootImpl()->GetFrame()->GetDocument();
2924 if (input_event.GetType() != WebInputEvent::Type::kMouseMove) {
2925 FirstMeaningfulPaintDetector::From(main_frame_document)
2926 .NotifyInputEvent();
2929 if (input_event.GetType() != WebInputEvent::Type::kMouseMove &&
2930 input_event.GetType() != WebInputEvent::Type::kMouseEnter &&
2931 input_event.GetType() != WebInputEvent::Type::kMouseLeave) {
2932 InteractiveDetector* interactive_detector(
2933 InteractiveDetector::From(main_frame_document));
2934 if (interactive_detector) {
2935 interactive_detector->OnInvalidatingInputEvent(input_event.TimeStamp());
2940 NotifyInputObservers(coalesced_event);
2942 // Notify the focus frame of the input. Note that the other frames are not
2943 // notified as input is only handled by the focused frame.
2944 Frame* frame = FocusedCoreFrame();
2945 if (auto* local_frame = DynamicTo<LocalFrame>(frame)) {
2946 if (auto* content_capture_manager =
2947 local_frame->LocalFrameRoot().GetOrResetContentCaptureManager()) {
2948 content_capture_manager->NotifyInputEvent(input_event.GetType(),
2953 // Skip the pointerrawupdate for mouse capture case.
2954 if (mouse_capture_element_ &&
2955 input_event.GetType() == WebInputEvent::Type::kPointerRawUpdate)
2956 return WebInputEventResult::kHandledSystem;
2958 if (mouse_capture_element_ &&
2959 WebInputEvent::IsMouseEventType(input_event.GetType()))
2960 return HandleCapturedMouseEvent(coalesced_event);
2962 // FIXME: This should take in the intended frame, not the local frame
2964 return WidgetEventHandler::HandleInputEvent(coalesced_event,
2965 LocalRootImpl()->GetFrame());
2968 WebInputEventResult WebFrameWidgetImpl::HandleCapturedMouseEvent(
2969 const WebCoalescedInputEvent& coalesced_event) {
2970 const WebInputEvent& input_event = coalesced_event.Event();
2971 TRACE_EVENT1("input", "captured mouse event", "type", input_event.GetType());
2972 // Save |mouse_capture_element_| since |MouseCaptureLost()| will clear it.
2973 HTMLPlugInElement* element = mouse_capture_element_;
2975 // Not all platforms call mouseCaptureLost() directly.
2976 if (input_event.GetType() == WebInputEvent::Type::kMouseUp) {
2977 SetMouseCapture(false);
2981 AtomicString event_type;
2982 switch (input_event.GetType()) {
2983 case WebInputEvent::Type::kMouseEnter:
2984 event_type = event_type_names::kMouseover;
2986 case WebInputEvent::Type::kMouseMove:
2987 event_type = event_type_names::kMousemove;
2989 case WebInputEvent::Type::kPointerRawUpdate:
2990 // There will be no mouse event for rawupdate events.
2991 event_type = event_type_names::kPointerrawupdate;
2993 case WebInputEvent::Type::kMouseLeave:
2994 event_type = event_type_names::kMouseout;
2996 case WebInputEvent::Type::kMouseDown:
2997 event_type = event_type_names::kMousedown;
2998 LocalFrame::NotifyUserActivation(
2999 element->GetDocument().GetFrame(),
3000 mojom::blink::UserActivationNotificationType::kInteraction);
3002 case WebInputEvent::Type::kMouseUp:
3003 event_type = event_type_names::kMouseup;
3009 WebMouseEvent transformed_event =
3010 TransformWebMouseEvent(LocalRootImpl()->GetFrameView(),
3011 static_cast<const WebMouseEvent&>(input_event));
3012 if (LocalFrame* frame = element->GetDocument().GetFrame()) {
3013 frame->GetEventHandler().HandleTargetedMouseEvent(
3014 element, transformed_event, event_type,
3015 TransformWebMouseEventVector(
3016 LocalRootImpl()->GetFrameView(),
3017 coalesced_event.GetCoalescedEventsPointers()),
3018 TransformWebMouseEventVector(
3019 LocalRootImpl()->GetFrameView(),
3020 coalesced_event.GetPredictedEventsPointers()));
3022 return WebInputEventResult::kHandledSystem;
3025 void WebFrameWidgetImpl::UpdateTextInputState() {
3026 widget_base_->UpdateTextInputState();
3029 void WebFrameWidgetImpl::UpdateSelectionBounds() {
3030 widget_base_->UpdateSelectionBounds();
3033 void WebFrameWidgetImpl::ShowVirtualKeyboard() {
3034 widget_base_->ShowVirtualKeyboard();
3037 void WebFrameWidgetImpl::FlushInputProcessedCallback() {
3038 widget_base_->FlushInputProcessedCallback();
3041 void WebFrameWidgetImpl::CancelCompositionForPepper() {
3042 widget_base_->CancelCompositionForPepper();
3045 void WebFrameWidgetImpl::RequestMouseLock(
3046 bool has_transient_user_activation,
3047 bool request_unadjusted_movement,
3048 mojom::blink::WidgetInputHandlerHost::RequestMouseLockCallback callback) {
3049 mojom::blink::WidgetInputHandlerHost* host =
3050 widget_base_->widget_input_handler_manager()->GetWidgetInputHandlerHost();
3052 // If we don't have a host just leave the callback uncalled. This simulates
3053 // the browser indefinitely postponing the mouse request which is valid.
3054 // Note that |callback| is not a mojo bound callback (until it is passed
3055 // into the mojo interface) and can be destructed without invoking the
3056 // callback. It does share the same signature as the mojo definition
3059 host->RequestMouseLock(has_transient_user_activation,
3060 request_unadjusted_movement, std::move(callback));
3064 void WebFrameWidgetImpl::MouseCaptureLost() {
3065 TRACE_EVENT_NESTABLE_ASYNC_END0("input", "capturing mouse",
3066 TRACE_ID_LOCAL(this));
3067 mouse_capture_element_ = nullptr;
3070 void WebFrameWidgetImpl::ApplyVisualProperties(
3071 const VisualProperties& visual_properties) {
3072 widget_base_->UpdateVisualProperties(visual_properties);
3075 bool WebFrameWidgetImpl::IsFullscreenGranted() {
3076 return is_fullscreen_granted_;
3079 bool WebFrameWidgetImpl::PinchGestureActiveInMainFrame() {
3080 return is_pinch_gesture_active_in_mainframe_;
3083 float WebFrameWidgetImpl::PageScaleInMainFrame() {
3084 return page_scale_factor_in_mainframe_;
3087 void WebFrameWidgetImpl::UpdateSurfaceAndScreenInfo(
3088 const viz::LocalSurfaceId& new_local_surface_id,
3089 const gfx::Rect& compositor_viewport_pixel_rect,
3090 const display::ScreenInfos& new_screen_infos) {
3091 widget_base_->UpdateSurfaceAndScreenInfo(
3092 new_local_surface_id, compositor_viewport_pixel_rect, new_screen_infos);
3095 void WebFrameWidgetImpl::UpdateScreenInfo(
3096 const display::ScreenInfos& new_screen_infos) {
3097 widget_base_->UpdateScreenInfo(new_screen_infos);
3100 void WebFrameWidgetImpl::UpdateSurfaceAndCompositorRect(
3101 const viz::LocalSurfaceId& new_local_surface_id,
3102 const gfx::Rect& compositor_viewport_pixel_rect) {
3103 widget_base_->UpdateSurfaceAndCompositorRect(new_local_surface_id,
3104 compositor_viewport_pixel_rect);
3107 void WebFrameWidgetImpl::UpdateCompositorViewportRect(
3108 const gfx::Rect& compositor_viewport_pixel_rect) {
3109 widget_base_->UpdateCompositorViewportRect(compositor_viewport_pixel_rect);
3112 const display::ScreenInfo& WebFrameWidgetImpl::GetScreenInfo() {
3113 return widget_base_->GetScreenInfo();
3116 const display::ScreenInfos& WebFrameWidgetImpl::GetScreenInfos() {
3117 return widget_base_->screen_infos();
3120 const display::ScreenInfo& WebFrameWidgetImpl::GetOriginalScreenInfo() {
3121 if (device_emulator_)
3122 return device_emulator_->GetOriginalScreenInfo();
3123 return widget_base_->GetScreenInfo();
3126 const display::ScreenInfos& WebFrameWidgetImpl::GetOriginalScreenInfos() {
3127 if (device_emulator_)
3128 return device_emulator_->original_screen_infos();
3129 return widget_base_->screen_infos();
3132 gfx::Rect WebFrameWidgetImpl::WindowRect() {
3133 return widget_base_->WindowRect();
3136 gfx::Rect WebFrameWidgetImpl::ViewRect() {
3137 return widget_base_->ViewRect();
3140 void WebFrameWidgetImpl::SetScreenRects(const gfx::Rect& widget_screen_rect,
3141 const gfx::Rect& window_screen_rect) {
3142 widget_base_->SetScreenRects(widget_screen_rect, window_screen_rect);
3145 gfx::Size WebFrameWidgetImpl::VisibleViewportSizeInDIPs() {
3146 return widget_base_->VisibleViewportSizeInDIPs();
3149 void WebFrameWidgetImpl::SetPendingWindowRect(
3150 const gfx::Rect& window_screen_rect) {
3151 widget_base_->SetPendingWindowRect(window_screen_rect);
3154 void WebFrameWidgetImpl::AckPendingWindowRect() {
3155 widget_base_->AckPendingWindowRect();
3158 bool WebFrameWidgetImpl::IsHidden() const {
3159 return widget_base_->is_hidden();
3162 WebString WebFrameWidgetImpl::GetLastToolTipTextForTesting() const {
3163 return GetPage()->GetChromeClient().GetLastToolTipTextForTesting();
3166 float WebFrameWidgetImpl::GetEmulatorScale() {
3167 if (device_emulator_)
3168 return device_emulator_->scale();
3172 void WebFrameWidgetImpl::IntrinsicSizingInfoChanged(
3173 mojom::blink::IntrinsicSizingInfoPtr sizing_info) {
3174 DCHECK(ForSubframe());
3175 GetAssociatedFrameWidgetHost()->IntrinsicSizingInfoChanged(
3176 std::move(sizing_info));
3179 void WebFrameWidgetImpl::AutoscrollStart(const gfx::PointF& position) {
3180 GetAssociatedFrameWidgetHost()->AutoscrollStart(std::move(position));
3183 void WebFrameWidgetImpl::AutoscrollFling(const gfx::Vector2dF& velocity) {
3184 GetAssociatedFrameWidgetHost()->AutoscrollFling(std::move(velocity));
3187 void WebFrameWidgetImpl::AutoscrollEnd() {
3188 GetAssociatedFrameWidgetHost()->AutoscrollEnd();
3191 void WebFrameWidgetImpl::DidMeaningfulLayout(WebMeaningfulLayout layout_type) {
3192 if (layout_type == blink::WebMeaningfulLayout::kVisuallyNonEmpty) {
3193 NotifyPresentationTime(WTF::BindOnce(
3194 &WebFrameWidgetImpl::PresentationCallbackForMeaningfulLayout,
3195 WrapWeakPersistent(this)));
3198 #if BUILDFLAG(IS_EFL)
3199 if (widget_base_ && widget_base_->LayerTreeHost()) {
3200 if (layout_type == blink::WebMeaningfulLayout::kVisuallyNonEmpty)
3201 widget_base_->LayerTreeHost()->SetDidFirstNonEmptyLayout();
3202 else if (layout_type == blink::WebMeaningfulLayout::kFinishedParsing)
3203 widget_base_->LayerTreeHost()->SetDidFinishDocumentParsing();
3207 ForEachLocalFrameControlledByWidget(
3208 local_root_->GetFrame(), [layout_type](WebLocalFrameImpl* local_frame) {
3209 local_frame->Client()->DidMeaningfulLayout(layout_type);
3213 void WebFrameWidgetImpl::PresentationCallbackForMeaningfulLayout(
3214 base::TimeTicks first_paint_time) {
3215 // |local_root_| may be null if the widget has shut down between when this
3216 // callback was requested and when it was resolved by the compositor.
3218 local_root_->ViewImpl()->DidFirstVisuallyNonEmptyPaint();
3221 widget_base_->DidFirstVisuallyNonEmptyPaint(first_paint_time);
3223 #if BUILDFLAG(IS_EFL)
3224 if (widget_base_ && widget_base_->LayerTreeHost())
3225 widget_base_->LayerTreeHost()->SetDidTriggerFirstNonEmptyLayoutPaint();
3229 void WebFrameWidgetImpl::RequestAnimationAfterDelay(
3230 const base::TimeDelta& delay) {
3231 widget_base_->RequestAnimationAfterDelay(delay);
3234 void WebFrameWidgetImpl::SetRootLayer(scoped_refptr<cc::Layer> layer) {
3235 if (!View()->does_composite()) {
3236 DCHECK(ForMainFrame());
3241 // Set up some initial state before we are setting the layer.
3242 if (ForSubframe() && layer) {
3243 // Child local roots will always have a transparent background color.
3244 widget_base_->LayerTreeHost()->set_background_color(SkColors::kTransparent);
3245 // Pass the limits even though this is for subframes, as the limits will
3246 // be needed in setting the raster scale.
3247 SetPageScaleStateAndLimits(1.f, false /* is_pinch_gesture_active */,
3248 View()->MinimumPageScaleFactor(),
3249 View()->MaximumPageScaleFactor());
3252 bool root_layer_exists = !!layer;
3253 if (widget_base_->WillBeDestroyed()) {
3256 widget_base_->LayerTreeHost()->SetRootLayer(std::move(layer));
3259 // Notify the WebView that we did set a layer.
3260 if (ForMainFrame()) {
3261 View()->DidChangeRootLayer(root_layer_exists);
3265 base::WeakPtr<AnimationWorkletMutatorDispatcherImpl>
3266 WebFrameWidgetImpl::EnsureCompositorMutatorDispatcher(
3267 scoped_refptr<base::SingleThreadTaskRunner> mutator_task_runner) {
3268 if (!mutator_task_runner_) {
3269 mutator_task_runner_ = std::move(mutator_task_runner);
3270 widget_base_->LayerTreeHost()->SetLayerTreeMutator(
3271 AnimationWorkletMutatorDispatcherImpl::CreateCompositorThreadClient(
3272 mutator_dispatcher_, mutator_task_runner_));
3275 DCHECK(mutator_task_runner_);
3276 return mutator_dispatcher_;
3279 HitTestResult WebFrameWidgetImpl::CoreHitTestResultAt(
3280 const gfx::PointF& point_in_viewport) {
3281 LocalFrameView* view = LocalRootImpl()->GetFrameView();
3282 gfx::PointF point_in_root_frame(view->ViewportToFrame(point_in_viewport));
3283 return HitTestResultForRootFramePos(point_in_root_frame);
3286 cc::AnimationHost* WebFrameWidgetImpl::AnimationHost() const {
3287 return widget_base_->AnimationHost();
3290 cc::AnimationTimeline* WebFrameWidgetImpl::ScrollAnimationTimeline() const {
3291 return widget_base_->ScrollAnimationTimeline();
3294 base::WeakPtr<PaintWorkletPaintDispatcher>
3295 WebFrameWidgetImpl::EnsureCompositorPaintDispatcher(
3296 scoped_refptr<base::SingleThreadTaskRunner>* paint_task_runner) {
3297 // We check paint_task_runner_ not paint_dispatcher_ because the dispatcher is
3298 // a base::WeakPtr that should only be used on the compositor thread.
3299 if (!paint_task_runner_) {
3300 widget_base_->LayerTreeHost()->SetPaintWorkletLayerPainter(
3301 PaintWorkletPaintDispatcher::CreateCompositorThreadPainter(
3302 &paint_dispatcher_));
3303 paint_task_runner_ = Thread::CompositorThread()->GetTaskRunner();
3305 DCHECK(paint_task_runner_);
3306 *paint_task_runner = paint_task_runner_;
3307 return paint_dispatcher_;
3310 void WebFrameWidgetImpl::SetDelegatedInkMetadata(
3311 std::unique_ptr<gfx::DelegatedInkMetadata> metadata) {
3312 widget_base_->LayerTreeHost()->SetDelegatedInkMetadata(std::move(metadata));
3315 // Enables measuring and reporting both presentation times and swap times in
3317 class ReportTimeSwapPromise : public cc::SwapPromise {
3319 ReportTimeSwapPromise(WebFrameWidgetImpl::PromiseCallbacks callbacks,
3320 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
3321 WebFrameWidgetImpl* widget)
3322 : promise_callbacks_(std::move(callbacks)),
3323 task_runner_(std::move(task_runner)),
3324 widget_(MakeCrossThreadWeakHandle(widget)) {}
3326 ReportTimeSwapPromise(const ReportTimeSwapPromise&) = delete;
3327 ReportTimeSwapPromise& operator=(const ReportTimeSwapPromise&) = delete;
3329 ~ReportTimeSwapPromise() override = default;
3331 void DidActivate() override {}
3333 void WillSwap(viz::CompositorFrameMetadata* metadata) override {
3334 DCHECK_GT(metadata->frame_token, 0u);
3335 // The interval between the current swap and its presentation time is
3336 // reported in UMA (see corresponding code in DidSwap() below).
3337 frame_token_ = metadata->frame_token;
3340 void DidSwap() override {
3341 DCHECK_GT(frame_token_, 0u);
3342 PostCrossThreadTask(
3343 *task_runner_, FROM_HERE,
3344 CrossThreadBindOnce(&RunCallbackAfterSwap,
3345 MakeUnwrappingCrossThreadWeakHandle(widget_),
3346 base::TimeTicks::Now(),
3347 std::move(promise_callbacks_), frame_token_));
3350 DidNotSwapAction DidNotSwap(DidNotSwapReason reason,
3351 base::TimeTicks timestamp) override {
3352 if (reason != DidNotSwapReason::SWAP_FAILS &&
3353 reason != DidNotSwapReason::COMMIT_NO_UPDATE) {
3354 return DidNotSwapAction::KEEP_ACTIVE;
3357 DidNotSwapAction action = DidNotSwapAction::BREAK_PROMISE;
3358 WebFrameWidgetImpl::PromiseCallbacks promise_callbacks_on_failure = {
3359 .swap_time_callback = std::move(promise_callbacks_.swap_time_callback),
3360 .presentation_time_callback =
3361 std::move(promise_callbacks_.presentation_time_callback)};
3363 #if BUILDFLAG(IS_APPLE)
3364 if (reason == DidNotSwapReason::COMMIT_FAILS &&
3365 promise_callbacks_.core_animation_error_code_callback) {
3366 action = DidNotSwapAction::KEEP_ACTIVE;
3368 promise_callbacks_on_failure.core_animation_error_code_callback =
3369 std::move(promise_callbacks_.core_animation_error_code_callback);
3373 if (!promise_callbacks_on_failure.IsEmpty()) {
3374 ReportSwapAndPresentationFailureOnTaskRunner(
3375 task_runner_, std::move(promise_callbacks_on_failure), timestamp);
3380 int64_t GetTraceId() const override { return 0; }
3383 static void RunCallbackAfterSwap(
3384 WebFrameWidgetImpl* widget,
3385 base::TimeTicks swap_time,
3386 WebFrameWidgetImpl::PromiseCallbacks callbacks,
3388 // If the widget was collected or the widget wasn't collected yet, but
3389 // it was closed don't schedule a presentation callback.
3390 if (widget && widget->widget_base_) {
3391 widget->widget_base_->AddPresentationCallback(
3393 WTF::BindOnce(&RunCallbackAfterPresentation,
3394 std::move(callbacks.presentation_time_callback),
3396 ReportTime(std::move(callbacks.swap_time_callback), swap_time);
3398 #if BUILDFLAG(IS_APPLE)
3399 if (callbacks.core_animation_error_code_callback) {
3400 widget->widget_base_->AddCoreAnimationErrorCodeCallback(
3402 std::move(callbacks.core_animation_error_code_callback));
3406 ReportTime(std::move(callbacks.swap_time_callback), swap_time);
3407 ReportTime(std::move(callbacks.presentation_time_callback), swap_time);
3408 #if BUILDFLAG(IS_APPLE)
3409 ReportErrorCode(std::move(callbacks.core_animation_error_code_callback),
3410 gfx::kCALayerUnknownNoWidget);
3415 static void RunCallbackAfterPresentation(
3416 base::OnceCallback<void(base::TimeTicks)> presentation_time_callback,
3417 base::TimeTicks swap_time,
3418 base::TimeTicks presentation_time) {
3419 DCHECK(!swap_time.is_null());
3420 bool presentation_time_is_valid =
3421 !presentation_time.is_null() && (presentation_time > swap_time);
3422 UMA_HISTOGRAM_BOOLEAN("PageLoad.Internal.Renderer.PresentationTime.Valid",
3423 presentation_time_is_valid);
3424 ReportTime(std::move(presentation_time_callback),
3425 presentation_time_is_valid ? presentation_time : swap_time);
3428 static void ReportTime(base::OnceCallback<void(base::TimeTicks)> callback,
3429 base::TimeTicks time) {
3431 std::move(callback).Run(time);
3434 #if BUILDFLAG(IS_APPLE)
3435 static void ReportErrorCode(
3436 base::OnceCallback<void(gfx::CALayerResult)> callback,
3437 gfx::CALayerResult error_code) {
3439 std::move(callback).Run(error_code);
3443 static void ReportSwapAndPresentationFailureOnTaskRunner(
3444 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
3445 WebFrameWidgetImpl::PromiseCallbacks callbacks,
3446 base::TimeTicks failure_time) {
3447 if (!task_runner->BelongsToCurrentThread()) {
3448 PostCrossThreadTask(
3449 *task_runner, FROM_HERE,
3450 CrossThreadBindOnce(&ReportSwapAndPresentationFailureOnTaskRunner,
3451 task_runner, std::move(callbacks), failure_time));
3455 ReportTime(std::move(callbacks.swap_time_callback), failure_time);
3456 ReportTime(std::move(callbacks.presentation_time_callback), failure_time);
3457 #if BUILDFLAG(IS_APPLE)
3458 ReportErrorCode(std::move(callbacks.core_animation_error_code_callback),
3459 gfx::kCALayerUnknownDidNotSwap);
3463 WebFrameWidgetImpl::PromiseCallbacks promise_callbacks_;
3465 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
3466 CrossThreadWeakHandle<WebFrameWidgetImpl> widget_;
3467 uint32_t frame_token_ = 0;
3470 void WebFrameWidgetImpl::NotifySwapAndPresentationTimeForTesting(
3471 PromiseCallbacks callbacks) {
3472 NotifySwapAndPresentationTime(std::move(callbacks));
3475 void WebFrameWidgetImpl::NotifyPresentationTimeInBlink(
3476 base::OnceCallback<void(base::TimeTicks)> presentation_callback) {
3477 NotifySwapAndPresentationTime(
3478 {.presentation_time_callback = std::move(presentation_callback)});
3481 void WebFrameWidgetImpl::NotifyPresentationTime(
3482 base::OnceCallback<void(base::TimeTicks)> presentation_callback) {
3483 NotifySwapAndPresentationTime(
3484 {.presentation_time_callback = std::move(presentation_callback)});
3487 #if BUILDFLAG(IS_APPLE)
3488 void WebFrameWidgetImpl::NotifyCoreAnimationErrorCode(
3489 base::OnceCallback<void(gfx::CALayerResult)>
3490 core_animation_error_code_callback) {
3491 NotifySwapAndPresentationTime(
3492 {.core_animation_error_code_callback =
3493 std::move(core_animation_error_code_callback)});
3497 void WebFrameWidgetImpl::NotifySwapAndPresentationTime(
3498 PromiseCallbacks callbacks) {
3499 if (!View()->does_composite())
3502 widget_base_->LayerTreeHost()->QueueSwapPromise(
3503 std::make_unique<ReportTimeSwapPromise>(std::move(callbacks),
3504 widget_base_->LayerTreeHost()
3505 ->GetTaskRunnerProvider()
3506 ->MainThreadTaskRunner(),
3510 void WebFrameWidgetImpl::WaitForDebuggerWhenShown() {
3511 local_root_->WaitForDebuggerWhenShown();
3514 void WebFrameWidgetImpl::SetTextZoomFactor(float text_zoom_factor) {
3515 local_root_->GetFrame()->SetTextZoomFactor(text_zoom_factor);
3518 float WebFrameWidgetImpl::TextZoomFactor() {
3519 return local_root_->GetFrame()->TextZoomFactor();
3522 void WebFrameWidgetImpl::SetMainFrameOverlayColor(SkColor color) {
3523 DCHECK(!local_root_->Parent());
3524 local_root_->GetFrame()->SetMainFrameColorOverlay(color);
3527 void WebFrameWidgetImpl::AddEditCommandForNextKeyEvent(const WebString& name,
3528 const WebString& value) {
3529 edit_commands_.push_back(mojom::blink::EditCommand::New(name, value));
3532 bool WebFrameWidgetImpl::HandleCurrentKeyboardEvent() {
3533 if (edit_commands_.empty()) {
3536 WebLocalFrame* frame = FocusedWebLocalFrameInWidget();
3538 frame = local_root_;
3539 bool did_execute_command = false;
3540 // Executing an edit command can run JS and we can end up reassigning
3541 // `edit_commands_` so move it to a stack variable before iterating on it.
3542 Vector<mojom::blink::EditCommandPtr> edit_commands =
3543 std::move(edit_commands_);
3544 for (const auto& command : edit_commands) {
3545 // In gtk and cocoa, it's possible to bind multiple edit commands to one
3546 // key (but it's the exception). Once one edit command is not executed, it
3547 // seems safest to not execute the rest.
3548 if (!frame->ExecuteCommand(command->name, command->value))
3550 did_execute_command = true;
3553 return did_execute_command;
3556 void WebFrameWidgetImpl::ClearEditCommands() {
3557 edit_commands_ = Vector<mojom::blink::EditCommandPtr>();
3560 WebTextInputInfo WebFrameWidgetImpl::TextInputInfo() {
3561 WebInputMethodController* controller = GetActiveWebInputMethodController();
3563 return WebTextInputInfo();
3564 return controller->TextInputInfo();
3567 ui::mojom::blink::VirtualKeyboardVisibilityRequest
3568 WebFrameWidgetImpl::GetLastVirtualKeyboardVisibilityRequest() {
3569 WebInputMethodController* controller = GetActiveWebInputMethodController();
3571 return ui::mojom::blink::VirtualKeyboardVisibilityRequest::NONE;
3572 return controller->GetLastVirtualKeyboardVisibilityRequest();
3575 bool WebFrameWidgetImpl::ShouldSuppressKeyboardForFocusedElement() {
3576 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
3579 return focused_frame->ShouldSuppressKeyboardForFocusedElement();
3582 void WebFrameWidgetImpl::GetEditContextBoundsInWindow(
3583 absl::optional<gfx::Rect>* edit_context_control_bounds,
3584 absl::optional<gfx::Rect>* edit_context_selection_bounds) {
3585 WebInputMethodController* controller = GetActiveWebInputMethodController();
3588 gfx::Rect control_bounds;
3589 gfx::Rect selection_bounds;
3590 controller->GetLayoutBounds(&control_bounds, &selection_bounds);
3591 *edit_context_control_bounds =
3592 widget_base_->BlinkSpaceToEnclosedDIPs(control_bounds);
3593 if (controller->IsEditContextActive()) {
3594 *edit_context_selection_bounds =
3595 widget_base_->BlinkSpaceToEnclosedDIPs(selection_bounds);
3599 int32_t WebFrameWidgetImpl::ComputeWebTextInputNextPreviousFlags() {
3600 WebInputMethodController* controller = GetActiveWebInputMethodController();
3603 return controller->ComputeWebTextInputNextPreviousFlags();
3606 void WebFrameWidgetImpl::ResetVirtualKeyboardVisibilityRequest() {
3607 WebInputMethodController* controller = GetActiveWebInputMethodController();
3610 controller->SetVirtualKeyboardVisibilityRequest(
3611 ui::mojom::blink::VirtualKeyboardVisibilityRequest::NONE);
3615 bool WebFrameWidgetImpl::GetSelectionBoundsInWindow(
3618 gfx::Rect* bounding_box,
3619 base::i18n::TextDirection* focus_dir,
3620 base::i18n::TextDirection* anchor_dir,
3621 bool* is_anchor_first) {
3622 if (ShouldDispatchImeEventsToPlugin()) {
3623 // TODO(kinaba) http://crbug.com/101101
3624 // Current Pepper IME API does not handle selection bounds. So we simply
3625 // use the caret position as an empty range for now. It will be updated
3626 // after Pepper API equips features related to surrounding text retrieval.
3627 gfx::Rect pepper_caret_in_dips = widget_base_->BlinkSpaceToEnclosedDIPs(
3628 GetFocusedPluginContainer()->GetPluginCaretBounds());
3629 if (pepper_caret_in_dips == *focus && pepper_caret_in_dips == *anchor)
3631 *focus = pepper_caret_in_dips;
3635 gfx::Rect focus_root_frame;
3636 gfx::Rect anchor_root_frame;
3637 gfx::Rect bounding_box_root_frame;
3638 CalculateSelectionBounds(focus_root_frame, anchor_root_frame,
3639 &bounding_box_root_frame);
3640 gfx::Rect focus_rect_in_dips =
3641 widget_base_->BlinkSpaceToEnclosedDIPs(gfx::Rect(focus_root_frame));
3642 gfx::Rect anchor_rect_in_dips =
3643 widget_base_->BlinkSpaceToEnclosedDIPs(gfx::Rect(anchor_root_frame));
3644 gfx::Rect bounding_box_in_dips = widget_base_->BlinkSpaceToEnclosedDIPs(
3645 gfx::Rect(bounding_box_root_frame));
3647 // if the bounds are the same return false.
3648 if (focus_rect_in_dips == *focus && anchor_rect_in_dips == *anchor)
3650 *focus = focus_rect_in_dips;
3651 *anchor = anchor_rect_in_dips;
3652 *bounding_box = bounding_box_in_dips;
3654 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
3657 focused_frame->SelectionTextDirection(*focus_dir, *anchor_dir);
3658 *is_anchor_first = focused_frame->IsSelectionAnchorFirst();
3662 void WebFrameWidgetImpl::ClearTextInputState() {
3663 widget_base_->ClearTextInputState();
3666 bool WebFrameWidgetImpl::IsPasting() {
3667 return widget_base_->is_pasting();
3670 bool WebFrameWidgetImpl::HandlingSelectRange() {
3671 return widget_base_->handling_select_range();
3674 void WebFrameWidgetImpl::SetFocus(bool focus) {
3675 widget_base_->SetFocus(
3676 focus ? mojom::blink::FocusState::kFocused
3677 : View()->IsActive()
3678 ? mojom::blink::FocusState::kNotFocusedAndActive
3679 : mojom::blink::FocusState::kNotFocusedAndNotActive);
3682 bool WebFrameWidgetImpl::HasFocus() {
3683 return widget_base_->has_focus();
3686 void WebFrameWidgetImpl::UpdateTooltipUnderCursor(const String& tooltip_text,
3687 TextDirection dir) {
3688 widget_base_->UpdateTooltipUnderCursor(tooltip_text, dir);
3691 void WebFrameWidgetImpl::UpdateTooltipFromKeyboard(const String& tooltip_text,
3693 const gfx::Rect& bounds) {
3694 widget_base_->UpdateTooltipFromKeyboard(tooltip_text, dir, bounds);
3697 void WebFrameWidgetImpl::ClearKeyboardTriggeredTooltip() {
3698 widget_base_->ClearKeyboardTriggeredTooltip();
3701 void WebFrameWidgetImpl::DidOverscroll(
3702 const gfx::Vector2dF& overscroll_delta,
3703 const gfx::Vector2dF& accumulated_overscroll,
3704 const gfx::PointF& position,
3705 const gfx::Vector2dF& velocity) {
3706 #if BUILDFLAG(IS_MAC)
3707 // On OSX the user can disable the elastic overscroll effect. If that's the
3708 // case, don't forward the overscroll notification.
3709 if (!widget_base_->LayerTreeHost()->GetSettings().enable_elastic_overscroll)
3713 cc::OverscrollBehavior overscroll_behavior =
3714 widget_base_->LayerTreeHost()->overscroll_behavior();
3715 if (!widget_base_->input_handler().DidOverscrollFromBlink(
3716 overscroll_delta, accumulated_overscroll, position, velocity,
3717 overscroll_behavior))
3720 // If we're currently handling an event, stash the overscroll data such that
3721 // it can be bundled in the event ack.
3722 if (mojom::blink::WidgetInputHandlerHost* host =
3723 widget_base_->widget_input_handler_manager()
3724 ->GetWidgetInputHandlerHost()) {
3725 host->DidOverscroll(mojom::blink::DidOverscrollParams::New(
3726 accumulated_overscroll, overscroll_delta, velocity, position,
3727 overscroll_behavior));
3731 void WebFrameWidgetImpl::InjectScrollbarGestureScroll(
3732 const gfx::Vector2dF& delta,
3733 ui::ScrollGranularity granularity,
3734 cc::ElementId scrollable_area_element_id,
3735 blink::WebInputEvent::Type injected_type) {
3736 // create a GestureScroll Event and post it to the compositor thread
3737 // TODO(crbug.com/1126098) use original input event's timestamp.
3738 // TODO(crbug.com/1082590) ensure continuity in scroll metrics collection
3739 base::TimeTicks now = base::TimeTicks::Now();
3740 std::unique_ptr<WebGestureEvent> gesture_event =
3741 WebGestureEvent::GenerateInjectedScrollbarGestureScroll(
3742 injected_type, now, gfx::PointF(0, 0), delta, granularity);
3743 if (injected_type == WebInputEvent::Type::kGestureScrollBegin) {
3744 gesture_event->data.scroll_begin.scrollable_area_element_id =
3745 scrollable_area_element_id.GetInternalValue();
3746 gesture_event->data.scroll_begin.main_thread_hit_tested_reasons =
3747 cc::MainThreadScrollingReason::kScrollbarScrolling;
3750 // Notifies TestWebFrameWidget of the injected event. Does nothing outside
3751 // of unit tests. This would happen in WidgetBase::QueueSyntheticEvent if
3752 // scroll unification were not enabled.
3753 WillQueueSyntheticEvent(
3754 WebCoalescedInputEvent(*gesture_event, ui::LatencyInfo()));
3756 widget_base_->widget_input_handler_manager()
3757 ->DispatchScrollGestureToCompositor(std::move(gesture_event));
3760 void WebFrameWidgetImpl::DidChangeCursor(const ui::Cursor& cursor) {
3761 widget_base_->SetCursor(cursor);
3764 bool WebFrameWidgetImpl::SetComposition(
3766 const Vector<ui::ImeTextSpan>& ime_text_spans,
3767 const gfx::Range& replacement_range,
3768 int selection_start,
3769 int selection_end) {
3770 WebInputMethodController* controller = GetActiveWebInputMethodController();
3774 return controller->SetComposition(
3775 text, ime_text_spans,
3776 replacement_range.IsValid()
3777 ? WebRange(base::checked_cast<int>(replacement_range.start()),
3778 base::checked_cast<int>(replacement_range.length()))
3780 selection_start, selection_end);
3783 void WebFrameWidgetImpl::CommitText(
3785 const Vector<ui::ImeTextSpan>& ime_text_spans,
3786 const gfx::Range& replacement_range,
3787 int relative_cursor_pos) {
3788 WebInputMethodController* controller = GetActiveWebInputMethodController();
3791 controller->CommitText(
3792 text, ime_text_spans,
3793 replacement_range.IsValid()
3794 ? WebRange(base::checked_cast<int>(replacement_range.start()),
3795 base::checked_cast<int>(replacement_range.length()))
3797 relative_cursor_pos);
3800 void WebFrameWidgetImpl::FinishComposingText(bool keep_selection) {
3801 WebInputMethodController* controller = GetActiveWebInputMethodController();
3804 controller->FinishComposingText(
3805 keep_selection ? WebInputMethodController::kKeepSelection
3806 : WebInputMethodController::kDoNotKeepSelection);
3809 bool WebFrameWidgetImpl::IsProvisional() {
3810 return LocalRoot()->IsProvisional();
3813 cc::ElementId WebFrameWidgetImpl::GetScrollableContainerIdAt(
3814 const gfx::PointF& point) {
3815 gfx::PointF hit_test_point = point;
3816 LocalFrameView* view = LocalRootImpl()->GetFrameView();
3817 hit_test_point.Scale(1 / view->InputEventsScaleFactor());
3818 return HitTestResultForRootFramePos(hit_test_point).GetScrollableContainer();
3821 bool WebFrameWidgetImpl::ShouldHandleImeEvents() {
3822 if (ForMainFrame()) {
3825 // TODO(ekaramad): main frame widget returns true only if it has focus.
3826 // We track page focus in all WebViews on the page but the WebFrameWidgets
3827 // corresponding to child local roots do not get the update. For now, this
3828 // method returns true when the WebFrameWidget is for a child local frame,
3829 // i.e., IME events will be processed regardless of page focus. We should
3830 // revisit this after page focus for OOPIFs has been fully resolved
3831 // (https://crbug.com/689777).
3832 return LocalRootImpl();
3836 void WebFrameWidgetImpl::SetEditCommandsForNextKeyEvent(
3837 Vector<mojom::blink::EditCommandPtr> edit_commands) {
3838 edit_commands_ = std::move(edit_commands);
3841 void WebFrameWidgetImpl::FocusChangeComplete() {
3842 blink::WebLocalFrame* focused = LocalRoot()->View()->FocusedFrame();
3844 if (focused && focused->AutofillClient())
3845 focused->AutofillClient()->DidCompleteFocusChangeInFrame();
3848 void WebFrameWidgetImpl::ShowVirtualKeyboardOnElementFocus() {
3849 widget_base_->ShowVirtualKeyboardOnElementFocus();
3852 #if BUILDFLAG(IS_EFL)
3853 void WebFrameWidgetImpl::DidUpdateTextOfFocusedElementByNonUserInput() {
3854 widget_base_->DidUpdateTextOfFocusedElementByNonUserInput();
3857 void WebFrameWidgetImpl::ProcessTouchAction(WebTouchAction touch_action) {
3858 widget_base_->ProcessTouchAction(touch_action);
3861 void WebFrameWidgetImpl::SetPanAction(mojom::blink::PanAction pan_action) {
3862 if (!widget_base_->widget_input_handler_manager())
3864 mojom::blink::WidgetInputHandlerHost* host =
3865 widget_base_->widget_input_handler_manager()->GetWidgetInputHandlerHost();
3868 host->SetPanAction(pan_action);
3871 void WebFrameWidgetImpl::DidHandleGestureEvent(const WebGestureEvent& event) {
3872 #if BUILDFLAG(IS_ANDROID) || defined(USE_AURA) || BUILDFLAG(IS_IOS)
3873 if (event.GetType() == WebInputEvent::Type::kGestureTap) {
3874 widget_base_->ShowVirtualKeyboard();
3875 } else if (event.GetType() == WebInputEvent::Type::kGestureLongPress) {
3876 WebInputMethodController* controller = GetActiveWebInputMethodController();
3877 if (!controller || controller->TextInputInfo().value.IsEmpty())
3878 widget_base_->UpdateTextInputState();
3880 widget_base_->ShowVirtualKeyboard();
3882 #elif BUILDFLAG(IS_EFL)
3886 if ((event.GetType() == WebInputEvent::Type::kGestureTap) ||
3887 (event.GetType() == WebInputEvent::Type::kGestureLongPress)) {
3888 widget_base_->ShowVirtualKeyboard();
3893 void WebFrameWidgetImpl::SetHasPointerRawUpdateEventHandlers(
3894 bool has_handlers) {
3895 widget_base_->widget_input_handler_manager()
3896 ->input_event_queue()
3897 ->HasPointerRawUpdateEventHandlers(has_handlers);
3900 void WebFrameWidgetImpl::SetNeedsLowLatencyInput(bool needs_low_latency) {
3901 widget_base_->widget_input_handler_manager()
3902 ->input_event_queue()
3903 ->SetNeedsLowLatency(needs_low_latency);
3906 void WebFrameWidgetImpl::RequestUnbufferedInputEvents() {
3907 widget_base_->widget_input_handler_manager()
3908 ->input_event_queue()
3909 ->RequestUnbufferedInputEvents();
3912 void WebFrameWidgetImpl::SetNeedsUnbufferedInputForDebugger(bool unbuffered) {
3913 widget_base_->widget_input_handler_manager()
3914 ->input_event_queue()
3915 ->SetNeedsUnbufferedInputForDebugger(unbuffered);
3918 void WebFrameWidgetImpl::DidNavigate() {
3919 // The input handler wants to know about navigation so that it can
3920 // suppress input until the newly navigated page has a committed frame.
3921 // It also resets the state for UMA reporting of input arrival with respect
3922 // to document lifecycle.
3923 if (!widget_base_->widget_input_handler_manager())
3925 widget_base_->widget_input_handler_manager()->DidNavigate();
3928 void WebFrameWidgetImpl::FlushInputForTesting(base::OnceClosure done_callback) {
3929 widget_base_->widget_input_handler_manager()->FlushEventQueuesForTesting(
3930 std::move(done_callback));
3933 void WebFrameWidgetImpl::SetMouseCapture(bool capture) {
3934 if (mojom::blink::WidgetInputHandlerHost* host =
3935 widget_base_->widget_input_handler_manager()
3936 ->GetWidgetInputHandlerHost()) {
3937 host->SetMouseCapture(capture);
3941 gfx::Range WebFrameWidgetImpl::CompositionRange() {
3942 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
3943 if (!focused_frame || ShouldDispatchImeEventsToPlugin())
3944 return gfx::Range::InvalidRange();
3946 blink::WebInputMethodController* controller =
3947 focused_frame->GetInputMethodController();
3948 WebRange web_range = controller->CompositionRange();
3949 if (web_range.IsNull())
3950 return gfx::Range::InvalidRange();
3951 return gfx::Range(web_range.StartOffset(), web_range.EndOffset());
3954 void WebFrameWidgetImpl::GetCompositionCharacterBoundsInWindow(
3955 Vector<gfx::Rect>* bounds_in_dips) {
3956 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
3957 if (!focused_frame || ShouldDispatchImeEventsToPlugin())
3959 blink::WebInputMethodController* controller =
3960 focused_frame->GetInputMethodController();
3961 blink::WebVector<gfx::Rect> bounds_from_blink;
3962 if (!controller->GetCompositionCharacterBounds(bounds_from_blink))
3965 for (auto& rect : bounds_from_blink) {
3966 bounds_in_dips->push_back(widget_base_->BlinkSpaceToEnclosedDIPs(rect));
3972 void GetLineBounds(Vector<gfx::QuadF>& line_quads,
3973 TextControlInnerEditorElement* inner_editor) {
3974 for (const Node& node : NodeTraversal::DescendantsOf(*inner_editor)) {
3975 if (!node.GetLayoutObject() || !node.GetLayoutObject()->IsText()) {
3978 node.GetLayoutObject()->AbsoluteQuads(line_quads,
3979 kApplyRemoteMainFrameTransform);
3985 Vector<gfx::Rect> WebFrameWidgetImpl::CalculateVisibleLineBoundsOnScreen() {
3986 Vector<gfx::Rect> bounds_in_dips;
3987 Element* focused_element = FocusedElement();
3988 if (!focused_element) {
3989 return bounds_in_dips;
3991 TextControlElement* text_control = ToTextControlOrNull(focused_element);
3992 if (!text_control || text_control->IsDisabledOrReadOnly() ||
3993 text_control->Value().empty() || !text_control->GetLayoutObject()) {
3994 return bounds_in_dips;
3997 Vector<gfx::QuadF> bounds_from_blink;
3998 GetLineBounds(bounds_from_blink, text_control->InnerEditorElement());
4000 gfx::Rect screen = GetPage()->GetVisualViewport().VisibleContentRect();
4001 for (auto& quad : bounds_from_blink) {
4002 gfx::Rect bounding_box = gfx::ToRoundedRect(quad.BoundingBox());
4003 bounding_box.Intersect(screen);
4004 if (bounding_box.IsEmpty()) {
4008 bounds_in_dips.push_back(
4009 focused_element->GetLayoutObject()->GetFrameView()->FrameToScreen(
4012 return bounds_in_dips;
4015 Vector<gfx::Rect>& WebFrameWidgetImpl::GetVisibleLineBoundsOnScreen() {
4016 return input_visible_line_bounds_;
4019 void WebFrameWidgetImpl::UpdateLineBounds() {
4020 Vector<gfx::Rect> line_bounds = CalculateVisibleLineBoundsOnScreen();
4021 if (line_bounds == input_visible_line_bounds_) {
4024 input_visible_line_bounds_.swap(line_bounds);
4025 if (mojom::blink::WidgetInputHandlerHost* host =
4026 widget_base_->widget_input_handler_manager()
4027 ->GetWidgetInputHandlerHost()) {
4028 host->ImeCompositionRangeChanged(gfx::Range::InvalidRange(), absl::nullopt,
4029 input_visible_line_bounds_);
4033 void WebFrameWidgetImpl::AddImeTextSpansToExistingText(
4036 const Vector<ui::ImeTextSpan>& ime_text_spans) {
4037 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4040 focused_frame->AddImeTextSpansToExistingText(ime_text_spans, start, end);
4043 Vector<ui::mojom::blink::ImeTextSpanInfoPtr>
4044 WebFrameWidgetImpl::GetImeTextSpansInfo(
4045 const WebVector<ui::ImeTextSpan>& ime_text_spans) {
4046 auto* focused_frame = FocusedWebLocalFrameInWidget();
4048 return Vector<ui::mojom::blink::ImeTextSpanInfoPtr>();
4050 Vector<ui::mojom::blink::ImeTextSpanInfoPtr> ime_text_spans_info;
4052 for (const auto& ime_text_span : ime_text_spans) {
4054 auto length = base::checked_cast<wtf_size_t>(ime_text_span.end_offset -
4055 ime_text_span.start_offset);
4056 focused_frame->FirstRectForCharacterRange(
4057 base::checked_cast<wtf_size_t>(ime_text_span.start_offset), length,
4060 ime_text_spans_info.push_back(ui::mojom::blink::ImeTextSpanInfo::New(
4061 ime_text_span, widget_base_->BlinkSpaceToEnclosedDIPs(rect)));
4063 return ime_text_spans_info;
4066 void WebFrameWidgetImpl::ClearImeTextSpansByType(uint32_t start,
4068 ui::ImeTextSpan::Type type) {
4069 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4072 focused_frame->ClearImeTextSpansByType(type, start, end);
4075 void WebFrameWidgetImpl::SetCompositionFromExistingText(
4078 const Vector<ui::ImeTextSpan>& ime_text_spans) {
4079 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4082 focused_frame->SetCompositionFromExistingText(start, end, ime_text_spans);
4085 void WebFrameWidgetImpl::ExtendSelectionAndDelete(int32_t before,
4087 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4090 focused_frame->ExtendSelectionAndDelete(before, after);
4093 void WebFrameWidgetImpl::ExtendSelectionAndReplace(
4096 const String& replacement_text) {
4097 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4098 if (!focused_frame) {
4101 focused_frame->ExtendSelectionAndReplace(base::checked_cast<int>(before),
4102 base::checked_cast<int>(after),
4106 void WebFrameWidgetImpl::DeleteSurroundingText(int32_t before, int32_t after) {
4107 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4110 focused_frame->DeleteSurroundingText(before, after);
4113 void WebFrameWidgetImpl::DeleteSurroundingTextInCodePoints(int32_t before,
4115 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4118 focused_frame->DeleteSurroundingTextInCodePoints(before, after);
4121 void WebFrameWidgetImpl::SetEditableSelectionOffsets(int32_t start,
4123 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4126 focused_frame->SetEditableSelectionOffsets(start, end);
4129 void WebFrameWidgetImpl::ExecuteEditCommand(const String& command,
4130 const String& value) {
4131 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4134 focused_frame->ExecuteCommand(command, value);
4137 void WebFrameWidgetImpl::Undo() {
4138 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4141 focused_frame->ExecuteCommand(WebString::FromLatin1("Undo"));
4144 void WebFrameWidgetImpl::Redo() {
4145 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4148 focused_frame->ExecuteCommand(WebString::FromLatin1("Redo"));
4151 void WebFrameWidgetImpl::Cut() {
4152 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4155 focused_frame->ExecuteCommand(WebString::FromLatin1("Cut"));
4158 void WebFrameWidgetImpl::Copy() {
4159 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4162 focused_frame->ExecuteCommand(WebString::FromLatin1("Copy"));
4165 void WebFrameWidgetImpl::CopyToFindPboard() {
4166 #if BUILDFLAG(IS_MAC)
4167 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4170 To<WebLocalFrameImpl>(focused_frame)->CopyToFindPboard();
4174 void WebFrameWidgetImpl::CenterSelection() {
4175 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4176 if (!focused_frame) {
4179 To<WebLocalFrameImpl>(focused_frame)->CenterSelection();
4182 void WebFrameWidgetImpl::Paste() {
4183 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4186 focused_frame->ExecuteCommand(WebString::FromLatin1("Paste"));
4189 void WebFrameWidgetImpl::PasteAndMatchStyle() {
4190 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4193 focused_frame->ExecuteCommand(WebString::FromLatin1("PasteAndMatchStyle"));
4196 void WebFrameWidgetImpl::Delete() {
4197 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4200 focused_frame->ExecuteCommand(WebString::FromLatin1("Delete"));
4203 void WebFrameWidgetImpl::SelectAll() {
4204 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4207 focused_frame->ExecuteCommand(WebString::FromLatin1("SelectAll"));
4210 void WebFrameWidgetImpl::CollapseSelection() {
4211 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4214 const blink::WebRange& range =
4215 focused_frame->GetInputMethodController()->GetSelectionOffsets();
4219 focused_frame->SelectRange(blink::WebRange(range.EndOffset(), 0),
4220 blink::WebLocalFrame::kHideSelectionHandle,
4221 mojom::blink::SelectionMenuBehavior::kHide,
4222 blink::WebLocalFrame::kSelectionDoNotSetFocus);
4225 void WebFrameWidgetImpl::Replace(const String& word) {
4226 auto* focused_frame = FocusedWebLocalFrameInWidget();
4229 if (!focused_frame->HasSelection()) {
4230 focused_frame->SelectAroundCaret(mojom::blink::SelectionGranularity::kWord,
4231 /*should_show_handle=*/false,
4232 /*should_show_context_menu=*/false);
4234 focused_frame->ReplaceSelection(word);
4235 // If the resulting selection is not actually a change in selection, we do not
4236 // need to explicitly notify about the selection change.
4237 focused_frame->Client()->SyncSelectionIfRequired(
4238 blink::SyncCondition::kNotForced);
4241 void WebFrameWidgetImpl::ReplaceMisspelling(const String& word) {
4242 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4245 if (!focused_frame->HasSelection())
4247 focused_frame->ReplaceMisspelledRange(word);
4250 void WebFrameWidgetImpl::SelectRange(const gfx::Point& base_in_dips,
4251 const gfx::Point& extent_in_dips) {
4252 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4255 focused_frame->SelectRange(
4256 widget_base_->DIPsToRoundedBlinkSpace(base_in_dips),
4257 widget_base_->DIPsToRoundedBlinkSpace(extent_in_dips));
4260 void WebFrameWidgetImpl::AdjustSelectionByCharacterOffset(
4263 mojom::blink::SelectionMenuBehavior selection_menu_behavior) {
4264 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4267 blink::WebRange range =
4268 focused_frame->GetInputMethodController()->GetSelectionOffsets();
4272 // Sanity checks to disallow empty and out of range selections.
4273 if (start - end > range.length() || range.StartOffset() + start < 0)
4276 // A negative adjust amount moves the selection towards the beginning of
4277 // the document, a positive amount moves the selection towards the end of
4279 focused_frame->SelectRange(blink::WebRange(range.StartOffset() + start,
4280 range.length() + end - start),
4281 blink::WebLocalFrame::kPreserveHandleVisibility,
4282 selection_menu_behavior,
4283 blink::WebLocalFrame::kSelectionSetFocus);
4286 void WebFrameWidgetImpl::MoveRangeSelectionExtent(
4287 const gfx::Point& extent_in_dips) {
4288 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4291 focused_frame->MoveRangeSelectionExtent(
4292 widget_base_->DIPsToRoundedBlinkSpace(extent_in_dips));
4295 void WebFrameWidgetImpl::ScrollFocusedEditableNodeIntoView() {
4296 WebLocalFrameImpl* local_frame = FocusedWebLocalFrameInWidget();
4300 // OnSynchronizeVisualProperties does not call DidChangeVisibleViewport
4301 // on OOPIFs. Since we are starting a new scroll operation now, call
4302 // DidChangeVisibleViewport to ensure that we don't assume the element
4303 // is already in view and ignore the scroll.
4304 local_frame->ResetHasScrolledFocusedEditableIntoView();
4305 local_frame->ScrollFocusedEditableElementIntoView();
4308 void WebFrameWidgetImpl::WaitForPageScaleAnimationForTesting(
4309 WaitForPageScaleAnimationForTestingCallback callback) {
4310 DCHECK(ForMainFrame());
4311 DCHECK(LocalRootImpl()->GetFrame()->IsOutermostMainFrame());
4312 page_scale_animation_for_testing_callback_ = std::move(callback);
4315 void WebFrameWidgetImpl::ZoomToFindInPageRect(
4316 const gfx::Rect& rect_in_root_frame) {
4317 if (ForMainFrame()) {
4318 View()->ZoomToFindInPageRect(rect_in_root_frame);
4320 GetAssociatedFrameWidgetHost()->ZoomToFindInPageRectInMainFrame(
4321 rect_in_root_frame);
4325 void WebFrameWidgetImpl::MoveCaret(const gfx::Point& point_in_dips) {
4326 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4329 focused_frame->MoveCaretSelection(
4330 widget_base_->DIPsToRoundedBlinkSpace(point_in_dips));
4333 void WebFrameWidgetImpl::SelectAroundCaret(
4334 mojom::blink::SelectionGranularity granularity,
4335 bool should_show_handle,
4336 bool should_show_context_menu,
4337 SelectAroundCaretCallback callback) {
4338 auto* focused_frame = FocusedWebLocalFrameInWidget();
4339 if (!focused_frame) {
4340 std::move(callback).Run(std::move(nullptr));
4344 int extended_start_adjust = 0;
4345 int extended_end_adjust = 0;
4346 int word_start_adjust = 0;
4347 int word_end_adjust = 0;
4348 blink::WebRange initial_range = focused_frame->SelectionRange();
4349 SetHandlingInputEvent(true);
4351 if (initial_range.IsNull()) {
4352 std::move(callback).Run(std::move(nullptr));
4356 // If the requested granularity is not word, still calculate the hypothetical
4357 // word selection offsets. This is needed for contextual search to support
4358 // legacy semantics for the word that was tapped.
4359 blink::WebRange word_range;
4360 if (granularity != mojom::blink::SelectionGranularity::kWord) {
4361 word_range = focused_frame->GetWordSelectionRangeAroundCaret();
4364 // Select around the caret at the specified |granularity|.
4365 if (!focused_frame->SelectAroundCaret(granularity, should_show_handle,
4366 should_show_context_menu)) {
4367 std::move(callback).Run(std::move(nullptr));
4371 blink::WebRange extended_range = focused_frame->SelectionRange();
4372 DCHECK(!extended_range.IsNull());
4373 extended_start_adjust =
4374 extended_range.StartOffset() - initial_range.StartOffset();
4375 extended_end_adjust = extended_range.EndOffset() - initial_range.EndOffset();
4377 if (granularity == mojom::blink::SelectionGranularity::kWord) {
4378 // Since the requested granularity was word, simply set the word offset
4379 // to be the same as the extended offset values.
4380 word_start_adjust = extended_start_adjust;
4381 word_end_adjust = extended_end_adjust;
4383 // Calculate the word offset compared to the initial selection (caret).
4384 DCHECK(!word_range.IsNull());
4385 word_start_adjust = word_range.StartOffset() - initial_range.StartOffset();
4386 word_end_adjust = word_range.EndOffset() - initial_range.EndOffset();
4389 SetHandlingInputEvent(false);
4390 auto result = mojom::blink::SelectAroundCaretResult::New();
4391 result->extended_start_adjust = extended_start_adjust;
4392 result->extended_end_adjust = extended_end_adjust;
4393 result->word_start_adjust = word_start_adjust;
4394 result->word_end_adjust = word_end_adjust;
4395 std::move(callback).Run(std::move(result));
4398 void WebFrameWidgetImpl::ForEachRemoteFrameControlledByWidget(
4399 base::FunctionRef<void(RemoteFrame*)> callback) {
4400 ForEachRemoteFrameChildrenControlledByWidget(local_root_->GetFrame(),
4404 void WebFrameWidgetImpl::CalculateSelectionBounds(
4405 gfx::Rect& anchor_root_frame,
4406 gfx::Rect& focus_root_frame,
4407 gfx::Rect* bounding_box_in_root_frame) {
4408 const LocalFrame* local_frame = FocusedLocalFrameInWidget();
4414 auto& selection = local_frame->Selection();
4415 if (!selection.ComputeAbsoluteBounds(anchor, focus))
4418 // Apply the visual viewport for main frames this will apply the page scale.
4419 // For subframes it will just be a 1:1 transformation and the browser
4420 // will then apply later transformations to these rects.
4421 VisualViewport& visual_viewport = GetPage()->GetVisualViewport();
4422 anchor_root_frame = visual_viewport.RootFrameToViewport(
4423 local_frame->View()->ConvertToRootFrame(anchor));
4424 focus_root_frame = visual_viewport.RootFrameToViewport(
4425 local_frame->View()->ConvertToRootFrame(focus));
4427 // Calculate the bounding box of the selection area.
4428 if (bounding_box_in_root_frame) {
4430 CreateRange(selection.GetSelectionInDOMTree().ComputeRange());
4431 const gfx::Rect bounding_box = ToEnclosingRect(range->BoundingRect());
4433 *bounding_box_in_root_frame = visual_viewport.RootFrameToViewport(
4434 local_frame->View()->ConvertToRootFrame(bounding_box));
4438 const viz::LocalSurfaceId& WebFrameWidgetImpl::LocalSurfaceIdFromParent() {
4439 return widget_base_->local_surface_id_from_parent();
4442 cc::LayerTreeHost* WebFrameWidgetImpl::LayerTreeHost() {
4443 return widget_base_->LayerTreeHost();
4446 cc::LayerTreeHost* WebFrameWidgetImpl::LayerTreeHostForTesting() const {
4447 return widget_base_->LayerTreeHost();
4450 ScreenMetricsEmulator* WebFrameWidgetImpl::DeviceEmulator() {
4451 return device_emulator_.Get();
4454 bool WebFrameWidgetImpl::AutoResizeMode() {
4455 return View()->AutoResizeMode();
4458 void WebFrameWidgetImpl::SetScreenMetricsEmulationParameters(
4460 const DeviceEmulationParams& params) {
4462 View()->ActivateDevToolsTransform(params);
4464 View()->DeactivateDevToolsTransform();
4467 void WebFrameWidgetImpl::SetScreenInfoAndSize(
4468 const display::ScreenInfos& screen_infos,
4469 const gfx::Size& widget_size_in_dips,
4470 const gfx::Size& visible_viewport_size_in_dips) {
4471 // Emulation happens on regular main frames which don't use auto-resize mode.
4472 DCHECK(!AutoResizeMode());
4474 UpdateScreenInfo(screen_infos);
4475 widget_base_->SetVisibleViewportSizeInDIPs(visible_viewport_size_in_dips);
4476 Resize(widget_base_->DIPsToCeiledBlinkSpace(widget_size_in_dips));
4479 float WebFrameWidgetImpl::GetCompositingScaleFactor() {
4480 return compositing_scale_factor_;
4483 const cc::LayerTreeDebugState& WebFrameWidgetImpl::GetLayerTreeDebugState() {
4484 return widget_base_->LayerTreeHost()->GetDebugState();
4487 void WebFrameWidgetImpl::SetLayerTreeDebugState(
4488 const cc::LayerTreeDebugState& state) {
4489 widget_base_->LayerTreeHost()->SetDebugState(state);
4492 void WebFrameWidgetImpl::NotifyCompositingScaleFactorChanged(
4493 float compositing_scale_factor) {
4494 compositing_scale_factor_ = compositing_scale_factor;
4496 // Update the scale factor for remote frames which in turn depends on the
4497 // compositing scale factor set in the widget.
4498 ForEachRemoteFrameControlledByWidget([](RemoteFrame* remote_frame) {
4499 // Only RemoteFrames with a local parent frame participate in compositing
4500 // (and thus have a view).
4501 if (remote_frame->View())
4502 remote_frame->View()->UpdateCompositingScaleFactor();
4506 void WebFrameWidgetImpl::NotifyPageScaleFactorChanged(
4507 float page_scale_factor,
4508 bool is_pinch_gesture_active) {
4509 // Store the value to give to any new RemoteFrame that will be created as a
4510 // descendant of this widget.
4511 page_scale_factor_in_mainframe_ = page_scale_factor;
4512 is_pinch_gesture_active_in_mainframe_ = is_pinch_gesture_active;
4513 // Push the page scale factor down to any child RemoteFrames.
4514 // TODO(danakj): This ends up setting the page scale factor in the
4515 // RenderWidgetHost of the child WebFrameWidgetImpl, so that it can bounce
4516 // the value down to its WebFrameWidgetImpl. Since this is essentially a
4517 // global value per-page, we could instead store it once in the browser
4518 // (such as in RenderViewHost) and distribute it to each WebFrameWidgetImpl
4520 ForEachRemoteFrameControlledByWidget(
4521 [page_scale_factor, is_pinch_gesture_active](RemoteFrame* remote_frame) {
4522 remote_frame->PageScaleFactorChanged(page_scale_factor,
4523 is_pinch_gesture_active);
4527 void WebFrameWidgetImpl::SetPageScaleStateAndLimits(
4528 float page_scale_factor,
4529 bool is_pinch_gesture_active,
4532 widget_base_->LayerTreeHost()->SetPageScaleFactorAndLimits(page_scale_factor,
4535 // Only propagate page scale from the main frame.
4536 if (ForMainFrame()) {
4537 // If page scale hasn't changed, then just return without notifying
4538 // the remote frames.
4539 if (page_scale_factor == page_scale_factor_in_mainframe_ &&
4540 is_pinch_gesture_active == is_pinch_gesture_active_in_mainframe_) {
4544 NotifyPageScaleFactorChanged(page_scale_factor, is_pinch_gesture_active);
4548 void WebFrameWidgetImpl::UpdateViewportDescription(
4549 const ViewportDescription& viewport) {
4550 bool is_device_width = viewport.max_width.IsDeviceWidth();
4551 bool is_zoom_at_least_one = viewport.zoom >= 1.0 || viewport.min_zoom >= 1;
4552 widget_base_->LayerTreeHost()->UpdateViewportIsMobileOptimized(
4553 (is_device_width && is_zoom_at_least_one) ||
4554 (is_device_width && !viewport.zoom_is_explicit) ||
4555 (viewport.max_width.IsAuto() && is_zoom_at_least_one));
4558 bool WebFrameWidgetImpl::UpdateScreenRects(
4559 const gfx::Rect& widget_screen_rect,
4560 const gfx::Rect& window_screen_rect) {
4561 if (!device_emulator_)
4563 device_emulator_->OnUpdateScreenRects(widget_screen_rect, window_screen_rect);
4567 #if BUILDFLAG(IS_EFL)
4568 void WebFrameWidgetImpl::GetContentSnapshot(const gfx::Rect& snapshot_rect,
4569 float page_scale_factor,
4570 SkBitmap* snapshot) {
4571 WebView* view = View();
4572 if (!view || !view->MainFrame()) {
4573 LOG(ERROR) << "SoftBitmap:Capture Invalid view";
4577 if (view->HasAcceleratedCanvasWithinViewport()) {
4579 << "SoftBitmap:Capture avoided for WebGl/Cavas2D content on viewport";
4583 if (view->MainFrameWidget()->Size().IsEmpty()) {
4584 LOG(ERROR) << "SoftBitmap:Capture Invalid size";
4588 snapshot->allocPixels(SkImageInfo::MakeN32Premul(snapshot_rect.width(),
4589 snapshot_rect.height()));
4590 SkCanvas canvas(*snapshot);
4591 if (!view->PaintSoftBitmap(&canvas, snapshot_rect)) {
4592 LOG(ERROR) << "SoftBitmap:Capture PaintSoftBitmap failed";
4596 *snapshot = skia::ImageOperations::Resize(
4597 *snapshot, skia::ImageOperations::RESIZE_GOOD,
4598 page_scale_factor * snapshot->width(),
4599 page_scale_factor * snapshot->height());
4602 SkColor WebFrameWidgetImpl::GetBackgroundColor() {
4603 SkColor bg_color = View()->BackgroundColor();
4607 gfx::RectF WebFrameWidgetImpl::UpdateFocusedNodeBounds() {
4608 Element* element = FocusedElement();
4610 return gfx::RectF();
4612 WebElement web_element = WebElement(element);
4614 if (!web_element.IsNull() && web_element.IsElementNode()) {
4615 gfx::RectF focused_node_bounds_scaled = gfx::ScaleRect(
4616 gfx::RectF(web_element.BoundsInWidget()), View()->PageScaleFactor());
4617 return focused_node_bounds_scaled;
4619 return gfx::RectF();
4622 void WebFrameWidgetImpl::SetLongPollingGlobalTimeout(uint64_t timeout) {
4623 WebView* view = View();
4625 view->SetLongPollingGlobalTimeout(timeout);
4628 bool WebFrameWidgetImpl::QueryInputType() {
4629 Element* element = FocusedElement();
4633 auto* input_element = DynamicTo<HTMLInputElement>(element);
4634 if (input_element && input_element->type() == input_type_names::kPassword)
4640 void WebFrameWidgetImpl::SelectClosestWord(uint32_t x, uint32_t y) {
4644 blink::WebFrame* main_frame = View()->MainFrame();
4648 SetHandlingInputEvent(true);
4649 main_frame->SelectClosestWord(x, y);
4650 SetHandlingInputEvent(false);
4653 void WebFrameWidgetImpl::SelectFocusedLink() {
4654 Element* element = FocusedElement();
4658 WebElement web_element = WebElement(element);
4659 if (web_element.IsNull() || web_element.IsEditable() ||
4660 web_element.HasHTMLTagName("select")) {
4664 gfx::Rect box_rect = web_element.BoundsInWidget();
4665 if (box_rect.IsEmpty())
4671 float page_scale = View()->PageScaleFactor();
4672 int focused_x = (box_rect.x() + box_rect.width() / 2) / page_scale;
4673 int focused_y = (box_rect.y() + box_rect.height() / 2) / page_scale;
4675 SelectClosestWord(focused_x, focused_y);
4678 gfx::Rect WebFrameWidgetImpl::RequestSelectionRect() {
4682 return gfx::Rect(View()->CurrentSelectionRect());
4685 void WebFrameWidgetImpl::ResetLastInteractedElements() {
4686 #if defined(TIZEN_AUTOFILL_FW)
4690 if (auto* frame = View()->FocusedFrame())
4691 frame->ResetLastInteractedElements();
4695 void WebFrameWidgetImpl::PrintToPdf(uint32_t width,
4697 const base::FilePath& filename) {
4698 WebLocalFrame* focused_frame = FocusedWebLocalFrameInWidget();
4699 if (!focused_frame || !focused_frame->Client())
4702 focused_frame->Client()->PrintToPdf(
4703 width, height, filename,
4704 content::RenderFrame::FromWebFrame(focused_frame));
4707 void WebFrameWidgetImpl::SetMainFrameScrollbarVisible(bool visible) {
4708 blink::WebView* view = View();
4709 if (!view || !view->MainFrame() || !view->MainFrame()->ToWebLocalFrame())
4712 view->MainFrame()->ToWebLocalFrame()->ChangeScrollbarVisibility(visible);
4715 bool WebFrameWidgetImpl::RequestMainFrameScrollbarVisible(bool& visible) {
4716 blink::WebView* view = View();
4717 if (!view || !view->MainFrame() || !view->MainFrame()->ToWebLocalFrame())
4720 auto local_frame = view->MainFrame()->ToWebLocalFrame();
4721 visible = local_frame->HasHorizontalScrollbar() ||
4722 local_frame->HasVerticalScrollbar();
4726 #if BUILDFLAG(IS_TIZEN_TV)
4727 bool WebFrameWidgetImpl::IsHitScrollbar() {
4728 return View()->IsHitScrollbar();
4731 bool WebFrameWidgetImpl::IsMouseDownEventSwallowed() {
4732 return View()->IsMouseDownEventSwallowed();
4735 void WebFrameWidgetImpl::SetFloatVideoWindowState(bool enabled) {
4736 View()->SetFloatVideoWindowState(enabled);
4739 void WebFrameWidgetImpl::SuspendNetworkLoading() {
4740 View()->SuspendNetworkLoading();
4743 void WebFrameWidgetImpl::ResumeNetworkLoading() {
4744 View()->ResumeNetworkLoading();
4746 #endif // IS_TIZEN_TV
4749 #if BUILDFLAG(IS_TIZEN)
4750 void WebFrameWidgetImpl::SetMaxRefreshRate(uint32_t max_refresh_rate) {
4751 widget_base_->SetMaxRefreshRate(max_refresh_rate);
4755 #if BUILDFLAG(IS_TIZEN)
4756 void WebFrameWidgetImpl::DidChangeLoadState(bool is_loading) {
4757 widget_base_->LayerTreeHost()->DidChangeLoadState(is_loading);
4761 void WebFrameWidgetImpl::OrientationChanged() {
4762 local_root_->SendOrientationChangeEvent();
4765 #if BUILDFLAG(IS_TIZEN)
4766 void WebFrameWidgetImpl::PauseScheduledTasks() {
4767 View()->PauseScheduledTasks();
4770 void WebFrameWidgetImpl::UnPauseScheduledTasks() {
4771 View()->UnpauseScheduledTasks();
4775 void WebFrameWidgetImpl::DidUpdateSurfaceAndScreen(
4776 const display::ScreenInfos& previous_original_screen_infos) {
4777 display::ScreenInfo screen_info = widget_base_->GetScreenInfo();
4778 View()->SetZoomFactorForDeviceScaleFactor(screen_info.device_scale_factor);
4780 if (ShouldAutoDetermineCompositingToLCDTextSetting()) {
4781 // This causes compositing state to be modified which dirties the
4782 // document lifecycle. Android Webview relies on the document
4783 // lifecycle being clean after the RenderWidget is initialized, in
4784 // order to send IPCs that query and change compositing state. So
4785 // WebFrameWidgetImpl::Resize() must come after this call, as it runs the
4786 // entire document lifecycle.
4787 View()->GetSettings()->SetLCDTextPreference(
4788 widget_base_->ComputeLCDTextPreference());
4791 // When the device scale changes, the size and position of the popup would
4792 // need to be adjusted, which we can't do. Just close the popup, which is
4793 // also consistent with page zoom and resize behavior.
4794 display::ScreenInfos original_screen_infos = GetOriginalScreenInfos();
4795 if (previous_original_screen_infos.current().device_scale_factor !=
4796 original_screen_infos.current().device_scale_factor) {
4797 View()->CancelPagePopup();
4800 const bool window_screen_has_changed =
4801 !Screen::AreWebExposedScreenPropertiesEqual(
4802 previous_original_screen_infos.current(),
4803 original_screen_infos.current());
4805 // Update Screens interface data before firing any events. The API is designed
4806 // to offer synchronous access to the most up-to-date cached screen
4807 // information when a change event is fired. It is not required but it
4808 // is convenient to have all ScreenDetailed objects be up to date when any
4809 // window.screen events are fired as well.
4810 ForEachLocalFrameControlledByWidget(
4811 LocalRootImpl()->GetFrame(),
4812 [&original_screen_infos,
4813 window_screen_has_changed](WebLocalFrameImpl* local_frame) {
4814 auto* screen = local_frame->GetFrame()->DomWindow()->screen();
4815 screen->UpdateDisplayId(original_screen_infos.current().display_id);
4816 CoreInitializer::GetInstance().DidUpdateScreens(
4817 *local_frame->GetFrame(), original_screen_infos);
4818 if (window_screen_has_changed)
4819 screen->DispatchEvent(*Event::Create(event_type_names::kChange));
4822 if (previous_original_screen_infos != original_screen_infos) {
4823 // Propagate changes down to child local root RenderWidgets and
4824 // BrowserPlugins in other frame trees/processes.
4825 ForEachRemoteFrameControlledByWidget(
4826 [&original_screen_infos](RemoteFrame* remote_frame) {
4827 remote_frame->DidChangeScreenInfos(original_screen_infos);
4832 gfx::Rect WebFrameWidgetImpl::ViewportVisibleRect() {
4833 if (ForMainFrame()) {
4834 return widget_base_->CompositorViewportRect();
4836 return child_data().compositor_visible_rect;
4840 absl::optional<display::mojom::blink::ScreenOrientation>
4841 WebFrameWidgetImpl::ScreenOrientationOverride() {
4842 return View()->ScreenOrientationOverride();
4845 void WebFrameWidgetImpl::WasHidden() {
4846 ForEachLocalFrameControlledByWidget(local_root_->GetFrame(),
4847 [](WebLocalFrameImpl* local_frame) {
4848 local_frame->Client()->WasHidden();
4851 if (animation_frame_timing_monitor_) {
4852 animation_frame_timing_monitor_->Shutdown();
4853 animation_frame_timing_monitor_.Clear();
4857 void WebFrameWidgetImpl::WasShown(bool was_evicted) {
4858 ForEachLocalFrameControlledByWidget(local_root_->GetFrame(),
4859 [](WebLocalFrameImpl* local_frame) {
4860 local_frame->Client()->WasShown();
4863 ForEachRemoteFrameControlledByWidget(
4864 // On eviction, the last SurfaceId is invalidated. We need to
4865 // allocate a new id.
4866 &RemoteFrame::ResendVisualProperties);
4869 CHECK(local_root_ && local_root_->GetFrame());
4870 if (!animation_frame_timing_monitor_ &&
4871 RuntimeEnabledFeatures::LongAnimationFrameMonitoringEnabled(
4872 local_root_->GetFrame()->DomWindow())) {
4873 animation_frame_timing_monitor_ =
4874 MakeGarbageCollected<AnimationFrameTimingMonitor>(
4875 *this, local_root_->GetFrame()->GetProbeSink());
4879 void WebFrameWidgetImpl::RunPaintBenchmark(int repeat_count,
4880 cc::PaintBenchmarkResult& result) {
4881 if (!ForMainFrame())
4883 if (auto* frame_view = LocalRootImpl()->GetFrameView())
4884 frame_view->RunPaintBenchmark(repeat_count, result);
4887 void WebFrameWidgetImpl::NotifyInputObservers(
4888 const WebCoalescedInputEvent& coalesced_event) {
4889 LocalFrame* frame = FocusedLocalFrameInWidget();
4893 LocalFrameView* frame_view = frame->View();
4897 const WebInputEvent& input_event = coalesced_event.Event();
4898 auto& paint_timing_detector = frame_view->GetPaintTimingDetector();
4900 if (paint_timing_detector.NeedToNotifyInputOrScroll())
4901 paint_timing_detector.NotifyInputEvent(input_event.GetType());
4904 Frame* WebFrameWidgetImpl::FocusedCoreFrame() const {
4905 return GetPage() ? GetPage()->GetFocusController().FocusedOrMainFrame()
4909 Element* WebFrameWidgetImpl::FocusedElement() const {
4910 LocalFrame* frame = GetPage()->GetFocusController().FocusedFrame();
4914 Document* document = frame->GetDocument();
4918 return document->FocusedElement();
4921 HitTestResult WebFrameWidgetImpl::HitTestResultForRootFramePos(
4922 const gfx::PointF& pos_in_root_frame) {
4923 gfx::PointF doc_point =
4924 LocalRootImpl()->GetFrame()->View()->ConvertFromRootFrame(
4926 HitTestLocation location(doc_point);
4927 HitTestResult result =
4928 LocalRootImpl()->GetFrame()->View()->HitTestWithThrottlingAllowed(
4929 location, HitTestRequest::kReadOnly | HitTestRequest::kActive);
4933 KURL WebFrameWidgetImpl::GetURLForDebugTrace() {
4934 WebFrame* main_frame = View()->MainFrame();
4935 if (main_frame->IsWebLocalFrame())
4936 return main_frame->ToWebLocalFrame()->GetDocument().Url();
4940 float WebFrameWidgetImpl::GetTestingDeviceScaleFactorOverride() {
4941 return device_scale_factor_for_testing_;
4944 void WebFrameWidgetImpl::ReleaseMouseLockAndPointerCaptureForTesting() {
4945 GetPage()->GetPointerLockController().ExitPointerLock();
4949 const viz::FrameSinkId& WebFrameWidgetImpl::GetFrameSinkId() {
4950 // It is valid to create a WebFrameWidget with an invalid frame sink id for
4951 // printing and placeholders. But if we go to use it, it should be valid.
4952 DCHECK(frame_sink_id_.is_valid());
4953 return frame_sink_id_;
4956 WebHitTestResult WebFrameWidgetImpl::HitTestResultAt(const gfx::PointF& point) {
4957 return CoreHitTestResultAt(point);
4960 void WebFrameWidgetImpl::SetZoomLevelForTesting(double zoom_level) {
4961 DCHECK(ForMainFrame());
4962 DCHECK_NE(zoom_level, -INFINITY);
4963 zoom_level_for_testing_ = zoom_level;
4964 SetZoomLevel(zoom_level);
4967 void WebFrameWidgetImpl::ResetZoomLevelForTesting() {
4968 DCHECK(ForMainFrame());
4969 zoom_level_for_testing_ = -INFINITY;
4973 void WebFrameWidgetImpl::SetDeviceScaleFactorForTesting(float factor) {
4974 DCHECK(ForMainFrame());
4975 DCHECK_GE(factor, 0.f);
4977 // Stash the window size before we adjust the scale factor, as subsequent
4978 // calls to convert will use the new scale factor.
4979 gfx::Size size_in_dips = widget_base_->BlinkSpaceToFlooredDIPs(Size());
4980 device_scale_factor_for_testing_ = factor;
4982 // Receiving a 0 is used to reset between tests, it removes the override in
4983 // order to listen to the browser for the next test.
4987 // We are changing the device scale factor from the renderer, so allocate a
4988 // new viz::LocalSurfaceId to avoid surface invariants violations in tests.
4989 widget_base_->LayerTreeHost()->RequestNewLocalSurfaceId();
4991 display::ScreenInfos screen_infos = widget_base_->screen_infos();
4992 screen_infos.mutable_current().device_scale_factor = factor;
4993 gfx::Size size_with_dsf = gfx::ScaleToCeiledSize(size_in_dips, factor);
4994 widget_base_->UpdateCompositorViewportAndScreenInfo(gfx::Rect(size_with_dsf),
4996 if (!AutoResizeMode()) {
4997 // This picks up the new device scale factor as
4998 // `UpdateCompositorViewportAndScreenInfo()` has applied a new value.
4999 Resize(widget_base_->DIPsToCeiledBlinkSpace(size_in_dips));
5003 FrameWidgetTestHelper*
5004 WebFrameWidgetImpl::GetFrameWidgetTestHelperForTesting() {
5008 void WebFrameWidgetImpl::PrepareForFinalLifecyclUpdateForTesting() {
5009 ForEachLocalFrameControlledByWidget(
5010 LocalRootImpl()->GetFrame(), [](WebLocalFrameImpl* local_frame) {
5011 LocalFrame* core_frame = local_frame->GetFrame();
5012 // A frame in the frame tree is fully attached and must always have a
5015 Document* document = core_frame->GetDocument();
5016 // Similarly, a fully attached frame must always have a document.
5019 // In a web test, a rendering update may not have occurred before the
5020 // test finishes so ensure the transition moves out of rendering
5022 if (RuntimeEnabledFeatures::ViewTransitionOnNavigationEnabled()) {
5023 if (auto* transition =
5024 ViewTransitionUtils::GetTransition(*document)) {
5025 transition->ActivateFromSnapshot();
5031 void WebFrameWidgetImpl::SetMayThrottleIfUndrawnFrames(
5032 bool may_throttle_if_undrawn_frames) {
5033 if (!View()->does_composite())
5035 widget_base_->LayerTreeHost()->SetMayThrottleIfUndrawnFrames(
5036 may_throttle_if_undrawn_frames);
5039 int WebFrameWidgetImpl::GetVirtualKeyboardResizeHeight() const {
5040 DCHECK(!virtual_keyboard_resize_height_physical_px_ || ForTopMostMainFrame());
5041 return virtual_keyboard_resize_height_physical_px_;
5044 void WebFrameWidgetImpl::SetVirtualKeyboardResizeHeightForTesting(int height) {
5045 virtual_keyboard_resize_height_physical_px_ = height;
5048 bool WebFrameWidgetImpl::GetMayThrottleIfUndrawnFramesForTesting() {
5049 return widget_base_->LayerTreeHost()
5050 ->GetMayThrottleIfUndrawnFramesForTesting();
5053 WebPlugin* WebFrameWidgetImpl::GetFocusedPluginContainer() {
5054 LocalFrame* focused_frame = FocusedLocalFrameInWidget();
5057 if (auto* container = focused_frame->GetWebPluginContainer())
5058 return container->Plugin();
5062 bool WebFrameWidgetImpl::HasPendingPageScaleAnimation() {
5063 return LayerTreeHost()->HasPendingPageScaleAnimation();
5066 void WebFrameWidgetImpl::SetSourceURLForCompositor(ukm::SourceId source_id,
5068 LayerTreeHost()->SetSourceURL(source_id, GURL(url));
5071 base::ReadOnlySharedMemoryRegion
5072 WebFrameWidgetImpl::CreateSharedMemoryForSmoothnessUkm() {
5073 return LayerTreeHost()->CreateSharedMemoryForSmoothnessUkm();
5076 bool WebFrameWidgetImpl::CanComposeInline() {
5077 if (auto* plugin = GetFocusedPluginContainer())
5078 return plugin->CanComposeInline();
5082 bool WebFrameWidgetImpl::ShouldDispatchImeEventsToPlugin() {
5083 if (auto* plugin = GetFocusedPluginContainer())
5084 return plugin->ShouldDispatchImeEventsToPlugin();
5088 void WebFrameWidgetImpl::ImeSetCompositionForPlugin(
5090 const Vector<ui::ImeTextSpan>& ime_text_spans,
5091 const gfx::Range& replacement_range,
5092 int selection_start,
5093 int selection_end) {
5094 if (auto* plugin = GetFocusedPluginContainer()) {
5095 plugin->ImeSetCompositionForPlugin(
5097 std::vector<ui::ImeTextSpan>(ime_text_spans.begin(),
5098 ime_text_spans.end()),
5099 replacement_range, selection_start, selection_end);
5103 void WebFrameWidgetImpl::ImeCommitTextForPlugin(
5105 const Vector<ui::ImeTextSpan>& ime_text_spans,
5106 const gfx::Range& replacement_range,
5107 int relative_cursor_pos) {
5108 if (auto* plugin = GetFocusedPluginContainer()) {
5109 plugin->ImeCommitTextForPlugin(
5111 std::vector<ui::ImeTextSpan>(ime_text_spans.begin(),
5112 ime_text_spans.end()),
5113 replacement_range, relative_cursor_pos);
5117 void WebFrameWidgetImpl::ImeFinishComposingTextForPlugin(bool keep_selection) {
5118 if (auto* plugin = GetFocusedPluginContainer())
5119 plugin->ImeFinishComposingTextForPlugin(keep_selection);
5122 void WebFrameWidgetImpl::SetWindowRect(const gfx::Rect& requested_rect,
5123 const gfx::Rect& adjusted_rect) {
5124 DCHECK(ForMainFrame());
5125 SetPendingWindowRect(adjusted_rect);
5126 View()->SendWindowRectToMainFrameHost(
5127 requested_rect, WTF::BindOnce(&WebFrameWidgetImpl::AckPendingWindowRect,
5128 WrapWeakPersistent(this)));
5131 void WebFrameWidgetImpl::SetWindowRectSynchronouslyForTesting(
5132 const gfx::Rect& new_window_rect) {
5133 DCHECK(ForMainFrame());
5134 SetWindowRectSynchronously(new_window_rect);
5137 void WebFrameWidgetImpl::SetWindowRectSynchronously(
5138 const gfx::Rect& new_window_rect) {
5139 // This method is only call in tests, and it applies the |new_window_rect| to
5141 // a) widget size (in |size_|)
5142 // b) blink viewport (in |visible_viewport_size_|)
5143 // c) compositor viewport (in cc::LayerTreeHost)
5144 // Normally the browser controls these three things independently, but this is
5145 // used in tests to control the size from the renderer.
5147 // We are resizing the window from the renderer, so allocate a new
5148 // viz::LocalSurfaceId to avoid surface invariants violations in tests.
5149 widget_base_->LayerTreeHost()->RequestNewLocalSurfaceId();
5151 gfx::Rect compositor_viewport_pixel_rect(gfx::ScaleToCeiledSize(
5152 new_window_rect.size(),
5153 widget_base_->GetScreenInfo().device_scale_factor));
5154 widget_base_->UpdateSurfaceAndScreenInfo(
5155 widget_base_->local_surface_id_from_parent(),
5156 compositor_viewport_pixel_rect, widget_base_->screen_infos());
5158 Resize(new_window_rect.size());
5159 widget_base_->SetScreenRects(new_window_rect, new_window_rect);
5162 void WebFrameWidgetImpl::DidCreateLocalRootView() {
5163 // If this WebWidget still hasn't received its size from the embedder, block
5164 // the parser. This is necessary, because the parser can cause layout to
5165 // happen, which needs to be done with the correct size.
5166 if (ForSubframe() && !size_) {
5167 child_data().did_suspend_parsing = true;
5168 LocalRootImpl()->GetFrame()->Loader().GetDocumentLoader()->BlockParser();
5172 bool WebFrameWidgetImpl::ShouldAutoDetermineCompositingToLCDTextSetting() {
5176 void WebFrameWidgetImpl::NotifyZoomLevelChanged(LocalFrame* root) {
5178 Document* document = root->GetDocument();
5180 if (LocalFrameView* view = document->View())
5181 view->GetLayoutShiftTracker().NotifyZoomLevelChanged();
5185 #if BUILDFLAG(IS_EFL)
5186 void WebFrameWidgetImpl::NotifyKeyEvent(WebInputEvent::Type type,
5188 GetAssociatedFrameWidgetHost()->HandleKeyEvent(type, processed);
5192 #if BUILDFLAG(IS_TIZEN_TV)
5193 void WebFrameWidgetImpl::NotifyTrackInfoToBrowser(int active_track_id,
5194 const std::string& url,
5195 const std::string& lang) {
5196 LOG(INFO) << __func__ << " active_track_id:" << active_track_id
5197 << " url:" << url << " lang:" << lang;
5198 widget_base_->NotifyTrackInfoToBrowser(active_track_id, url, lang);
5201 void WebFrameWidgetImpl::MoveFocusToBrowser(int direction) {
5202 widget_base_->MoveFocusToBrowser(direction);
5206 #if BUILDFLAG(IS_TIZEN)
5207 void WebFrameWidgetImpl::SetDrawsTransparentBackground(
5208 bool draws_transparent_background) {
5209 WebViewImpl* webview = View();
5213 SkColor backgroundColor = draws_transparent_background
5214 ? static_cast<SkColor>(0x00000000)
5215 : static_cast<SkColor>(0xFFFFFFFF);
5217 webview->SetPageBaseBackgroundColor(absl::make_optional(backgroundColor));
5218 // set transparent bg for Render process
5219 if (draws_transparent_background) {
5220 widget_base_->LayerTreeHost()->set_background_color(SkColors::kTransparent);
5224 void WebFrameWidgetImpl::SetBackgroundColor(int32_t red,
5228 WebViewImpl* webview = View();
5232 SkColor backgroundColor = SkColorSetARGB(alpha, red, green, blue);
5233 webview->SetPageBaseBackgroundColor(absl::make_optional(backgroundColor));
5237 } // namespace blink