Commit 9ae31e0d authored by Christopher Cameron's avatar Christopher Cameron Committed by Commit Bot

WebContentsViewMac: Simplify deferring close during event loops

This issue is best docuemnted in https://crrev.com/31183. The best
repro is to
- Nativate to https://crbug.com/25462
- Download test.html
- Open test.html from the downloads bar
- Tab-drag test.html out, and hold the drag for at least 5 seconds

The implmenetation of this functionality effectively uses
WebContentsViewCocoa (via cancelPreviousPerformRequestsWithTarget and
performSelector) as a weak pointer for WebContentsViewMac. This is not
the right tool for the job, and is guaranteed to not work when
WebContentsViewCocoa is in another process.

Change this to use a weak pointer for weak pointer functionality.

Merge WebContentsView::IsEventTracking and CloseTabAfterEventTracking
into a single function.

Bug: Cleaning up WebContentsView
Change-Id: I215744f048d5c49be00ae94ecdbfdbbdbd62415a
Reviewed-on: https://chromium-review.googlesource.com/c/1492754Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Commit-Queue: Avi Drissman <avi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#636914}
parent e21d2862
...@@ -5726,10 +5726,8 @@ void WebContentsImpl::Close(RenderViewHost* rvh) { ...@@ -5726,10 +5726,8 @@ void WebContentsImpl::Close(RenderViewHost* rvh) {
// TODO(shess): This could get more fine-grained. For instance, // TODO(shess): This could get more fine-grained. For instance,
// closing a tab in another window while selecting text in the // closing a tab in another window while selecting text in the
// current window's Omnibox should be just fine. // current window's Omnibox should be just fine.
if (view_->IsEventTracking()) { if (view_->CloseTabAfterEventTrackingIfNeeded())
view_->CloseTabAfterEventTracking();
return; return;
}
#endif #endif
// Ignore this if it comes from a RenderViewHost that we aren't showing. // Ignore this if it comes from a RenderViewHost that we aren't showing.
......
...@@ -33,7 +33,6 @@ WebContentsNSViewBridge::~WebContentsNSViewBridge() { ...@@ -33,7 +33,6 @@ WebContentsNSViewBridge::~WebContentsNSViewBridge() {
// 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
// WebContentsViewMac instance due to Cocoa retain count. // WebContentsViewMac instance due to Cocoa retain count.
[cocoa_view_ cancelDeferredClose];
[cocoa_view_ clearWebContentsView]; [cocoa_view_ clearWebContentsView];
[cocoa_view_ removeFromSuperview]; [cocoa_view_ removeFromSuperview];
} }
......
...@@ -123,13 +123,12 @@ class WebContentsView { ...@@ -123,13 +123,12 @@ class WebContentsView {
virtual void SetOverscrollControllerEnabled(bool enabled) = 0; virtual void SetOverscrollControllerEnabled(bool enabled) = 0;
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
// If we close the tab while a UI control is in an event-tracking // If we close the tab while a UI control is in an event-tracking loop, the
// loop, the control may message freed objects and crash. // the control may message freed objects and crash. WebContents::Close will
// WebContents::Close() calls IsEventTracking(), and if it returns // call this. If it returns true, then WebContents::Close will early-out, and
// true CloseTabAfterEventTracking() is called and the close is not // it will be the responsibility of |this| to call CloseTab when the nested
// completed. // loop has ended.
virtual bool IsEventTracking() const = 0; virtual bool CloseTabAfterEventTrackingIfNeeded() = 0;
virtual void CloseTabAfterEventTracking() = 0;
#endif #endif
}; };
......
...@@ -110,13 +110,9 @@ void WebContentsViewChildFrame::SetOverscrollControllerEnabled(bool enabled) { ...@@ -110,13 +110,9 @@ void WebContentsViewChildFrame::SetOverscrollControllerEnabled(bool enabled) {
} }
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
bool WebContentsViewChildFrame::IsEventTracking() const { bool WebContentsViewChildFrame::CloseTabAfterEventTrackingIfNeeded() {
return false; return false;
} }
void WebContentsViewChildFrame::CloseTabAfterEventTracking() {
NOTREACHED();
}
#endif #endif
void WebContentsViewChildFrame::RestoreFocus() { void WebContentsViewChildFrame::RestoreFocus() {
......
...@@ -50,8 +50,7 @@ class WebContentsViewChildFrame : public WebContentsView, ...@@ -50,8 +50,7 @@ class WebContentsViewChildFrame : public WebContentsView,
RenderViewHost* new_host) override; RenderViewHost* new_host) override;
void SetOverscrollControllerEnabled(bool enabled) override; void SetOverscrollControllerEnabled(bool enabled) override;
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
bool IsEventTracking() const override; bool CloseTabAfterEventTrackingIfNeeded() override;
void CloseTabAfterEventTracking() override;
#endif #endif
// Backend implementation of RenderViewHostDelegateView. // Backend implementation of RenderViewHostDelegateView.
......
...@@ -60,9 +60,7 @@ CONTENT_EXPORT ...@@ -60,9 +60,7 @@ CONTENT_EXPORT
dragOperationMask:(NSDragOperation)operationMask dragOperationMask:(NSDragOperation)operationMask
image:(NSImage*)image image:(NSImage*)image
offset:(NSPoint)offset; offset:(NSPoint)offset;
- (void)cancelDeferredClose;
- (void)clearWebContentsView; - (void)clearWebContentsView;
- (void)closeTabAfterEvent;
- (void)updateWebContentsVisibility; - (void)updateWebContentsVisibility;
- (void)viewDidBecomeFirstResponder:(NSNotification*)notification; - (void)viewDidBecomeFirstResponder:(NSNotification*)notification;
- (content::WebContentsImpl*)webContents; - (content::WebContentsImpl*)webContents;
......
...@@ -47,9 +47,6 @@ using content::WebContentsViewMac; ...@@ -47,9 +47,6 @@ using content::WebContentsViewMac;
} }
- (void)dealloc { - (void)dealloc {
// Cancel any deferred tab closes, just in case.
[self cancelDeferredClose];
// This probably isn't strictly necessary, but can't hurt. // This probably isn't strictly necessary, but can't hurt.
[self unregisterDraggedTypes]; [self unregisterDraggedTypes];
...@@ -235,24 +232,12 @@ using content::WebContentsViewMac; ...@@ -235,24 +232,12 @@ using content::WebContentsViewMac;
return result; return result;
} }
- (void)cancelDeferredClose {
SEL aSel = @selector(closeTabAfterEvent);
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:aSel
object:nil];
}
- (void)clearWebContentsView { - (void)clearWebContentsView {
webContentsView_ = nullptr; webContentsView_ = nullptr;
client_ = nullptr; client_ = nullptr;
[dragSource_ clearWebContentsView]; [dragSource_ clearWebContentsView];
} }
- (void)closeTabAfterEvent {
if (webContentsView_)
webContentsView_->CloseTab();
}
- (void)viewDidBecomeFirstResponder:(NSNotification*)notification { - (void)viewDidBecomeFirstResponder:(NSNotification*)notification {
if (!client_) if (!client_)
return; return;
......
...@@ -169,12 +169,9 @@ void WebContentsViewGuest::SetOverscrollControllerEnabled(bool enabled) { ...@@ -169,12 +169,9 @@ void WebContentsViewGuest::SetOverscrollControllerEnabled(bool enabled) {
} }
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
bool WebContentsViewGuest::IsEventTracking() const { bool WebContentsViewGuest::CloseTabAfterEventTrackingIfNeeded() {
return false; return false;
} }
void WebContentsViewGuest::CloseTabAfterEventTracking() {
}
#endif #endif
WebContents* WebContentsViewGuest::web_contents() { WebContents* WebContentsViewGuest::web_contents() {
......
...@@ -68,8 +68,7 @@ class WebContentsViewGuest : public WebContentsView, ...@@ -68,8 +68,7 @@ class WebContentsViewGuest : public WebContentsView,
RenderViewHost* new_host) override; RenderViewHost* new_host) override;
void SetOverscrollControllerEnabled(bool enabled) override; void SetOverscrollControllerEnabled(bool enabled) override;
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
bool IsEventTracking() const override; bool CloseTabAfterEventTrackingIfNeeded() override;
void CloseTabAfterEventTracking() override;
#endif #endif
// Backend implementation of RenderViewHostDelegateView. // Backend implementation of RenderViewHostDelegateView.
......
...@@ -83,8 +83,7 @@ class WebContentsViewMac : public WebContentsView, ...@@ -83,8 +83,7 @@ class WebContentsViewMac : public WebContentsView,
void RenderViewHostChanged(RenderViewHost* old_host, void RenderViewHostChanged(RenderViewHost* old_host,
RenderViewHost* new_host) override; RenderViewHost* new_host) override;
void SetOverscrollControllerEnabled(bool enabled) override; void SetOverscrollControllerEnabled(bool enabled) override;
bool IsEventTracking() const override; bool CloseTabAfterEventTrackingIfNeeded() override;
void CloseTabAfterEventTracking() override;
// RenderViewHostDelegateView: // RenderViewHostDelegateView:
void StartDragging(const DropData& drop_data, void StartDragging(const DropData& drop_data,
...@@ -195,6 +194,9 @@ class WebContentsViewMac : public WebContentsView, ...@@ -195,6 +194,9 @@ class WebContentsViewMac : public WebContentsView,
mojo::AssociatedBinding<mojom::WebContentsNSViewClient> mojo::AssociatedBinding<mojom::WebContentsNSViewClient>
ns_view_client_binding_; ns_view_client_binding_;
// Used by CloseTabAfterEventTrackingIfNeeded.
base::WeakPtrFactory<WebContentsViewMac> deferred_close_weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(WebContentsViewMac); DISALLOW_COPY_AND_ASSIGN(WebContentsViewMac);
}; };
......
...@@ -80,7 +80,8 @@ WebContentsViewMac::WebContentsViewMac(WebContentsImpl* web_contents, ...@@ -80,7 +80,8 @@ WebContentsViewMac::WebContentsViewMac(WebContentsImpl* web_contents,
: web_contents_(web_contents), : web_contents_(web_contents),
delegate_(delegate), delegate_(delegate),
ns_view_id_(ui::NSViewIds::GetNewId()), ns_view_id_(ui::NSViewIds::GetNewId()),
ns_view_client_binding_(this) {} ns_view_client_binding_(this),
deferred_close_weak_ptr_factory_(this) {}
WebContentsViewMac::~WebContentsViewMac() { WebContentsViewMac::~WebContentsViewMac() {
if (views_host_) if (views_host_)
...@@ -395,19 +396,21 @@ void WebContentsViewMac::RenderViewHostChanged(RenderViewHost* old_host, ...@@ -395,19 +396,21 @@ void WebContentsViewMac::RenderViewHostChanged(RenderViewHost* old_host,
void WebContentsViewMac::SetOverscrollControllerEnabled(bool enabled) { void WebContentsViewMac::SetOverscrollControllerEnabled(bool enabled) {
} }
bool WebContentsViewMac::IsEventTracking() const {
return base::MessagePumpMac::IsHandlingSendEvent();
}
// Arrange to call CloseTab() after we're back to the main event loop. // Arrange to call CloseTab() after we're back to the main event loop.
// The obvious way to do this would be PostNonNestableTask(), but that // The obvious way to do this would be to post a NonNestable task, but that
// will fire when the event-tracking loop polls for events. So we // would fire when the event-tracking loop polls for events. So we need to
// need to bounce the message via Cocoa, instead. // bounce the message via Cocoa, instead.
void WebContentsViewMac::CloseTabAfterEventTracking() { bool WebContentsViewMac::CloseTabAfterEventTrackingIfNeeded() {
[cocoa_view() cancelDeferredClose]; if (!base::MessagePumpMac::IsHandlingSendEvent())
[cocoa_view() performSelector:@selector(closeTabAfterEvent) return false;
withObject:nil
afterDelay:0.0]; deferred_close_weak_ptr_factory_.InvalidateWeakPtrs();
auto weak_ptr = deferred_close_weak_ptr_factory_.GetWeakPtr();
CFRunLoopPerformBlock(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, ^{
if (weak_ptr)
weak_ptr->CloseTab();
});
return true;
} }
void WebContentsViewMac::CloseTab() { void WebContentsViewMac::CloseTab() {
......
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