Commit 0502abaf authored by Christopher Cameron's avatar Christopher Cameron Committed by Commit Bot

RemoteMacViews: Unify views::View to content::WebContentsView interfaces

There exist two interface through which a views::View is stitched to
a content::WebContentsView
- the ui::Layer is attached via a cr_setParentUiLayer method
- accessibility is attached via the accesibilityHostable protocol

Lifetimes of the embedding are slightly unclear because the attached
WebContentsView may be destroyed the NativeViewHost detaches it.

Replace the AccessibilityHostable protocol with a ViewsHostable
protocol, and add a C++ interface, ui::ViewsHostableView, which provides
a single place through which a views::View and a content::WebContentsView
are stitched together
- have content::WebContentsViewMac implement ui::ViewsHostableView
- have views::NativeWidgetHost implement ui::ViewsHostableView::Host

Use this explicit interface to ensure that the views::NativeWidgetHost
detaches from the content::WebContentsViewMac before it is destroyed.

Additional parameters and method will be added to the
ui::ViewsHostableView interface to enable stitching together
out-of-process NSViews.

R=lgrey
TBR=avi (content/ OWNERship)

Bug: 821561
Change-Id: Iddc46278cd06b9e27d3f12aa5a9e830273f3b562
Reviewed-on: https://chromium-review.googlesource.com/1252641
Commit-Queue: ccameron <ccameron@chromium.org>
Reviewed-by: default avatarLeonard Grey <lgrey@chromium.org>
Cr-Commit-Position: refs/heads/master@{#595521}
parent 8f9f2d7c
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
#include "content/browser/web_contents/web_contents_view.h" #include "content/browser/web_contents/web_contents_view.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "content/common/drag_event_source_info.h" #include "content/common/drag_event_source_info.h"
#import "ui/base/cocoa/accessibility_hostable.h"
#import "ui/base/cocoa/base_view.h" #import "ui/base/cocoa/base_view.h"
#import "ui/base/cocoa/views_hostable.h"
#include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size.h"
@class WebDragDest; @class WebDragDest;
...@@ -42,7 +42,7 @@ class Layer; ...@@ -42,7 +42,7 @@ class Layer;
} }
CONTENT_EXPORT CONTENT_EXPORT
@interface WebContentsViewCocoa : BaseView<AccessibilityHostable> { @interface WebContentsViewCocoa : BaseView<ViewsHostable> {
@private @private
// Instances of this class are owned by both webContentsView_ and AppKit. It // Instances of this class are owned by both webContentsView_ and AppKit. It
// is possible for an instance to outlive its webContentsView_. The // is possible for an instance to outlive its webContentsView_. The
...@@ -56,6 +56,12 @@ CONTENT_EXPORT ...@@ -56,6 +56,12 @@ CONTENT_EXPORT
- (void)setMouseDownCanMoveWindow:(BOOL)canMove; - (void)setMouseDownCanMoveWindow:(BOOL)canMove;
// Sets |accessibilityParent| as the object returned when the
// receiver is queried for its accessibility parent.
// TODO(lgrey/ellyjones): Remove this in favor of setAccessibilityParent:
// when we switch to the new accessibility API.
- (void)setAccessibilityParentElement:(id)accessibilityParent;
// Returns the available drag operations. This is a required method for // Returns the available drag operations. This is a required method for
// NSDraggingSource. It is supposedly deprecated, but the non-deprecated API // NSDraggingSource. It is supposedly deprecated, but the non-deprecated API
// -[NSWindow dragImage:...] still relies on it. // -[NSWindow dragImage:...] still relies on it.
...@@ -69,7 +75,8 @@ namespace content { ...@@ -69,7 +75,8 @@ namespace content {
// contains all of the contents of the tab and associated child views. // contains all of the contents of the tab and associated child views.
class WebContentsViewMac : public WebContentsView, class WebContentsViewMac : public WebContentsView,
public RenderViewHostDelegateView, public RenderViewHostDelegateView,
public PopupMenuHelper::Delegate { public PopupMenuHelper::Delegate,
public ui::ViewsHostableView {
public: public:
// The corresponding WebContentsImpl is passed in the constructor, and manages // The corresponding WebContentsImpl is passed in the constructor, and manages
// our lifetime. This doesn't need to be the case, but is this way currently // our lifetime. This doesn't need to be the case, but is this way currently
...@@ -132,12 +139,14 @@ class WebContentsViewMac : public WebContentsView, ...@@ -132,12 +139,14 @@ class WebContentsViewMac : public WebContentsView,
// PopupMenuHelper::Delegate: // PopupMenuHelper::Delegate:
void OnMenuClosed() override; void OnMenuClosed() override;
// ViewsHostableView:
void OnViewsHostableAttached(ViewsHostableView::Host* host) override;
void OnViewsHostableDetached() override;
// A helper method for closing the tab in the // A helper method for closing the tab in the
// CloseTabAfterEventTracking() implementation. // CloseTabAfterEventTracking() implementation.
void CloseTab(); void CloseTab();
void SetParentUiLayer(ui::Layer* parent_ui_layer);
WebContentsImpl* web_contents() { return web_contents_; } WebContentsImpl* web_contents() { return web_contents_; }
WebContentsViewDelegate* delegate() { return delegate_.get(); } WebContentsViewDelegate* delegate() { return delegate_.get(); }
...@@ -149,6 +158,8 @@ class WebContentsViewMac : public WebContentsView, ...@@ -149,6 +158,8 @@ class WebContentsViewMac : public WebContentsView,
RenderWidgetHostViewCreateFunction create_render_widget_host_view); RenderWidgetHostViewCreateFunction create_render_widget_host_view);
private: private:
void SetParentUiLayer(ui::Layer* parent_ui_layer);
// Returns the fullscreen view, if one exists; otherwise, returns the content // Returns the fullscreen view, if one exists; otherwise, returns the content
// native view. This ensures that the view currently attached to a NSWindow is // native view. This ensures that the view currently attached to a NSWindow is
// being used to query or set first responder state. // being used to query or set first responder state.
...@@ -170,7 +181,8 @@ class WebContentsViewMac : public WebContentsView, ...@@ -170,7 +181,8 @@ class WebContentsViewMac : public WebContentsView,
// destroyed. // destroyed.
std::list<base::WeakPtr<RenderWidgetHostViewBase>> child_views_; std::list<base::WeakPtr<RenderWidgetHostViewBase>> child_views_;
ui::Layer* parent_ui_layer_ = nullptr; // Interface to the views::View host of this view.
ViewsHostableView::Host* views_host_ = nullptr;
std::unique_ptr<PopupMenuHelper> popup_menu_helper_; std::unique_ptr<PopupMenuHelper> popup_menu_helper_;
......
...@@ -108,6 +108,9 @@ WebContentsViewMac::WebContentsViewMac(WebContentsImpl* web_contents, ...@@ -108,6 +108,9 @@ WebContentsViewMac::WebContentsViewMac(WebContentsImpl* web_contents,
: web_contents_(web_contents), delegate_(delegate) {} : web_contents_(web_contents), delegate_(delegate) {}
WebContentsViewMac::~WebContentsViewMac() { WebContentsViewMac::~WebContentsViewMac() {
if (views_host_)
views_host_->OnHostableViewDestroying();
DCHECK(!views_host_);
// This handles the case where a renderer close call was deferred // This handles the case where a renderer close call was deferred
// while the user was operating a UI control which resulted in a // while the user was operating a UI control which resulted in a
// close. In that case, the Cocoa view outlives the // close. In that case, the Cocoa view outlives the
...@@ -354,7 +357,8 @@ RenderWidgetHostViewBase* WebContentsViewMac::CreateViewForWidget( ...@@ -354,7 +357,8 @@ RenderWidgetHostViewBase* WebContentsViewMac::CreateViewForWidget(
// Add the RenderWidgetHostView to the ui::Layer heirarchy. // Add the RenderWidgetHostView to the ui::Layer heirarchy.
child_views_.push_back(view->GetWeakPtr()); child_views_.push_back(view->GetWeakPtr());
SetParentUiLayer(parent_ui_layer_); if (views_host_)
SetParentUiLayer(views_host_->GetUiLayer());
// Fancy layout comes later; for now just make it our size and resize it // 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 // with us. In case there are other siblings of the content area, we want
...@@ -431,7 +435,6 @@ void WebContentsViewMac::CloseTab() { ...@@ -431,7 +435,6 @@ void WebContentsViewMac::CloseTab() {
} }
void WebContentsViewMac::SetParentUiLayer(ui::Layer* parent_ui_layer) { void WebContentsViewMac::SetParentUiLayer(ui::Layer* parent_ui_layer) {
parent_ui_layer_ = parent_ui_layer;
// Remove any child NSViews that have been destroyed. // Remove any child NSViews that have been destroyed.
for (auto iter = child_views_.begin(); iter != child_views_.end();) { for (auto iter = child_views_.begin(); iter != child_views_.end();) {
if (*iter) if (*iter)
...@@ -441,6 +444,26 @@ void WebContentsViewMac::SetParentUiLayer(ui::Layer* parent_ui_layer) { ...@@ -441,6 +444,26 @@ void WebContentsViewMac::SetParentUiLayer(ui::Layer* parent_ui_layer) {
} }
} }
////////////////////////////////////////////////////////////////////////////////
// WebContentsViewMac, ViewsHostableView:
void WebContentsViewMac::OnViewsHostableAttached(
ViewsHostableView::Host* host) {
views_host_ = host;
SetParentUiLayer(views_host_->GetUiLayer());
[cocoa_view_
setAccessibilityParentElement:views_host_->GetAccessibilityElement()];
}
void WebContentsViewMac::OnViewsHostableDetached() {
DCHECK(views_host_);
views_host_ = nullptr;
SetParentUiLayer(nullptr);
[cocoa_view_ setAccessibilityParentElement:nil];
}
} // namespace content } // namespace content
@implementation WebContentsViewCocoa @implementation WebContentsViewCocoa
...@@ -655,11 +678,6 @@ void WebContentsViewMac::SetParentUiLayer(ui::Layer* parent_ui_layer) { ...@@ -655,11 +678,6 @@ void WebContentsViewMac::SetParentUiLayer(ui::Layer* parent_ui_layer) {
FocusThroughTabTraversal(direction == NSSelectingPrevious); FocusThroughTabTraversal(direction == NSSelectingPrevious);
} }
- (void)cr_setParentUiLayer:(ui::Layer*)parentUiLayer {
if (webContentsView_)
webContentsView_->SetParentUiLayer(parentUiLayer);
}
- (void)updateWebContentsVisibility { - (void)updateWebContentsVisibility {
WebContentsImpl* webContents = [self webContents]; WebContentsImpl* webContents = [self webContents];
if (!webContents || webContents->IsBeingDestroyed()) if (!webContents || webContents->IsBeingDestroyed())
...@@ -724,11 +742,15 @@ void WebContentsViewMac::SetParentUiLayer(ui::Layer* parent_ui_layer) { ...@@ -724,11 +742,15 @@ void WebContentsViewMac::SetParentUiLayer(ui::Layer* parent_ui_layer) {
[self updateWebContentsVisibility]; [self updateWebContentsVisibility];
} }
// AccessibilityHostable protocol implementation.
- (void)setAccessibilityParentElement:(id)accessibilityParent { - (void)setAccessibilityParentElement:(id)accessibilityParent {
accessibilityParent_.reset([accessibilityParent retain]); accessibilityParent_.reset([accessibilityParent retain]);
} }
// ViewsHostable protocol implementation.
- (ui::ViewsHostableView*)viewsHostableView {
return webContentsView_;
}
// NSAccessibility informal protocol implementation. // NSAccessibility informal protocol implementation.
- (id)accessibilityAttributeValue:(NSString*)attribute { - (id)accessibilityAttributeValue:(NSString*)attribute {
if (accessibilityParent_ && if (accessibilityParent_ &&
......
...@@ -89,7 +89,6 @@ jumbo_component("base") { ...@@ -89,7 +89,6 @@ jumbo_component("base") {
"clipboard/clipboard_win.cc", "clipboard/clipboard_win.cc",
"clipboard/clipboard_win.h", "clipboard/clipboard_win.h",
"clipboard/custom_data_helper_mac.mm", "clipboard/custom_data_helper_mac.mm",
"cocoa/accessibility_hostable.h",
"cocoa/animation_utils.h", "cocoa/animation_utils.h",
"cocoa/appkit_utils.h", "cocoa/appkit_utils.h",
"cocoa/appkit_utils.mm", "cocoa/appkit_utils.mm",
...@@ -152,6 +151,7 @@ jumbo_component("base") { ...@@ -152,6 +151,7 @@ jumbo_component("base") {
"cocoa/user_interface_item_command_handler.h", "cocoa/user_interface_item_command_handler.h",
"cocoa/view_description.h", "cocoa/view_description.h",
"cocoa/view_description.mm", "cocoa/view_description.mm",
"cocoa/views_hostable.h",
"cocoa/weak_ptr_nsobject.h", "cocoa/weak_ptr_nsobject.h",
"cocoa/weak_ptr_nsobject.mm", "cocoa/weak_ptr_nsobject.mm",
"cocoa/window_size_constants.h", "cocoa/window_size_constants.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 UI_BASE_COCOA_ACCESSIBILITY_HOSTABLE_H_
#define UI_BASE_COCOA_ACCESSIBILITY_HOSTABLE_H_
#import <objc/objc.h>
// An object that can be hosted in another accessibility hierarchy.
// This allows for stitching together heterogenous accessibility
// hierarchies, for example the AXPlatformNodeCocoa-based views
// toolkit hierarchy and the BrowserAccessibilityCocoa-based
// web content hierarchy.
@protocol AccessibilityHostable
// Sets |accessibilityParent| as the object returned when the
// receiver is queried for its accessibility parent.
// TODO(lgrey/ellyjones): Remove this in favor of setAccessibilityParent:
// when we switch to the new accessibility API.
- (void)setAccessibilityParentElement:(id)accessibilityParent;
@end
#endif // UI_BASE_COCOA_ACCESSIBILITY_HOSTABLE_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 UI_BASE_COCOA_VIEWS_HOSTABLE_H_
#define UI_BASE_COCOA_VIEWS_HOSTABLE_H_
#import <objc/objc.h>
#include "ui/base/ui_base_export.h"
#include "ui/gfx/geometry/rect.h"
namespace ui {
class Layer;
// Interface that it used to stitch a content::WebContentsView into a
// views::View.
class ViewsHostableView {
public:
// Host interface through which the WebContentsView may indicate that its C++
// object is destroying.
class Host {
public:
// Query the ui::Layer of the host.
virtual ui::Layer* GetUiLayer() const = 0;
// Query the parent accessibility element of the host.
virtual id GetAccessibilityElement() const = 0;
// Called when the hostable view will be destroyed.
virtual void OnHostableViewDestroying() = 0;
};
// Called when the content::WebContentsView's NSView is added as a subview of
// the views::View's NSView (note that these are the browser-side NSViews).
// This is responsible for:
// - Adding the WebContentsView's ui::Layer to the parent's ui::Layer tree.
// - Stitching together the accessibility tree between the views::View and
// 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;
};
} // namespace ui
// The protocol through which an NSView indicates support for the
// ViewsHostableView interface.
@protocol ViewsHostable
- (ui::ViewsHostableView*)viewsHostableView;
@end
#endif // UI_BASE_COCOA_VIEWS_HOSTABLE_H_
...@@ -7,24 +7,32 @@ ...@@ -7,24 +7,32 @@
#include "base/mac/scoped_nsobject.h" #include "base/mac/scoped_nsobject.h"
#include "base/macros.h" #include "base/macros.h"
#include "ui/base/cocoa/views_hostable.h"
#include "ui/views/controls/native/native_view_host_wrapper.h" #include "ui/views/controls/native/native_view_host_wrapper.h"
#include "ui/views/views_export.h" #include "ui/views/views_export.h"
namespace ui { namespace ui {
class LayerOwner; class LayerOwner;
} class ViewsHostableView;
} // namespace ui
namespace views { namespace views {
class NativeViewHost; class NativeViewHost;
// Mac implementation of NativeViewHostWrapper. // Mac implementation of NativeViewHostWrapper.
class NativeViewHostMac : public NativeViewHostWrapper { class NativeViewHostMac : public NativeViewHostWrapper,
public ui::ViewsHostableView::Host {
public: public:
explicit NativeViewHostMac(NativeViewHost* host); explicit NativeViewHostMac(NativeViewHost* host);
~NativeViewHostMac() override; ~NativeViewHostMac() override;
// Overridden from NativeViewHostWrapper: // ViewsHostableView::Host:
ui::Layer* GetUiLayer() const override;
id GetAccessibilityElement() const override;
void OnHostableViewDestroying() override;
// NativeViewHostWrapper:
void AttachNativeView() override; void AttachNativeView() override;
void NativeViewDetaching(bool destroyed) override; void NativeViewDetaching(bool destroyed) override;
void AddedToWidget() override; void AddedToWidget() override;
...@@ -48,6 +56,11 @@ class NativeViewHostMac : public NativeViewHostWrapper { ...@@ -48,6 +56,11 @@ class NativeViewHostMac : public NativeViewHostWrapper {
// Retain the native view as it may be destroyed at an unpredictable time. // Retain the native view as it may be destroyed at an unpredictable time.
base::scoped_nsobject<NSView> native_view_; base::scoped_nsobject<NSView> native_view_;
// If |native_view| supports the ViewsHostable protocol, then this is the
// the corresponding ViewsHostableView interface (which is implemeted only
// by WebContents and tests).
ui::ViewsHostableView* native_view_hostable_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(NativeViewHostMac); DISALLOW_COPY_AND_ASSIGN(NativeViewHostMac);
}; };
......
...@@ -8,19 +8,11 @@ ...@@ -8,19 +8,11 @@
#include "base/mac/foundation_util.h" #include "base/mac/foundation_util.h"
#import "ui/accessibility/platform/ax_platform_node_mac.h" #import "ui/accessibility/platform/ax_platform_node_mac.h"
#import "ui/base/cocoa/accessibility_hostable.h"
#import "ui/views/cocoa/bridged_native_widget_host_impl.h" #import "ui/views/cocoa/bridged_native_widget_host_impl.h"
#include "ui/views/controls/native/native_view_host.h" #include "ui/views/controls/native/native_view_host.h"
#include "ui/views/widget/native_widget_mac.h" #include "ui/views/widget/native_widget_mac.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
// NSViews that can be drawn as a ui::Layer directly will implement this
// interface. Calling cr_setParentLayer will embed the ui::Layer of the NSView
// under |parentUiLayer|.
@interface NSView (UICompositor)
- (void)cr_setParentUiLayer:(ui::Layer*)parentUiLayer;
@end
namespace views { namespace views {
namespace { namespace {
...@@ -59,6 +51,40 @@ NativeViewHostMac::NativeViewHostMac(NativeViewHost* host) : host_(host) { ...@@ -59,6 +51,40 @@ NativeViewHostMac::NativeViewHostMac(NativeViewHost* host) : host_(host) {
NativeViewHostMac::~NativeViewHostMac() { NativeViewHostMac::~NativeViewHostMac() {
} }
////////////////////////////////////////////////////////////////////////////////
// NativeViewHostMac, ViewsHostableView::Host implementation:
ui::Layer* NativeViewHostMac::GetUiLayer() const {
return host_->layer();
}
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.
// This is necessary because a closer ancestor might already be attaching
// to the NSView/content hierarchy.
// For example, web content is currently embedded into the views hierarchy
// roughly like this:
// BrowserView (views)
// |_ WebView (views)
// |_ NativeViewHost (views)
// |_ WebContentView (Cocoa, is |native_view_| in this scenario,
// | accessibility ignored).
// |_ RenderWidgetHostView (Cocoa)
// WebView specifies either the RenderWidgetHostView or the native view as
// its accessibility element. That means that if we were to set it as
// |native_view_|'s parent, the RenderWidgetHostView would be its own
// accessibility parent! Instead, we want to find the browser view and
// attach to its node.
return ClosestPlatformAncestorNode(host_->parent());
}
void NativeViewHostMac::OnHostableViewDestroying() {
DCHECK(native_view_hostable_);
host_->NativeViewDestroyed();
DCHECK(!native_view_hostable_);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// NativeViewHostMac, NativeViewHostWrapper implementation: // NativeViewHostMac, NativeViewHostWrapper implementation:
...@@ -66,46 +92,25 @@ void NativeViewHostMac::AttachNativeView() { ...@@ -66,46 +92,25 @@ void NativeViewHostMac::AttachNativeView() {
DCHECK(host_->native_view()); DCHECK(host_->native_view());
DCHECK(!native_view_); DCHECK(!native_view_);
native_view_.reset([host_->native_view() retain]); native_view_.reset([host_->native_view() retain]);
if ([native_view_ respondsToSelector:@selector(cr_setParentUiLayer:)])
[native_view_ cr_setParentUiLayer:host_->layer()];
if ([native_view_ conformsToProtocol:@protocol(AccessibilityHostable)]) {
// Find the closest ancestor view that participates in the views toolkit
// accessibility hierarchy and set its element as the native view's parent.
// This is necessary because a closer ancestor might already be attaching
// to the NSView/content hierarchy.
// For example, web content is currently embedded into the views hierarchy
// roughly like this:
// BrowserView (views)
// |_ WebView (views)
// |_ NativeViewHost (views)
// |_ WebContentView (Cocoa, is |native_view_| in this scenario,
// | accessibility ignored).
// |_ RenderWidgetHostView (Cocoa)
// WebView specifies either the RenderWidgetHostView or the native view as
// its accessibility element. That means that if we were to set it as
// |native_view_|'s parent, the RenderWidgetHostView would be its own
// accessibility parent! Instead, we want to find the browser view and
// attach to its node.
id hostable = native_view_;
[hostable setAccessibilityParentElement:ClosestPlatformAncestorNode(
host_->parent())];
}
EnsureNativeViewHasNoChildWidgets(native_view_); EnsureNativeViewHasNoChildWidgets(native_view_);
BridgedNativeWidgetHostImpl* bridge_host = BridgedNativeWidgetHostImpl* bridge_host =
BridgedNativeWidgetHostImpl::GetFromNativeWindow( BridgedNativeWidgetHostImpl::GetFromNativeWindow(
host_->GetWidget()->GetNativeWindow()); host_->GetWidget()->GetNativeWindow());
DCHECK(bridge_host); DCHECK(bridge_host);
bridge_host->SetAssociationForView(host_, native_view_); bridge_host->SetAssociationForView(host_, native_view_);
if ([native_view_ conformsToProtocol:@protocol(ViewsHostable)]) {
id hostable = native_view_;
native_view_hostable_ = [hostable viewsHostableView];
if (native_view_hostable_)
native_view_hostable_->OnViewsHostableAttached(this);
}
} }
void NativeViewHostMac::NativeViewDetaching(bool destroyed) { void NativeViewHostMac::NativeViewDetaching(bool destroyed) {
// |destroyed| is only true if this class calls host_->NativeViewDestroyed(). // |destroyed| is only true if this class calls host_->NativeViewDestroyed(),
// Aura does this after observing an aura OnWindowDestroying, but NSViews // which is called if a hosted WebContentsView about to be destroyed (note
// are reference counted so there isn't a reliable signal. Instead, a // that its corresponding NSView may still exist).
// reference is retained until the NativeViewHost is detached.
DCHECK(!destroyed);
// |native_view_| can be nil here if RemovedFromWidget() is called before // |native_view_| can be nil here if RemovedFromWidget() is called before
// NativeViewHost::Detach(). // NativeViewHost::Detach().
...@@ -118,11 +123,9 @@ void NativeViewHostMac::NativeViewDetaching(bool destroyed) { ...@@ -118,11 +123,9 @@ void NativeViewHostMac::NativeViewDetaching(bool destroyed) {
[host_->native_view() setHidden:YES]; [host_->native_view() setHidden:YES];
[host_->native_view() removeFromSuperview]; [host_->native_view() removeFromSuperview];
if ([native_view_ respondsToSelector:@selector(cr_setParentUiLayer:)]) if (native_view_hostable_) {
[native_view_ cr_setParentUiLayer:nullptr]; native_view_hostable_->OnViewsHostableDetached();
if ([native_view_ conformsToProtocol:@protocol(AccessibilityHostable)]) { native_view_hostable_ = nullptr;
id hostable = native_view_;
[hostable setAccessibilityParentElement:nil];
} }
EnsureNativeViewHasNoChildWidgets(host_->native_view()); EnsureNativeViewHasNoChildWidgets(host_->native_view());
......
...@@ -12,17 +12,35 @@ ...@@ -12,17 +12,35 @@
#import "base/mac/scoped_nsobject.h" #import "base/mac/scoped_nsobject.h"
#include "base/macros.h" #include "base/macros.h"
#import "testing/gtest_mac.h" #import "testing/gtest_mac.h"
#import "ui/base/cocoa/accessibility_hostable.h" #import "ui/base/cocoa/views_hostable.h"
#include "ui/views/controls/native/native_view_host.h" #include "ui/views/controls/native/native_view_host.h"
#include "ui/views/controls/native/native_view_host_test_base.h" #include "ui/views/controls/native/native_view_host_test_base.h"
#include "ui/views/view.h" #include "ui/views/view.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
@interface TestAccessibilityHostableView : NSView<AccessibilityHostable> class TestViewsHostable : public ui::ViewsHostableView {
@property(nonatomic, assign) id accessibilityParentElement; public:
id parent_accessibility_element() const {
return parent_accessibility_element_;
}
private:
// ui::ViewsHostableView:
void OnViewsHostableAttached(ui::ViewsHostableView::Host* host) override {
parent_accessibility_element_ = host->GetAccessibilityElement();
}
void OnViewsHostableDetached() override {
parent_accessibility_element_ = nil;
}
id parent_accessibility_element_ = nil;
};
@interface TestViewsHostableView : NSView<ViewsHostable>
@property(nonatomic, assign) ui::ViewsHostableView* viewsHostableView;
@end @end
@implementation TestAccessibilityHostableView @implementation TestViewsHostableView
@synthesize accessibilityParentElement = accessibilityParentElement_; @synthesize viewsHostableView = viewsHostableView_;
@end @end
namespace views { namespace views {
...@@ -115,15 +133,18 @@ TEST_F(NativeViewHostMacTest, AccessibilityParent) { ...@@ -115,15 +133,18 @@ TEST_F(NativeViewHostMacTest, AccessibilityParent) {
CreateHost(); CreateHost();
host()->Detach(); host()->Detach();
base::scoped_nsobject<TestAccessibilityHostableView> view( base::scoped_nsobject<TestViewsHostableView> view(
[[TestAccessibilityHostableView alloc] init]); [[TestViewsHostableView alloc] init]);
TestViewsHostable views_hostable;
[view setViewsHostableView:&views_hostable];
host()->Attach(view); host()->Attach(view);
EXPECT_NSEQ([view accessibilityParentElement], EXPECT_NSEQ(views_hostable.parent_accessibility_element(),
toplevel()->GetRootView()->GetNativeViewAccessible()); toplevel()->GetRootView()->GetNativeViewAccessible());
host()->Detach(); host()->Detach();
DestroyHost(); DestroyHost();
EXPECT_FALSE([view accessibilityParentElement]); EXPECT_FALSE(views_hostable.parent_accessibility_element());
} }
// Test that the content windows' bounds are set to the correct values while the // Test that the content windows' bounds are set to the correct values while the
......
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