Bug 1309596,implementation of UpdateDragImage on mac, r=mstange

This commit is contained in:
Neil Deakin 2016-12-23 18:09:44 -05:00
Родитель 7b92d68429
Коммит 6598d2a0fc
3 изменённых файлов: 142 добавлений и 44 удалений

Просмотреть файл

@ -5811,6 +5811,9 @@ GetIntegerDeltaForEvent(NSEvent* aEvent)
if (mDragService) {
// set the dragend point from the current mouse location
nsDragService* dragService = static_cast<nsDragService *>(mDragService);
FlipCocoaScreenCoordinate(aPoint);
dragService->SetDragEndPoint(gfx::IntPoint::Round(aPoint.x, aPoint.y));
NSPoint pnt = [NSEvent mouseLocation];
FlipCocoaScreenCoordinate(pnt);
dragService->SetDragEndPoint(gfx::IntPoint::Round(pnt.x, pnt.y));
@ -5856,11 +5859,8 @@ GetIntegerDeltaForEvent(NSEvent* aEvent)
}
if (dragService) {
NSPoint pnt = [NSEvent mouseLocation];
FlipCocoaScreenCoordinate(pnt);
LayoutDeviceIntPoint devPoint = mGeckoChild->CocoaPointsToDevPixels(pnt);
dragService->DragMoved(devPoint.x, devPoint.y);
nsDragService* ds = static_cast<nsDragService *>(dragService.get());
ds->DragMovedWithView(aSession, aPoint);
}
NS_OBJC_END_TRY_ABORT_BLOCK;

Просмотреть файл

@ -28,20 +28,34 @@ public:
uint32_t aActionType);
// nsIDragService
NS_IMETHOD EndDragSession(bool aDoneDrag);
NS_IMETHOD UpdateDragImage(nsIDOMNode* aImage, int32_t aImageX, int32_t aImageY);
// nsIDragSession
NS_IMETHOD GetData(nsITransferable * aTransferable, uint32_t aItemIndex);
NS_IMETHOD IsDataFlavorSupported(const char *aDataFlavor, bool *_retval);
NS_IMETHOD GetNumDropItems(uint32_t * aNumItems);
void DragMovedWithView(NSDraggingSession* aSession, NSPoint aPoint);
protected:
virtual ~nsDragService();
private:
// Creates and returns the drag image for a drag. aImagePoint will be set to
// the origin of the drag relative to mNativeDragView.
NSImage* ConstructDragImage(nsIDOMNode* aDOMNode,
mozilla::LayoutDeviceIntRect* aDragRect,
nsIScriptableRegion* aRegion);
nsIScriptableRegion* aRegion,
NSPoint* aImagePoint);
// Creates and returns the drag image for a drag. aPoint should be the origin
// of the drag, for example the mouse coordinate of the mousedown event.
// aDragRect will be set the area of the drag relative to this.
NSImage* ConstructDragImage(nsIDOMNode* aDOMNode,
nsIScriptableRegion* aRegion,
mozilla::CSSIntPoint aPoint,
mozilla::LayoutDeviceIntRect* aDragRect);
bool IsValidType(NSString* availableType, bool allowFileURL);
NSString* GetStringForType(NSPasteboardItem* item, const NSString* type,
bool allowFileURL = false);
@ -51,6 +65,8 @@ private:
nsCOMPtr<nsIArray> mDataItems; // only valid for a drag started within gecko
ChildView* mNativeDragView;
NSEvent* mNativeDragEvent;
bool mDragImageChanged;
};
#endif // nsDragService_h_

Просмотреть файл

@ -57,10 +57,8 @@ NSString* const kUTTypeURLName = @"public.url-name";
NSString* const kCustomTypesPboardType = @"org.mozilla.custom-clipdata";
nsDragService::nsDragService()
: mNativeDragView(nil), mNativeDragEvent(nil), mDragImageChanged(false)
{
mNativeDragView = nil;
mNativeDragEvent = nil;
EnsureLogInitialized();
}
@ -70,22 +68,65 @@ nsDragService::~nsDragService()
NSImage*
nsDragService::ConstructDragImage(nsIDOMNode* aDOMNode,
LayoutDeviceIntRect* aDragRect,
nsIScriptableRegion* aRegion)
nsIScriptableRegion* aRegion,
NSPoint* aDragPoint)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(gLastDragView);
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView);
LayoutDeviceIntRect dragRect(0, 0, 20, 20);
NSImage* image = ConstructDragImage(mSourceNode, aRegion, mScreenPosition, &dragRect);
if (!image) {
// if no image was returned, just draw a rectangle
NSSize size;
size.width = nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.width, scaleFactor);
size.height = nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.height, scaleFactor);
image = [[NSImage alloc] initWithSize:size];
[image lockFocus];
[[NSColor grayColor] set];
NSBezierPath* path = [NSBezierPath bezierPath];
[path setLineWidth:2.0];
[path moveToPoint:NSMakePoint(0, 0)];
[path lineToPoint:NSMakePoint(0, size.height)];
[path lineToPoint:NSMakePoint(size.width, size.height)];
[path lineToPoint:NSMakePoint(size.width, 0)];
[path lineToPoint:NSMakePoint(0, 0)];
[path stroke];
[image unlockFocus];
}
LayoutDeviceIntPoint pt(dragRect.x, dragRect.YMost());
NSPoint point = nsCocoaUtils::DevPixelsToCocoaPoints(pt, scaleFactor);
point.y = nsCocoaUtils::FlippedScreenY(point.y);
point = nsCocoaUtils::ConvertPointFromScreen([mNativeDragView window], point);
*aDragPoint = [mNativeDragView convertPoint:point fromView:nil];
return image;
NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
}
NSImage*
nsDragService::ConstructDragImage(nsIDOMNode* aDOMNode,
nsIScriptableRegion* aRegion,
CSSIntPoint aPoint,
LayoutDeviceIntRect* aDragRect)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView);
RefPtr<SourceSurface> surface;
nsPresContext* pc;
nsresult rv = DrawDrag(aDOMNode, aRegion, mScreenPosition,
nsresult rv = DrawDrag(aDOMNode, aRegion, aPoint,
aDragRect, &surface, &pc);
if (pc && (!aDragRect->width || !aDragRect->height)) {
// just use some suitable defaults
int32_t size = nsCocoaUtils::CocoaPointsToDevPixels(20, scaleFactor);
aDragRect->SetRect(pc->CSSPixelsToDevPixels(mScreenPosition.x),
pc->CSSPixelsToDevPixels(mScreenPosition.y), size, size);
aDragRect->SetRect(pc->CSSPixelsToDevPixels(aPoint.x),
pc->CSSPixelsToDevPixels(aPoint.y), size, size);
}
if (NS_FAILED(rv) || !surface)
@ -293,36 +334,12 @@ nsDragService::InvokeDragSessionImpl(nsIArray* aTransferableArray,
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(gLastDragView);
LayoutDeviceIntRect dragRect(0, 0, 20, 20);
NSImage* image = ConstructDragImage(mSourceNode, &dragRect, aDragRgn);
if (!image) {
// if no image was returned, just draw a rectangle
NSSize size;
size.width = nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.width, scaleFactor);
size.height = nsCocoaUtils::DevPixelsToCocoaPoints(dragRect.height, scaleFactor);
image = [[NSImage alloc] initWithSize:size];
[image lockFocus];
[[NSColor grayColor] set];
NSBezierPath* path = [NSBezierPath bezierPath];
[path setLineWidth:2.0];
[path moveToPoint:NSMakePoint(0, 0)];
[path lineToPoint:NSMakePoint(0, size.height)];
[path lineToPoint:NSMakePoint(size.width, size.height)];
[path lineToPoint:NSMakePoint(size.width, 0)];
[path lineToPoint:NSMakePoint(0, 0)];
[path stroke];
[image unlockFocus];
}
NSPoint draggingPoint;
NSImage* image = ConstructDragImage(mSourceNode, aDragRgn, &draggingPoint);
// Make drag image appear in the right place under the cursor.
LayoutDeviceIntPoint pt(dragRect.x, dragRect.YMost());
NSPoint point = nsCocoaUtils::DevPixelsToCocoaPoints(pt, scaleFactor);
point.y = nsCocoaUtils::FlippedScreenY(point.y);
point = nsCocoaUtils::ConvertPointFromScreen([gLastDragView window], point);
NSPoint localPoint = [gLastDragView convertPoint:point fromView:nil];
NSRect localDragRect = image.alignmentRect;
localDragRect.origin.x = localPoint.x;
localDragRect.origin.y = localPoint.y - localDragRect.size.height;
localDragRect.origin.x = draggingPoint.x;
localDragRect.origin.y = draggingPoint.y - localDragRect.size.height;
NSDraggingItem* dragItem =
[[NSDraggingItem alloc] initWithPasteboardWriter:pbItem];
@ -621,6 +638,71 @@ nsDragService::GetNumDropItems(uint32_t* aNumItems)
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
NS_IMETHODIMP
nsDragService::UpdateDragImage(nsIDOMNode* aImage, int32_t aImageX, int32_t aImageY)
{
nsBaseDragService::UpdateDragImage(aImage, aImageX, aImageY);
mDragImageChanged = true;
return NS_OK;
}
void
nsDragService::DragMovedWithView(NSDraggingSession* aSession, NSPoint aPoint)
{
aPoint.y = nsCocoaUtils::FlippedScreenY(aPoint.y);
// XXX It feels like we should be using the backing scale factor at aPoint
// rather than the initial drag view, but I've seen no ill effects of this.
CGFloat scaleFactor = nsCocoaUtils::GetBackingScaleFactor(mNativeDragView);
LayoutDeviceIntPoint devPoint = nsCocoaUtils::CocoaPointsToDevPixels(aPoint, scaleFactor);
// If the image has changed, call enumerateDraggingItemsWithOptions to get
// the item being dragged and update its image.
if (mDragImageChanged && mNativeDragView) {
mDragImageChanged = false;
nsPresContext* pc = nullptr;
nsCOMPtr<nsIContent> content = do_QueryInterface(mImage);
if (content) {
nsCOMPtr<nsIDocument> document = content->OwnerDoc();
if (document) {
nsIPresShell* shell = document->GetShell();
pc = shell ? shell->GetPresContext() : nullptr;
}
}
if (pc) {
void (^changeImageBlock) (NSDraggingItem*, NSInteger, BOOL*) =
^(NSDraggingItem* draggingItem, NSInteger idx, BOOL* stop) {
// We never add more than one item right now, but check just in case.
if (idx > 0) {
return;
}
CSSIntPoint screenPoint =
CSSIntPoint(pc->DevPixelsToIntCSSPixels(devPoint.x),
pc->DevPixelsToIntCSSPixels(devPoint.y));
// Create a new image; if one isn't returned don't change the current one.
LayoutDeviceIntRect newRect;
NSImage* image = ConstructDragImage(mSourceNode, nullptr, screenPoint, &newRect);
if (image) {
NSRect draggingRect = nsCocoaUtils::GeckoRectToCocoaRectDevPix(newRect, scaleFactor);
[draggingItem setDraggingFrame:draggingRect contents:image];
}
};
[aSession enumerateDraggingItemsWithOptions:NSDraggingItemEnumerationConcurrent
forView:nil
classes:[NSArray arrayWithObject:[NSPasteboardItem class]]
searchOptions:nil
usingBlock:changeImageBlock];
}
}
DragMoved(devPoint.x, devPoint.y);
}
NS_IMETHODIMP
nsDragService::EndDragSession(bool aDoneDrag)
{