webengine/osswebengine/WebKit/Misc/WebNSViewExtras.m
changeset 0 dd21522fd290
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2  * Copyright (C) 2005, 2006 Apple Computer, Inc.  All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  *
       
     8  * 1.  Redistributions of source code must retain the above copyright
       
     9  *     notice, this list of conditions and the following disclaimer. 
       
    10  * 2.  Redistributions in binary form must reproduce the above copyright
       
    11  *     notice, this list of conditions and the following disclaimer in the
       
    12  *     documentation and/or other materials provided with the distribution. 
       
    13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
       
    14  *     its contributors may be used to endorse or promote products derived
       
    15  *     from this software without specific prior written permission. 
       
    16  *
       
    17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
       
    18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
    19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
       
    20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
       
    21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
       
    22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
       
    23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
       
    24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
       
    26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    27  */
       
    28 
       
    29 #import <WebKit/WebNSViewExtras.h>
       
    30 
       
    31 #import <WebKit/DOMExtensions.h>
       
    32 #import <WebKit/WebDataSource.h>
       
    33 #import <WebKit/WebFramePrivate.h>
       
    34 #import <WebKit/WebFrameViewInternal.h>
       
    35 #import <WebKit/WebNSImageExtras.h>
       
    36 #import <WebKit/WebNSPasteboardExtras.h>
       
    37 #import <WebKit/WebNSURLExtras.h>
       
    38 #import <WebKit/WebView.h>
       
    39 #import <WebKitSystemInterface.h>
       
    40 
       
    41 #define WebDragStartHysteresisX                 5.0f
       
    42 #define WebDragStartHysteresisY                 5.0f
       
    43 #define WebMaxDragImageSize                     NSMakeSize(400.0f, 400.0f)
       
    44 #define WebMaxOriginalImageArea                 (1500.0f * 1500.0f)
       
    45 #define WebDragIconRightInset                   7.0f
       
    46 #define WebDragIconBottomInset                  3.0f
       
    47 
       
    48 @implementation NSView (WebExtras)
       
    49 
       
    50 // FIXME: Safari 2.0 is the only client of _web_superviewOfClass:stoppingAtClass:
       
    51 // remove this method once Open Source users have a new version to use with TOT WebKit.
       
    52 - (NSView *)_web_superviewOfClass:(Class)class stoppingAtClass:(Class)limitClass
       
    53 {
       
    54     NSView *view = self;
       
    55     while ((view = [view superview]) != nil) {
       
    56         if ([view isKindOfClass:class]) {
       
    57             return view;
       
    58         } else if (limitClass && [view isKindOfClass:limitClass]) {
       
    59             break;
       
    60         }
       
    61     }
       
    62 
       
    63     return nil;
       
    64 }
       
    65 
       
    66 - (NSView *)_web_superviewOfClass:(Class)class
       
    67 {
       
    68     NSView *view = [self superview];
       
    69     while (view  && ![view isKindOfClass:class])
       
    70         view = [view superview];
       
    71     return view;
       
    72 }
       
    73 
       
    74 - (WebFrameView *)_web_parentWebFrameView
       
    75 {
       
    76     return (WebFrameView *)[self _web_superviewOfClass:[WebFrameView class]];
       
    77 }
       
    78 
       
    79 // FIXME: Mail is the only client of _webView, remove this method once no versions of Mail need it.
       
    80 - (WebView *)_webView
       
    81 {
       
    82     return (WebView *)[self _web_superviewOfClass:[WebView class]];
       
    83 }
       
    84 
       
    85 /* Determine whether a mouse down should turn into a drag; started as copy of NSTableView code */
       
    86 - (BOOL)_web_dragShouldBeginFromMouseDown:(NSEvent *)mouseDownEvent
       
    87                            withExpiration:(NSDate *)expiration
       
    88                               xHysteresis:(float)xHysteresis
       
    89                               yHysteresis:(float)yHysteresis
       
    90 {
       
    91     NSEvent *nextEvent, *firstEvent, *dragEvent, *mouseUp;
       
    92     BOOL dragIt;
       
    93 
       
    94     if ([mouseDownEvent type] != NSLeftMouseDown) {
       
    95         return NO;
       
    96     }
       
    97 
       
    98     nextEvent = nil;
       
    99     firstEvent = nil;
       
   100     dragEvent = nil;
       
   101     mouseUp = nil;
       
   102     dragIt = NO;
       
   103 
       
   104     while ((nextEvent = [[self window] nextEventMatchingMask:(NSLeftMouseUpMask | NSLeftMouseDraggedMask)
       
   105                                                    untilDate:expiration
       
   106                                                       inMode:NSEventTrackingRunLoopMode
       
   107                                                      dequeue:YES]) != nil) {
       
   108         if (firstEvent == nil) {
       
   109             firstEvent = nextEvent;
       
   110         }
       
   111 
       
   112         if ([nextEvent type] == NSLeftMouseDragged) {
       
   113             float deltax = ABS([nextEvent locationInWindow].x - [mouseDownEvent locationInWindow].x);
       
   114             float deltay = ABS([nextEvent locationInWindow].y - [mouseDownEvent locationInWindow].y);
       
   115             dragEvent = nextEvent;
       
   116 
       
   117             if (deltax >= xHysteresis) {
       
   118                 dragIt = YES;
       
   119                 break;
       
   120             }
       
   121 
       
   122             if (deltay >= yHysteresis) {
       
   123                 dragIt = YES;
       
   124                 break;
       
   125             }
       
   126         } else if ([nextEvent type] == NSLeftMouseUp) {
       
   127             mouseUp = nextEvent;
       
   128             break;
       
   129         }
       
   130     }
       
   131 
       
   132     // Since we've been dequeuing the events (If we don't, we'll never see the mouse up...),
       
   133     // we need to push some of the events back on.  It makes sense to put the first and last
       
   134     // drag events and the mouse up if there was one.
       
   135     if (mouseUp != nil) {
       
   136         [NSApp postEvent:mouseUp atStart:YES];
       
   137     }
       
   138     if (dragEvent != nil) {
       
   139         [NSApp postEvent:dragEvent atStart:YES];
       
   140     }
       
   141     if (firstEvent != mouseUp && firstEvent != dragEvent) {
       
   142         [NSApp postEvent:firstEvent atStart:YES];
       
   143     }
       
   144 
       
   145     return dragIt;
       
   146 }
       
   147 
       
   148 - (BOOL)_web_dragShouldBeginFromMouseDown:(NSEvent *)mouseDownEvent
       
   149                            withExpiration:(NSDate *)expiration
       
   150 {
       
   151     return [self _web_dragShouldBeginFromMouseDown:mouseDownEvent
       
   152                                     withExpiration:expiration
       
   153                                        xHysteresis:WebDragStartHysteresisX
       
   154                                        yHysteresis:WebDragStartHysteresisY];
       
   155 }
       
   156 
       
   157 
       
   158 - (NSDragOperation)_web_dragOperationForDraggingInfo:(id <NSDraggingInfo>)sender
       
   159 {
       
   160     if (![NSApp modalWindow] && 
       
   161         ![[self window] attachedSheet] &&
       
   162         [sender draggingSource] != self &&
       
   163         [[sender draggingPasteboard] _web_bestURL]) {
       
   164 
       
   165         return NSDragOperationCopy;
       
   166     }
       
   167     
       
   168     return NSDragOperationNone;
       
   169 }
       
   170 
       
   171 - (void)_web_DragImageForElement:(DOMElement *)element
       
   172                          rect:(NSRect)rect
       
   173                         event:(NSEvent *)event
       
   174                    pasteboard:(NSPasteboard *)pasteboard 
       
   175                        source:(id)source
       
   176                        offset:(NSPoint *)dragImageOffset
       
   177 {
       
   178     NSPoint mouseDownPoint = [self convertPoint:[event locationInWindow] fromView:nil];
       
   179     NSImage *dragImage;
       
   180     NSPoint origin;
       
   181 
       
   182     NSImage *image = [element image];
       
   183     if (image != nil && [image size].height * [image size].width <= WebMaxOriginalImageArea) {
       
   184         NSSize originalSize = rect.size;
       
   185         origin = rect.origin;
       
   186         
       
   187         dragImage = [[image copy] autorelease];
       
   188         [dragImage setScalesWhenResized:YES];
       
   189         [dragImage setSize:originalSize];
       
   190         
       
   191         [dragImage _web_scaleToMaxSize:WebMaxDragImageSize];
       
   192         NSSize newSize = [dragImage size];
       
   193         
       
   194         [dragImage _web_dissolveToFraction:WebDragImageAlpha];
       
   195         
       
   196         // Properly orient the drag image and orient it differently if it's smaller than the original
       
   197         origin.x = mouseDownPoint.x - (((mouseDownPoint.x - origin.x) / originalSize.width) * newSize.width);
       
   198         origin.y = origin.y + originalSize.height;
       
   199         origin.y = mouseDownPoint.y - (((mouseDownPoint.y - origin.y) / originalSize.height) * newSize.height);
       
   200     } else {
       
   201         // FIXME: This has been broken for a while.
       
   202         // There's no way to get the MIME type for the image from a DOM element.
       
   203         // The old code used WKGetPreferredExtensionForMIMEType([image MIMEType]);
       
   204         NSString *extension = @"";
       
   205         dragImage = [[NSWorkspace sharedWorkspace] iconForFileType:extension];
       
   206         NSSize offset = NSMakeSize([dragImage size].width - WebDragIconRightInset, -WebDragIconBottomInset);
       
   207         origin = NSMakePoint(mouseDownPoint.x - offset.width, mouseDownPoint.y - offset.height);
       
   208     }
       
   209 
       
   210     // This is the offset from the lower left corner of the image to the mouse location.  Because we
       
   211     // are a flipped view the calculation of Y is inverted.
       
   212     if (dragImageOffset) {
       
   213         dragImageOffset->x = mouseDownPoint.x - origin.x;
       
   214         dragImageOffset->y = origin.y - mouseDownPoint.y;
       
   215     }
       
   216     
       
   217     // Per kwebster, offset arg is ignored
       
   218     [self dragImage:dragImage at:origin offset:NSZeroSize event:event pasteboard:pasteboard source:source slideBack:YES];
       
   219 }
       
   220 
       
   221 - (BOOL)_web_firstResponderIsSelfOrDescendantView
       
   222 {
       
   223     NSResponder *responder = [[self window] firstResponder];
       
   224     return (responder && 
       
   225            (responder == self || 
       
   226            ([responder isKindOfClass:[NSView class]] && [(NSView *)responder isDescendantOf:self])));
       
   227 }
       
   228 
       
   229 - (NSRect)_web_convertRect:(NSRect)aRect toView:(NSView *)aView
       
   230 {
       
   231     // Converting to this view's window; let -convertRect:toView: handle it
       
   232     if (aView == nil)
       
   233         return [self convertRect:aRect toView:nil];
       
   234         
       
   235     // This view must be in a window.  Do whatever weird thing -convertRect:toView: does in this situation.
       
   236     NSWindow *thisWindow = [self window];
       
   237     if (!thisWindow)
       
   238         return [self convertRect:aRect toView:aView];
       
   239     
       
   240     // The other view must be in a window, too.
       
   241     NSWindow *otherWindow = [aView window];
       
   242     if (!otherWindow)
       
   243         return [self convertRect:aRect toView:aView];
       
   244 
       
   245     // Convert to this window's coordinates
       
   246     NSRect convertedRect = [self convertRect:aRect toView:nil];
       
   247     
       
   248     // Convert to screen coordinates
       
   249     convertedRect.origin = [thisWindow convertBaseToScreen:convertedRect.origin];
       
   250     
       
   251     // Convert to other window's coordinates
       
   252     convertedRect.origin = [otherWindow convertScreenToBase:convertedRect.origin];
       
   253     
       
   254     // Convert to other view's coordinates
       
   255     convertedRect = [aView convertRect:convertedRect fromView:nil];
       
   256     
       
   257     return convertedRect;
       
   258 }
       
   259 
       
   260 @end