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