|
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 |