webengine/osswebengine/WebKit/Misc/WebNSViewExtras.m
changeset 0 dd21522fd290
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/WebKit/Misc/WebNSViewExtras.m	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,260 @@
+/*
+ * 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>
+#import <WebKitSystemInterface.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)
+
+// FIXME: Safari 2.0 is the only client of _web_superviewOfClass:stoppingAtClass:
+// remove this method once Open Source users have a new version to use with TOT WebKit.
+- (NSView *)_web_superviewOfClass:(Class)class stoppingAtClass:(Class)limitClass
+{
+    NSView *view = self;
+    while ((view = [view superview]) != nil) {
+        if ([view isKindOfClass:class]) {
+            return view;
+        } else if (limitClass && [view isKindOfClass:limitClass]) {
+            break;
+        }
+    }
+
+    return nil;
+}
+
+- (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