1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "content/browser/renderer_host/render_widget_host_view_mac.h" 6 7#import <Carbon/Carbon.h> 8 9#include <limits> 10#include <utility> 11 12#include "base/bind.h" 13#include "base/command_line.h" 14#include "base/feature_list.h" 15#include "base/logging.h" 16#include "base/mac/mac_util.h" 17#include "base/mac/scoped_cftyperef.h" 18#include "base/macros.h" 19#include "base/optional.h" 20#include "base/strings/sys_string_conversions.h" 21#include "base/strings/utf_string_conversions.h" 22#include "base/time/time.h" 23#include "components/remote_cocoa/browser/ns_view_ids.h" 24#include "components/remote_cocoa/common/application.mojom.h" 25#include "components/viz/common/features.h" 26#include "components/viz/common/switches.h" 27#import "content/app_shim_remote_cocoa/render_widget_host_ns_view_bridge.h" 28#import "content/app_shim_remote_cocoa/render_widget_host_view_cocoa.h" 29#import "content/browser/accessibility/browser_accessibility_cocoa.h" 30#import "content/browser/accessibility/browser_accessibility_mac.h" 31#include "content/browser/accessibility/browser_accessibility_manager_mac.h" 32#include "content/browser/renderer_host/cursor_manager.h" 33#include "content/browser/renderer_host/input/motion_event_web.h" 34#import "content/browser/renderer_host/input/synthetic_gesture_target_mac.h" 35#include "content/browser/renderer_host/input/web_input_event_builders_mac.h" 36#include "content/browser/renderer_host/render_view_host_delegate.h" 37#include "content/browser/renderer_host/render_view_host_impl.h" 38#include "content/browser/renderer_host/render_widget_helper.h" 39#include "content/browser/renderer_host/render_widget_host_input_event_router.h" 40#import "content/browser/renderer_host/text_input_client_mac.h" 41#import "content/browser/renderer_host/ui_events_helper.h" 42#include "content/public/browser/browser_context.h" 43#include "content/public/browser/browser_plugin_guest_manager.h" 44#include "content/public/browser/native_web_keyboard_event.h" 45#include "content/public/browser/render_widget_host.h" 46#include "content/public/browser/web_contents.h" 47#include "skia/ext/platform_canvas.h" 48#include "skia/ext/skia_utils_mac.h" 49#include "third_party/blink/public/common/input/web_input_event.h" 50#import "ui/base/clipboard/clipboard_util_mac.h" 51#include "ui/base/cocoa/animation_utils.h" 52#include "ui/base/cocoa/cocoa_base_utils.h" 53#include "ui/base/cocoa/remote_accessibility_api.h" 54#import "ui/base/cocoa/secure_password_input.h" 55#include "ui/base/cocoa/text_services_context_menu.h" 56#include "ui/base/ime/mojom/text_input_state.mojom.h" 57#include "ui/base/mojom/attributed_string.mojom.h" 58#include "ui/base/ui_base_features.h" 59#include "ui/display/display.h" 60#include "ui/display/screen.h" 61#include "ui/events/cocoa/cocoa_event_utils.h" 62#include "ui/events/gesture_detection/gesture_provider_config_helper.h" 63#include "ui/events/keycodes/dom/dom_code.h" 64#include "ui/events/keycodes/dom/dom_keyboard_layout_map.h" 65#include "ui/gfx/geometry/dip_util.h" 66#include "ui/gfx/mac/coordinate_conversion.h" 67 68using blink::WebInputEvent; 69using blink::WebMouseEvent; 70using blink::WebGestureEvent; 71using blink::WebTouchEvent; 72 73namespace content { 74 75//////////////////////////////////////////////////////////////////////////////// 76// BrowserCompositorMacClient, public: 77 78SkColor RenderWidgetHostViewMac::BrowserCompositorMacGetGutterColor() const { 79 // When making an element on the page fullscreen the element's background 80 // may not match the page's, so use black as the gutter color to avoid 81 // flashes of brighter colors during the transition. 82 if (host()->delegate() && host()->delegate()->IsFullscreen()) { 83 return SK_ColorBLACK; 84 } 85 return last_frame_root_background_color_; 86} 87 88void RenderWidgetHostViewMac::OnFrameTokenChanged(uint32_t frame_token) { 89 OnFrameTokenChangedForView(frame_token); 90} 91 92void RenderWidgetHostViewMac::DestroyCompositorForShutdown() { 93 // When RenderWidgetHostViewMac was owned by an NSView, this function was 94 // necessary to ensure that the ui::Compositor did not outlive the 95 // infrastructure that was needed to support it. 96 // https://crbug.com/805726 97 Destroy(); 98} 99 100bool RenderWidgetHostViewMac::OnBrowserCompositorSurfaceIdChanged() { 101 return host()->SynchronizeVisualProperties(); 102} 103 104std::vector<viz::SurfaceId> 105RenderWidgetHostViewMac::CollectSurfaceIdsForEviction() { 106 return host()->CollectSurfaceIdsForEviction(); 107} 108 109//////////////////////////////////////////////////////////////////////////////// 110// AcceleratedWidgetMacNSView, public: 111 112void RenderWidgetHostViewMac::AcceleratedWidgetCALayerParamsUpdated() { 113 // Set the background color for the root layer from the frame that just 114 // swapped. See RenderWidgetHostViewAura for more details. Note that this is 115 // done only after the swap has completed, so that the background is not set 116 // before the frame is up. 117 SetBackgroundLayerColor(last_frame_root_background_color_); 118 119 // Update the contents that the NSView is displaying. 120 const gfx::CALayerParams* ca_layer_params = 121 browser_compositor_->GetLastCALayerParams(); 122 if (ca_layer_params) 123 ns_view_->SetCALayerParams(*ca_layer_params); 124 125 // Take this opportunity to update the VSync parameters, if needed. 126 if (display_link_) { 127 base::TimeTicks timebase; 128 base::TimeDelta interval; 129 if (display_link_->GetVSyncParameters(&timebase, &interval)) 130 browser_compositor_->UpdateVSyncParameters(timebase, interval); 131 } 132} 133 134//////////////////////////////////////////////////////////////////////////////// 135// views::AccessibilityFocusOverrider::Client: 136id RenderWidgetHostViewMac::GetAccessibilityFocusedUIElement() { 137 // If content is overlayed with a focused popup from native UI code, this 138 // getter must return the current menu item as the focused element, rather 139 // than the focus within the content. An example of this occurs with the 140 // Autofill feature, where focus is actually still in the textbox although 141 // the UX acts as if focus is in the popup. 142 gfx::NativeViewAccessible popup_focus_override = 143 ui::AXPlatformNode::GetPopupFocusOverride(); 144 if (popup_focus_override) 145 return popup_focus_override; 146 147 BrowserAccessibilityManager* manager = 148 host()->GetRootBrowserAccessibilityManager(); 149 if (manager) { 150 BrowserAccessibility* focused_item = manager->GetFocus(); 151 DCHECK(focused_item); 152 if (focused_item) { 153 BrowserAccessibilityCocoa* focused_item_cocoa = 154 ToBrowserAccessibilityCocoa(focused_item); 155 DCHECK(focused_item_cocoa); 156 if (focused_item_cocoa) 157 return focused_item_cocoa; 158 } 159 } 160 return nil; 161} 162 163/////////////////////////////////////////////////////////////////////////////// 164// RenderWidgetHostViewMac, public: 165 166RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget) 167 : RenderWidgetHostViewBase(widget), 168 page_at_minimum_scale_(true), 169 mouse_wheel_phase_handler_(this), 170 is_loading_(false), 171 popup_parent_host_view_(nullptr), 172 popup_child_host_view_(nullptr), 173 gesture_provider_(ui::GetGestureProviderConfig( 174 ui::GestureProviderConfigType::CURRENT_PLATFORM), 175 this), 176 accessibility_focus_overrider_(this), 177 weak_factory_(this) { 178 // The NSView is on the other side of |ns_view_|. 179 in_process_ns_view_bridge_ = 180 std::make_unique<remote_cocoa::RenderWidgetHostNSViewBridge>(this, this); 181 ns_view_ = in_process_ns_view_bridge_.get(); 182 183 // Guess that the initial screen we will be on is the screen of the current 184 // window (since that's the best guess that we have, and is usually right). 185 // https://crbug.com/357443 186 display_ = 187 display::Screen::GetScreen()->GetDisplayNearestWindow([NSApp keyWindow]); 188 189 viz::FrameSinkId frame_sink_id = host()->GetFrameSinkId(); 190 191 browser_compositor_.reset(new BrowserCompositorMac( 192 this, this, host()->is_hidden(), display_, frame_sink_id)); 193 DCHECK(![GetInProcessNSView() window]); 194 195 host()->SetView(this); 196 197 // Let the page-level input event router know about our surface ID 198 // namespace for surface-based hit testing. 199 if (host()->delegate() && host()->delegate()->GetInputEventRouter()) { 200 host()->delegate()->GetInputEventRouter()->AddFrameSinkIdOwner( 201 GetFrameSinkId(), this); 202 } 203 204 RenderWidgetHostOwnerDelegate* owner_delegate = host()->owner_delegate(); 205 if (owner_delegate) { 206 // TODO(mostynb): actually use prefs. Landing this as a separate CL 207 // first to rebaseline some unreliable web tests. 208 // NOTE: This will not be run for child frame widgets, which do not have 209 // an owner delegate and won't get a RenderViewHost here. 210 ignore_result(owner_delegate->GetWebkitPreferencesForWidget()); 211 } 212 213 cursor_manager_.reset(new CursorManager(this)); 214 215 if (GetTextInputManager()) 216 GetTextInputManager()->AddObserver(this); 217 218 host()->render_frame_metadata_provider()->AddObserver(this); 219} 220 221RenderWidgetHostViewMac::~RenderWidgetHostViewMac() { 222 if (popup_parent_host_view_) { 223 DCHECK(!popup_parent_host_view_->popup_child_host_view_ || 224 popup_parent_host_view_->popup_child_host_view_ == this); 225 popup_parent_host_view_->popup_child_host_view_ = nullptr; 226 } 227 if (popup_child_host_view_) { 228 DCHECK(!popup_child_host_view_->popup_parent_host_view_ || 229 popup_child_host_view_->popup_parent_host_view_ == this); 230 popup_child_host_view_->popup_parent_host_view_ = nullptr; 231 } 232} 233 234void RenderWidgetHostViewMac::MigrateNSViewBridge( 235 remote_cocoa::mojom::Application* remote_cocoa_application, 236 uint64_t parent_ns_view_id) { 237 // Destroy the previous remote accessibility element. 238 remote_window_accessible_.reset(); 239 240 // Disconnect from the previous bridge (this will have the effect of 241 // destroying the associated bridge), and close the receiver (to allow it 242 // to be re-bound). Note that |in_process_ns_view_bridge_| remains valid. 243 remote_ns_view_client_receiver_.reset(); 244 remote_ns_view_.reset(); 245 246 // Enable accessibility focus overriding for remote NSViews. 247 accessibility_focus_overrider_.SetAppIsRemote(remote_cocoa_application != 248 nullptr); 249 250 // If no host is specified, then use the locally hosted NSView. 251 if (!remote_cocoa_application) { 252 ns_view_ = in_process_ns_view_bridge_.get(); 253 return; 254 } 255 256 mojo::PendingAssociatedRemote<remote_cocoa::mojom::RenderWidgetHostNSViewHost> 257 client = remote_ns_view_client_receiver_.BindNewEndpointAndPassRemote(); 258 mojo::PendingAssociatedReceiver<remote_cocoa::mojom::RenderWidgetHostNSView> 259 view_receiver = remote_ns_view_.BindNewEndpointAndPassReceiver(); 260 261 // Cast from PendingAssociatedRemote<mojom::RenderWidgetHostNSViewHost> and 262 // mojo::PendingAssociatedReceiver<mojom::RenderWidgetHostNSView> to the 263 // public interfaces accepted by the application. 264 // TODO(ccameron): Remove the need for this cast. 265 // https://crbug.com/888290 266 mojo::PendingAssociatedRemote<remote_cocoa::mojom::StubInterface> stub_client( 267 client.PassHandle(), 0); 268 mojo::PendingAssociatedReceiver<remote_cocoa::mojom::StubInterface> 269 stub_bridge_receiver(view_receiver.PassHandle()); 270 remote_cocoa_application->CreateRenderWidgetHostNSView( 271 std::move(stub_client), std::move(stub_bridge_receiver)); 272 273 ns_view_ = remote_ns_view_.get(); 274 275 // Popup windows will specify an invalid |parent_ns_view_id|, because popups 276 // have their own NSWindows (of which they are the content NSView). 277 if (parent_ns_view_id != remote_cocoa::kInvalidNSViewId) 278 remote_ns_view_->SetParentWebContentsNSView(parent_ns_view_id); 279} 280 281void RenderWidgetHostViewMac::SetParentUiLayer(ui::Layer* parent_ui_layer) { 282 if (parent_ui_layer && !display_only_using_parent_ui_layer_) { 283 // The first time that we display using a parent ui::Layer, permanently 284 // switch from drawing using Cocoa to only drawing using ui::Views. Erase 285 // the existing content being drawn by Cocoa (which may have been set due 286 // to races, e.g, in https://crbug.com/845807). Note that this transition 287 // must be done lazily because not all code has been updated to use 288 // ui::Views (e.g, content_shell). 289 display_only_using_parent_ui_layer_ = true; 290 ns_view_->DisableDisplay(); 291 } 292 if (browser_compositor_) 293 browser_compositor_->SetParentUiLayer(parent_ui_layer); 294} 295 296void RenderWidgetHostViewMac::SetParentAccessibilityElement( 297 id parent_accessibility_element) { 298 [GetInProcessNSView() 299 setAccessibilityParentElement:parent_accessibility_element]; 300} 301 302RenderWidgetHostViewCocoa* RenderWidgetHostViewMac::GetInProcessNSView() const { 303 if (in_process_ns_view_bridge_) 304 return in_process_ns_view_bridge_->GetNSView(); 305 return nullptr; 306} 307 308void RenderWidgetHostViewMac::SetDelegate( 309 NSObject<RenderWidgetHostViewMacDelegate>* delegate) { 310 [GetInProcessNSView() setResponderDelegate:delegate]; 311} 312 313ui::TextInputType RenderWidgetHostViewMac::GetTextInputType() { 314 if (!GetActiveWidget()) 315 return ui::TEXT_INPUT_TYPE_NONE; 316 return text_input_manager_->GetTextInputState()->type; 317} 318 319RenderWidgetHostImpl* RenderWidgetHostViewMac::GetActiveWidget() { 320 return text_input_manager_ ? text_input_manager_->GetActiveWidget() : nullptr; 321} 322 323const TextInputManager::CompositionRangeInfo* 324RenderWidgetHostViewMac::GetCompositionRangeInfo() { 325 return text_input_manager_ ? text_input_manager_->GetCompositionRangeInfo() 326 : nullptr; 327} 328 329const TextInputManager::TextSelection* 330RenderWidgetHostViewMac::GetTextSelection() { 331 return text_input_manager_ ? text_input_manager_->GetTextSelection( 332 GetFocusedViewForTextSelection()) 333 : nullptr; 334} 335 336/////////////////////////////////////////////////////////////////////////////// 337// RenderWidgetHostViewMac, RenderWidgetHostView implementation: 338 339void RenderWidgetHostViewMac::InitAsChild(gfx::NativeView parent_view) { 340 DCHECK_EQ(widget_type_, WidgetType::kFrame); 341} 342 343void RenderWidgetHostViewMac::InitAsPopup( 344 RenderWidgetHostView* parent_host_view, 345 const gfx::Rect& pos) { 346 DCHECK_EQ(widget_type_, WidgetType::kPopup); 347 348 popup_parent_host_view_ = 349 static_cast<RenderWidgetHostViewMac*>(parent_host_view); 350 351 RenderWidgetHostViewMac* old_child = 352 popup_parent_host_view_->popup_child_host_view_; 353 if (old_child) { 354 DCHECK(old_child->popup_parent_host_view_ == popup_parent_host_view_); 355 old_child->popup_parent_host_view_ = nullptr; 356 } 357 popup_parent_host_view_->popup_child_host_view_ = this; 358 359 // Use transparent background color for the popup in order to avoid flashing 360 // the white background on popup open when dark color-scheme is used. 361 SetContentBackgroundColor(SK_ColorTRANSPARENT); 362 363 // This path is used by the time/date picker. 364 // When FormControlsRefresh is enabled the popup window should use 365 // the native shadow. 366 bool has_shadow = features::IsFormControlsRefreshEnabled(); 367 ns_view_->InitAsPopup(pos, has_shadow); 368} 369 370void RenderWidgetHostViewMac::InitAsFullscreen( 371 RenderWidgetHostView* reference_host_view) { 372 // This path appears never to be reached. 373 NOTREACHED(); 374} 375 376RenderWidgetHostViewBase* 377RenderWidgetHostViewMac::GetFocusedViewForTextSelection() { 378 // We obtain the TextSelection from focused RWH which is obtained from the 379 // frame tree. 380 return GetFocusedWidget() ? GetFocusedWidget()->GetView() : nullptr; 381} 382 383RenderWidgetHostDelegate* 384RenderWidgetHostViewMac::GetFocusedRenderWidgetHostDelegate() { 385 if (auto* focused_widget = GetFocusedWidget()) 386 return focused_widget->delegate(); 387 return host()->delegate(); 388} 389 390RenderWidgetHostImpl* RenderWidgetHostViewMac::GetWidgetForKeyboardEvent() { 391 DCHECK(in_keyboard_event_); 392 return RenderWidgetHostImpl::FromID(keyboard_event_widget_process_id_, 393 keyboard_event_widget_routing_id_); 394} 395 396RenderWidgetHostImpl* RenderWidgetHostViewMac::GetWidgetForIme() { 397 if (in_keyboard_event_) 398 return GetWidgetForKeyboardEvent(); 399 return GetActiveWidget(); 400} 401 402void RenderWidgetHostViewMac::UpdateNSViewAndDisplayProperties() { 403 display_link_ = ui::DisplayLinkMac::GetForDisplay(display_.id()); 404 if (!display_link_) { 405 // Note that on some headless systems, the display link will fail to be 406 // created, so this should not be a fatal error. 407 LOG(ERROR) << "Failed to create display link."; 408 } 409 410 // During auto-resize it is the responsibility of the caller to ensure that 411 // the NSView and RenderWidgetHostImpl are kept in sync. 412 if (host()->auto_resize_enabled()) 413 return; 414 415 if (host()->delegate()) 416 host()->delegate()->SendScreenRects(); 417 else 418 host()->SendScreenRects(); 419 420 // RenderWidgetHostImpl will query BrowserCompositorMac for the dimensions 421 // to send to the renderer, so it is required that BrowserCompositorMac be 422 // updated first. Only notify RenderWidgetHostImpl of the update if any 423 // properties it will query have changed. 424 if (browser_compositor_->UpdateSurfaceFromNSView( 425 view_bounds_in_window_dip_.size(), display_)) { 426 host()->NotifyScreenInfoChanged(); 427 } 428} 429 430void RenderWidgetHostViewMac::GetScreenInfo(blink::ScreenInfo* screen_info) { 431 browser_compositor_->GetRendererScreenInfo(screen_info); 432} 433 434void RenderWidgetHostViewMac::Show() { 435 is_visible_ = true; 436 ns_view_->SetVisible(is_visible_); 437 browser_compositor_->SetViewVisible(is_visible_); 438 WasUnOccluded(); 439} 440 441void RenderWidgetHostViewMac::Hide() { 442 is_visible_ = false; 443 ns_view_->SetVisible(is_visible_); 444 browser_compositor_->SetViewVisible(is_visible_); 445 WasOccluded(); 446} 447 448void RenderWidgetHostViewMac::WasUnOccluded() { 449 if (!host()->is_hidden()) 450 return; 451 452 browser_compositor_->SetRenderWidgetHostIsHidden(false); 453 454 DelegatedFrameHost* delegated_frame_host = 455 browser_compositor_->GetDelegatedFrameHost(); 456 457 bool has_saved_frame = 458 browser_compositor_->has_saved_frame_before_state_transition(); 459 460 auto tab_switch_start_state = TakeRecordContentToVisibleTimeRequest(); 461 462 const bool renderer_should_record_presentation_time = !has_saved_frame; 463 host()->WasShown(renderer_should_record_presentation_time 464 ? tab_switch_start_state.Clone() 465 : blink::mojom::RecordContentToVisibleTimeRequestPtr()); 466 467 if (delegated_frame_host) { 468 // If the frame for the renderer is already available, then the 469 // tab-switching time is the presentation time for the browser-compositor. 470 const bool record_presentation_time = has_saved_frame; 471 delegated_frame_host->WasShown( 472 browser_compositor_->GetRendererLocalSurfaceId(), 473 browser_compositor_->GetRendererSize(), 474 record_presentation_time 475 ? std::move(tab_switch_start_state) 476 : blink::mojom::RecordContentToVisibleTimeRequestPtr()); 477 } 478} 479 480void RenderWidgetHostViewMac::WasOccluded() { 481 if (host()->is_hidden()) 482 return; 483 484 host()->WasHidden(); 485 browser_compositor_->SetRenderWidgetHostIsHidden(true); 486} 487 488void RenderWidgetHostViewMac::SetSize(const gfx::Size& size) { 489 gfx::Rect rect = GetViewBounds(); 490 rect.set_size(size); 491 SetBounds(rect); 492} 493 494void RenderWidgetHostViewMac::SetBounds(const gfx::Rect& rect) { 495 ns_view_->SetBounds(rect); 496} 497 498gfx::NativeView RenderWidgetHostViewMac::GetNativeView() { 499 return GetInProcessNSView(); 500} 501 502gfx::NativeViewAccessible RenderWidgetHostViewMac::GetNativeViewAccessible() { 503 return GetInProcessNSView(); 504} 505 506void RenderWidgetHostViewMac::Focus() { 507 // Ignore redundant calls, as they can cause unending loops of focus-setting. 508 // https://crbug.com/998123 509 if (is_first_responder_) 510 return; 511 ns_view_->MakeFirstResponder(); 512} 513 514bool RenderWidgetHostViewMac::HasFocus() { 515 return is_first_responder_; 516} 517 518bool RenderWidgetHostViewMac::IsSurfaceAvailableForCopy() { 519 return browser_compositor_->GetDelegatedFrameHost() 520 ->CanCopyFromCompositingSurface(); 521} 522 523bool RenderWidgetHostViewMac::IsShowing() { 524 return is_visible_; 525} 526 527gfx::Rect RenderWidgetHostViewMac::GetViewBounds() { 528 return view_bounds_in_window_dip_ + 529 window_frame_in_screen_dip_.OffsetFromOrigin(); 530} 531 532bool RenderWidgetHostViewMac::IsMouseLocked() { 533 return mouse_locked_; 534} 535 536void RenderWidgetHostViewMac::UpdateCursor(const WebCursor& cursor) { 537 GetCursorManager()->UpdateCursor(this, cursor); 538} 539 540void RenderWidgetHostViewMac::DisplayCursor(const WebCursor& cursor) { 541 ns_view_->DisplayCursor(cursor.cursor()); 542} 543 544CursorManager* RenderWidgetHostViewMac::GetCursorManager() { 545 return cursor_manager_.get(); 546} 547 548void RenderWidgetHostViewMac::OnDidNavigateMainFrameToNewPage() { 549 gesture_provider_.ResetDetection(); 550} 551 552void RenderWidgetHostViewMac::SetIsLoading(bool is_loading) { 553 is_loading_ = is_loading; 554 // If we ever decide to show the waiting cursor while the page is loading 555 // like Chrome does on Windows, call |UpdateCursor()| here. 556} 557 558void RenderWidgetHostViewMac::OnUpdateTextInputStateCalled( 559 TextInputManager* text_input_manager, 560 RenderWidgetHostViewBase* updated_view, 561 bool did_update_state) { 562 if (!did_update_state) 563 return; 564 565 const ui::mojom::TextInputState* state = 566 text_input_manager->GetTextInputState(); 567 if (state) 568 ns_view_->SetTextInputState(state->type, state->flags); 569 else 570 ns_view_->SetTextInputState(ui::TEXT_INPUT_TYPE_NONE, 0); 571 572 // |updated_view| is the last view to change its TextInputState which can be 573 // used to start/stop monitoring composition info when it has a focused 574 // editable text input field. 575 RenderWidgetHostImpl* widget_host = 576 RenderWidgetHostImpl::From(updated_view->GetRenderWidgetHost()); 577 578 // We might end up here when |updated_view| has had active TextInputState and 579 // then got destroyed. In that case, |updated_view->GetRenderWidgetHost()| 580 // returns nullptr. 581 if (!widget_host) 582 return; 583 584 // Set the monitor state based on the text input focus state. 585 const bool has_focus = HasFocus(); 586 bool need_monitor_composition = 587 has_focus && state && state->type != ui::TEXT_INPUT_TYPE_NONE; 588 589 widget_host->RequestCompositionUpdates(false /* immediate_request */, 590 need_monitor_composition); 591 592 if (has_focus) { 593 SetTextInputActive(true); 594 595 // Let AppKit cache the new input context to make IMEs happy. 596 // See http://crbug.com/73039. 597 [NSApp updateWindows]; 598 } 599} 600 601void RenderWidgetHostViewMac::OnImeCancelComposition( 602 TextInputManager* text_input_manager, 603 RenderWidgetHostViewBase* updated_view) { 604 ns_view_->CancelComposition(); 605} 606 607void RenderWidgetHostViewMac::OnImeCompositionRangeChanged( 608 TextInputManager* text_input_manager, 609 RenderWidgetHostViewBase* updated_view) { 610 const TextInputManager::CompositionRangeInfo* info = 611 GetCompositionRangeInfo(); 612 if (!info) 613 return; 614 // The RangeChanged message is only sent with valid values. The current 615 // caret position (start == end) will be sent if there is no IME range. 616 ns_view_->SetCompositionRangeInfo(info->range); 617} 618 619void RenderWidgetHostViewMac::OnSelectionBoundsChanged( 620 TextInputManager* text_input_manager, 621 RenderWidgetHostViewBase* updated_view) { 622 DCHECK_EQ(GetTextInputManager(), text_input_manager); 623 624 // The rest of the code is to support the Mac Zoom feature tracking the 625 // text caret; we can skip it if that feature is not currently enabled. 626 if (!UAZoomEnabled()) 627 return; 628 629 RenderWidgetHostViewBase* focused_view = GetFocusedViewForTextSelection(); 630 if (!focused_view) 631 return; 632 633 const TextInputManager::SelectionRegion* region = 634 GetTextInputManager()->GetSelectionRegion(focused_view); 635 if (!region) 636 return; 637 638 // Create a rectangle for the edge of the selection focus, which will be 639 // the same as the caret position if the selection is collapsed. That's 640 // what we want to try to keep centered on-screen if possible. 641 gfx::Rect gfx_caret_rect(region->focus.edge_start_rounded().x(), 642 region->focus.edge_start_rounded().y(), 1, 643 region->focus.GetHeight()); 644 gfx_caret_rect += view_bounds_in_window_dip_.OffsetFromOrigin(); 645 gfx_caret_rect += window_frame_in_screen_dip_.OffsetFromOrigin(); 646 647 // Note that UAZoomChangeFocus wants unflipped screen coordinates. 648 NSRect caret_rect = NSRectFromCGRect(gfx_caret_rect.ToCGRect()); 649 UAZoomChangeFocus(&caret_rect, &caret_rect, kUAZoomFocusTypeInsertionPoint); 650} 651 652void RenderWidgetHostViewMac::OnTextSelectionChanged( 653 TextInputManager* text_input_manager, 654 RenderWidgetHostViewBase* updated_view) { 655 DCHECK_EQ(GetTextInputManager(), text_input_manager); 656 657 const TextInputManager::TextSelection* selection = GetTextSelection(); 658 if (!selection) 659 return; 660 661 ns_view_->SetTextSelection(selection->text(), selection->offset(), 662 selection->range()); 663} 664 665void RenderWidgetHostViewMac::OnGestureEvent( 666 const ui::GestureEventData& gesture) { 667 blink::WebGestureEvent web_gesture = 668 ui::CreateWebGestureEventFromGestureEventData(gesture); 669 670 ui::LatencyInfo latency_info(ui::SourceEventType::TOUCH); 671 672 if (ShouldRouteEvents()) { 673 blink::WebGestureEvent gesture_event(web_gesture); 674 host()->delegate()->GetInputEventRouter()->RouteGestureEvent( 675 this, &gesture_event, latency_info); 676 } else { 677 host()->ForwardGestureEventWithLatencyInfo(web_gesture, latency_info); 678 } 679} 680 681void RenderWidgetHostViewMac::OnRenderFrameMetadataChangedAfterActivation() { 682 last_frame_root_background_color_ = host() 683 ->render_frame_metadata_provider() 684 ->LastRenderFrameMetadata() 685 .root_background_color; 686} 687 688void RenderWidgetHostViewMac::RenderProcessGone() { 689 Destroy(); 690} 691 692void RenderWidgetHostViewMac::Destroy() { 693 host()->render_frame_metadata_provider()->RemoveObserver(this); 694 695 // Unlock the mouse in the NSView's process before destroying our bridge to 696 // it. 697 if (mouse_locked_) { 698 mouse_locked_ = false; 699 ns_view_->SetCursorLocked(false); 700 } 701 702 // Destroy the local and remote briges to the NSView. Note that the NSView on 703 // the other side of |ns_view_| may outlive us due to other retains. 704 ns_view_ = nullptr; 705 in_process_ns_view_bridge_.reset(); 706 remote_ns_view_client_receiver_.reset(); 707 remote_ns_view_.reset(); 708 709 // Delete the delegated frame state, which will reach back into 710 // host(). 711 browser_compositor_.reset(); 712 713 // Make sure none of our observers send events for us to process after 714 // we release host(). 715 NotifyObserversAboutShutdown(); 716 717 if (text_input_manager_) 718 text_input_manager_->RemoveObserver(this); 719 720 mouse_wheel_phase_handler_.IgnorePendingWheelEndEvent(); 721 722 // The call to the base class will set host() to nullptr. 723 RenderWidgetHostViewBase::Destroy(); 724 725 delete this; 726} 727 728void RenderWidgetHostViewMac::SetTooltipText( 729 const base::string16& tooltip_text) { 730 GetCursorManager()->SetTooltipTextForView(this, tooltip_text); 731} 732 733void RenderWidgetHostViewMac::DisplayTooltipText( 734 const base::string16& tooltip_text) { 735 ns_view_->SetTooltipText(tooltip_text); 736} 737 738viz::ScopedSurfaceIdAllocator 739RenderWidgetHostViewMac::DidUpdateVisualProperties( 740 const cc::RenderFrameMetadata& metadata) { 741 base::OnceCallback<void()> allocation_task = base::BindOnce( 742 base::IgnoreResult( 743 &RenderWidgetHostViewMac::OnDidUpdateVisualPropertiesComplete), 744 weak_factory_.GetWeakPtr(), metadata); 745 return browser_compositor_->GetScopedRendererSurfaceIdAllocator( 746 std::move(allocation_task)); 747} 748 749void RenderWidgetHostViewMac::DidNavigate() { 750 browser_compositor_->DidNavigate(); 751} 752 753gfx::Size RenderWidgetHostViewMac::GetRequestedRendererSize() { 754 return browser_compositor_->GetRendererSize(); 755} 756 757namespace { 758 759// A helper function for CombineTextNodesAndMakeCallback() below. It would 760// ordinarily be a helper lambda in that class method, but it processes a tree 761// and needs to be recursive, and that's crazy difficult to do with a lambda. 762// TODO(avi): Move this to be a lambda when P0839R0 lands in C++. 763void AddTextNodesToVector(const ui::AXNode* node, 764 std::vector<base::string16>* strings) { 765 const ui::AXNodeData& node_data = node->data(); 766 767 if (node_data.role == ax::mojom::Role::kStaticText) { 768 if (node_data.HasStringAttribute(ax::mojom::StringAttribute::kName)) { 769 strings->emplace_back( 770 node_data.GetString16Attribute(ax::mojom::StringAttribute::kName)); 771 } 772 return; 773 } 774 775 for (const auto* child : node->children()) 776 AddTextNodesToVector(child, strings); 777} 778 779using SpeechCallback = base::OnceCallback<void(const base::string16&)>; 780void CombineTextNodesAndMakeCallback(SpeechCallback callback, 781 const ui::AXTreeUpdate& update) { 782 std::vector<base::string16> text_node_contents; 783 text_node_contents.reserve(update.nodes.size()); 784 785 ui::AXTree tree(update); 786 787 AddTextNodesToVector(tree.root(), &text_node_contents); 788 789 std::move(callback).Run( 790 base::JoinString(text_node_contents, base::ASCIIToUTF16("\n"))); 791} 792 793} // namespace 794 795void RenderWidgetHostViewMac::GetPageTextForSpeech(SpeechCallback callback) { 796 // Note that the WebContents::RequestAXTreeSnapshot() call has a limit on the 797 // number of nodes returned. For large pages, this call might hit that limit. 798 // This is a reasonable thing. The "Start Speaking" call dates back to the 799 // earliest days of the Mac, before accessibility. It was designed to show off 800 // the speech capabilities of the Mac, which is fine, but is mostly 801 // inapplicable nowadays. Is it useful to have the Mac read megabytes of text 802 // with zero control over positioning, with no fast-forward or rewind? What 803 // does it even mean to read a Web 2.0 dynamic, AJAXy page aloud from 804 // beginning to end? 805 // 806 // If this is an issue, please file a bug explaining the situation and how the 807 // limits of this feature affect you in the real world. 808 809 GetWebContents()->RequestAXTreeSnapshot( 810 base::BindOnce(CombineTextNodesAndMakeCallback, std::move(callback)), 811 ui::AXMode::kWebContents); 812} 813 814void RenderWidgetHostViewMac::SpeakSelection() { 815 const TextInputManager::TextSelection* selection = GetTextSelection(); 816 if (selection && !selection->selected_text().empty()) { 817 ui::TextServicesContextMenu::SpeakText(selection->selected_text()); 818 return; 819 } 820 821 // With no selection, speak an approximation of the entire contents of the 822 // page. 823 GetPageTextForSpeech(base::BindOnce(ui::TextServicesContextMenu::SpeakText)); 824} 825 826void RenderWidgetHostViewMac::SetWindowFrameInScreen(const gfx::Rect& rect) { 827 DCHECK(GetInProcessNSView() && ![GetInProcessNSView() window]) 828 << "This method should only be called in headless browser!"; 829 OnWindowFrameInScreenChanged(rect); 830} 831 832// 833// RenderWidgetHostViewCocoa uses the stored selection text, 834// which implements NSServicesRequests protocol. 835// 836 837void RenderWidgetHostViewMac::SetShowingContextMenu(bool showing) { 838 ns_view_->SetShowingContextMenu(showing); 839} 840 841uint32_t RenderWidgetHostViewMac::GetCaptureSequenceNumber() const { 842 return latest_capture_sequence_number_; 843} 844 845void RenderWidgetHostViewMac::CopyFromSurface( 846 const gfx::Rect& src_subrect, 847 const gfx::Size& dst_size, 848 base::OnceCallback<void(const SkBitmap&)> callback) { 849 base::WeakPtr<RenderWidgetHostImpl> popup_host; 850 base::WeakPtr<DelegatedFrameHost> popup_frame_host; 851 if (popup_child_host_view_) { 852 popup_host = popup_child_host_view_->host()->GetWeakPtr(); 853 popup_frame_host = popup_child_host_view_->BrowserCompositor() 854 ->GetDelegatedFrameHost() 855 ->GetWeakPtr(); 856 } 857 RenderWidgetHostViewBase::CopyMainAndPopupFromSurface( 858 host()->GetWeakPtr(), 859 browser_compositor_->GetDelegatedFrameHost()->GetWeakPtr(), popup_host, 860 popup_frame_host, src_subrect, dst_size, display_.device_scale_factor(), 861 std::move(callback)); 862} 863 864void RenderWidgetHostViewMac::EnsureSurfaceSynchronizedForWebTest() { 865 ++latest_capture_sequence_number_; 866 browser_compositor_->ForceNewSurfaceId(); 867} 868 869void RenderWidgetHostViewMac::OnDidUpdateVisualPropertiesComplete( 870 const cc::RenderFrameMetadata& metadata) { 871 browser_compositor_->UpdateSurfaceFromChild( 872 host()->auto_resize_enabled(), metadata.device_scale_factor, 873 metadata.viewport_size_in_pixels, 874 metadata.local_surface_id.value_or(viz::LocalSurfaceId())); 875} 876 877void RenderWidgetHostViewMac::TakeFallbackContentFrom( 878 RenderWidgetHostView* view) { 879 DCHECK(!static_cast<RenderWidgetHostViewBase*>(view) 880 ->IsRenderWidgetHostViewChildFrame()); 881 RenderWidgetHostViewMac* view_mac = 882 static_cast<RenderWidgetHostViewMac*>(view); 883 ScopedCAActionDisabler disabler; 884 base::Optional<SkColor> color = view_mac->GetBackgroundColor(); 885 if (color) 886 SetBackgroundColor(*color); 887 888 // Make the NSView for |this| display the same content as is being displayed 889 // in the NSView for |view_mac|. 890 const gfx::CALayerParams* ca_layer_params = 891 view_mac->browser_compositor_->GetLastCALayerParams(); 892 if (ca_layer_params) 893 ns_view_->SetCALayerParams(*ca_layer_params); 894 browser_compositor_->TakeFallbackContentFrom( 895 view_mac->browser_compositor_.get()); 896} 897 898bool RenderWidgetHostViewMac::GetLineBreakIndex( 899 const std::vector<gfx::Rect>& bounds, 900 const gfx::Range& range, 901 size_t* line_break_point) { 902 DCHECK(line_break_point); 903 if (range.start() >= bounds.size() || range.is_reversed() || range.is_empty()) 904 return false; 905 906 // We can't check line breaking completely from only rectangle array. Thus we 907 // assume the line breaking as the next character's y offset is larger than 908 // a threshold. Currently the threshold is determined as minimum y offset plus 909 // 75% of maximum height. 910 // TODO(nona): Check the threshold is reliable or not. 911 // TODO(nona): Bidi support. 912 const size_t loop_end_idx = 913 std::min(bounds.size(), static_cast<size_t>(range.end())); 914 int max_height = 0; 915 int min_y_offset = std::numeric_limits<int32_t>::max(); 916 for (size_t idx = range.start(); idx < loop_end_idx; ++idx) { 917 max_height = std::max(max_height, bounds[idx].height()); 918 min_y_offset = std::min(min_y_offset, bounds[idx].y()); 919 } 920 int line_break_threshold = min_y_offset + (max_height * 3 / 4); 921 for (size_t idx = range.start(); idx < loop_end_idx; ++idx) { 922 if (bounds[idx].y() > line_break_threshold) { 923 *line_break_point = idx; 924 return true; 925 } 926 } 927 return false; 928} 929 930gfx::Rect RenderWidgetHostViewMac::GetFirstRectForCompositionRange( 931 const gfx::Range& range, 932 gfx::Range* actual_range) { 933 const TextInputManager::CompositionRangeInfo* composition_info = 934 GetCompositionRangeInfo(); 935 if (!composition_info) 936 return gfx::Rect(); 937 938 DCHECK(actual_range); 939 DCHECK(!composition_info->character_bounds.empty()); 940 DCHECK(range.start() <= composition_info->character_bounds.size()); 941 DCHECK(range.end() <= composition_info->character_bounds.size()); 942 943 if (range.is_empty()) { 944 *actual_range = range; 945 if (range.start() == composition_info->character_bounds.size()) { 946 return gfx::Rect( 947 composition_info->character_bounds[range.start() - 1].right(), 948 composition_info->character_bounds[range.start() - 1].y(), 0, 949 composition_info->character_bounds[range.start() - 1].height()); 950 } else { 951 return gfx::Rect( 952 composition_info->character_bounds[range.start()].x(), 953 composition_info->character_bounds[range.start()].y(), 0, 954 composition_info->character_bounds[range.start()].height()); 955 } 956 } 957 958 size_t end_idx; 959 if (!GetLineBreakIndex(composition_info->character_bounds, range, &end_idx)) { 960 end_idx = range.end(); 961 } 962 *actual_range = gfx::Range(range.start(), end_idx); 963 gfx::Rect rect = composition_info->character_bounds[range.start()]; 964 for (size_t i = range.start() + 1; i < end_idx; ++i) { 965 rect.Union(composition_info->character_bounds[i]); 966 } 967 return rect; 968} 969 970gfx::Range RenderWidgetHostViewMac::ConvertCharacterRangeToCompositionRange( 971 const gfx::Range& request_range) { 972 const TextInputManager::CompositionRangeInfo* composition_info = 973 GetCompositionRangeInfo(); 974 if (!composition_info) 975 return gfx::Range::InvalidRange(); 976 977 if (composition_info->range.is_empty()) 978 return gfx::Range::InvalidRange(); 979 980 if (composition_info->range.is_reversed()) 981 return gfx::Range::InvalidRange(); 982 983 if (request_range.start() < composition_info->range.start() || 984 request_range.start() > composition_info->range.end() || 985 request_range.end() > composition_info->range.end()) { 986 return gfx::Range::InvalidRange(); 987 } 988 989 return gfx::Range(request_range.start() - composition_info->range.start(), 990 request_range.end() - composition_info->range.start()); 991} 992 993WebContents* RenderWidgetHostViewMac::GetWebContents() { 994 return WebContents::FromRenderViewHost(RenderViewHost::From(host())); 995} 996 997bool RenderWidgetHostViewMac::GetCachedFirstRectForCharacterRange( 998 const gfx::Range& requested_range, 999 gfx::Rect* rect, 1000 gfx::Range* actual_range) { 1001 if (!GetTextInputManager()) 1002 return false; 1003 1004 DCHECK(rect); 1005 // This exists to make IMEs more responsive, see http://crbug.com/115920 1006 TRACE_EVENT0("browser", 1007 "RenderWidgetHostViewMac::GetFirstRectForCharacterRange"); 1008 1009 const TextInputManager::TextSelection* selection = GetTextSelection(); 1010 if (!selection) 1011 return false; 1012 1013 // If requested range is same as caret location, we can just return it. 1014 if (selection->range().is_empty() && requested_range == selection->range()) { 1015 DCHECK(GetFocusedWidget()); 1016 if (actual_range) 1017 *actual_range = requested_range; 1018 *rect = GetTextInputManager() 1019 ->GetSelectionRegion(GetFocusedWidget()->GetView()) 1020 ->caret_rect; 1021 return true; 1022 } 1023 1024 const TextInputManager::CompositionRangeInfo* composition_info = 1025 GetCompositionRangeInfo(); 1026 if (!composition_info || composition_info->range.is_empty()) { 1027 if (!requested_range.IsBoundedBy(selection->range())) 1028 return false; 1029 DCHECK(GetFocusedWidget()); 1030 if (actual_range) 1031 *actual_range = selection->range(); 1032 *rect = GetTextInputManager() 1033 ->GetSelectionRegion(GetFocusedWidget()->GetView()) 1034 ->first_selection_rect; 1035 return true; 1036 } 1037 1038 const gfx::Range request_range_in_composition = 1039 ConvertCharacterRangeToCompositionRange(requested_range); 1040 if (request_range_in_composition == gfx::Range::InvalidRange()) 1041 return false; 1042 1043 // If firstRectForCharacterRange in WebFrame is failed in renderer, 1044 // ImeCompositionRangeChanged will be sent with empty vector. 1045 if (!composition_info || composition_info->character_bounds.empty()) 1046 return false; 1047 DCHECK_EQ(composition_info->character_bounds.size(), 1048 composition_info->range.length()); 1049 1050 gfx::Range ui_actual_range; 1051 *rect = GetFirstRectForCompositionRange(request_range_in_composition, 1052 &ui_actual_range); 1053 if (actual_range) { 1054 *actual_range = 1055 gfx::Range(composition_info->range.start() + ui_actual_range.start(), 1056 composition_info->range.start() + ui_actual_range.end()); 1057 } 1058 return true; 1059} 1060 1061void RenderWidgetHostViewMac::FocusedNodeChanged( 1062 bool is_editable_node, 1063 const gfx::Rect& node_bounds_in_screen) { 1064 ns_view_->CancelComposition(); 1065 1066 // If the Mac Zoom feature is enabled, update it with the bounds of the 1067 // current focused node so that it can ensure that it's scrolled into view. 1068 // Don't do anything if it's an editable node, as this will be handled by 1069 // OnSelectionBoundsChanged instead. 1070 if (UAZoomEnabled() && !is_editable_node) { 1071 NSRect bounds = NSRectFromCGRect(node_bounds_in_screen.ToCGRect()); 1072 UAZoomChangeFocus(&bounds, NULL, kUAZoomFocusTypeOther); 1073 } 1074} 1075 1076void RenderWidgetHostViewMac::ResetFallbackToFirstNavigationSurface() { 1077 browser_compositor_->GetDelegatedFrameHost() 1078 ->ResetFallbackToFirstNavigationSurface(); 1079} 1080 1081bool RenderWidgetHostViewMac::RequestRepaintForTesting() { 1082 return browser_compositor_->ForceNewSurfaceId(); 1083} 1084 1085void RenderWidgetHostViewMac::TransformPointToRootSurface(gfx::PointF* point) { 1086 browser_compositor_->TransformPointToRootSurface(point); 1087} 1088 1089gfx::Rect RenderWidgetHostViewMac::GetBoundsInRootWindow() { 1090 return window_frame_in_screen_dip_; 1091} 1092 1093blink::mojom::PointerLockResult RenderWidgetHostViewMac::LockMouse( 1094 bool request_unadjusted_movement) { 1095 if (mouse_locked_) 1096 return blink::mojom::PointerLockResult::kSuccess; 1097 1098 if (request_unadjusted_movement && !IsUnadjustedMouseMovementSupported()) { 1099 return blink::mojom::PointerLockResult::kUnsupportedOptions; 1100 } 1101 1102 mouse_locked_ = true; 1103 mouse_lock_unadjusted_movement_ = request_unadjusted_movement; 1104 1105 // Lock position of mouse cursor and hide it. 1106 ns_view_->SetCursorLockedUnacceleratedMovement(request_unadjusted_movement); 1107 ns_view_->SetCursorLocked(true); 1108 1109 // Clear the tooltip window. 1110 ns_view_->SetTooltipText(base::string16()); 1111 1112 return blink::mojom::PointerLockResult::kSuccess; 1113} 1114 1115blink::mojom::PointerLockResult RenderWidgetHostViewMac::ChangeMouseLock( 1116 bool request_unadjusted_movement) { 1117 if (request_unadjusted_movement && !IsUnadjustedMouseMovementSupported()) { 1118 return blink::mojom::PointerLockResult::kUnsupportedOptions; 1119 } 1120 1121 mouse_lock_unadjusted_movement_ = request_unadjusted_movement; 1122 ns_view_->SetCursorLockedUnacceleratedMovement(request_unadjusted_movement); 1123 return blink::mojom::PointerLockResult::kSuccess; 1124} 1125 1126void RenderWidgetHostViewMac::UnlockMouse() { 1127 if (!mouse_locked_) 1128 return; 1129 mouse_locked_ = false; 1130 mouse_lock_unadjusted_movement_ = false; 1131 ns_view_->SetCursorLocked(false); 1132 ns_view_->SetCursorLockedUnacceleratedMovement(false); 1133 1134 if (host()) 1135 host()->LostMouseLock(); 1136} 1137 1138bool RenderWidgetHostViewMac::GetIsMouseLockedUnadjustedMovementForTesting() { 1139 return mouse_locked_ && mouse_lock_unadjusted_movement_; 1140} 1141 1142bool RenderWidgetHostViewMac::IsUnadjustedMouseMovementSupported() { 1143 // kCGEventUnacceleratedPointerMovementX/Y were first added as CGEventField 1144 // enum values in the 10.15.1 SDK. 1145 // 1146 // While they do seem to work at runtime back to 10.14, the safest approach is 1147 // to limit their use to 10.15.1 and newer to avoid relying on private or 1148 // undocumented APIs on earlier OSes. 1149 if (@available(macOS 10.15.1, *)) { 1150 return true; 1151 } 1152 return false; 1153} 1154 1155bool RenderWidgetHostViewMac::LockKeyboard( 1156 base::Optional<base::flat_set<ui::DomCode>> dom_codes) { 1157 base::Optional<std::vector<uint32_t>> uint_dom_codes; 1158 if (dom_codes) { 1159 uint_dom_codes.emplace(); 1160 for (const auto& dom_code : *dom_codes) 1161 uint_dom_codes->push_back(static_cast<uint32_t>(dom_code)); 1162 } 1163 is_keyboard_locked_ = true; 1164 ns_view_->LockKeyboard(uint_dom_codes); 1165 return true; 1166} 1167 1168void RenderWidgetHostViewMac::UnlockKeyboard() { 1169 if (!is_keyboard_locked_) 1170 return; 1171 1172 is_keyboard_locked_ = false; 1173 ns_view_->UnlockKeyboard(); 1174} 1175 1176bool RenderWidgetHostViewMac::IsKeyboardLocked() { 1177 return is_keyboard_locked_; 1178} 1179 1180base::flat_map<std::string, std::string> 1181RenderWidgetHostViewMac::GetKeyboardLayoutMap() { 1182 return ui::GenerateDomKeyboardLayoutMap(); 1183} 1184 1185void RenderWidgetHostViewMac::GestureEventAck( 1186 const WebGestureEvent& event, 1187 blink::mojom::InputEventResultState ack_result) { 1188 ForwardTouchpadZoomEventIfNecessary(event, ack_result); 1189 1190 // Stop flinging if a GSU event with momentum phase is sent to the renderer 1191 // but not consumed. 1192 StopFlingingIfNecessary(event, ack_result); 1193 1194 bool consumed = ack_result == blink::mojom::InputEventResultState::kConsumed; 1195 switch (event.GetType()) { 1196 case WebInputEvent::Type::kGestureScrollBegin: 1197 case WebInputEvent::Type::kGestureScrollUpdate: 1198 case WebInputEvent::Type::kGestureScrollEnd: 1199 [GetInProcessNSView() processedGestureScrollEvent:event 1200 consumed:consumed]; 1201 return; 1202 default: 1203 break; 1204 } 1205 mouse_wheel_phase_handler_.GestureEventAck(event, ack_result); 1206} 1207 1208void RenderWidgetHostViewMac::ProcessAckedTouchEvent( 1209 const TouchEventWithLatencyInfo& touch, 1210 blink::mojom::InputEventResultState ack_result) { 1211 const bool event_consumed = 1212 ack_result == blink::mojom::InputEventResultState::kConsumed; 1213 gesture_provider_.OnTouchEventAck( 1214 touch.event.unique_touch_event_id, event_consumed, 1215 InputEventResultStateIsSetNonBlocking(ack_result)); 1216 if (touch.event.touch_start_or_first_touch_move && event_consumed && 1217 host()->delegate() && host()->delegate()->GetInputEventRouter()) { 1218 host() 1219 ->delegate() 1220 ->GetInputEventRouter() 1221 ->OnHandledTouchStartOrFirstTouchMove( 1222 touch.event.unique_touch_event_id); 1223 } 1224} 1225 1226void RenderWidgetHostViewMac::DidOverscroll( 1227 const ui::DidOverscrollParams& params) { 1228 [GetInProcessNSView() processedOverscroll:params]; 1229} 1230 1231std::unique_ptr<SyntheticGestureTarget> 1232RenderWidgetHostViewMac::CreateSyntheticGestureTarget() { 1233 RenderWidgetHostImpl* host = 1234 RenderWidgetHostImpl::From(GetRenderWidgetHost()); 1235 return std::unique_ptr<SyntheticGestureTarget>( 1236 new SyntheticGestureTargetMac(host, GetInProcessNSView())); 1237} 1238 1239const viz::LocalSurfaceId& RenderWidgetHostViewMac::GetLocalSurfaceId() const { 1240 return browser_compositor_->GetRendererLocalSurfaceId(); 1241} 1242 1243const viz::FrameSinkId& RenderWidgetHostViewMac::GetFrameSinkId() const { 1244 return browser_compositor_->GetDelegatedFrameHost()->frame_sink_id(); 1245} 1246 1247bool RenderWidgetHostViewMac::ShouldRouteEvents() const { 1248 // Event routing requires a valid frame sink (that is, that we be connected to 1249 // a ui::Compositor), which is not guaranteed to be the case. 1250 // https://crbug.com/844095 1251 if (!browser_compositor_->GetRootFrameSinkId().is_valid()) 1252 return false; 1253 1254 return host()->delegate() && host()->delegate()->GetInputEventRouter(); 1255} 1256 1257void RenderWidgetHostViewMac::SendTouchpadZoomEvent( 1258 const WebGestureEvent* event) { 1259 DCHECK(event->IsTouchpadZoomEvent()); 1260 if (ShouldRouteEvents()) { 1261 host()->delegate()->GetInputEventRouter()->RouteGestureEvent( 1262 this, event, ui::LatencyInfo(ui::SourceEventType::TOUCHPAD)); 1263 return; 1264 } 1265 host()->ForwardGestureEvent(*event); 1266} 1267 1268void RenderWidgetHostViewMac::InjectTouchEvent( 1269 const WebTouchEvent& event, 1270 const ui::LatencyInfo& latency_info) { 1271 ui::FilteredGestureProvider::TouchHandlingResult result = 1272 gesture_provider_.OnTouchEvent(MotionEventWeb(event)); 1273 if (!result.succeeded) 1274 return; 1275 1276 if (ShouldRouteEvents()) { 1277 WebTouchEvent touch_event(event); 1278 host()->delegate()->GetInputEventRouter()->RouteTouchEvent( 1279 this, &touch_event, latency_info); 1280 } else { 1281 host()->ForwardTouchEventWithLatencyInfo(event, latency_info); 1282 } 1283} 1284 1285bool RenderWidgetHostViewMac::HasFallbackSurface() const { 1286 return browser_compositor_->GetDelegatedFrameHost()->HasFallbackSurface(); 1287} 1288 1289bool RenderWidgetHostViewMac::TransformPointToCoordSpaceForView( 1290 const gfx::PointF& point, 1291 RenderWidgetHostViewBase* target_view, 1292 gfx::PointF* transformed_point) { 1293 if (target_view == this) { 1294 *transformed_point = point; 1295 return true; 1296 } 1297 1298 return target_view->TransformPointToLocalCoordSpace( 1299 point, GetCurrentSurfaceId(), transformed_point); 1300} 1301 1302viz::FrameSinkId RenderWidgetHostViewMac::GetRootFrameSinkId() { 1303 return browser_compositor_->GetRootFrameSinkId(); 1304} 1305 1306viz::SurfaceId RenderWidgetHostViewMac::GetCurrentSurfaceId() const { 1307 // |browser_compositor_| could be null if this method is called during its 1308 // destruction. 1309 if (!browser_compositor_) 1310 return viz::SurfaceId(); 1311 return browser_compositor_->GetDelegatedFrameHost()->GetCurrentSurfaceId(); 1312} 1313 1314void RenderWidgetHostViewMac::ShutdownHost() { 1315 weak_factory_.InvalidateWeakPtrs(); 1316 host()->ShutdownAndDestroyWidget(true); 1317 // Do not touch any members at this point, |this| has been deleted. 1318} 1319 1320void RenderWidgetHostViewMac::SetActive(bool active) { 1321 if (host()) { 1322 host()->SetActive(active); 1323 if (active) { 1324 if (HasFocus()) 1325 host()->Focus(); 1326 } else { 1327 host()->Blur(); 1328 } 1329 } 1330 if (HasFocus()) 1331 SetTextInputActive(active); 1332 if (!active) 1333 UnlockMouse(); 1334} 1335 1336void RenderWidgetHostViewMac::ShowDefinitionForSelection() { 1337 // This will round-trip to the NSView to determine the selection range. 1338 ns_view_->ShowDictionaryOverlayForSelection(); 1339} 1340 1341void RenderWidgetHostViewMac::UpdateBackgroundColor() { 1342 // This is called by the embedding code prior to the first frame appearing, 1343 // to set a reasonable color to show before the web content generates its 1344 // first frame. This will be overridden by the web contents. 1345 DCHECK(RenderWidgetHostViewBase::GetBackgroundColor()); 1346 SkColor color = *RenderWidgetHostViewBase::GetBackgroundColor(); 1347 SetBackgroundLayerColor(color); 1348 browser_compositor_->SetBackgroundColor(color); 1349} 1350 1351base::Optional<SkColor> RenderWidgetHostViewMac::GetBackgroundColor() { 1352 // This is used to specify a color to temporarily show while waiting for web 1353 // content. This should never return transparent, since that will cause bugs 1354 // where views are initialized as having a transparent background 1355 // inappropriately. 1356 // https://crbug.com/735407 1357 base::Optional<SkColor> color = 1358 RenderWidgetHostViewBase::GetBackgroundColor(); 1359 return (color && *color == SK_ColorTRANSPARENT) ? SK_ColorWHITE : color; 1360} 1361 1362void RenderWidgetHostViewMac::SetBackgroundLayerColor(SkColor color) { 1363 if (color == background_layer_color_) 1364 return; 1365 background_layer_color_ = color; 1366 ns_view_->SetBackgroundColor(color); 1367} 1368 1369base::Optional<DisplayFeature> RenderWidgetHostViewMac::GetDisplayFeature() { 1370 return display_feature_; 1371} 1372 1373void RenderWidgetHostViewMac::SetDisplayFeatureForTesting( 1374 const DisplayFeature* display_feature) { 1375 if (display_feature) 1376 display_feature_ = *display_feature; 1377 else 1378 display_feature_ = base::nullopt; 1379} 1380 1381BrowserAccessibilityManager* 1382RenderWidgetHostViewMac::CreateBrowserAccessibilityManager( 1383 BrowserAccessibilityDelegate* delegate, 1384 bool for_root_frame) { 1385 return new BrowserAccessibilityManagerMac( 1386 BrowserAccessibilityManagerMac::GetEmptyDocument(), delegate); 1387} 1388 1389gfx::NativeViewAccessible 1390RenderWidgetHostViewMac::AccessibilityGetNativeViewAccessible() { 1391 return GetInProcessNSView(); 1392} 1393 1394gfx::NativeViewAccessible 1395RenderWidgetHostViewMac::AccessibilityGetNativeViewAccessibleForWindow() { 1396 if (remote_window_accessible_) 1397 return remote_window_accessible_.get(); 1398 return [GetInProcessNSView() window]; 1399} 1400 1401void RenderWidgetHostViewMac::SetTextInputActive(bool active) { 1402 const bool should_enable_password_input = 1403 active && GetTextInputType() == ui::TEXT_INPUT_TYPE_PASSWORD; 1404 if (should_enable_password_input) 1405 password_input_enabler_.reset(new ui::ScopedPasswordInputEnabler()); 1406 else 1407 password_input_enabler_.reset(); 1408} 1409 1410MouseWheelPhaseHandler* RenderWidgetHostViewMac::GetMouseWheelPhaseHandler() { 1411 return &mouse_wheel_phase_handler_; 1412} 1413 1414/////////////////////////////////////////////////////////////////////////////// 1415// RenderWidgetHostNSViewHostHelper and mojom::RenderWidgetHostNSViewHost 1416// implementation: 1417 1418id RenderWidgetHostViewMac::GetRootBrowserAccessibilityElement() { 1419 if (auto* manager = host()->GetRootBrowserAccessibilityManager()) 1420 return ToBrowserAccessibilityCocoa(manager->GetRoot()); 1421 return nil; 1422} 1423 1424id RenderWidgetHostViewMac::GetFocusedBrowserAccessibilityElement() { 1425 return GetAccessibilityFocusedUIElement(); 1426} 1427 1428void RenderWidgetHostViewMac::SetAccessibilityWindow(NSWindow* window) { 1429 // When running in-process, just use the NSView's NSWindow as its own 1430 // accessibility element. 1431 remote_window_accessible_.reset(); 1432} 1433 1434bool RenderWidgetHostViewMac::SyncIsWidgetForMainFrame( 1435 bool* is_for_main_frame) { 1436 *is_for_main_frame = !!host()->owner_delegate(); 1437 return true; 1438} 1439 1440void RenderWidgetHostViewMac::SyncIsWidgetForMainFrame( 1441 SyncIsWidgetForMainFrameCallback callback) { 1442 bool is_for_main_frame; 1443 SyncIsWidgetForMainFrame(&is_for_main_frame); 1444 std::move(callback).Run(is_for_main_frame); 1445} 1446 1447void RenderWidgetHostViewMac::RequestShutdown() { 1448 if (!weak_factory_.HasWeakPtrs()) { 1449 base::ThreadTaskRunnerHandle::Get()->PostTask( 1450 FROM_HERE, base::BindOnce(&RenderWidgetHostViewMac::ShutdownHost, 1451 weak_factory_.GetWeakPtr())); 1452 } 1453} 1454 1455void RenderWidgetHostViewMac::OnFirstResponderChanged(bool is_first_responder) { 1456 if (is_first_responder_ == is_first_responder) 1457 return; 1458 is_first_responder_ = is_first_responder; 1459 accessibility_focus_overrider_.SetViewIsFirstResponder(is_first_responder_); 1460 if (is_first_responder_) { 1461 host()->GotFocus(); 1462 SetTextInputActive(true); 1463 } else { 1464 SetTextInputActive(false); 1465 host()->LostFocus(); 1466 } 1467} 1468 1469void RenderWidgetHostViewMac::OnWindowIsKeyChanged(bool is_key) { 1470 if (is_window_key_ == is_key) 1471 return; 1472 is_window_key_ = is_key; 1473 accessibility_focus_overrider_.SetWindowIsKey(is_window_key_); 1474 if (is_first_responder_) 1475 SetActive(is_key); 1476} 1477 1478void RenderWidgetHostViewMac::OnBoundsInWindowChanged( 1479 const gfx::Rect& view_bounds_in_window_dip, 1480 bool attached_to_window) { 1481 bool view_size_changed = 1482 view_bounds_in_window_dip_.size() != view_bounds_in_window_dip.size(); 1483 1484 if (attached_to_window) { 1485 view_bounds_in_window_dip_ = view_bounds_in_window_dip; 1486 } else { 1487 // If not attached to a window, do not update the bounds origin (since it is 1488 // meaningless, and the last value is the best guess at the next meaningful 1489 // value). 1490 view_bounds_in_window_dip_.set_size(view_bounds_in_window_dip.size()); 1491 } 1492 1493 if (view_size_changed) 1494 UpdateNSViewAndDisplayProperties(); 1495} 1496 1497void RenderWidgetHostViewMac::OnWindowFrameInScreenChanged( 1498 const gfx::Rect& window_frame_in_screen_dip) { 1499 if (window_frame_in_screen_dip_ == window_frame_in_screen_dip) 1500 return; 1501 1502 window_frame_in_screen_dip_ = window_frame_in_screen_dip; 1503 if (host()->delegate()) 1504 host()->delegate()->SendScreenRects(); 1505 else 1506 host()->SendScreenRects(); 1507} 1508 1509void RenderWidgetHostViewMac::OnDisplayChanged( 1510 const display::Display& display) { 1511 display_ = display; 1512 UpdateNSViewAndDisplayProperties(); 1513} 1514 1515void RenderWidgetHostViewMac::BeginKeyboardEvent() { 1516 DCHECK(!in_keyboard_event_); 1517 in_keyboard_event_ = true; 1518 RenderWidgetHostImpl* widget_host = host(); 1519 if (widget_host && widget_host->delegate()) { 1520 widget_host = 1521 widget_host->delegate()->GetFocusedRenderWidgetHost(widget_host); 1522 } 1523 if (widget_host) { 1524 keyboard_event_widget_process_id_ = widget_host->GetProcess()->GetID(); 1525 keyboard_event_widget_routing_id_ = widget_host->GetRoutingID(); 1526 } 1527} 1528 1529void RenderWidgetHostViewMac::EndKeyboardEvent() { 1530 in_keyboard_event_ = false; 1531 keyboard_event_widget_process_id_ = 0; 1532 keyboard_event_widget_routing_id_ = 0; 1533} 1534 1535void RenderWidgetHostViewMac::ForwardKeyboardEvent( 1536 const NativeWebKeyboardEvent& key_event, 1537 const ui::LatencyInfo& latency_info) { 1538 if (auto* widget_host = GetWidgetForKeyboardEvent()) { 1539 widget_host->ForwardKeyboardEventWithLatencyInfo(key_event, latency_info); 1540 } 1541} 1542 1543void RenderWidgetHostViewMac::ForwardKeyboardEventWithCommands( 1544 const NativeWebKeyboardEvent& key_event, 1545 const ui::LatencyInfo& latency_info, 1546 std::vector<blink::mojom::EditCommandPtr> commands) { 1547 if (auto* widget_host = GetWidgetForKeyboardEvent()) { 1548 widget_host->ForwardKeyboardEventWithCommands(key_event, latency_info, 1549 std::move(commands)); 1550 } 1551} 1552 1553void RenderWidgetHostViewMac::RouteOrProcessMouseEvent( 1554 const blink::WebMouseEvent& const_web_event) { 1555 blink::WebMouseEvent web_event = const_web_event; 1556 ui::LatencyInfo latency_info(ui::SourceEventType::OTHER); 1557 latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_UI_COMPONENT); 1558 if (ShouldRouteEvents()) { 1559 host()->delegate()->GetInputEventRouter()->RouteMouseEvent(this, &web_event, 1560 latency_info); 1561 } else { 1562 ProcessMouseEvent(web_event, latency_info); 1563 } 1564} 1565 1566void RenderWidgetHostViewMac::RouteOrProcessTouchEvent( 1567 const blink::WebTouchEvent& const_web_event) { 1568 blink::WebTouchEvent web_event = const_web_event; 1569 ui::FilteredGestureProvider::TouchHandlingResult result = 1570 gesture_provider_.OnTouchEvent(MotionEventWeb(web_event)); 1571 if (!result.succeeded) 1572 return; 1573 1574 ui::LatencyInfo latency_info(ui::SourceEventType::OTHER); 1575 latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_UI_COMPONENT); 1576 if (ShouldRouteEvents()) { 1577 host()->delegate()->GetInputEventRouter()->RouteTouchEvent(this, &web_event, 1578 latency_info); 1579 } else { 1580 ProcessTouchEvent(web_event, latency_info); 1581 } 1582} 1583 1584void RenderWidgetHostViewMac::RouteOrProcessWheelEvent( 1585 const blink::WebMouseWheelEvent& const_web_event) { 1586 blink::WebMouseWheelEvent web_event = const_web_event; 1587 ui::LatencyInfo latency_info(ui::SourceEventType::WHEEL); 1588 latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_UI_COMPONENT); 1589 mouse_wheel_phase_handler_.AddPhaseIfNeededAndScheduleEndEvent( 1590 web_event, ShouldRouteEvents()); 1591 if (web_event.phase == blink::WebMouseWheelEvent::kPhaseEnded) { 1592 // A wheel end event is scheduled and will get dispatched if momentum 1593 // phase doesn't start in 100ms. Don't sent the wheel end event 1594 // immediately. 1595 return; 1596 } 1597 if (ShouldRouteEvents()) { 1598 host()->delegate()->GetInputEventRouter()->RouteMouseWheelEvent( 1599 this, &web_event, latency_info); 1600 } else { 1601 ProcessMouseWheelEvent(web_event, latency_info); 1602 } 1603} 1604 1605void RenderWidgetHostViewMac::ForwardMouseEvent( 1606 const blink::WebMouseEvent& web_event) { 1607 if (host()) 1608 host()->ForwardMouseEvent(web_event); 1609 1610 if (web_event.GetType() == WebInputEvent::Type::kMouseLeave) 1611 ns_view_->SetTooltipText(base::string16()); 1612} 1613 1614void RenderWidgetHostViewMac::ForwardWheelEvent( 1615 const blink::WebMouseWheelEvent& const_web_event) { 1616 blink::WebMouseWheelEvent web_event = const_web_event; 1617 mouse_wheel_phase_handler_.AddPhaseIfNeededAndScheduleEndEvent(web_event, 1618 false); 1619} 1620 1621void RenderWidgetHostViewMac::GestureBegin(blink::WebGestureEvent begin_event, 1622 bool is_synthetically_injected) { 1623 gesture_begin_event_ = std::make_unique<WebGestureEvent>(begin_event); 1624 1625 // If the page is at the minimum zoom level, require a threshold be reached 1626 // before the pinch has an effect. Synthetic pinches are not subject to this 1627 // threshold. 1628 // TODO(crbug.com/1038683): |page_at_minimum_scale_| is always true, should it 1629 // be removed or correctly set based on RenderFrameMetadata? 1630 if (page_at_minimum_scale_) { 1631 pinch_has_reached_zoom_threshold_ = is_synthetically_injected; 1632 pinch_unused_amount_ = 1; 1633 } 1634} 1635 1636void RenderWidgetHostViewMac::GestureUpdate( 1637 blink::WebGestureEvent update_event) { 1638 // If, due to nesting of multiple gestures (e.g, from multiple touch 1639 // devices), the beginning of the gesture has been lost, skip the remainder 1640 // of the gesture. 1641 if (!gesture_begin_event_) 1642 return; 1643 1644 if (!pinch_has_reached_zoom_threshold_) { 1645 pinch_unused_amount_ *= update_event.data.pinch_update.scale; 1646 if (pinch_unused_amount_ < 0.667 || pinch_unused_amount_ > 1.5) 1647 pinch_has_reached_zoom_threshold_ = true; 1648 } 1649 1650 // Send a GesturePinchBegin event if none has been sent yet. 1651 if (!gesture_begin_pinch_sent_) { 1652 // Before starting a pinch sequence, send the pending wheel end event to 1653 // finish scrolling. 1654 mouse_wheel_phase_handler_.DispatchPendingWheelEndEvent(); 1655 WebGestureEvent begin_event(*gesture_begin_event_); 1656 begin_event.SetType(WebInputEvent::Type::kGesturePinchBegin); 1657 begin_event.SetSourceDevice(blink::WebGestureDevice::kTouchpad); 1658 begin_event.SetNeedsWheelEvent(true); 1659 SendTouchpadZoomEvent(&begin_event); 1660 gesture_begin_pinch_sent_ = YES; 1661 } 1662 1663 // Send a GesturePinchUpdate event. 1664 update_event.data.pinch_update.zoom_disabled = 1665 !pinch_has_reached_zoom_threshold_; 1666 SendTouchpadZoomEvent(&update_event); 1667} 1668 1669void RenderWidgetHostViewMac::GestureEnd(blink::WebGestureEvent end_event) { 1670 gesture_begin_event_.reset(); 1671 if (gesture_begin_pinch_sent_) { 1672 SendTouchpadZoomEvent(&end_event); 1673 gesture_begin_pinch_sent_ = false; 1674 } 1675} 1676 1677void RenderWidgetHostViewMac::SmartMagnify( 1678 const blink::WebGestureEvent& smart_magnify_event) { 1679 SendTouchpadZoomEvent(&smart_magnify_event); 1680} 1681 1682void RenderWidgetHostViewMac::ImeSetComposition( 1683 const base::string16& text, 1684 const std::vector<ui::ImeTextSpan>& ime_text_spans, 1685 const gfx::Range& replacement_range, 1686 int selection_start, 1687 int selection_end) { 1688 if (auto* widget_host = GetWidgetForIme()) { 1689 widget_host->ImeSetComposition(text, ime_text_spans, replacement_range, 1690 selection_start, selection_end); 1691 } 1692} 1693 1694void RenderWidgetHostViewMac::ImeCommitText( 1695 const base::string16& text, 1696 const gfx::Range& replacement_range) { 1697 if (auto* widget_host = GetWidgetForIme()) { 1698 widget_host->ImeCommitText(text, std::vector<ui::ImeTextSpan>(), 1699 replacement_range, 0); 1700 } 1701} 1702 1703void RenderWidgetHostViewMac::ImeFinishComposingText() { 1704 if (auto* widget_host = GetWidgetForIme()) { 1705 widget_host->ImeFinishComposingText(false); 1706 } 1707} 1708 1709void RenderWidgetHostViewMac::ImeCancelCompositionFromCocoa() { 1710 if (auto* widget_host = GetWidgetForIme()) { 1711 widget_host->ImeCancelComposition(); 1712 } 1713} 1714 1715void RenderWidgetHostViewMac::LookUpDictionaryOverlayFromRange( 1716 const gfx::Range& range) { 1717 content::RenderWidgetHostViewBase* focused_view = 1718 GetFocusedViewForTextSelection(); 1719 if (!focused_view) 1720 return; 1721 1722 RenderWidgetHostImpl* widget_host = 1723 RenderWidgetHostImpl::From(focused_view->GetRenderWidgetHost()); 1724 if (!widget_host) 1725 return; 1726 1727 int32_t target_widget_process_id = widget_host->GetProcess()->GetID(); 1728 int32_t target_widget_routing_id = widget_host->GetRoutingID(); 1729 TextInputClientMac::GetInstance()->GetStringFromRange( 1730 widget_host, range, 1731 base::BindOnce(&RenderWidgetHostViewMac::OnGotStringForDictionaryOverlay, 1732 weak_factory_.GetWeakPtr(), target_widget_process_id, 1733 target_widget_routing_id)); 1734} 1735 1736void RenderWidgetHostViewMac::LookUpDictionaryOverlayAtPoint( 1737 const gfx::PointF& root_point) { 1738 if (!host() || !host()->delegate() || 1739 !host()->delegate()->GetInputEventRouter()) 1740 return; 1741 1742 gfx::PointF transformed_point; 1743 RenderWidgetHostImpl* widget_host = 1744 host()->delegate()->GetInputEventRouter()->GetRenderWidgetHostAtPoint( 1745 this, root_point, &transformed_point); 1746 if (!widget_host) 1747 return; 1748 1749 // For popups, do not support QuickLook. 1750 if (popup_parent_host_view_) 1751 return; 1752 1753 int32_t target_widget_process_id = widget_host->GetProcess()->GetID(); 1754 int32_t target_widget_routing_id = widget_host->GetRoutingID(); 1755 TextInputClientMac::GetInstance()->GetStringAtPoint( 1756 widget_host, gfx::ToFlooredPoint(transformed_point), 1757 base::BindOnce(&RenderWidgetHostViewMac::OnGotStringForDictionaryOverlay, 1758 weak_factory_.GetWeakPtr(), target_widget_process_id, 1759 target_widget_routing_id)); 1760} 1761 1762bool RenderWidgetHostViewMac::SyncGetCharacterIndexAtPoint( 1763 const gfx::PointF& root_point, 1764 uint32_t* index) { 1765 *index = UINT32_MAX; 1766 1767 if (!host() || !host()->delegate() || 1768 !host()->delegate()->GetInputEventRouter()) 1769 return true; 1770 1771 gfx::PointF transformed_point; 1772 RenderWidgetHostImpl* widget_host = 1773 host()->delegate()->GetInputEventRouter()->GetRenderWidgetHostAtPoint( 1774 this, root_point, &transformed_point); 1775 if (!widget_host) 1776 return true; 1777 1778 *index = TextInputClientMac::GetInstance()->GetCharacterIndexAtPoint( 1779 widget_host, gfx::ToFlooredPoint(transformed_point)); 1780 return true; 1781} 1782 1783void RenderWidgetHostViewMac::SyncGetCharacterIndexAtPoint( 1784 const gfx::PointF& root_point, 1785 SyncGetCharacterIndexAtPointCallback callback) { 1786 uint32_t index; 1787 SyncGetCharacterIndexAtPoint(root_point, &index); 1788 std::move(callback).Run(index); 1789} 1790 1791bool RenderWidgetHostViewMac::SyncGetFirstRectForRange( 1792 const gfx::Range& requested_range, 1793 const gfx::Rect& in_rect, 1794 const gfx::Range& in_actual_range, 1795 gfx::Rect* rect, 1796 gfx::Range* actual_range, 1797 bool* success) { 1798 *rect = in_rect; 1799 *actual_range = in_actual_range; 1800 if (!GetFocusedWidget()) { 1801 *success = false; 1802 return true; 1803 } 1804 *success = true; 1805 if (!GetCachedFirstRectForCharacterRange(requested_range, rect, 1806 actual_range)) { 1807 // https://crbug.com/121917 1808 base::ScopedAllowBlocking allow_wait; 1809 *rect = TextInputClientMac::GetInstance()->GetFirstRectForRange( 1810 GetFocusedWidget(), requested_range); 1811 // TODO(thakis): Pipe |actualRange| through TextInputClientMac machinery. 1812 *actual_range = requested_range; 1813 } 1814 return true; 1815} 1816 1817void RenderWidgetHostViewMac::SyncGetFirstRectForRange( 1818 const gfx::Range& requested_range, 1819 const gfx::Rect& rect, 1820 const gfx::Range& actual_range, 1821 SyncGetFirstRectForRangeCallback callback) { 1822 gfx::Rect out_rect; 1823 gfx::Range out_actual_range; 1824 bool success; 1825 SyncGetFirstRectForRange(requested_range, rect, actual_range, &out_rect, 1826 &out_actual_range, &success); 1827 std::move(callback).Run(out_rect, out_actual_range, success); 1828} 1829 1830void RenderWidgetHostViewMac::ExecuteEditCommand(const std::string& command) { 1831 if (host()->delegate()) { 1832 host()->delegate()->ExecuteEditCommand(command, base::nullopt); 1833 } 1834} 1835 1836void RenderWidgetHostViewMac::Undo() { 1837 if (auto* delegate = GetFocusedRenderWidgetHostDelegate()) { 1838 delegate->Undo(); 1839 } 1840} 1841 1842void RenderWidgetHostViewMac::Redo() { 1843 if (auto* delegate = GetFocusedRenderWidgetHostDelegate()) { 1844 delegate->Redo(); 1845 } 1846} 1847 1848void RenderWidgetHostViewMac::Cut() { 1849 if (auto* delegate = GetFocusedRenderWidgetHostDelegate()) { 1850 delegate->Cut(); 1851 } 1852} 1853 1854void RenderWidgetHostViewMac::Copy() { 1855 if (auto* delegate = GetFocusedRenderWidgetHostDelegate()) { 1856 delegate->Copy(); 1857 } 1858} 1859 1860void RenderWidgetHostViewMac::CopyToFindPboard() { 1861 WebContents* web_contents = GetWebContents(); 1862 if (web_contents) 1863 web_contents->CopyToFindPboard(); 1864} 1865 1866void RenderWidgetHostViewMac::Paste() { 1867 if (auto* delegate = GetFocusedRenderWidgetHostDelegate()) { 1868 delegate->Paste(); 1869 } 1870} 1871 1872void RenderWidgetHostViewMac::PasteAndMatchStyle() { 1873 if (auto* delegate = GetFocusedRenderWidgetHostDelegate()) { 1874 delegate->PasteAndMatchStyle(); 1875 } 1876} 1877 1878void RenderWidgetHostViewMac::SelectAll() { 1879 if (auto* delegate = GetFocusedRenderWidgetHostDelegate()) { 1880 delegate->SelectAll(); 1881 } 1882} 1883 1884bool RenderWidgetHostViewMac::SyncIsSpeaking(bool* is_speaking) { 1885 *is_speaking = ui::TextServicesContextMenu::IsSpeaking(); 1886 return true; 1887} 1888 1889void RenderWidgetHostViewMac::SyncIsSpeaking(SyncIsSpeakingCallback callback) { 1890 bool is_speaking; 1891 SyncIsSpeaking(&is_speaking); 1892 std::move(callback).Run(is_speaking); 1893} 1894 1895void RenderWidgetHostViewMac::StartSpeaking() { 1896 RenderWidgetHostView* target = this; 1897 WebContents* web_contents = GetWebContents(); 1898 if (web_contents) { 1899 content::BrowserPluginGuestManager* guest_manager = 1900 web_contents->GetBrowserContext()->GetGuestManager(); 1901 if (guest_manager) { 1902 content::WebContents* guest = 1903 guest_manager->GetFullPageGuest(web_contents); 1904 if (guest) { 1905 target = guest->GetRenderWidgetHostView(); 1906 } 1907 } 1908 } 1909 target->SpeakSelection(); 1910} 1911 1912void RenderWidgetHostViewMac::StopSpeaking() { 1913 ui::TextServicesContextMenu::StopSpeaking(); 1914} 1915 1916void RenderWidgetHostViewMac::SetRemoteAccessibilityWindowToken( 1917 const std::vector<uint8_t>& window_token) { 1918 if (window_token.empty()) { 1919 remote_window_accessible_.reset(); 1920 } else { 1921 remote_window_accessible_ = 1922 ui::RemoteAccessibility::GetRemoteElementFromToken(window_token); 1923 } 1924} 1925 1926/////////////////////////////////////////////////////////////////////////////// 1927// mojom::RenderWidgetHostNSViewHost functions that translate events and 1928// forward them to the RenderWidgetHostNSViewHostHelper implementation: 1929 1930void RenderWidgetHostViewMac::ForwardKeyboardEventWithCommands( 1931 std::unique_ptr<blink::WebCoalescedInputEvent> input_event, 1932 const std::vector<uint8_t>& native_event_data, 1933 bool skip_in_browser, 1934 std::vector<blink::mojom::EditCommandPtr> edit_commands) { 1935 if (!input_event || !blink::WebInputEvent::IsKeyboardEventType( 1936 input_event->Event().GetType())) { 1937 DLOG(ERROR) << "Absent or non-KeyboardEventType event."; 1938 return; 1939 } 1940 const blink::WebKeyboardEvent& keyboard_event = 1941 static_cast<const blink::WebKeyboardEvent&>(input_event->Event()); 1942 NativeWebKeyboardEvent native_event(keyboard_event, nil); 1943 native_event.skip_in_browser = skip_in_browser; 1944 // The NSEvent constructed from the InputEvent sent over mojo is not even 1945 // close to the original NSEvent, resulting in all sorts of bugs. Use the 1946 // native event serialization to reconstruct the NSEvent. 1947 // https://crbug.com/919167,943197,964052 1948 [native_event.os_event release]; 1949 native_event.os_event = [ui::EventFromData(native_event_data) retain]; 1950 ForwardKeyboardEventWithCommands(native_event, input_event->latency_info(), 1951 std::move(edit_commands)); 1952} 1953 1954void RenderWidgetHostViewMac::RouteOrProcessMouseEvent( 1955 std::unique_ptr<blink::WebCoalescedInputEvent> input_event) { 1956 if (!input_event || 1957 !blink::WebInputEvent::IsMouseEventType(input_event->Event().GetType())) { 1958 DLOG(ERROR) << "Absent or non-MouseEventType event."; 1959 return; 1960 } 1961 const blink::WebMouseEvent& mouse_event = 1962 static_cast<const blink::WebMouseEvent&>(input_event->Event()); 1963 RouteOrProcessMouseEvent(mouse_event); 1964} 1965 1966void RenderWidgetHostViewMac::RouteOrProcessTouchEvent( 1967 std::unique_ptr<blink::WebCoalescedInputEvent> input_event) { 1968 if (!input_event || 1969 !blink::WebInputEvent::IsTouchEventType(input_event->Event().GetType())) { 1970 DLOG(ERROR) << "Absent or non-TouchEventType event."; 1971 return; 1972 } 1973 const blink::WebTouchEvent& touch_event = 1974 static_cast<const blink::WebTouchEvent&>(input_event->Event()); 1975 RouteOrProcessTouchEvent(touch_event); 1976} 1977 1978void RenderWidgetHostViewMac::RouteOrProcessWheelEvent( 1979 std::unique_ptr<blink::WebCoalescedInputEvent> input_event) { 1980 if (!input_event || input_event->Event().GetType() != 1981 blink::WebInputEvent::Type::kMouseWheel) { 1982 DLOG(ERROR) << "Absent or non-MouseWheel event."; 1983 return; 1984 } 1985 const blink::WebMouseWheelEvent& wheel_event = 1986 static_cast<const blink::WebMouseWheelEvent&>(input_event->Event()); 1987 RouteOrProcessWheelEvent(wheel_event); 1988} 1989 1990void RenderWidgetHostViewMac::ForwardMouseEvent( 1991 std::unique_ptr<blink::WebCoalescedInputEvent> input_event) { 1992 if (!input_event || 1993 !blink::WebInputEvent::IsMouseEventType(input_event->Event().GetType())) { 1994 DLOG(ERROR) << "Absent or non-MouseEventType event."; 1995 return; 1996 } 1997 const blink::WebMouseEvent& mouse_event = 1998 static_cast<const blink::WebMouseEvent&>(input_event->Event()); 1999 ForwardMouseEvent(mouse_event); 2000} 2001 2002void RenderWidgetHostViewMac::ForwardWheelEvent( 2003 std::unique_ptr<blink::WebCoalescedInputEvent> input_event) { 2004 if (!input_event || input_event->Event().GetType() != 2005 blink::WebInputEvent::Type::kMouseWheel) { 2006 DLOG(ERROR) << "Absent or non-MouseWheel event."; 2007 return; 2008 } 2009 const blink::WebMouseWheelEvent& wheel_event = 2010 static_cast<const blink::WebMouseWheelEvent&>(input_event->Event()); 2011 ForwardWheelEvent(wheel_event); 2012} 2013 2014void RenderWidgetHostViewMac::GestureBegin( 2015 std::unique_ptr<blink::WebCoalescedInputEvent> input_event, 2016 bool is_synthetically_injected) { 2017 if (!input_event || !blink::WebInputEvent::IsGestureEventType( 2018 input_event->Event().GetType())) { 2019 DLOG(ERROR) << "Absent or non-GestureEventType event."; 2020 return; 2021 } 2022 blink::WebGestureEvent gesture_event = 2023 static_cast<const blink::WebGestureEvent&>(input_event->Event()); 2024 // Strip the gesture type, because it is not known. 2025 gesture_event.SetType(blink::WebInputEvent::Type::kUndefined); 2026 GestureBegin(gesture_event, is_synthetically_injected); 2027} 2028 2029void RenderWidgetHostViewMac::GestureUpdate( 2030 std::unique_ptr<blink::WebCoalescedInputEvent> input_event) { 2031 if (!input_event || !blink::WebInputEvent::IsGestureEventType( 2032 input_event->Event().GetType())) { 2033 DLOG(ERROR) << "Absent or non-GestureEventType event."; 2034 return; 2035 } 2036 const blink::WebGestureEvent& gesture_event = 2037 static_cast<const blink::WebGestureEvent&>(input_event->Event()); 2038 GestureUpdate(gesture_event); 2039} 2040 2041void RenderWidgetHostViewMac::GestureEnd( 2042 std::unique_ptr<blink::WebCoalescedInputEvent> input_event) { 2043 if (!input_event || !blink::WebInputEvent::IsGestureEventType( 2044 input_event->Event().GetType())) { 2045 DLOG(ERROR) << "Absent or non-GestureEventType event."; 2046 return; 2047 } 2048 blink::WebGestureEvent gesture_event = 2049 static_cast<const blink::WebGestureEvent&>(input_event->Event()); 2050 GestureEnd(gesture_event); 2051} 2052 2053void RenderWidgetHostViewMac::SmartMagnify( 2054 std::unique_ptr<blink::WebCoalescedInputEvent> input_event) { 2055 if (!input_event || !blink::WebInputEvent::IsGestureEventType( 2056 input_event->Event().GetType())) { 2057 DLOG(ERROR) << "Absent or non-GestureEventType event."; 2058 return; 2059 } 2060 const blink::WebGestureEvent& gesture_event = 2061 static_cast<const blink::WebGestureEvent&>(input_event->Event()); 2062 SmartMagnify(gesture_event); 2063} 2064 2065void RenderWidgetHostViewMac::OnGotStringForDictionaryOverlay( 2066 int32_t target_widget_process_id, 2067 int32_t target_widget_routing_id, 2068 ui::mojom::AttributedStringPtr attributed_string, 2069 const gfx::Point& baseline_point) { 2070 if (!attributed_string || attributed_string->string.empty()) { 2071 // The PDF plugin does not support getting the attributed string at point. 2072 // Until it does, use NSPerformService(), which opens Dictionary.app. 2073 // TODO(shuchen): Support GetStringAtPoint() & GetStringFromRange() for PDF. 2074 // https://crbug.com/152438 2075 // This often just opens a blank dictionary, not the definition of |string|. 2076 // https://crbug.com/830047 2077 // This path will be taken, inappropriately, when a lookup gesture was 2078 // performed at a location that doesn't have text, but some text is 2079 // selected. 2080 // https://crbug.com/830906 2081 if (auto* selection = GetTextSelection()) { 2082 const base::string16& selected_text = selection->selected_text(); 2083 NSString* ns_selected_text = base::SysUTF16ToNSString(selected_text); 2084 if ([ns_selected_text length] == 0) 2085 return; 2086 scoped_refptr<ui::UniquePasteboard> pasteboard = new ui::UniquePasteboard; 2087 if ([pasteboard->get() writeObjects:@[ ns_selected_text ]]) { 2088 NSPerformService(@"Look Up in Dictionary", pasteboard->get()); 2089 } 2090 } 2091 } else { 2092 // By the time we get here |widget_host| might have been destroyed. 2093 // https://crbug.com/737032 2094 auto* widget_host = content::RenderWidgetHost::FromID( 2095 target_widget_process_id, target_widget_routing_id); 2096 gfx::Point updated_baseline_point = baseline_point; 2097 if (widget_host) { 2098 if (auto* rwhv = widget_host->GetView()) { 2099 updated_baseline_point = 2100 rwhv->TransformPointToRootCoordSpace(baseline_point); 2101 } 2102 } 2103 ns_view_->ShowDictionaryOverlay(std::move(attributed_string), 2104 updated_baseline_point); 2105 } 2106} 2107 2108Class GetRenderWidgetHostViewCocoaClassForTesting() { 2109 return [RenderWidgetHostViewCocoa class]; 2110} 2111 2112} // namespace content 2113