WebNSViewExtras.m 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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. #import <WebKit/WebNSViewExtras.h>
  29. #import <WebKit/DOMExtensions.h>
  30. #import <WebKit/WebDataSource.h>
  31. #import <WebKit/WebFramePrivate.h>
  32. #import <WebKit/WebFrameViewInternal.h>
  33. #import <WebKit/WebNSImageExtras.h>
  34. #import <WebKit/WebNSPasteboardExtras.h>
  35. #import <WebKit/WebNSURLExtras.h>
  36. #import <WebKit/WebView.h>
  37. #define WebDragStartHysteresisX 5.0f
  38. #define WebDragStartHysteresisY 5.0f
  39. #define WebMaxDragImageSize NSMakeSize(400.0f, 400.0f)
  40. #define WebMaxOriginalImageArea (1500.0f * 1500.0f)
  41. #define WebDragIconRightInset 7.0f
  42. #define WebDragIconBottomInset 3.0f
  43. @implementation NSView (WebExtras)
  44. - (NSView *)_web_superviewOfClass:(Class)class
  45. {
  46. NSView *view = [self superview];
  47. while (view && ![view isKindOfClass:class])
  48. view = [view superview];
  49. return view;
  50. }
  51. - (WebFrameView *)_web_parentWebFrameView
  52. {
  53. return (WebFrameView *)[self _web_superviewOfClass:[WebFrameView class]];
  54. }
  55. // FIXME: Mail is the only client of _webView, remove this method once no versions of Mail need it.
  56. - (WebView *)_webView
  57. {
  58. return (WebView *)[self _web_superviewOfClass:[WebView class]];
  59. }
  60. /* Determine whether a mouse down should turn into a drag; started as copy of NSTableView code */
  61. - (BOOL)_web_dragShouldBeginFromMouseDown:(NSEvent *)mouseDownEvent
  62. withExpiration:(NSDate *)expiration
  63. xHysteresis:(float)xHysteresis
  64. yHysteresis:(float)yHysteresis
  65. {
  66. NSEvent *nextEvent, *firstEvent, *dragEvent, *mouseUp;
  67. BOOL dragIt;
  68. if ([mouseDownEvent type] != NSLeftMouseDown) {
  69. return NO;
  70. }
  71. nextEvent = nil;
  72. firstEvent = nil;
  73. dragEvent = nil;
  74. mouseUp = nil;
  75. dragIt = NO;
  76. while ((nextEvent = [[self window] nextEventMatchingMask:(NSLeftMouseUpMask | NSLeftMouseDraggedMask)
  77. untilDate:expiration
  78. inMode:NSEventTrackingRunLoopMode
  79. dequeue:YES]) != nil) {
  80. if (firstEvent == nil) {
  81. firstEvent = nextEvent;
  82. }
  83. if ([nextEvent type] == NSLeftMouseDragged) {
  84. float deltax = ABS([nextEvent locationInWindow].x - [mouseDownEvent locationInWindow].x);
  85. float deltay = ABS([nextEvent locationInWindow].y - [mouseDownEvent locationInWindow].y);
  86. dragEvent = nextEvent;
  87. if (deltax >= xHysteresis) {
  88. dragIt = YES;
  89. break;
  90. }
  91. if (deltay >= yHysteresis) {
  92. dragIt = YES;
  93. break;
  94. }
  95. } else if ([nextEvent type] == NSLeftMouseUp) {
  96. mouseUp = nextEvent;
  97. break;
  98. }
  99. }
  100. // Since we've been dequeuing the events (If we don't, we'll never see the mouse up...),
  101. // we need to push some of the events back on. It makes sense to put the first and last
  102. // drag events and the mouse up if there was one.
  103. if (mouseUp != nil) {
  104. [NSApp postEvent:mouseUp atStart:YES];
  105. }
  106. if (dragEvent != nil) {
  107. [NSApp postEvent:dragEvent atStart:YES];
  108. }
  109. if (firstEvent != mouseUp && firstEvent != dragEvent) {
  110. [NSApp postEvent:firstEvent atStart:YES];
  111. }
  112. return dragIt;
  113. }
  114. - (BOOL)_web_dragShouldBeginFromMouseDown:(NSEvent *)mouseDownEvent
  115. withExpiration:(NSDate *)expiration
  116. {
  117. return [self _web_dragShouldBeginFromMouseDown:mouseDownEvent
  118. withExpiration:expiration
  119. xHysteresis:WebDragStartHysteresisX
  120. yHysteresis:WebDragStartHysteresisY];
  121. }
  122. - (NSDragOperation)_web_dragOperationForDraggingInfo:(id <NSDraggingInfo>)sender
  123. {
  124. if (![NSApp modalWindow] &&
  125. ![[self window] attachedSheet] &&
  126. [sender draggingSource] != self &&
  127. [[sender draggingPasteboard] _web_bestURL]) {
  128. return NSDragOperationCopy;
  129. }
  130. return NSDragOperationNone;
  131. }
  132. - (void)_web_DragImageForElement:(DOMElement *)element
  133. rect:(NSRect)rect
  134. event:(NSEvent *)event
  135. pasteboard:(NSPasteboard *)pasteboard
  136. source:(id)source
  137. offset:(NSPoint *)dragImageOffset
  138. {
  139. NSPoint mouseDownPoint = [self convertPoint:[event locationInWindow] fromView:nil];
  140. NSImage *dragImage;
  141. NSPoint origin;
  142. NSImage *image = [element image];
  143. if (image != nil && [image size].height * [image size].width <= WebMaxOriginalImageArea) {
  144. NSSize originalSize = rect.size;
  145. origin = rect.origin;
  146. dragImage = [[image copy] autorelease];
  147. [dragImage setScalesWhenResized:YES];
  148. [dragImage setSize:originalSize];
  149. [dragImage _web_scaleToMaxSize:WebMaxDragImageSize];
  150. NSSize newSize = [dragImage size];
  151. [dragImage _web_dissolveToFraction:WebDragImageAlpha];
  152. // Properly orient the drag image and orient it differently if it's smaller than the original
  153. origin.x = mouseDownPoint.x - (((mouseDownPoint.x - origin.x) / originalSize.width) * newSize.width);
  154. origin.y = origin.y + originalSize.height;
  155. origin.y = mouseDownPoint.y - (((mouseDownPoint.y - origin.y) / originalSize.height) * newSize.height);
  156. } else {
  157. // FIXME: This has been broken for a while.
  158. // There's no way to get the MIME type for the image from a DOM element.
  159. // The old code used WKGetPreferredExtensionForMIMEType([image MIMEType]);
  160. NSString *extension = @"";
  161. dragImage = [[NSWorkspace sharedWorkspace] iconForFileType:extension];
  162. NSSize offset = NSMakeSize([dragImage size].width - WebDragIconRightInset, -WebDragIconBottomInset);
  163. origin = NSMakePoint(mouseDownPoint.x - offset.width, mouseDownPoint.y - offset.height);
  164. }
  165. // This is the offset from the lower left corner of the image to the mouse location. Because we
  166. // are a flipped view the calculation of Y is inverted.
  167. if (dragImageOffset) {
  168. dragImageOffset->x = mouseDownPoint.x - origin.x;
  169. dragImageOffset->y = origin.y - mouseDownPoint.y;
  170. }
  171. // Per kwebster, offset arg is ignored
  172. [self dragImage:dragImage at:origin offset:NSZeroSize event:event pasteboard:pasteboard source:source slideBack:YES];
  173. }
  174. - (BOOL)_web_firstResponderIsSelfOrDescendantView
  175. {
  176. NSResponder *responder = [[self window] firstResponder];
  177. return (responder &&
  178. (responder == self ||
  179. ([responder isKindOfClass:[NSView class]] && [(NSView *)responder isDescendantOf:self])));
  180. }
  181. - (NSRect)_web_convertRect:(NSRect)aRect toView:(NSView *)aView
  182. {
  183. // Converting to this view's window; let -convertRect:toView: handle it
  184. if (aView == nil)
  185. return [self convertRect:aRect toView:nil];
  186. // This view must be in a window. Do whatever weird thing -convertRect:toView: does in this situation.
  187. NSWindow *thisWindow = [self window];
  188. if (!thisWindow)
  189. return [self convertRect:aRect toView:aView];
  190. // The other view must be in a window, too.
  191. NSWindow *otherWindow = [aView window];
  192. if (!otherWindow)
  193. return [self convertRect:aRect toView:aView];
  194. // Convert to this window's coordinates
  195. NSRect convertedRect = [self convertRect:aRect toView:nil];
  196. // Convert to screen coordinates
  197. convertedRect.origin = [thisWindow convertBaseToScreen:convertedRect.origin];
  198. // Convert to other window's coordinates
  199. convertedRect.origin = [otherWindow convertScreenToBase:convertedRect.origin];
  200. // Convert to other view's coordinates
  201. convertedRect = [aView convertRect:convertedRect fromView:nil];
  202. return convertedRect;
  203. }
  204. @end