1// Copyright 2018 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 "components/remote_cocoa/app_shim/application_bridge.h"
6
7#include "base/bind.h"
8#include "base/no_destructor.h"
9#include "components/remote_cocoa/app_shim/alert.h"
10#include "components/remote_cocoa/app_shim/color_panel_bridge.h"
11#include "components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h"
12#include "components/remote_cocoa/app_shim/native_widget_ns_window_host_helper.h"
13#include "mojo/public/cpp/bindings/associated_remote.h"
14#include "mojo/public/cpp/bindings/self_owned_receiver.h"
15#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
16#include "ui/base/cocoa/remote_accessibility_api.h"
17
18namespace remote_cocoa {
19
20namespace {
21
22class NativeWidgetBridgeOwner : public NativeWidgetNSWindowHostHelper {
23 public:
24  NativeWidgetBridgeOwner(
25      uint64_t bridge_id,
26      mojo::PendingAssociatedReceiver<mojom::NativeWidgetNSWindow>
27          bridge_receiver,
28      mojo::PendingAssociatedRemote<mojom::NativeWidgetNSWindowHost>
29          host_remote,
30      mojo::PendingAssociatedRemote<mojom::TextInputHost>
31          text_input_host_remote) {
32    host_remote_.Bind(std::move(host_remote),
33                      ui::WindowResizeHelperMac::Get()->task_runner());
34    text_input_host_remote_.Bind(
35        std::move(text_input_host_remote),
36        ui::WindowResizeHelperMac::Get()->task_runner());
37    bridge_ = std::make_unique<NativeWidgetNSWindowBridge>(
38        bridge_id, host_remote_.get(), this, text_input_host_remote_.get());
39    bridge_->BindReceiver(
40        std::move(bridge_receiver),
41        base::BindOnce(&NativeWidgetBridgeOwner::OnMojoDisconnect,
42                       base::Unretained(this)));
43  }
44
45 private:
46  ~NativeWidgetBridgeOwner() override {}
47
48  void OnMojoDisconnect() { delete this; }
49
50  // NativeWidgetNSWindowHostHelper:
51  id GetNativeViewAccessible() override {
52    if (!remote_accessibility_element_) {
53      int64_t browser_pid = 0;
54      std::vector<uint8_t> element_token;
55      host_remote_->GetRootViewAccessibilityToken(&browser_pid, &element_token);
56      [NSAccessibilityRemoteUIElement
57          registerRemoteUIProcessIdentifier:browser_pid];
58      remote_accessibility_element_ =
59          ui::RemoteAccessibility::GetRemoteElementFromToken(element_token);
60    }
61    return remote_accessibility_element_.get();
62  }
63  void DispatchKeyEvent(ui::KeyEvent* event) override {
64    bool event_handled = false;
65    host_remote_->DispatchKeyEventRemote(std::make_unique<ui::KeyEvent>(*event),
66                                         &event_handled);
67    if (event_handled)
68      event->SetHandled();
69  }
70  bool DispatchKeyEventToMenuController(ui::KeyEvent* event) override {
71    bool event_swallowed = false;
72    bool event_handled = false;
73    host_remote_->DispatchKeyEventToMenuControllerRemote(
74        std::make_unique<ui::KeyEvent>(*event), &event_swallowed,
75        &event_handled);
76    if (event_handled)
77      event->SetHandled();
78    return event_swallowed;
79  }
80  void GetWordAt(const gfx::Point& location_in_content,
81                 bool* found_word,
82                 gfx::DecoratedText* decorated_word,
83                 gfx::Point* baseline_point) override {
84    *found_word = false;
85  }
86  remote_cocoa::DragDropClient* GetDragDropClient() override {
87    // Drag-drop only doesn't work across mojo yet.
88    return nullptr;
89  }
90  ui::TextInputClient* GetTextInputClient() override {
91    // Text input doesn't work across mojo yet.
92    return nullptr;
93  }
94
95  mojo::AssociatedRemote<mojom::NativeWidgetNSWindowHost> host_remote_;
96  mojo::AssociatedRemote<mojom::TextInputHost> text_input_host_remote_;
97
98  std::unique_ptr<NativeWidgetNSWindowBridge> bridge_;
99  base::scoped_nsobject<NSAccessibilityRemoteUIElement>
100      remote_accessibility_element_;
101};
102
103}  // namespace
104
105// static
106ApplicationBridge* ApplicationBridge::Get() {
107  static base::NoDestructor<ApplicationBridge> application_bridge;
108  return application_bridge.get();
109}
110
111void ApplicationBridge::BindReceiver(
112    mojo::PendingAssociatedReceiver<mojom::Application> receiver) {
113  receiver_.Bind(std::move(receiver),
114                 ui::WindowResizeHelperMac::Get()->task_runner());
115}
116
117void ApplicationBridge::SetContentNSViewCreateCallbacks(
118    RenderWidgetHostNSViewCreateCallback render_widget_host_create_callback,
119    WebContentsNSViewCreateCallback web_conents_create_callback) {
120  render_widget_host_create_callback_ = render_widget_host_create_callback;
121  web_conents_create_callback_ = web_conents_create_callback;
122}
123
124void ApplicationBridge::CreateAlert(
125    mojo::PendingReceiver<mojom::AlertBridge> bridge_receiver) {
126  // The resulting object manages its own lifetime.
127  ignore_result(new AlertBridge(std::move(bridge_receiver)));
128}
129
130void ApplicationBridge::ShowColorPanel(
131    mojo::PendingReceiver<mojom::ColorPanel> receiver,
132    mojo::PendingRemote<mojom::ColorPanelHost> host) {
133  mojo::MakeSelfOwnedReceiver(
134      std::make_unique<ColorPanelBridge>(std::move(host)), std::move(receiver));
135}
136
137void ApplicationBridge::CreateNativeWidgetNSWindow(
138    uint64_t bridge_id,
139    mojo::PendingAssociatedReceiver<mojom::NativeWidgetNSWindow>
140        bridge_receiver,
141    mojo::PendingAssociatedRemote<mojom::NativeWidgetNSWindowHost> host,
142    mojo::PendingAssociatedRemote<mojom::TextInputHost> text_input_host) {
143  // The resulting object will be destroyed when its message pipe is closed.
144  ignore_result(
145      new NativeWidgetBridgeOwner(bridge_id, std::move(bridge_receiver),
146                                  std::move(host), std::move(text_input_host)));
147}
148
149void ApplicationBridge::CreateRenderWidgetHostNSView(
150    mojo::PendingAssociatedRemote<mojom::StubInterface> host,
151    mojo::PendingAssociatedReceiver<mojom::StubInterface> view_receiver) {
152  if (!render_widget_host_create_callback_)
153    return;
154  render_widget_host_create_callback_.Run(host.PassHandle(),
155                                          view_receiver.PassHandle());
156}
157
158void ApplicationBridge::CreateWebContentsNSView(
159    uint64_t view_id,
160    mojo::PendingAssociatedRemote<mojom::StubInterface> host,
161    mojo::PendingAssociatedReceiver<mojom::StubInterface> view_receiver) {
162  if (!web_conents_create_callback_)
163    return;
164  web_conents_create_callback_.Run(view_id, host.PassHandle(),
165                                   view_receiver.PassHandle());
166}
167
168ApplicationBridge::ApplicationBridge() = default;
169
170ApplicationBridge::~ApplicationBridge() = default;
171
172}  // namespace remote_cocoa
173