Commit ed40bff2 authored by Christopher Cameron's avatar Christopher Cameron Committed by Commit Bot

RemoteMacViews: Add mojo interface for WebContentsViewMac

The NSView hierarchy for most windows is
- BridgedNativeWidget
  - WebContentsView (*)
    - RenderWidgetHostView
This patch adds a cross-process interface for WebContentsView. This
interface created via the NSViewBridgeFactory interface, using the
new mojo method CreateWebContentsNSViewBridge.

Add the mojo interface content::mojom::WebContentsNSViewBridge and
content::mojom::WebContentsNSViewClient.
- The interface that is exposed is motivated by the native Cocoa calls
  made by views::NativeViewHostMac (which are targeting the
  WebContentsViewCocoa).
- Note that this interface is public (unlike RenderWidgetHostNSView)
  because it doesn't have any content-private dependencies.

Add methods to the C++ interface ui::ViewsHostableView (which is
implemented by WebContentsViewMac), to perform all of the functions
currently done by Cocoa calls on WebContentsViewCocoa.

Add the class content::WebContentsNSViewBridge, which implements the
new mojo interface.
- This performs the same Cocoa calls that are done in the browswer
  process.
- Note that this class does not instantiate WebContentsViewCocoa (the
  NSView sub-class used by WebContents), rather, it uses a vanilla
  NSView. This may change in the future, if need be.
- Note that this NSView is in addition to the WebContentsViewCocoa
  created in the browser process (not in place of it).

Update RenderWidgetHostMac::MigrateNSViewBridge to take the arguments
that content::WebContentsViewMac will send it.

Bug: 821651
Change-Id: Ic1dd5c469a8dab32837cdf23cdda34d24d6240cb
Reviewed-on: https://chromium-review.googlesource.com/1253095
Commit-Queue: ccameron <ccameron@chromium.org>
Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#595751}
parent 12234dec
......@@ -1919,6 +1919,8 @@ jumbo_source_set("browser") {
sources += [
"gpu/ca_transaction_gpu_coordinator.cc",
"gpu/ca_transaction_gpu_coordinator.h",
"web_contents/web_contents_ns_view_bridge.h",
"web_contents/web_contents_ns_view_bridge.mm",
]
deps += [ "//ui/events:dom_keyboard_layout" ]
}
......
......@@ -4,9 +4,12 @@
#include "content/public/browser/ns_view_bridge_factory_impl.h"
#include <utility>
#include "base/macros.h"
#include "base/no_destructor.h"
#include "content/browser/renderer_host/render_widget_host_ns_view_bridge_local.h"
#include "content/browser/web_contents/web_contents_ns_view_bridge.h"
namespace content {
......@@ -40,6 +43,17 @@ void NSViewBridgeFactoryImpl::CreateRenderWidgetHostNSViewBridge(
std::move(client), std::move(bridge_request)));
}
void NSViewBridgeFactoryImpl::CreateWebContentsNSViewBridge(
uint64_t view_id,
mojom::WebContentsNSViewClientAssociatedPtrInfo client,
mojom::WebContentsNSViewBridgeAssociatedRequest bridge_request) {
// Note that the resulting object will be destroyed when its underlying pipe
// is closed.
ignore_result(new WebContentsNSViewBridge(
view_id, mojom::WebContentsNSViewClientAssociatedPtr(std::move(client)),
std::move(bridge_request)));
}
NSViewBridgeFactoryImpl::NSViewBridgeFactoryImpl() : binding_(this) {}
NSViewBridgeFactoryImpl::~NSViewBridgeFactoryImpl() {}
......
......@@ -42,6 +42,7 @@ class ScopedPasswordInputEnabler;
namespace content {
class CursorManager;
class NSViewBridgeFactoryHost;
class RenderWidgetHost;
class RenderWidgetHostNSViewBridgeLocal;
class RenderWidgetHostViewMac;
......@@ -447,6 +448,12 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// https://crbug.com/831843
RenderWidgetHostImpl* GetWidgetForKeyboardEvent();
// Migrate the NSView for this RenderWidgetHostView to be in the process
// hosted by |bridge_factory_host|, and make it a child view of the NSView
// referred to by |parent_ns_view_id|.
void MigrateNSViewBridge(NSViewBridgeFactoryHost* bridge_factory_host,
uint64_t parent_ns_view_id);
protected:
// This class is to be deleted through the Destroy method.
~RenderWidgetHostViewMac() override;
......@@ -469,10 +476,6 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// invoke it from the message loop.
void ShutdownHost();
// Update |ns_view_bridge_| so that the instance that it points at be hosted
// in the process indicated |host_id|.
void MigrateNSViewBridge(uint64_t host_id);
// Send updated vsync parameters to the top level display.
void UpdateDisplayVSyncParameters();
......@@ -512,11 +515,8 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
std::unique_ptr<RenderWidgetHostNSViewBridgeLocal> ns_view_bridge_local_;
// If the NSView is hosted in a remote process and accessed via mojo then
// - |ns_view_bridge_factory_host_id_| can be used to look up the needed
// NSViewBridgeFactoryHost.
// - |ns_view_bridge_| will point to |ns_view_bridge_remote_|
// - |ns_view_client_binding_| is the binding provided to the bridge.
uint64_t ns_view_bridge_factory_host_id_;
mojom::RenderWidgetHostNSViewBridgeAssociatedPtr ns_view_bridge_remote_;
mojo::AssociatedBinding<mojom::RenderWidgetHostNSViewClient>
ns_view_client_binding_;
......
......@@ -152,8 +152,6 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget,
: RenderWidgetHostViewBase(widget),
page_at_minimum_scale_(true),
mouse_wheel_phase_handler_(this),
ns_view_bridge_factory_host_id_(
NSViewBridgeFactoryHost::kLocalDirectHostId),
ns_view_client_binding_(this),
is_loading_(false),
is_guest_view_hack_(is_guest_view_hack),
......@@ -232,50 +230,41 @@ RenderWidgetHostViewMac::~RenderWidgetHostViewMac() {
}
}
void RenderWidgetHostViewMac::MigrateNSViewBridge(uint64_t factory_host_id) {
if (factory_host_id == ns_view_bridge_factory_host_id_)
return;
// Look up the NSViewBridgeFactoryHost, if any, for this id.
NSViewBridgeFactoryHost* factory_host = nullptr;
if (factory_host_id != NSViewBridgeFactoryHost::kLocalDirectHostId) {
factory_host = NSViewBridgeFactoryHost::GetFromHostId(factory_host_id);
if (!factory_host) {
DLOG(ERROR) << "Failed to look up NSViewBridgeFactoryHost!";
return;
}
}
ns_view_bridge_factory_host_id_ = factory_host_id;
void RenderWidgetHostViewMac::MigrateNSViewBridge(
NSViewBridgeFactoryHost* bridge_factory_host,
uint64_t parent_ns_view_id) {
// Disconnect from the previous bridge (this will have the effect of
// destroying the associated bridge), and close the binding (to allow it
// to be re-bound). Note that |ns_view_bridge_local_| remains valid.
ns_view_client_binding_.Close();
ns_view_bridge_remote_.reset();
if (factory_host) {
mojom::RenderWidgetHostNSViewClientAssociatedPtr client;
ns_view_client_binding_.Bind(mojo::MakeRequest(&client));
mojom::RenderWidgetHostNSViewBridgeAssociatedRequest bridge_request =
mojo::MakeRequest(&ns_view_bridge_remote_);
// Cast from mojom::RenderWidgetHostNSViewClientPtr and
// mojom::RenderWidgetHostNSViewBridgeRequest to the public interfaces
// accepted by the factory.
// TODO(ccameron): Remove the need for this cast.
// https://crbug.com/888290
mojo::AssociatedInterfacePtrInfo<mojom::StubInterface> stub_client(
client.PassInterface().PassHandle(), 0);
mojom::StubInterfaceAssociatedRequest stub_bridge_request(
bridge_request.PassHandle());
factory_host->GetFactory()->CreateRenderWidgetHostNSViewBridge(
std::move(stub_client), std::move(stub_bridge_request));
ns_view_bridge_ = ns_view_bridge_remote_.get();
} else {
// If no host is specified, then use the locally hosted NSView.
if (!bridge_factory_host) {
ns_view_bridge_ = ns_view_bridge_local_.get();
return;
}
mojom::RenderWidgetHostNSViewClientAssociatedPtr client;
ns_view_client_binding_.Bind(mojo::MakeRequest(&client));
mojom::RenderWidgetHostNSViewBridgeAssociatedRequest bridge_request =
mojo::MakeRequest(&ns_view_bridge_remote_);
// Cast from mojom::RenderWidgetHostNSViewClientPtr and
// mojom::RenderWidgetHostNSViewBridgeRequest to the public interfaces
// accepted by the factory.
// TODO(ccameron): Remove the need for this cast.
// https://crbug.com/888290
mojo::AssociatedInterfacePtrInfo<mojom::StubInterface> stub_client(
client.PassInterface().PassHandle(), 0);
mojom::StubInterfaceAssociatedRequest stub_bridge_request(
bridge_request.PassHandle());
bridge_factory_host->GetFactory()->CreateRenderWidgetHostNSViewBridge(
std::move(stub_client), std::move(stub_bridge_request));
ns_view_bridge_ = ns_view_bridge_remote_.get();
ns_view_bridge_remote_->SetParentWebContentsNSView(parent_ns_view_id);
}
void RenderWidgetHostViewMac::SetParentUiLayer(ui::Layer* parent_ui_layer) {
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_WEB_CONTENTS_WEB_CONTENTS_NS_VIEW_BRIDGE_H_
#define CONTENT_BROWSER_WEB_CONTENTS_WEB_CONTENTS_NS_VIEW_BRIDGE_H_
#import <Cocoa/Cocoa.h>
#include <memory>
#import "base/mac/scoped_nsobject.h"
#include "base/macros.h"
#include "content/common/content_export.h"
#include "content/public/common/web_contents_ns_view_bridge.mojom.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
#include "ui/base/cocoa/ns_view_ids.h"
namespace content {
// A C++ wrapper around a WebContentsView's NSView in a non-browser process.
class CONTENT_EXPORT WebContentsNSViewBridge
: public mojom::WebContentsNSViewBridge {
public:
// Create a bridge that will access its client in another process via a mojo
// interface. This object will be deleted when |bridge_request|'s connection
// closes.
WebContentsNSViewBridge(
uint64_t view_id,
mojom::WebContentsNSViewClientAssociatedPtr client,
mojom::WebContentsNSViewBridgeAssociatedRequest bridge_request);
// mojom::WebContentsNSViewBridge:
void SetParentViewsNSView(uint64_t parent_ns_view_id) override;
void Show(const gfx::Rect& bounds_in_window) override;
void Hide() override;
void MakeFirstResponder() override;
private:
~WebContentsNSViewBridge() override;
void OnConnectionError();
base::scoped_nsobject<NSView> cocoa_view_;
mojom::WebContentsNSViewClientAssociatedPtr client_;
mojo::AssociatedBinding<mojom::WebContentsNSViewBridge> binding_;
std::unique_ptr<ui::ScopedNSViewIdMapping> view_id_;
DISALLOW_COPY_AND_ASSIGN(WebContentsNSViewBridge);
};
} // namespace content
#endif // CONTENT_BROWSER_WEB_CONTENTS_WEB_CONTENTS_NS_VIEW_BRIDGE_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/web_contents/web_contents_ns_view_bridge.h"
namespace content {
WebContentsNSViewBridge::WebContentsNSViewBridge(
uint64_t view_id,
mojom::WebContentsNSViewClientAssociatedPtr client,
mojom::WebContentsNSViewBridgeAssociatedRequest bridge_request)
: client_(std::move(client)), binding_(this) {
binding_.Bind(std::move(bridge_request));
// This object will be destroyed when its connection is closed.
binding_.set_connection_error_handler(base::BindOnce(
&WebContentsNSViewBridge::OnConnectionError, base::Unretained(this)));
// Note that this is an ordinary NSView (as opposed to a full
// WebContentsViewCocoa).
cocoa_view_.reset([[NSView alloc] initWithFrame:NSZeroRect]);
view_id_ =
std::make_unique<ui::ScopedNSViewIdMapping>(view_id, cocoa_view_.get());
}
WebContentsNSViewBridge::~WebContentsNSViewBridge() {
[cocoa_view_ removeFromSuperview];
}
void WebContentsNSViewBridge::OnConnectionError() {
delete this;
}
void WebContentsNSViewBridge::SetParentViewsNSView(uint64_t parent_ns_view_id) {
NSView* parent_ns_view = ui::NSViewIds::GetNSView(parent_ns_view_id);
// If the browser passed an invalid handle, then there is no recovery.
CHECK(parent_ns_view);
[parent_ns_view addSubview:cocoa_view_];
}
void WebContentsNSViewBridge::Show(const gfx::Rect& bounds_in_window) {
NSRect ns_bounds_in_window =
NSMakeRect(bounds_in_window.x(),
[[[cocoa_view_ window] contentView] frame].size.height -
bounds_in_window.y() - bounds_in_window.height(),
bounds_in_window.width(), bounds_in_window.height());
NSRect ns_bounds_in_superview =
[[cocoa_view_ superview] convertRect:ns_bounds_in_window fromView:nil];
[cocoa_view_ setFrame:ns_bounds_in_superview];
[cocoa_view_ setHidden:NO];
}
void WebContentsNSViewBridge::Hide() {
[cocoa_view_ setHidden:YES];
}
void WebContentsNSViewBridge::MakeFirstResponder() {
if ([cocoa_view_ acceptsFirstResponder])
[[cocoa_view_ window] makeFirstResponder:cocoa_view_];
}
} // namespace content
......@@ -19,6 +19,8 @@
#include "content/browser/web_contents/web_contents_view.h"
#include "content/common/content_export.h"
#include "content/common/drag_event_source_info.h"
#include "content/public/common/web_contents_ns_view_bridge.mojom.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
#import "ui/base/cocoa/base_view.h"
#import "ui/base/cocoa/views_hostable.h"
#include "ui/gfx/geometry/size.h"
......@@ -37,10 +39,6 @@ namespace gfx {
class Vector2d;
}
namespace ui {
class Layer;
}
CONTENT_EXPORT
@interface WebContentsViewCocoa : BaseView<ViewsHostable> {
@private
......@@ -76,6 +74,7 @@ namespace content {
class WebContentsViewMac : public WebContentsView,
public RenderViewHostDelegateView,
public PopupMenuHelper::Delegate,
public mojom::WebContentsNSViewClient,
public ui::ViewsHostableView {
public:
// The corresponding WebContentsImpl is passed in the constructor, and manages
......@@ -142,6 +141,9 @@ class WebContentsViewMac : public WebContentsView,
// ViewsHostableView:
void OnViewsHostableAttached(ViewsHostableView::Host* host) override;
void OnViewsHostableDetached() override;
void OnViewsHostableShow(const gfx::Rect& bounds_in_window) override;
void OnViewsHostableHide() override;
void OnViewsHostableMakeFirstResponder() override;
// A helper method for closing the tab in the
// CloseTabAfterEventTracking() implementation.
......@@ -158,7 +160,9 @@ class WebContentsViewMac : public WebContentsView,
RenderWidgetHostViewCreateFunction create_render_widget_host_view);
private:
void SetParentUiLayer(ui::Layer* parent_ui_layer);
// Return the list of child RenderWidgetHostViewMacs. This will remove any
// destroyed instances before returning.
std::list<RenderWidgetHostViewMac*> GetChildViews();
// Returns the fullscreen view, if one exists; otherwise, returns the content
// native view. This ensures that the view currently attached to a NSWindow is
......@@ -186,6 +190,14 @@ class WebContentsViewMac : public WebContentsView,
std::unique_ptr<PopupMenuHelper> popup_menu_helper_;
// The id that may be used to look up this NSView.
const uint64_t ns_view_id_;
// Mojo bindings for an out of process instance of this NSView.
mojom::WebContentsNSViewBridgeAssociatedPtr ns_view_bridge_remote_;
mojo::AssociatedBinding<mojom::WebContentsNSViewClient>
ns_view_client_binding_;
DISALLOW_COPY_AND_ASSIGN(WebContentsViewMac);
};
......
......@@ -23,12 +23,15 @@
#import "content/browser/web_contents/web_drag_source_mac.h"
#include "content/common/view_messages.h"
#include "content/public/browser/interstitial_page.h"
#include "content/public/browser/ns_view_bridge_factory_host.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_view_delegate.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "skia/ext/skia_utils_mac.h"
#import "third_party/mozilla/NSPasteboard+Utils.h"
#include "ui/base/clipboard/custom_data_helper.h"
#include "ui/base/cocoa/cocoa_base_utils.h"
#include "ui/base/cocoa/ns_view_ids.h"
#include "ui/base/dragdrop/cocoa_dnd_util.h"
#include "ui/display/screen.h"
#include "ui/gfx/image/image_skia_util_mac.h"
......@@ -105,7 +108,10 @@ WebContentsView* CreateWebContentsView(
WebContentsViewMac::WebContentsViewMac(WebContentsImpl* web_contents,
WebContentsViewDelegate* delegate)
: web_contents_(web_contents), delegate_(delegate) {}
: web_contents_(web_contents),
delegate_(delegate),
ns_view_id_(ui::NSViewIds::GetNewId()),
ns_view_client_binding_(this) {}
WebContentsViewMac::~WebContentsViewMac() {
if (views_host_)
......@@ -357,8 +363,14 @@ RenderWidgetHostViewBase* WebContentsViewMac::CreateViewForWidget(
// Add the RenderWidgetHostView to the ui::Layer heirarchy.
child_views_.push_back(view->GetWeakPtr());
if (views_host_)
SetParentUiLayer(views_host_->GetUiLayer());
if (views_host_) {
NSViewBridgeFactoryHost* factory_host =
NSViewBridgeFactoryHost::GetFromHostId(
views_host_->GetViewsFactoryHostId());
view->MigrateNSViewBridge(factory_host, ns_view_id_);
view->SetParentUiLayer(views_host_->GetUiLayer());
}
// Fancy layout comes later; for now just make it our size and resize it
// with us. In case there are other siblings of the content area, we want
......@@ -434,14 +446,18 @@ void WebContentsViewMac::CloseTab() {
web_contents_->Close(web_contents_->GetRenderViewHost());
}
void WebContentsViewMac::SetParentUiLayer(ui::Layer* parent_ui_layer) {
std::list<RenderWidgetHostViewMac*> WebContentsViewMac::GetChildViews() {
// Remove any child NSViews that have been destroyed.
std::list<RenderWidgetHostViewMac*> result;
for (auto iter = child_views_.begin(); iter != child_views_.end();) {
if (*iter)
(*iter++)->SetParentUiLayer(parent_ui_layer);
else
if (*iter) {
result.push_back(reinterpret_cast<RenderWidgetHostViewMac*>(iter->get()));
iter++;
} else {
iter = child_views_.erase(iter);
}
}
return result;
}
////////////////////////////////////////////////////////////////////////////////
......@@ -450,22 +466,71 @@ void WebContentsViewMac::SetParentUiLayer(ui::Layer* parent_ui_layer) {
void WebContentsViewMac::OnViewsHostableAttached(
ViewsHostableView::Host* host) {
views_host_ = host;
SetParentUiLayer(views_host_->GetUiLayer());
[cocoa_view_
setAccessibilityParentElement:views_host_->GetAccessibilityElement()];
// Create an NSView in the target process, if one exists.
uint64_t factory_host_id = views_host_->GetViewsFactoryHostId();
NSViewBridgeFactoryHost* factory_host =
NSViewBridgeFactoryHost::GetFromHostId(factory_host_id);
if (factory_host) {
mojom::WebContentsNSViewClientAssociatedPtr client;
ns_view_client_binding_.Bind(mojo::MakeRequest(&client));
mojom::WebContentsNSViewBridgeAssociatedRequest bridge_request =
mojo::MakeRequest(&ns_view_bridge_remote_);
factory_host->GetFactory()->CreateWebContentsNSViewBridge(
ns_view_id_, client.PassInterface(), std::move(bridge_request));
ns_view_bridge_remote_->SetParentViewsNSView(views_host_->GetNSViewId());
} else if (factory_host_id != NSViewBridgeFactoryHost::kLocalDirectHostId) {
LOG(ERROR) << "Failed to look up NSViewBridgeFactoryHost!";
}
for (auto* rwhv_mac : GetChildViews()) {
rwhv_mac->MigrateNSViewBridge(factory_host, ns_view_id_);
rwhv_mac->SetParentUiLayer(views_host_->GetUiLayer());
}
}
void WebContentsViewMac::OnViewsHostableDetached() {
DCHECK(views_host_);
views_host_ = nullptr;
SetParentUiLayer(nullptr);
for (auto* rwhv_mac : GetChildViews()) {
rwhv_mac->MigrateNSViewBridge(nullptr, 0);
rwhv_mac->SetParentUiLayer(nullptr);
}
[cocoa_view_ setAccessibilityParentElement:nil];
// Disconnect from the bridge. This will have the effect of destroying the
// associated bridge instance with its NSView.
ns_view_client_binding_.Close();
ns_view_bridge_remote_.reset();
}
void WebContentsViewMac::OnViewsHostableShow(
const gfx::Rect& bounds_in_window) {
if (ns_view_bridge_remote_)
ns_view_bridge_remote_->Show(bounds_in_window);
}
void WebContentsViewMac::OnViewsHostableHide() {
if (ns_view_bridge_remote_)
ns_view_bridge_remote_->Hide();
}
void WebContentsViewMac::OnViewsHostableMakeFirstResponder() {
if (ns_view_bridge_remote_)
ns_view_bridge_remote_->MakeFirstResponder();
}
} // namespace content
////////////////////////////////////////////////////////////////////////////////
// WebContentsViewCocoa
@implementation WebContentsViewCocoa
- (id)initWithWebContentsViewMac:(WebContentsViewMac*)w {
......
......@@ -8,6 +8,7 @@
#include "base/macros.h"
#include "content/common/content_export.h"
#include "content/public/common/ns_view_bridge_factory.mojom.h"
#include "content/public/common/web_contents_ns_view_bridge.mojom.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
namespace content {
......@@ -26,6 +27,10 @@ class CONTENT_EXPORT NSViewBridgeFactoryImpl
void CreateRenderWidgetHostNSViewBridge(
mojom::StubInterfaceAssociatedPtrInfo client,
mojom::StubInterfaceAssociatedRequest bridge_request) override;
void CreateWebContentsNSViewBridge(
uint64_t view_id,
mojom::WebContentsNSViewClientAssociatedPtrInfo client,
mojom::WebContentsNSViewBridgeAssociatedRequest bridge_request) override;
private:
friend class base::NoDestructor<NSViewBridgeFactoryImpl>;
......
......@@ -363,7 +363,10 @@ mojom("interfaces") {
}
if (is_mac) {
sources += [ "ns_view_bridge_factory.mojom" ]
sources += [
"ns_view_bridge_factory.mojom",
"web_contents_ns_view_bridge.mojom",
]
}
public_deps = [
......
......@@ -4,6 +4,8 @@
module content.mojom;
import "content/public/common/web_contents_ns_view_bridge.mojom";
// Empty interface that is used by NSViewBridgeFactory in place of
// RenderWidgetHostNSViewBridge and RenderWidgetHostNSViewClient (which are the
// real interface that should be used). The reason that the correct interfaces
......@@ -17,9 +19,18 @@ interface StubInterface {};
interface NSViewBridgeFactory {
// Create and take ownership of the NSView for a RenderWidgetHostView. The
// resulting object is to be destroyed by calling its Destroy method.
// resulting object will be destroyed when the connection is closed.
CreateRenderWidgetHostNSViewBridge(
associated StubInterface client,
associated StubInterface& bridge_request);
// Create and take ownership of the NSView for a WebContentsView. The
// resulting object will be destroyed when the connection is closed.
// The value of |view_id| may be used to look up the NSView (e.g, to add
// child NSViews.
CreateWebContentsNSViewBridge(
uint64 view_id,
associated WebContentsNSViewClient client,
associated WebContentsNSViewBridge& bridge_request);
};
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
module content.mojom;
import "ui/gfx/geometry/mojo/geometry.mojom";
// Interface through which a WebContentsViewMac communicates with its NSView in
// another process.
interface WebContentsNSViewBridge {
// Set this to be a child NSView of the NSView mapped to by
// |parent_ns_view_id|. In practice, this NSView will always be from a
// views::View.
SetParentViewsNSView(uint64 parent_ns_view_id);
// Un-hide the NSView and set its frame in its window to |bounds_in_window|.
Show(gfx.mojom.Rect bounds_in_window);
// Hide the NSView.
Hide();
// Make the NSView be the first responder for its window.
MakeFirstResponder();
};
// Interface through which the NSView in another process communicates with its
// owning WebContentsViewMac. This interface has no methods yet, but is included
// for symmetry and future use.
interface WebContentsNSViewClient {};
......@@ -25,6 +25,15 @@ class ViewsHostableView {
// Query the ui::Layer of the host.
virtual ui::Layer* GetUiLayer() const = 0;
// Return the id for the process in which the host NSView exists. Used to
// migrate the content::WebContentsView and content::RenderWidgetHostview
// to that process.
virtual uint64_t GetViewsFactoryHostId() const = 0;
// The id for the views::View's NSView. Used to add the
// content::WebContentsView's NSView as a child view.
virtual uint64_t GetNSViewId() const = 0;
// Query the parent accessibility element of the host.
virtual id GetAccessibilityElement() const = 0;
......@@ -40,10 +49,20 @@ class ViewsHostableView {
// the WebContentsView.
// - Stitching together any app-shim-side NSViews.
virtual void OnViewsHostableAttached(Host* host) = 0;
// Called when the WebContentsView's NSView has been removed from the
// views::View's NSView. This is responsible for un-doing all of the actions
// taken when attaching.
virtual void OnViewsHostableDetached() = 0;
// Called when the WebContentsView's NSView is to be shown or resized.
virtual void OnViewsHostableShow(const gfx::Rect& bounds_in_window) = 0;
// Called when the WebContentsView's NSView is to be hidden.
virtual void OnViewsHostableHide() = 0;
// Called when the WebContentsView's NSView is to be made a first responder.
virtual void OnViewsHostableMakeFirstResponder() = 0;
};
} // namespace ui
......
......@@ -18,6 +18,7 @@ class ViewsHostableView;
namespace views {
class BridgedNativeWidgetHostImpl;
class NativeViewHost;
// Mac implementation of NativeViewHostWrapper.
......@@ -29,6 +30,8 @@ class NativeViewHostMac : public NativeViewHostWrapper,
// ViewsHostableView::Host:
ui::Layer* GetUiLayer() const override;
uint64_t GetViewsFactoryHostId() const override;
uint64_t GetNSViewId() const override;
id GetAccessibilityElement() const override;
void OnHostableViewDestroying() override;
......@@ -50,6 +53,9 @@ class NativeViewHostMac : public NativeViewHostWrapper,
gfx::NativeCursor GetCursor(int x, int y) override;
private:
// Return the BridgedNativeWidgetHostImpl for this hosted view.
BridgedNativeWidgetHostImpl* GetBridgedNativeWidgetHost() const;
// Our associated NativeViewHost. Owns this.
NativeViewHost* host_;
......
......@@ -51,6 +51,12 @@ NativeViewHostMac::NativeViewHostMac(NativeViewHost* host) : host_(host) {
NativeViewHostMac::~NativeViewHostMac() {
}
BridgedNativeWidgetHostImpl* NativeViewHostMac::GetBridgedNativeWidgetHost()
const {
return BridgedNativeWidgetHostImpl::GetFromNativeWindow(
host_->GetWidget()->GetNativeWindow());
}
////////////////////////////////////////////////////////////////////////////////
// NativeViewHostMac, ViewsHostableView::Host implementation:
......@@ -58,6 +64,20 @@ ui::Layer* NativeViewHostMac::GetUiLayer() const {
return host_->layer();
}
uint64_t NativeViewHostMac::GetViewsFactoryHostId() const {
auto* bridge_host = GetBridgedNativeWidgetHost();
if (bridge_host && bridge_host->bridge_factory_host())
return bridge_host->bridge_factory_host()->GetHostId();
return 0;
}
uint64_t NativeViewHostMac::GetNSViewId() const {
auto* bridge_host = GetBridgedNativeWidgetHost();
if (bridge_host)
return bridge_host->GetRootViewNSViewId();
return 0;
}
id NativeViewHostMac::GetAccessibilityElement() const {
// Find the closest ancestor view that participates in the views toolkit
// accessibility hierarchy and set its element as the native view's parent.
......@@ -93,9 +113,8 @@ void NativeViewHostMac::AttachNativeView() {
DCHECK(!native_view_);
native_view_.reset([host_->native_view() retain]);
EnsureNativeViewHasNoChildWidgets(native_view_);
BridgedNativeWidgetHostImpl* bridge_host =
BridgedNativeWidgetHostImpl::GetFromNativeWindow(
host_->GetWidget()->GetNativeWindow());
auto* bridge_host = GetBridgedNativeWidgetHost();
DCHECK(bridge_host);
bridge_host->SetAssociationForView(host_, native_view_);
......@@ -129,9 +148,7 @@ void NativeViewHostMac::NativeViewDetaching(bool destroyed) {
}
EnsureNativeViewHasNoChildWidgets(host_->native_view());
BridgedNativeWidgetHostImpl* bridge_host =
BridgedNativeWidgetHostImpl::GetFromNativeWindow(
host_->GetWidget()->GetNativeWindow());
auto* bridge_host = GetBridgedNativeWidgetHost();
// BridgedNativeWidgetImpl can be null when Widget is closing.
if (bridge_host)
bridge_host->ClearAssociationForView(host_);
......@@ -195,15 +212,24 @@ void NativeViewHostMac::ShowWidget(int x,
[[host_->native_view() superview] convertRect:window_rect fromView:nil];
[host_->native_view() setFrame:container_rect];
[host_->native_view() setHidden:NO];
if (native_view_hostable_)
native_view_hostable_->OnViewsHostableShow(gfx::Rect(x, y, w, h));
}
void NativeViewHostMac::HideWidget() {
[host_->native_view() setHidden:YES];
if (native_view_hostable_)
native_view_hostable_->OnViewsHostableHide();
}
void NativeViewHostMac::SetFocus() {
if ([host_->native_view() acceptsFirstResponder])
[[host_->native_view() window] makeFirstResponder:host_->native_view()];
if (native_view_hostable_)
native_view_hostable_->OnViewsHostableMakeFirstResponder();
}
gfx::NativeView NativeViewHostMac::GetNativeViewContainer() const {
......
......@@ -32,6 +32,9 @@ class TestViewsHostable : public ui::ViewsHostableView {
void OnViewsHostableDetached() override {
parent_accessibility_element_ = nil;
}
void OnViewsHostableShow(const gfx::Rect& bounds_in_window) override {}
void OnViewsHostableHide() override {}
void OnViewsHostableMakeFirstResponder() override {}
id parent_accessibility_element_ = nil;
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment