123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- /*
- * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #import <WebKit/WebNSViewExtras.h>
- #import <WebKit/DOMExtensions.h>
- #import <WebKit/WebDataSource.h>
- #import <WebKit/WebFramePrivate.h>
- #import <WebKit/WebFrameViewInternal.h>
- #import <WebKit/WebNSImageExtras.h>
- #import <WebKit/WebNSPasteboardExtras.h>
- #import <WebKit/WebNSURLExtras.h>
- #import <WebKit/WebView.h>
- #define WebDragStartHysteresisX 5.0f
- #define WebDragStartHysteresisY 5.0f
- #define WebMaxDragImageSize NSMakeSize(400.0f, 400.0f)
- #define WebMaxOriginalImageArea (1500.0f * 1500.0f)
- #define WebDragIconRightInset 7.0f
- #define WebDragIconBottomInset 3.0f
- @implementation NSView (WebExtras)
- - (NSView *)_web_superviewOfClass:(Class)class
- {
- NSView *view = [self superview];
- while (view && ![view isKindOfClass:class])
- view = [view superview];
- return view;
- }
- - (WebFrameView *)_web_parentWebFrameView
- {
- return (WebFrameView *)[self _web_superviewOfClass:[WebFrameView class]];
- }
- // FIXME: Mail is the only client of _webView, remove this method once no versions of Mail need it.
- - (WebView *)_webView
- {
- return (WebView *)[self _web_superviewOfClass:[WebView class]];
- }
- /* Determine whether a mouse down should turn into a drag; started as copy of NSTableView code */
- - (BOOL)_web_dragShouldBeginFromMouseDown:(NSEvent *)mouseDownEvent
- withExpiration:(NSDate *)expiration
- xHysteresis:(float)xHysteresis
- yHysteresis:(float)yHysteresis
- {
- NSEvent *nextEvent, *firstEvent, *dragEvent, *mouseUp;
- BOOL dragIt;
- if ([mouseDownEvent type] != NSLeftMouseDown) {
- return NO;
- }
- nextEvent = nil;
- firstEvent = nil;
- dragEvent = nil;
- mouseUp = nil;
- dragIt = NO;
- while ((nextEvent = [[self window] nextEventMatchingMask:(NSLeftMouseUpMask | NSLeftMouseDraggedMask)
- untilDate:expiration
- inMode:NSEventTrackingRunLoopMode
- dequeue:YES]) != nil) {
- if (firstEvent == nil) {
- firstEvent = nextEvent;
- }
- if ([nextEvent type] == NSLeftMouseDragged) {
- float deltax = ABS([nextEvent locationInWindow].x - [mouseDownEvent locationInWindow].x);
- float deltay = ABS([nextEvent locationInWindow].y - [mouseDownEvent locationInWindow].y);
- dragEvent = nextEvent;
- if (deltax >= xHysteresis) {
- dragIt = YES;
- break;
- }
- if (deltay >= yHysteresis) {
- dragIt = YES;
- break;
- }
- } else if ([nextEvent type] == NSLeftMouseUp) {
- mouseUp = nextEvent;
- break;
- }
- }
- // Since we've been dequeuing the events (If we don't, we'll never see the mouse up...),
- // we need to push some of the events back on. It makes sense to put the first and last
- // drag events and the mouse up if there was one.
- if (mouseUp != nil) {
- [NSApp postEvent:mouseUp atStart:YES];
- }
- if (dragEvent != nil) {
- [NSApp postEvent:dragEvent atStart:YES];
- }
- if (firstEvent != mouseUp && firstEvent != dragEvent) {
- [NSApp postEvent:firstEvent atStart:YES];
- }
- return dragIt;
- }
- - (BOOL)_web_dragShouldBeginFromMouseDown:(NSEvent *)mouseDownEvent
- withExpiration:(NSDate *)expiration
- {
- return [self _web_dragShouldBeginFromMouseDown:mouseDownEvent
- withExpiration:expiration
- xHysteresis:WebDragStartHysteresisX
- yHysteresis:WebDragStartHysteresisY];
- }
- - (NSDragOperation)_web_dragOperationForDraggingInfo:(id <NSDraggingInfo>)sender
- {
- if (![NSApp modalWindow] &&
- ![[self window] attachedSheet] &&
- [sender draggingSource] != self &&
- [[sender draggingPasteboard] _web_bestURL]) {
- return NSDragOperationCopy;
- }
-
- return NSDragOperationNone;
- }
- - (void)_web_DragImageForElement:(DOMElement *)element
- rect:(NSRect)rect
- event:(NSEvent *)event
- pasteboard:(NSPasteboard *)pasteboard
- source:(id)source
- offset:(NSPoint *)dragImageOffset
- {
- NSPoint mouseDownPoint = [self convertPoint:[event locationInWindow] fromView:nil];
- NSImage *dragImage;
- NSPoint origin;
- NSImage *image = [element image];
- if (image != nil && [image size].height * [image size].width <= WebMaxOriginalImageArea) {
- NSSize originalSize = rect.size;
- origin = rect.origin;
-
- dragImage = [[image copy] autorelease];
- [dragImage setScalesWhenResized:YES];
- [dragImage setSize:originalSize];
-
- [dragImage _web_scaleToMaxSize:WebMaxDragImageSize];
- NSSize newSize = [dragImage size];
-
- [dragImage _web_dissolveToFraction:WebDragImageAlpha];
-
- // Properly orient the drag image and orient it differently if it's smaller than the original
- origin.x = mouseDownPoint.x - (((mouseDownPoint.x - origin.x) / originalSize.width) * newSize.width);
- origin.y = origin.y + originalSize.height;
- origin.y = mouseDownPoint.y - (((mouseDownPoint.y - origin.y) / originalSize.height) * newSize.height);
- } else {
- // FIXME: This has been broken for a while.
- // There's no way to get the MIME type for the image from a DOM element.
- // The old code used WKGetPreferredExtensionForMIMEType([image MIMEType]);
- NSString *extension = @"";
- dragImage = [[NSWorkspace sharedWorkspace] iconForFileType:extension];
- NSSize offset = NSMakeSize([dragImage size].width - WebDragIconRightInset, -WebDragIconBottomInset);
- origin = NSMakePoint(mouseDownPoint.x - offset.width, mouseDownPoint.y - offset.height);
- }
- // This is the offset from the lower left corner of the image to the mouse location. Because we
- // are a flipped view the calculation of Y is inverted.
- if (dragImageOffset) {
- dragImageOffset->x = mouseDownPoint.x - origin.x;
- dragImageOffset->y = origin.y - mouseDownPoint.y;
- }
-
- // Per kwebster, offset arg is ignored
- [self dragImage:dragImage at:origin offset:NSZeroSize event:event pasteboard:pasteboard source:source slideBack:YES];
- }
- - (BOOL)_web_firstResponderIsSelfOrDescendantView
- {
- NSResponder *responder = [[self window] firstResponder];
- return (responder &&
- (responder == self ||
- ([responder isKindOfClass:[NSView class]] && [(NSView *)responder isDescendantOf:self])));
- }
- - (NSRect)_web_convertRect:(NSRect)aRect toView:(NSView *)aView
- {
- // Converting to this view's window; let -convertRect:toView: handle it
- if (aView == nil)
- return [self convertRect:aRect toView:nil];
-
- // This view must be in a window. Do whatever weird thing -convertRect:toView: does in this situation.
- NSWindow *thisWindow = [self window];
- if (!thisWindow)
- return [self convertRect:aRect toView:aView];
-
- // The other view must be in a window, too.
- NSWindow *otherWindow = [aView window];
- if (!otherWindow)
- return [self convertRect:aRect toView:aView];
- // Convert to this window's coordinates
- NSRect convertedRect = [self convertRect:aRect toView:nil];
-
- // Convert to screen coordinates
- convertedRect.origin = [thisWindow convertBaseToScreen:convertedRect.origin];
-
- // Convert to other window's coordinates
- convertedRect.origin = [otherWindow convertScreenToBase:convertedRect.origin];
-
- // Convert to other view's coordinates
- convertedRect = [aView convertRect:convertedRect fromView:nil];
-
- return convertedRect;
- }
- @end
|