Skip to content

Commit

Permalink
Revert "Switch to the (old) new way of doing file promising"
Browse files Browse the repository at this point in the history
This reverts commit 4278cdb.

# Conflicts:
#	content/app_shim_remote_cocoa/web_drag_source_mac.mm
  • Loading branch information
blueboxd committed Dec 23, 2022
1 parent 521e2f8 commit ea3d931
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 95 deletions.
20 changes: 10 additions & 10 deletions content/app_shim_remote_cocoa/web_contents_view_cocoa.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,17 @@ class WebContentsNSViewHost;
@class WebDragSource;

CONTENT_EXPORT
@interface WebContentsViewCocoa
: BaseView <ViewsHostable, NSDraggingSource, NSDraggingDestination> {
@interface WebContentsViewCocoa : BaseView <ViewsHostable> {
@private
// Instances of this class are owned by both `_host` and AppKit. The `_host`
// must call `-setHost:nil` in its destructor.
// Instances of this class are owned by both host_ and AppKit. It is
// possible for an instance to outlive its webContentsView_. The host_ must
// call -clearHostAndView in its destructor.
raw_ptr<remote_cocoa::mojom::WebContentsNSViewHost> _host;

// The interface exported to views::Views that embed this as a sub-view.
raw_ptr<ui::ViewsHostableView> _viewsHostableView;

base::scoped_nsobject<WebDragSource> _dragSource;
BOOL _mouseDownCanMoveWindow;

// Utility to copy screenshots to a usable directory for PWAs. This utility
Expand All @@ -44,12 +45,6 @@ CONTENT_EXPORT
// https://crbug.com/1148078
std::unique_ptr<remote_cocoa::DroppedScreenShotCopierMac>
_droppedScreenShotCopier;

// Drag variables.
base::scoped_nsobject<WebDragSource> _dragSource;
NSDragOperation _dragOperation;
NSPoint _dragOffset;
CGFloat _dragImageHeight;
}

// Set or un-set the mojo interface through which to communicate with the
Expand All @@ -62,6 +57,11 @@ CONTENT_EXPORT
// in-PWA-process instances, to limit the workaround's effect to just PWAs.
- (void)enableDroppedScreenShotCopier;

// Returns the available drag operations. This is a required method for
// NSDraggingSource. It is supposedly deprecated, but the non-deprecated API
// -[NSWindow dragImage:...] still relies on it.
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal;

// Private interface.
// TODO(ccameron): Document these functions.
- (instancetype)initWithViewsHostableView:(ui::ViewsHostableView*)v;
Expand Down
117 changes: 59 additions & 58 deletions content/app_shim_remote_cocoa/web_contents_view_cocoa.mm
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
#include "ui/base/cocoa/cocoa_base_utils.h"
#include "ui/base/dragdrop/cocoa_dnd_util.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/gfx/image/image.h"
#include "ui/resources/grit/ui_resources.h"

#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
Expand All @@ -33,6 +31,14 @@
using remote_cocoa::mojom::DraggingInfo;
using remote_cocoa::mojom::SelectionDirection;

namespace {
// Time to delay clearing the pasteboard for after a drag ends. This is
// required because Safari requests data from multiple processes, and clearing
// the pasteboard after the first access results in unreliable drag operations
// (http://crbug.com/1227001).
const int64_t kPasteboardClearDelay = 0.5 * NSEC_PER_SEC;
}

namespace remote_cocoa {

// DroppedScreenShotCopierMac is a utility to copy screenshots to a usable
Expand Down Expand Up @@ -224,68 +230,64 @@ - (void)startDragWithDropData:(const DropData&)dropData
[pasteboard clearContents];

_dragSource.reset([[WebDragSource alloc] initWithHost:_host
dropData:dropData]);
NSDraggingItem* draggingItem = [[[NSDraggingItem alloc]
initWithPasteboardWriter:_dragSource] autorelease];

if (!image) {
image = content::GetContentClient()
->GetNativeImageNamed(IDR_DEFAULT_FAVICON)
.ToNSImage();
}

NSRect imageRect = NSMakeRect(mouseLocation.x, mouseLocation.y,
image.size.width, image.size.height);
imageRect.origin.x -= offset.x;
// Deal with Cocoa's flipped coordinate system.
imageRect.origin.y -= image.size.height - offset.y;
[draggingItem setDraggingFrame:imageRect contents:image];

_dragOperation = operationMask;
_dragOffset = offset;
_dragImageHeight = image.size.height;

// Run the drag operation.
[self beginDraggingSessionWithItems:@[ draggingItem ]
event:dragEvent
source:self];
view:self
dropData:&dropData
image:image
offset:offset
pasteboard:pasteboard
dragOperationMask:operationMask]);
[_dragSource startDrag];
}

// NSDraggingSource methods

- (NSDragOperation)draggingSession:(NSDraggingSession*)session
sourceOperationMaskForDraggingContext:(NSDraggingContext)context {
return _dragOperation;
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
if (_dragSource)
return [_dragSource draggingSourceOperationMaskForLocal:isLocal];
// No web drag source - this is the case for dragging a file from the
// downloads manager. Default to copy operation. Note: It is desirable to
// allow the user to either move or copy, but this requires additional
// plumbing to update the download item's path once its moved.
return NSDragOperationCopy;
}

// Called when a drag initiated in our view ends.
- (void)draggingSession:(NSDraggingSession*)session
endedAtPoint:(NSPoint)screenPoint
operation:(NSDragOperation)operation {
// Reconstruct the screen point by removing the offset. It seems like the
// underlying drag machinery is measuring from the corner of the dragged
// image.
screenPoint.x += _dragOffset.x;
screenPoint.y += _dragImageHeight - _dragOffset.y;

NSPoint localPoint = NSZeroPoint;
if (self.window) {
NSPoint basePoint =
ui::ConvertPointFromScreenToWindow(self.window, screenPoint);
localPoint = [self convertPoint:basePoint fromView:nil];
}
- (void)draggedImage:(NSImage*)anImage
endedAt:(NSPoint)screenPoint
operation:(NSDragOperation)operation {
[_dragSource
endDragAt:screenPoint
operation:ui::DragDropTypes::NSDragOperationToDragOperation(operation)];

WebDragSource* currentDragSource = _dragSource.get();

dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, (int64_t)kPasteboardClearDelay),
dispatch_get_main_queue(), ^{
if (_dragSource.get() == currentDragSource) {
// Clear the drag pasteboard. Even though this is called in dealloc,
// we need an explicit call because NSPasteboard can retain the drag
// source.
[_dragSource clearPasteboard];
_dragSource.reset();
}
});
}

// Called when a drag initiated in our view moves.
- (void)draggedImage:(NSImage*)draggedImage movedTo:(NSPoint)screenPoint {
}

// Called when a file drag is dropped and the promised files need to be written.
- (NSArray*)namesOfPromisedFilesDroppedAtDestination:(NSURL*)dropDest {
if (![dropDest isFileURL])
return nil;

// Flip the two points as per Cocoa's coordinate system.
NSRect viewFrame = self.frame;
NSRect screenFrame = self.window.screen.frame;
_host->EndDrag(
operation,
gfx::PointF(localPoint.x, viewFrame.size.height - localPoint.y),
gfx::PointF(screenPoint.x, screenFrame.size.height - screenPoint.y));
NSString* fileName = [_dragSource dragPromisedFileTo:[dropDest path]];
if (!fileName)
return nil;

// The drag is complete. Disconnect the drag source.
[_dragSource webContentsIsGone];
_dragSource.reset();
return @[ fileName ];
}

// NSDraggingDestination methods
Expand Down Expand Up @@ -344,9 +346,8 @@ - (void)clearViewsHostableView {
}

- (void)setHost:(remote_cocoa::mojom::WebContentsNSViewHost*)host {
if (!host) {
[_dragSource webContentsIsGone];
}
if (!host)
[_dragSource clearHostAndWebContentsView];
_host = host;
}

Expand Down
74 changes: 61 additions & 13 deletions content/app_shim_remote_cocoa/web_drag_source_mac.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@

#import <Cocoa/Cocoa.h>

#include <memory>

#include "base/files/file_path.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_nsobject.h"
#include "content/common/content_export.h"
#include "content/public/common/drop_data.h"
#include "url/gurl.h"

namespace content {
Expand All @@ -26,18 +27,37 @@ class WebContentsNSViewHost;
} // namespace mojom
} // namespace remote_cocoa

// A class that handles managing the data for drags from the
// WebContentsViewCocoa.
// A class that handles tracking and event processing for a drag and drop
// originating from the content area.
CONTENT_EXPORT
@interface WebDragSource : NSObject <NSPasteboardWriting> {
@interface WebDragSource : NSObject {
@private
// The host through which to communicate with the WebContents. Owns
// this object. This pointer gets reset when the WebContents goes away with
// `webContentsIsGone`.
// The host through which to communicate with the WebContentsImpl. Owns
// |self| and resets |host_| via clearHostAndWebContentsView.
raw_ptr<remote_cocoa::mojom::WebContentsNSViewHost> _host;

// The drop data.
content::DropData _dropData;
// The view from which the drag was initiated. Weak reference.
// An instance of this class may outlive |contentsView_|. The destructor of
// |contentsView_| must set this ivar to |nullptr|.
NSView* _contentsView;

// Our drop data. Should only be initialized once.
std::unique_ptr<content::DropData> _dropData;

// The image to show as drag image. Can be nil.
base::scoped_nsobject<NSImage> _dragImage;

// The offset to draw |dragImage_| at.
NSPoint _imageOffset;

// Our pasteboard.
base::scoped_nsobject<NSPasteboard> _pasteboard;

// Change count associated with this pasteboard owner change.
int _changeCount;

// A mask of the allowed drag operations.
NSDragOperation _dragOperationMask;

// The file name to be saved to for a drag-out download.
base::FilePath _downloadFileName;
Expand All @@ -49,12 +69,40 @@ CONTENT_EXPORT
base::ScopedCFTypeRef<CFStringRef> _fileUTI;
}

// Initialize a WebDragSource object for a drag.
// 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.
- (instancetype)initWithHost:(remote_cocoa::mojom::WebContentsNSViewHost*)host
dropData:(const content::DropData&)dropData;
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)clearHostAndWebContentsView;

// Returns a mask of the allowed drag operations.
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal;

// Start the drag (on the originally provided contentsView); can do this right
// after -initWithContentsView:....
- (void)startDrag;

// End the drag and clear the pasteboard; hook up to
// -draggedImage:endedAt:operation:.
- (void)endDragAt:(NSPoint)screenPoint
operation:(NSDragOperation)operation;

// Remove this WebDragSource as the owner of the drag pasteboard.
- (void)clearPasteboard;

// Call when the WebContents is gone.
- (void)webContentsIsGone;
// Call to drag a promised file to the given path (should be called before
// -endDragAt:...); hook up to -namesOfPromisedFilesDroppedAtDestination:.
// Returns the file name (not including path) of the file deposited (or which
// will be deposited).
- (NSString*)dragPromisedFileTo:(NSString*)path;

@end

Expand Down
40 changes: 40 additions & 0 deletions content/browser/web_contents/web_contents_view_mac_unittest.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "content/browser/web_contents/web_contents_view_mac.h"

#include "base/mac/scoped_nsobject.h"
#import "content/app_shim_remote_cocoa/web_contents_view_cocoa.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/test_renderer_host.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gtest_mac.h"
#include "testing/platform_test.h"
#include "ui/base/test/cocoa_helper.h"
#import "ui/base/test/cocoa_helper.h"

namespace content {

namespace {

class WebContentsNSViewTest : public ui::CocoaTest {};

} // namespace

TEST_F(WebContentsNSViewTest, NonWebDragSourceTest) {
// The designated initializer is private but init should be fine in this case.
base::scoped_nsobject<WebContentsViewCocoa> view(
[[WebContentsViewCocoa alloc] init]);

// Tests that |draggingSourceOperationMaskForLocal:| returns the expected mask
// when dragging without a WebDragSource - i.e. when |startDragWithDropData:|
// hasn't yet been called. Dragging a file from the downloads manager, for
// example, requires this to work.
EXPECT_EQ(NSDragOperationCopy,
[view draggingSourceOperationMaskForLocal:YES]);
EXPECT_EQ(NSDragOperationCopy,
[view draggingSourceOperationMaskForLocal:NO]);
}

} // namespace content
Loading

0 comments on commit ea3d931

Please sign in to comment.