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

MacPWAs: Add factory for remote RenderWidgetHostView

Add a new interface, content::mojom::NSViewBridgeFactory. This may be
used to create a content::mojo::RenderWidgetHostNSViewBridge in
another process, and initialize its client to a specified
content::mojo::RenderWidgetHostNSViewClient.
  * Note that the interface created by mojom::NSViewBridgeFactory is a
    stub interface, mojom::StubInterface, which is cast to a
    mojom::RenderWidgetHostNSViewBridge. This is because the latter
    has content-internal dependencies, and so cannot be included in
    any other module.

Add a content::NSViewBridgeFactoryHost class that will own such
a connection. There will exist one instance of this class for each
AppShimHost in the browser process.
  * Included in this a "host id". This will be set at initialization to
    match a views::BridgeFactoryHost.
  * When embedding web contents into a views::View, the
    views::BridgedNativeWidgetHostImpl will specify this id to the
    content::RenderWidgetHostViewMac, to ensure that all NSViews be
    created in the same process.

Add a content::NSViewBridgeFactoryImpl class that implements the
content::mojom::NSViewBridgeFactory interface. There will exist one
global instance of this class in each app shim process.

Add to content::RenderWidgetHostViewMac a MigrateNSViewBridge function,
which will move corresponding NSView to a different host.

Add to RenderWidgetHostNSViewBridgeLocal a constructor that takes
mojo interfaces. This constructor is called in the app shim process.
Clarify that the creator of the RenderWidgetHostNSViewBridgeLocal is
its owner, and is responsible for its destruction.

Note that all interfaces are associated. This is because call ordering
needs to be preserved amongst multiple NSViews (e.g, to add one as a
subview of another, but only once both have been put in an expected
state).

Bug: 859152
Change-Id: I69f64c57cf51189ca75e215346f3ef1cbab23094
Reviewed-on: https://chromium-review.googlesource.com/1239763Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Reviewed-by: default avatarKen Rockot <rockot@chromium.org>
Commit-Queue: ccameron <ccameron@chromium.org>
Cr-Commit-Position: refs/heads/master@{#594797}
parent ae98e309
......@@ -2344,6 +2344,8 @@ jumbo_source_set("browser") {
"IOSurface.framework",
]
sources += [
"ns_view_bridge_factory_host.mm",
"ns_view_bridge_factory_impl.mm",
"renderer_host/popup_window_mac.h",
"renderer_host/popup_window_mac.mm",
"renderer_host/render_widget_host_ns_view_bridge_local.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/public/browser/ns_view_bridge_factory_host.h"
#include "base/no_destructor.h"
namespace content {
namespace {
using HostIdToFactoryMap = std::map<uint64_t, NSViewBridgeFactoryHost*>;
HostIdToFactoryMap* GetHostIdToFactoryMap() {
static base::NoDestructor<HostIdToFactoryMap> instance;
return instance.get();
}
} // namespace
// static
const uint64_t NSViewBridgeFactoryHost::kLocalDirectHostId = -1;
// static
NSViewBridgeFactoryHost* NSViewBridgeFactoryHost::GetFromHostId(
uint64_t host_id) {
auto found = GetHostIdToFactoryMap()->find(host_id);
if (found == GetHostIdToFactoryMap()->end())
return nullptr;
return found->second;
}
NSViewBridgeFactoryHost::NSViewBridgeFactoryHost(
mojom::NSViewBridgeFactoryAssociatedRequest* request,
uint64_t host_id)
: host_id_(host_id) {
*request = mojo::MakeRequest(&factory_);
DCHECK(!GetHostIdToFactoryMap()->count(host_id_));
GetHostIdToFactoryMap()->insert(std::make_pair(host_id_, this));
}
NSViewBridgeFactoryHost::~NSViewBridgeFactoryHost() {
GetHostIdToFactoryMap()->erase(host_id_);
}
mojom::NSViewBridgeFactory* NSViewBridgeFactoryHost::GetFactory() {
return factory_.get();
}
} // namespace content
// 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/public/browser/ns_view_bridge_factory_impl.h"
#include "base/macros.h"
#include "base/no_destructor.h"
#include "content/browser/renderer_host/render_widget_host_ns_view_bridge_local.h"
namespace content {
// static
NSViewBridgeFactoryImpl* NSViewBridgeFactoryImpl::Get() {
static base::NoDestructor<NSViewBridgeFactoryImpl> instance;
return instance.get();
}
void NSViewBridgeFactoryImpl::BindRequest(
mojom::NSViewBridgeFactoryAssociatedRequest request) {
binding_.Bind(std::move(request));
}
void NSViewBridgeFactoryImpl::CreateRenderWidgetHostNSViewBridge(
mojom::StubInterfaceAssociatedPtrInfo stub_client,
mojom::StubInterfaceAssociatedRequest stub_bridge_request) {
// Cast from the stub interface to the mojom::RenderWidgetHostNSViewClient
// and mojom::RenderWidgetHostNSViewBridge private interfaces.
// TODO(ccameron): Remove the need for this cast.
// https://crbug.com/888290
mojom::RenderWidgetHostNSViewClientAssociatedPtr client(
mojo::AssociatedInterfacePtrInfo<mojom::RenderWidgetHostNSViewClient>(
stub_client.PassHandle(), 0));
mojom::RenderWidgetHostNSViewBridgeAssociatedRequest bridge_request(
stub_bridge_request.PassHandle());
// Create a RenderWidgetHostNSViewBridgeLocal. The resulting object will be
// destroyed when its underlying pipe is closed.
ignore_result(new RenderWidgetHostNSViewBridgeLocal(
std::move(client), std::move(bridge_request)));
}
NSViewBridgeFactoryImpl::NSViewBridgeFactoryImpl() : binding_(this) {}
NSViewBridgeFactoryImpl::~NSViewBridgeFactoryImpl() {}
} // namespace content
......@@ -12,21 +12,33 @@
#import "content/browser/renderer_host/render_widget_host_view_cocoa.h"
#include "content/common/render_widget_host_ns_view.mojom.h"
#include "content/public/common/widget_type.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
#include "ui/accelerated_widget_mac/display_ca_layer_tree.h"
#include "ui/display/display_observer.h"
namespace content {
// Bridge to a locally-hosted NSView -- this is always instantiated in the same
// process as the NSView. The caller of this interface may exist in another
// process.
// process as the NSView. The owner of this class may exist in another
// process. Because the owner may exist in another process, this class must
// be destroyed explicitly by its Destroy method.
class RenderWidgetHostNSViewBridgeLocal
: public mojom::RenderWidgetHostNSViewBridge,
public display::DisplayObserver {
public:
// Create a bridge that will directly access its client in the same process
// via pointers. This object must be explicitly deleted.
RenderWidgetHostNSViewBridgeLocal(
mojom::RenderWidgetHostNSViewClient* client,
RenderWidgetHostNSViewClientHelper* client_helper);
// 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.
RenderWidgetHostNSViewBridgeLocal(
mojom::RenderWidgetHostNSViewClientAssociatedPtr client,
mojom::RenderWidgetHostNSViewBridgeAssociatedRequest bridge_request);
~RenderWidgetHostNSViewBridgeLocal() override;
// TODO(ccameron): RenderWidgetHostViewMac and other functions currently use
......@@ -62,12 +74,25 @@ class RenderWidgetHostNSViewBridgeLocal
void UnlockKeyboard() override;
private:
void Initialize(mojom::RenderWidgetHostNSViewClient* client,
RenderWidgetHostNSViewClientHelper* client_helper);
bool IsPopup() const { return !!popup_window_; }
// Called on a mojo connection error, deletes |this|.
void OnConnectionError();
// display::DisplayObserver implementation.
void OnDisplayMetricsChanged(const display::Display& display,
uint32_t metrics) override;
// If the client for |this| is in another process and to be accessed via
// mojo, then |remote_client_| and |binding_| maintain this interface, and
// |remote_client_helper_| is a wrapper around |remote_client_|.
mojom::RenderWidgetHostNSViewClientAssociatedPtr remote_client_;
mojo::AssociatedBinding<mojom::RenderWidgetHostNSViewBridge> binding_;
std::unique_ptr<RenderWidgetHostNSViewClientHelper> remote_client_helper_;
// The NSView used for input and display.
base::scoped_nsobject<RenderWidgetHostViewCocoa> cocoa_view_;
......
......@@ -6,6 +6,7 @@
#include "base/mac/scoped_cftyperef.h"
#include "base/strings/sys_string_conversions.h"
#include "content/browser/renderer_host/render_widget_host_ns_view_client_helper.h"
#include "content/common/cursors/webcursor.h"
#import "skia/ext/skia_utils_mac.h"
#import "ui/base/cocoa/animation_utils.h"
......@@ -16,6 +17,28 @@
namespace content {
RenderWidgetHostNSViewBridgeLocal::RenderWidgetHostNSViewBridgeLocal(
mojom::RenderWidgetHostNSViewClient* client,
RenderWidgetHostNSViewClientHelper* client_helper)
: binding_(nullptr) {
Initialize(client, client_helper);
}
RenderWidgetHostNSViewBridgeLocal::RenderWidgetHostNSViewBridgeLocal(
mojom::RenderWidgetHostNSViewClientAssociatedPtr client,
mojom::RenderWidgetHostNSViewBridgeAssociatedRequest bridge_request)
: remote_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(&RenderWidgetHostNSViewBridgeLocal::OnConnectionError,
base::Unretained(this)));
remote_client_helper_ =
RenderWidgetHostNSViewClientHelper::CreateForMojoClient(
remote_client_.get());
Initialize(remote_client_.get(), remote_client_helper_.get());
}
void RenderWidgetHostNSViewBridgeLocal::Initialize(
mojom::RenderWidgetHostNSViewClient* client,
RenderWidgetHostNSViewClientHelper* client_helper) {
display::Screen::GetScreen()->AddObserver(this);
......@@ -45,6 +68,10 @@ RenderWidgetHostNSViewBridgeLocal::~RenderWidgetHostNSViewBridgeLocal() {
popup_window_.reset();
}
void RenderWidgetHostNSViewBridgeLocal::OnConnectionError() {
delete this;
}
RenderWidgetHostViewCocoa*
RenderWidgetHostNSViewBridgeLocal::GetRenderWidgetHostViewCocoa() {
return cocoa_view_;
......
......@@ -23,6 +23,7 @@
#include "content/common/content_export.h"
#include "content/common/render_widget_host_ns_view.mojom.h"
#include "ipc/ipc_sender.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
#include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
#include "ui/accelerated_widget_mac/ca_transaction_observer.h"
#include "ui/accelerated_widget_mac/display_link_mac.h"
......@@ -469,6 +470,10 @@ 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();
......@@ -507,6 +512,16 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// not work when the RenderWidgetHostViewCocoa is hosted in an app process.
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_;
// State tracked by Show/Hide/IsShowing.
bool is_visible_ = false;
......
......@@ -36,6 +36,7 @@
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_plugin_guest_manager.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/ns_view_bridge_factory_host.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/web_contents.h"
#include "skia/ext/platform_canvas.h"
......@@ -151,6 +152,9 @@ 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),
popup_parent_host_view_(nullptr),
......@@ -232,6 +236,52 @@ 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;
// 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 {
ns_view_bridge_ = ns_view_bridge_local_.get();
}
}
void RenderWidgetHostViewMac::SetParentUiLayer(ui::Layer* parent_ui_layer) {
if (parent_ui_layer && !display_only_using_parent_ui_layer_) {
// The first time that we display using a parent ui::Layer, permanently
......@@ -650,10 +700,12 @@ void RenderWidgetHostViewMac::Destroy() {
ns_view_bridge_->SetCursorLocked(false);
}
// Destroy the brige to the NSView. Note that the NSView on the other side
// of |ns_view_bridge_| may outlive us due to other retains.
// Destroy the local and remote briges to the NSView. Note that the NSView on
// the other side of |ns_view_bridge_| may outlive us due to other retains.
ns_view_bridge_ = nullptr;
ns_view_bridge_local_.reset();
ns_view_client_binding_.Close();
ns_view_bridge_remote_.reset();
// Delete the delegated frame state, which will reach back into
// host().
......
......@@ -406,6 +406,13 @@ jumbo_source_set("browser_sources") {
]
}
if (is_mac) {
sources += [
"ns_view_bridge_factory_host.h",
"ns_view_bridge_factory_impl.h",
]
}
if (!is_android) {
sources += [
"host_zoom_map.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.
#ifndef CONTENT_PUBLIC_BROWSER_NS_VIEW_BRIDGE_FACTORY_HOST_H_
#define CONTENT_PUBLIC_BROWSER_NS_VIEW_BRIDGE_FACTORY_HOST_H_
#include "base/macros.h"
#include "content/common/content_export.h"
#include "content/public/common/ns_view_bridge_factory.mojom.h"
namespace content {
// The host interface to the factory that will instantiate content NSViews
// (RenderWidgetHostView and WebContentsView) in an app shim process. Each
// app shim will create an instance of this class for to create windows in
// its app.
class CONTENT_EXPORT NSViewBridgeFactoryHost {
public:
NSViewBridgeFactoryHost(mojom::NSViewBridgeFactoryAssociatedRequest* request,
uint64_t host_id);
~NSViewBridgeFactoryHost();
// The host id that refers to creating NSViews in the local process, and
// and accessing directly via pointers (instead of through mojo pipes).
static const uint64_t kLocalDirectHostId;
// Look up a NSViewBridgeFactoryHost from the host id. This host id can
// be used (e.g, by views::NativeViewHost) to associate different Cocoa
// factories that refer to the same app shim process.
static NSViewBridgeFactoryHost* GetFromHostId(uint64_t host_id);
mojom::NSViewBridgeFactory* GetFactory();
private:
const uint64_t host_id_;
mojom::NSViewBridgeFactoryAssociatedPtr factory_;
DISALLOW_COPY_AND_ASSIGN(NSViewBridgeFactoryHost);
};
} // namespace content
#endif // CONTENT_PUBLIC_BROWSER_NS_VIEW_BRIDGE_FACTORY_HOST_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.
#ifndef CONTENT_PUBLIC_BROWSER_NS_VIEW_BRIDGE_FACTORY_IMPL_H_
#define CONTENT_PUBLIC_BROWSER_NS_VIEW_BRIDGE_FACTORY_IMPL_H_
#include "base/macros.h"
#include "content/common/content_export.h"
#include "content/public/common/ns_view_bridge_factory.mojom.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
namespace content {
// The factory that creates content NSView (RenderWidgetHostView and, if
// necessary, WebContentsView) instances. This is a singleton object that is
// to be instantiated in the app shim process.
class CONTENT_EXPORT NSViewBridgeFactoryImpl
: public mojom::NSViewBridgeFactory {
public:
// Get the singleton instance of this factory for this app shim process.
static NSViewBridgeFactoryImpl* Get();
void BindRequest(mojom::NSViewBridgeFactoryAssociatedRequest request);
// mojom::NSViewBridgeFactory:
void CreateRenderWidgetHostNSViewBridge(
mojom::StubInterfaceAssociatedPtrInfo client,
mojom::StubInterfaceAssociatedRequest bridge_request) override;
private:
friend class base::NoDestructor<NSViewBridgeFactoryImpl>;
NSViewBridgeFactoryImpl();
~NSViewBridgeFactoryImpl() override;
mojo::AssociatedBinding<mojom::NSViewBridgeFactory> binding_;
DISALLOW_COPY_AND_ASSIGN(NSViewBridgeFactoryImpl);
};
} // namespace content
#endif // CONTENT_PUBLIC_BROWSER_NS_VIEW_BRIDGE_FACTORY_IMPL_H_
......@@ -362,6 +362,10 @@ mojom("interfaces") {
sources += [ "font_cache_win.mojom" ]
}
if (is_mac) {
sources += [ "ns_view_bridge_factory.mojom" ]
}
public_deps = [
":resource_type_bindings",
"//services/network/public/mojom",
......
// 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;
// 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
// cannot be used directly is that they have dependencies on content-internal
// mojo type serialization (in particular, content wrappings of Blink types).
// TODO(ccameron): Migrate the interfaces RenderWidgetHostNSViewBridge and
// RenderWidgetHostNSViewClient from content-internal types to ui types, and
// then move the interfaces to content/public.
// https://crbug.com/888290
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.
CreateRenderWidgetHostNSViewBridge(
associated StubInterface client,
associated StubInterface& bridge_request);
};
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