Commit 02e5964f authored by Christopher Cameron's avatar Christopher Cameron Committed by Commit Bot

WebContentsViewMac: Mojo-ify dragging part of drag-drop

This modifies 3 parts of WebContentsViewMac and its friends.

1: Initiation of a drag from web contents
This action follows the following path
  * WebContentsViewMac::StartDragging is called, which calls
  * -[WebContentsViewCocoa startDragWithDropData...], which
  * Creates a WebDragSource (to store state for the drag) and calls
  * -[WebDragSource startDrag], which calls
  * -[NSWindow dragImage...]
This doesn't work across processes because the WebContentsViewMac
now exists in the browser process and the WebContentsViewCocoa
exists in the app shim process. Fix this by adding the mojo method
WebContentsNSViewBridge::StartDrag, which is called by
WebContentsViewMac::StartDragging in the browser process, and makes
the -[WebContentsViewCocoa startDragWithDropData...] when it is
received in the app shim process.

2: Completion of a drag via -[NSDraggingSource draggedImage...]
This method takes the following path
  * -[WebContentsViewCocoa(NSDraggingSource) draggedImage...] is
    called by the system, which then calls
  * -[WebDragSource endDragAt:], which then calls
  * WebContentsImpl::SystemDragEnded and
    WebContentsImpl::DragSourceEndedAt
This doesn't work across processes because the WebContentsViewCocoa
is in the app shim process while the WebContentsImpl is in the browser
process. Fix this by adding the mojo method
WebContentsNSViewClient::EndDrag, which is called by WebDragSource
in the app shim process, and makes the WebContentsImpl calls when
it is received in the browser process.

3: -[NSDraggingInfo namesOfPromisedFilesDroppedAtDestination] is called
This method takes the following path
  * -[WebContentsViewCocoa(NSDraggingInfo) namesOfPromised...] calls
  * -[WebDragSource dragPromisedFileTo...], which creates a
  * DragDownloadFile, which uses the WebContentsImpl
Same as the above, the WebContentsViewCocoa cannot access the
WebContentsImpl, so we add a mojo method to bridge between the two.

Move tracking of state for the drag (e.g, the source RenderWidgetHost)
from WebDragSource to WebContentsViewMac.

This eliminates the last need for accessing the WebContentsViewMac
in WebContentsViewCocoa and WebDragSource, to remove the related
member variables.

Because the use of base::ThreadRestrictions::ScopedAllowIO is moved
by this patch, update it to be ScopedAllowBlocking and add
WebContentsViewMac as a friend of ScopedAllowBlocking.

Bug: 898608
Change-Id: I4e7f069e96902b7f0ef26e8579444be96b765a20
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1497543Reviewed-by: default avatardanakj <danakj@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Commit-Queue: ccameron <ccameron@chromium.org>
Cr-Commit-Position: refs/heads/master@{#637841}
parent 3fcb2b7c
......@@ -148,6 +148,7 @@ class SynchronousCompositor;
class SynchronousCompositorHost;
class SynchronousCompositorSyncCallBridge;
class TextInputClientMac;
class WebContentsViewMac;
} // namespace content
namespace cronet {
class CronetPrefsManager;
......@@ -319,6 +320,7 @@ class BASE_EXPORT ScopedAllowBlocking {
friend class android_webview::ScopedAllowInitGLBindings;
friend class content::BrowserProcessSubThread;
friend class content::GpuProcessTransportFactory;
friend class content::WebContentsViewMac;
friend class cronet::CronetPrefsManager;
friend class cronet::CronetURLRequestContext;
friend class mojo::CoreLibraryInitializer;
......
......@@ -47,6 +47,10 @@ class CONTENT_EXPORT WebContentsNSViewBridge
void SetVisible(bool visible) override;
void MakeFirstResponder() override;
void TakeFocus(bool reverse) override;
void StartDrag(const DropData& drop_data,
uint32_t operation_mask,
const gfx::ImageSkia& image,
const gfx::Vector2d& image_offset) override;
private:
base::scoped_nsobject<WebContentsViewCocoa> cocoa_view_;
......
......@@ -5,6 +5,8 @@
#include "content/browser/web_contents/web_contents_ns_view_bridge.h"
#import "content/browser/web_contents/web_contents_view_cocoa.h"
#include "content/browser/web_contents/web_contents_view_mac.h"
#include "ui/gfx/image/image_skia_util_mac.h"
namespace content {
......@@ -13,7 +15,7 @@ WebContentsNSViewBridge::WebContentsNSViewBridge(
mojom::WebContentsNSViewClientAssociatedPtr client)
: client_(std::move(client)) {
cocoa_view_.reset(
[[WebContentsViewCocoa alloc] initWithWebContentsViewMac:nullptr]);
[[WebContentsViewCocoa alloc] initWithViewsHostableView:nullptr]);
[cocoa_view_ setClient:client_.get()];
view_id_ =
std::make_unique<ui::ScopedNSViewIdMapping>(view_id, cocoa_view_.get());
......@@ -23,7 +25,8 @@ WebContentsNSViewBridge::WebContentsNSViewBridge(
uint64_t view_id,
WebContentsViewMac* web_contents_view) {
cocoa_view_.reset([[WebContentsViewCocoa alloc]
initWithWebContentsViewMac:web_contents_view]);
initWithViewsHostableView:web_contents_view]);
[cocoa_view_ setClient:web_contents_view];
view_id_ =
std::make_unique<ui::ScopedNSViewIdMapping>(view_id, cocoa_view_.get());
}
......@@ -33,7 +36,8 @@ WebContentsNSViewBridge::~WebContentsNSViewBridge() {
// while the user was operating a UI control which resulted in a
// close. In that case, the Cocoa view outlives the
// WebContentsViewMac instance due to Cocoa retain count.
[cocoa_view_ clearWebContentsView];
[cocoa_view_ setClient:nullptr];
[cocoa_view_ clearViewsHostableView];
[cocoa_view_ removeFromSuperview];
}
......@@ -82,4 +86,16 @@ void WebContentsNSViewBridge::TakeFocus(bool reverse) {
[[cocoa_view_ window] selectNextKeyView:cocoa_view_];
}
void WebContentsNSViewBridge::StartDrag(const DropData& drop_data,
uint32_t operation_mask,
const gfx::ImageSkia& image,
const gfx::Vector2d& image_offset) {
NSPoint offset = NSPointFromCGPoint(
gfx::PointAtOffsetFromOrigin(image_offset).ToCGPoint());
[cocoa_view_ startDragWithDropData:drop_data
dragOperationMask:operation_mask
image:gfx::NSImageFromImageSkia(image)
offset:offset];
}
} // namespace content
......@@ -12,9 +12,6 @@
namespace content {
struct DropData;
class RenderWidgetHostImpl;
class WebContentsImpl;
class WebContentsViewMac;
namespace mojom {
class WebContentsNSViewClient;
} // namespace mojom
......@@ -25,18 +22,22 @@ class WebContentsNSViewClient;
CONTENT_EXPORT
@interface WebContentsViewCocoa : BaseView <ViewsHostable> {
@private
// Instances of this class are owned by both webContentsView_ and AppKit. It
// is possible for an instance to outlive its webContentsView_. The
// webContentsView_ must call -clearWebContentsView in its destructor.
content::WebContentsViewMac* webContentsView_;
// Instances of this class are owned by both client_ and AppKit. It is
// possible for an instance to outlive its webContentsView_. The client_ must
// call -clearClientAndView in its destructor.
content::mojom::WebContentsNSViewClient* client_;
// The interface exported to views::Views that embed this as a sub-view.
ui::ViewsHostableView* viewsHostableView_;
base::scoped_nsobject<WebDragSource> dragSource_;
base::scoped_nsobject<id> accessibilityParent_;
BOOL mouseDownCanMoveWindow_;
}
// The mojo interface through which to communicate with the browser process.
@property(nonatomic, assign) content::mojom::WebContentsNSViewClient* client;
// Set or un-set the mojo interface through which to communicate with the
// browser process.
- (void)setClient:(content::mojom::WebContentsNSViewClient*)client;
- (void)setMouseDownCanMoveWindow:(BOOL)canMove;
......@@ -53,17 +54,15 @@ CONTENT_EXPORT
// Private interface.
// TODO(ccameron): Document these functions.
- (id)initWithWebContentsViewMac:(content::WebContentsViewMac*)w;
- (id)initWithViewsHostableView:(ui::ViewsHostableView*)v;
- (void)registerDragTypes;
- (void)startDragWithDropData:(const content::DropData&)dropData
sourceRWH:(content::RenderWidgetHostImpl*)sourceRWH
dragOperationMask:(NSDragOperation)operationMask
image:(NSImage*)image
offset:(NSPoint)offset;
- (void)clearWebContentsView;
- (void)clearViewsHostableView;
- (void)updateWebContentsVisibility;
- (void)viewDidBecomeFirstResponder:(NSNotification*)notification;
- (content::WebContentsImpl*)webContents;
@end
#endif // CONTENT_BROWSER_WEB_CONTENTS_WEB_CONTENTS_VIEW_COCOA_H_
......@@ -6,12 +6,8 @@
#import "base/mac/mac_util.h"
#include "base/mac/sdk_forward_declarations.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/browser/web_contents/web_contents_view_mac.h"
#import "content/browser/web_contents/web_drag_dest_mac.h"
#import "content/browser/web_contents/web_drag_source_mac.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_view_delegate.h"
#include "content/public/common/web_contents_ns_view_bridge.mojom.h"
#import "third_party/mozilla/NSPasteboard+Utils.h"
#include "ui/base/clipboard/clipboard_constants.h"
......@@ -21,20 +17,16 @@
using content::mojom::DraggingInfo;
using content::DropData;
using content::WebContentsImpl;
using content::WebContentsViewMac;
////////////////////////////////////////////////////////////////////////////////
// WebContentsViewCocoa
@implementation WebContentsViewCocoa
@synthesize client = client_;
- (id)initWithWebContentsViewMac:(WebContentsViewMac*)w {
- (id)initWithViewsHostableView:(ui::ViewsHostableView*)v {
self = [super initWithFrame:NSZeroRect];
if (self != nil) {
webContentsView_ = w;
viewsHostableView_ = v;
[self registerDragTypes];
[[NSNotificationCenter defaultCenter]
......@@ -99,12 +91,6 @@ using content::WebContentsViewMac;
[self registerForDraggedTypes:types];
}
- (WebContentsImpl*)webContents {
if (!webContentsView_)
return nullptr;
return webContentsView_->web_contents();
}
- (void)mouseEvent:(NSEvent*)theEvent {
if (!client_)
return;
......@@ -131,17 +117,15 @@ using content::WebContentsViewMac;
}
- (void)startDragWithDropData:(const DropData&)dropData
sourceRWH:(content::RenderWidgetHostImpl*)sourceRWH
dragOperationMask:(NSDragOperation)operationMask
image:(NSImage*)image
offset:(NSPoint)offset {
if (![self webContents])
if (!client_)
return;
dragSource_.reset([[WebDragSource alloc]
initWithContents:[self webContents]
initWithClient:client_
view:self
dropData:&dropData
sourceRWH:sourceRWH
image:image
offset:offset
pasteboard:[NSPasteboard pasteboardWithName:NSDragPboard]
......@@ -232,10 +216,14 @@ using content::WebContentsViewMac;
return result;
}
- (void)clearWebContentsView {
webContentsView_ = nullptr;
client_ = nullptr;
[dragSource_ clearWebContentsView];
- (void)clearViewsHostableView {
viewsHostableView_ = nullptr;
}
- (void)setClient:(content::mojom::WebContentsNSViewClient*)client {
if (!client)
[dragSource_ clearClientAndWebContentsView];
client_ = client;
}
- (void)viewDidBecomeFirstResponder:(NSNotification*)notification {
......@@ -337,7 +325,7 @@ using content::WebContentsViewMac;
// ViewsHostable protocol implementation.
- (ui::ViewsHostableView*)viewsHostableView {
return webContentsView_;
return viewsHostableView_;
}
// NSAccessibility informal protocol implementation.
......
......@@ -147,6 +147,13 @@ class WebContentsViewMac : public WebContentsView,
uint32_t* out_result) override;
bool PerformDragOperation(mojom::DraggingInfoPtr dragging_info,
bool* out_result) override;
bool DragPromisedFileTo(const base::FilePath& file_path,
const DropData& drop_data,
const GURL& download_url,
base::FilePath* out_file_path) override;
void EndDrag(uint32_t drag_opeation,
const gfx::PointF& local_point,
const gfx::PointF& screen_point) override;
// mojom::WebContentsNSViewClient, synchronous methods:
void DraggingEntered(mojom::DraggingInfoPtr dragging_info,
......@@ -155,6 +162,10 @@ class WebContentsViewMac : public WebContentsView,
DraggingUpdatedCallback callback) override;
void PerformDragOperation(mojom::DraggingInfoPtr dragging_info,
PerformDragOperationCallback callback) override;
void DragPromisedFileTo(const base::FilePath& file_path,
const DropData& drop_data,
const GURL& download_url,
DragPromisedFileToCallback callback) override;
// Return the list of child RenderWidgetHostViewMacs. This will remove any
// destroyed instances before returning.
......@@ -166,6 +177,9 @@ class WebContentsViewMac : public WebContentsView,
// Destination for drag-drop.
base::scoped_nsobject<WebDragDest> drag_dest_;
// Tracks the RenderWidgetHost where the current drag started.
base::WeakPtr<content::RenderWidgetHostImpl> drag_source_start_rwh_;
// Our optional delegate.
std::unique_ptr<WebContentsViewDelegate> delegate_;
......
......@@ -13,6 +13,9 @@
#include "base/mac/sdk_forward_declarations.h"
#include "base/message_loop/message_loop_current.h"
#import "base/message_loop/message_pump_mac.h"
#include "base/threading/thread_restrictions.h"
#include "content/browser/download/drag_download_file.h"
#include "content/browser/download/drag_download_util.h"
#include "content/browser/frame_host/popup_menu_helper_mac.h"
#include "content/browser/renderer_host/display_util.h"
#include "content/browser/renderer_host/render_view_host_factory.h"
......@@ -30,7 +33,6 @@
#include "mojo/public/cpp/bindings/interface_request.h"
#include "ui/base/cocoa/cocoa_base_utils.h"
#include "ui/base/cocoa/ns_view_ids.h"
#include "ui/gfx/image/image_skia_util_mac.h"
#include "ui/gfx/mac/coordinate_conversion.h"
using blink::WebDragOperation;
......@@ -51,9 +53,17 @@ STATIC_ASSERT_ENUM(NSDragOperationDelete, blink::kWebDragOperationDelete);
STATIC_ASSERT_ENUM(NSDragOperationEvery, blink::kWebDragOperationEvery);
namespace content {
namespace {
// This helper's sole task is to write out data for a promised file; the caller
// is responsible for opening the file. It takes the drop data and an open file
// stream.
void PromiseWriterHelper(const DropData& drop_data, base::File file) {
DCHECK(file.IsValid());
file.WriteAtCurrentPos(drop_data.file_contents.data(),
drop_data.file_contents.length());
}
WebContentsViewMac::RenderWidgetHostViewCreateFunction
g_create_render_widget_host_view = nullptr;
......@@ -143,14 +153,17 @@ void WebContentsViewMac::StartDragging(
base::MessageLoopCurrent::ScopedNestableTaskAllower allow;
NSDragOperation mask = static_cast<NSDragOperation>(allowed_operations) &
~NSDragOperationGeneric;
NSPoint offset = NSPointFromCGPoint(
gfx::PointAtOffsetFromOrigin(image_offset).ToCGPoint());
[drag_dest_ setDragStartTrackersForProcess:source_rwh->GetProcess()->GetID()];
[cocoa_view() startDragWithDropData:drop_data
sourceRWH:source_rwh
dragOperationMask:mask
image:gfx::NSImageFromImageSkia(image)
offset:offset];
drag_source_start_rwh_ = source_rwh->GetWeakPtr();
if (ns_view_bridge_remote_) {
// TODO(https://crbug.com/898608): Non-trivial gfx::ImageSkias fail to
// serialize.
ns_view_bridge_remote_->StartDrag(drop_data, mask, gfx::ImageSkia(),
image_offset);
} else {
ns_view_bridge_local_->StartDrag(drop_data, mask, image, image_offset);
}
}
void WebContentsViewMac::SizeContents(const gfx::Size& size) {
......@@ -299,7 +312,6 @@ void WebContentsViewMac::CreateView(
const gfx::Size& initial_size, gfx::NativeView context) {
ns_view_bridge_local_ =
std::make_unique<WebContentsNSViewBridge>(ns_view_id_, this);
[cocoa_view() setClient:this];
drag_dest_.reset([[WebDragDest alloc] initWithWebContentsImpl:web_contents_]);
if (delegate_)
......@@ -502,6 +514,75 @@ bool WebContentsViewMac::PerformDragOperation(
return true;
}
bool WebContentsViewMac::DragPromisedFileTo(const base::FilePath& file_path,
const DropData& drop_data,
const GURL& download_url,
base::FilePath* out_file_path) {
*out_file_path = file_path;
// This is called by -namesOfPromisedFilesDroppedAtDestination, which is
// requesting, on the UI thread, the name of the file that will be written
// by a drag operation. To know the name of this file, it is necessary to
// query the filesystem before returning, which will block the UI thread.
base::ScopedAllowBlocking allow_blocking;
base::File file(content::CreateFileForDrop(out_file_path));
if (!file.IsValid()) {
*out_file_path = base::FilePath();
return true;
}
if (download_url.is_valid() && web_contents_) {
scoped_refptr<DragDownloadFile> drag_file_downloader(new DragDownloadFile(
*out_file_path, std::move(file), download_url,
content::Referrer(web_contents_->GetLastCommittedURL(),
drop_data.referrer_policy),
web_contents_->GetEncoding(), web_contents_));
// The finalizer will take care of closing and deletion.
drag_file_downloader->Start(
new PromiseFileFinalizer(drag_file_downloader.get()));
} else {
// The writer will take care of closing and deletion.
base::PostTaskWithTraits(
FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
base::BindOnce(&PromiseWriterHelper, drop_data, std::move(file)));
}
// The DragDownloadFile constructor may have altered the value of
// |*out_file_path| if, say, an existing file at the drop site has the same
// name. Return the actual name that was used to write the file.
*out_file_path = file_path;
return true;
}
void WebContentsViewMac::EndDrag(uint32_t drag_operation,
const gfx::PointF& local_point,
const gfx::PointF& screen_point) {
web_contents_->SystemDragEnded(drag_source_start_rwh_.get());
// |localPoint| and |screenPoint| are in the root coordinate space, for
// non-root RenderWidgetHosts they need to be transformed.
gfx::PointF transformed_point = local_point;
gfx::PointF transformed_screen_point = screen_point;
if (drag_source_start_rwh_ && web_contents_->GetRenderWidgetHostView()) {
content::RenderWidgetHostViewBase* contentsViewBase =
static_cast<content::RenderWidgetHostViewBase*>(
web_contents_->GetRenderWidgetHostView());
content::RenderWidgetHostViewBase* dragStartViewBase =
static_cast<content::RenderWidgetHostViewBase*>(
drag_source_start_rwh_->GetView());
contentsViewBase->TransformPointToCoordSpaceForView(
local_point, dragStartViewBase, &transformed_point);
contentsViewBase->TransformPointToCoordSpaceForView(
screen_point, dragStartViewBase, &transformed_screen_point);
}
web_contents_->DragSourceEndedAt(
transformed_point.x(), transformed_point.y(),
transformed_screen_point.x(), transformed_screen_point.y(),
static_cast<blink::WebDragOperation>(drag_operation),
drag_source_start_rwh_.get());
}
void WebContentsViewMac::DraggingEntered(mojom::DraggingInfoPtr dragging_info,
DraggingEnteredCallback callback) {
uint32_t result = 0;
......@@ -524,6 +605,16 @@ void WebContentsViewMac::PerformDragOperation(
std::move(callback).Run(result);
}
void WebContentsViewMac::DragPromisedFileTo(
const base::FilePath& file_path,
const DropData& drop_data,
const GURL& download_url,
DragPromisedFileToCallback callback) {
base::FilePath actual_file_path;
DragPromisedFileTo(file_path, drop_data, download_url, &actual_file_path);
std::move(callback).Run(actual_file_path);
}
////////////////////////////////////////////////////////////////////////////////
// WebContentsViewMac, ViewsHostableView:
......
......@@ -17,20 +17,20 @@
#include "url/gurl.h"
namespace content {
class RenderWidgetHostImpl;
class WebContentsImpl;
struct DropData;
}
namespace mojom {
class WebContentsNSViewClient;
} // namespace mojom
} // namespace content
// A class that handles tracking and event processing for a drag and drop
// originating from the content area.
CONTENT_EXPORT
@interface WebDragSource : NSObject {
@private
// Our contents. Weak reference (owns or co-owns us).
// An instance of this class may outlive |contents_|. The destructor of
// |contents_| must set this ivar to |nullptr|.
content::WebContentsImpl* contents_;
// The client through which to communicate with the WebContentsImpl. Owns
// |self| and resets |client_| via clearClientAndWebContentsView.
content::mojom::WebContentsNSViewClient* client_;
// The view from which the drag was initiated. Weak reference.
// An instance of this class may outlive |contentsView_|. The destructor of
......@@ -60,25 +60,21 @@ CONTENT_EXPORT
// The file UTI associated with the file drag, if any.
base::ScopedCFTypeRef<CFStringRef> fileUTI_;
// Tracks the RenderWidgetHost where the current drag started.
base::WeakPtr<content::RenderWidgetHostImpl> dragStartRWH_;
}
// Initialize a WebDragSource object for a drag (originating on the given
// contentsView and with the given dropData and pboard). Fill the pasteboard
// with data types appropriate for dropData.
- (id)initWithContents:(content::WebContentsImpl*)contents
view:(NSView*)contentsView
dropData:(const content::DropData*)dropData
sourceRWH:(content::RenderWidgetHostImpl*)sourceRWH
image:(NSImage*)image
offset:(NSPoint)offset
pasteboard:(NSPasteboard*)pboard
dragOperationMask:(NSDragOperation)dragOperationMask;
- (id)initWithClient:(content::mojom::WebContentsNSViewClient*)client
view:(NSView*)contentsView
dropData:(const content::DropData*)dropData
image:(NSImage*)image
offset:(NSPoint)offset
pasteboard:(NSPasteboard*)pboard
dragOperationMask:(NSDragOperation)dragOperationMask;
// Call when the web contents is gone.
- (void)clearWebContentsView;
- (void)clearClientAndWebContentsView;
// Returns a mask of the allowed drag operations.
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal;
......
......@@ -16,18 +16,12 @@
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "content/browser/download/drag_download_file.h"
#include "content/browser/download/drag_download_util.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/common/content_client.h"
#include "content/public/common/drop_data.h"
#include "content/public/common/web_contents_ns_view_bridge.mojom.h"
#include "net/base/escape.h"
#include "net/base/filename_util.h"
#include "net/base/mime_util.h"
......@@ -43,26 +37,7 @@
using base::SysNSStringToUTF8;
using base::SysUTF8ToNSString;
using base::SysUTF16ToNSString;
using content::BrowserThread;
using content::DragDownloadFile;
using content::DropData;
using content::PromiseFileFinalizer;
using content::RenderViewHostImpl;
namespace {
// This helper's sole task is to write out data for a promised file; the caller
// is responsible for opening the file. It takes the drop data and an open file
// stream.
void PromiseWriterHelper(const DropData& drop_data,
base::File file) {
DCHECK(file.IsValid());
file.WriteAtCurrentPos(drop_data.file_contents.data(),
drop_data.file_contents.length());
}
} // namespace
@interface WebDragSource(Private)
......@@ -74,17 +49,15 @@ void PromiseWriterHelper(const DropData& drop_data,
@implementation WebDragSource
- (id)initWithContents:(content::WebContentsImpl*)contents
view:(NSView*)contentsView
dropData:(const DropData*)dropData
sourceRWH:(content::RenderWidgetHostImpl*)sourceRWH
image:(NSImage*)image
offset:(NSPoint)offset
pasteboard:(NSPasteboard*)pboard
dragOperationMask:(NSDragOperation)dragOperationMask {
- (id)initWithClient:(content::mojom::WebContentsNSViewClient*)client
view:(NSView*)contentsView
dropData:(const DropData*)dropData
image:(NSImage*)image
offset:(NSPoint)offset
pasteboard:(NSPasteboard*)pboard
dragOperationMask:(NSDragOperation)dragOperationMask {
if ((self = [super init])) {
contents_ = contents;
DCHECK(contents_);
client_ = client;
contentsView_ = contentsView;
DCHECK(contentsView_);
......@@ -92,7 +65,6 @@ void PromiseWriterHelper(const DropData& drop_data,
dropData_.reset(new DropData(*dropData));
DCHECK(dropData_.get());
dragStartRWH_ = sourceRWH->GetWeakPtr();
dragImage_.reset([image retain]);
imageOffset_ = offset;
......@@ -107,8 +79,8 @@ void PromiseWriterHelper(const DropData& drop_data,
return self;
}
- (void)clearWebContentsView {
contents_ = nil;
- (void)clearClientAndWebContentsView {
client_ = nullptr;
contentsView_ = nil;
}
......@@ -235,11 +207,9 @@ void PromiseWriterHelper(const DropData& drop_data,
- (void)endDragAt:(NSPoint)screenPoint
operation:(NSDragOperation)operation {
if (!contents_ || !contentsView_)
if (!client_ || !contentsView_)
return;
contents_->SystemDragEnded(dragStartRWH_.get());
if (dragImage_) {
screenPoint.x += imageOffset_.x;
// Deal with Cocoa's flipped coordinate system.
......@@ -251,10 +221,8 @@ void PromiseWriterHelper(const DropData& drop_data,
if ([contentsView_ window])
localPoint = [self convertScreenPoint:screenPoint];
NSRect viewFrame = [contentsView_ frame];
localPoint.y = viewFrame.size.height - localPoint.y;
// Flip |screenPoint|.
NSRect screenFrame = [[[contentsView_ window] screen] frame];
screenPoint.y = screenFrame.size.height - screenPoint.y;
// If AppKit returns a copy and move operation, mask off the move bit
// because WebCore does not understand what it means to do both, which
......@@ -262,73 +230,26 @@ void PromiseWriterHelper(const DropData& drop_data,
if (operation == (NSDragOperationMove | NSDragOperationCopy))
operation &= ~NSDragOperationMove;
// |localPoint| and |screenPoint| are in the root coordinate space, for
// non-root RenderWidgetHosts they need to be transformed.
gfx::PointF transformedPoint = gfx::PointF(localPoint.x, localPoint.y);
gfx::PointF transformedScreenPoint =
gfx::PointF(screenPoint.x, screenPoint.y);
if (dragStartRWH_ && contents_->GetRenderWidgetHostView()) {
content::RenderWidgetHostViewBase* contentsViewBase =
static_cast<content::RenderWidgetHostViewBase*>(
contents_->GetRenderWidgetHostView());
content::RenderWidgetHostViewBase* dragStartViewBase =
static_cast<content::RenderWidgetHostViewBase*>(
dragStartRWH_->GetView());
contentsViewBase->TransformPointToCoordSpaceForView(
gfx::PointF(localPoint.x, localPoint.y), dragStartViewBase,
&transformedPoint);
contentsViewBase->TransformPointToCoordSpaceForView(
gfx::PointF(screenPoint.x, screenPoint.y), dragStartViewBase,
&transformedScreenPoint);
}
contents_->DragSourceEndedAt(
transformedPoint.x(), transformedPoint.y(), transformedScreenPoint.x(),
transformedScreenPoint.y(),
static_cast<blink::WebDragOperation>(operation), dragStartRWH_.get());
client_->EndDrag(
operation,
gfx::PointF(localPoint.x, viewFrame.size.height - localPoint.y),
gfx::PointF(screenPoint.x, screenFrame.size.height - screenPoint.y));
// Make sure the pasteboard owner isn't us.
[pasteboard_ declareTypes:[NSArray array] owner:nil];
}
- (NSString*)dragPromisedFileTo:(NSString*)path {
if (!client_)
return nil;
// Be extra paranoid; avoid crashing.
if (!dropData_) {
NOTREACHED() << "No drag-and-drop data available for promised file.";
return nil;
}
base::FilePath filePath(SysNSStringToUTF8(path));
filePath = filePath.Append(downloadFileName_);
// CreateFileForDrop() will call base::PathExists(),
// which is blocking. Since this operation is already blocking the
// UI thread on OSX, it should be reasonable to let it happen.
base::ThreadRestrictions::ScopedAllowIO allowIO;
base::File file(content::CreateFileForDrop(&filePath));
if (!file.IsValid())
return nil;
if (downloadURL_.is_valid() && contents_) {
scoped_refptr<DragDownloadFile> dragFileDownloader(
new DragDownloadFile(filePath, std::move(file), downloadURL_,
content::Referrer(contents_->GetLastCommittedURL(),
dropData_->referrer_policy),
contents_->GetEncoding(), contents_));
// The finalizer will take care of closing and deletion.
dragFileDownloader->Start(new PromiseFileFinalizer(
dragFileDownloader.get()));
} else {
// The writer will take care of closing and deletion.
base::PostTaskWithTraits(
FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
base::BindOnce(&PromiseWriterHelper, *dropData_, std::move(file)));
}
// The DragDownloadFile constructor may have altered the value of |filePath|
// if, say, an existing file at the drop site has the same name. Return the
// actual name that was used to write the file.
client_->DragPromisedFileTo(filePath, *dropData_, downloadURL_, &filePath);
return SysUTF8ToNSString(filePath.BaseName().value());
}
......@@ -359,6 +280,8 @@ void PromiseWriterHelper(const DropData& drop_data,
// File.
if (!dropData_->file_contents.empty() ||
!dropData_->download_metadata.empty()) {
// TODO(https://crbug.com/898608): The |downloadFileName_| and
// |downloadURL_| values should be computed by the caller.
if (dropData_->download_metadata.empty()) {
base::Optional<base::FilePath> suggestedFilename =
dropData_->GetSafeFilenameForImageFileContents();
......
......@@ -24,13 +24,11 @@ TEST_F(WebDragSourceMacTest, DragInvalidlyEscapedBookmarklet) {
std::unique_ptr<DropData> dropData(new DropData);
dropData->url = GURL("javascript:%");
WebContentsImpl* contentsImpl = static_cast<WebContentsImpl*>(contents.get());
scoped_refptr<ui::UniquePasteboard> pasteboard1 = new ui::UniquePasteboard;
base::scoped_nsobject<WebDragSource> source([[WebDragSource alloc]
initWithContents:contentsImpl
initWithClient:nullptr
view:view
dropData:dropData.get()
sourceRWH:contentsImpl->GetRenderViewHost()->GetWidget()
image:nil
offset:NSZeroPoint
pasteboard:pasteboard1->get()
......
......@@ -377,7 +377,10 @@ mojom("interfaces") {
"ns_view_bridge_factory.mojom",
"web_contents_ns_view_bridge.mojom",
]
public_deps += [ "//ui/gfx/geometry/mojo" ]
public_deps += [
"//ui/gfx/geometry/mojo",
"//ui/gfx/image/mojo:interfaces",
]
}
component_output_prefix = "content_public_common_mojo_bindings"
......
......@@ -5,7 +5,9 @@
module content.mojom;
import "content/public/common/drop_data.mojom";
import "mojo/public/mojom/base/file_path.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
import "ui/gfx/image/mojo/image.mojom";
import "url/mojom/url.mojom";
// Interface through which a WebContentsViewMac communicates with its NSView in
......@@ -33,6 +35,12 @@ interface WebContentsNSViewBridge {
// iterated past the last or first focusable element on the page). The
// iteration direction is in |reverse|.
TakeFocus(bool reverse);
// Initiate a drag from the web contents area.
StartDrag(DropData drop_data,
uint32 operation_mask,
gfx.mojom.ImageSkia? image,
gfx.mojom.Vector2d image_offset);
};
// The method through which a window was focused (directly focused, or by
......@@ -108,10 +116,25 @@ interface WebContentsNSViewClient {
[Sync]
DraggingUpdated(DraggingInfo dragging_info) => (uint32 result);
// Called in response to the -[NSDraggingDestination performDragOperation]
// Called in response to the -[NSDraggingDestination performDragOperation:]
// method being called on the NSView. Returns the result of the operation in
// |result|.
[Sync]
PerformDragOperation(DraggingInfo dragging_info) => (bool result);
// Called in response to the -namesOfPromisedFilesDroppedAtDestination method
// being called on the NSView. The |file_path| input argument is the
// requested destination file, and the output |file_path| is the actual
// destination file.
[Sync]
DragPromisedFileTo(mojo_base.mojom.FilePath file_path,
DropData drop_data,
url.mojom.Url download_url) =>
(mojo_base.mojom.FilePath file_path);
// Called in to the -draggedImage: method being called on the NSView.
EndDrag(uint32 drag_operation,
gfx.mojom.PointF local_point,
gfx.mojom.PointF screen_point);
};
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