2009-03-31 Darin Adler <darin@apple.com>
[WebKit-https.git] / WebKit / mac / WebView / WebHTMLView.mm
1 /*
2  * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3  *           (C) 2006, 2007 Graham Dennis (graham.dennis@gmail.com)
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer. 
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution. 
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission. 
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #import "WebHTMLView.h"
31
32 #import "DOMNodeInternal.h"
33 #import "DOMRangeInternal.h"
34 #import "WebArchive.h"
35 #import "WebClipView.h"
36 #import "WebDOMOperationsPrivate.h"
37 #import "WebDataSourceInternal.h"
38 #import "WebDefaultUIDelegate.h"
39 #import "WebDocumentInternal.h"
40 #import "WebDynamicScrollBarsView.h"
41 #import "WebEditingDelegate.h"
42 #import "WebElementDictionary.h"
43 #import "WebFrameInternal.h"
44 #import "WebFramePrivate.h"
45 #import "WebFrameViewInternal.h"
46 #import "WebHTMLRepresentationPrivate.h"
47 #import "WebHTMLViewInternal.h"
48 #import "WebKitLogging.h"
49 #import "WebKitNSStringExtras.h"
50 #import "WebKitVersionChecks.h"
51 #import "WebLocalizableStrings.h"
52 #import "WebNSAttributedStringExtras.h"
53 #import "WebNSEventExtras.h"
54 #import "WebNSFileManagerExtras.h"
55 #import "WebNSImageExtras.h"
56 #import "WebNSObjectExtras.h"
57 #import "WebNSPasteboardExtras.h"
58 #import "WebNSPrintOperationExtras.h"
59 #import "WebNSURLExtras.h"
60 #import "WebNSViewExtras.h"
61 #import "WebNetscapePluginView.h"
62 #import "WebNodeHighlight.h"
63 #import "WebPluginController.h"
64 #import "WebPreferences.h"
65 #import "WebPreferencesPrivate.h"
66 #import "WebResourcePrivate.h"
67 #import "WebStringTruncator.h"
68 #import "WebTypesInternal.h"
69 #import "WebUIDelegatePrivate.h"
70 #import "WebViewInternal.h"
71 #import <AppKit/NSAccessibility.h>
72 #import <ApplicationServices/ApplicationServices.h>
73 #import <WebCore/CSSMutableStyleDeclaration.h>
74 #import <WebCore/CachedImage.h>
75 #import <WebCore/CachedResourceClient.h>
76 #import <WebCore/ColorMac.h>
77 #import <WebCore/ContextMenu.h>
78 #import <WebCore/ContextMenuController.h>
79 #import <WebCore/Document.h>
80 #import <WebCore/DocumentFragment.h>
81 #import <WebCore/DragController.h>
82 #import <WebCore/Editor.h>
83 #import <WebCore/EditorDeleteAction.h>
84 #import <WebCore/Element.h>
85 #import <WebCore/EventHandler.h>
86 #import <WebCore/ExceptionHandlers.h>
87 #import <WebCore/FloatRect.h>
88 #import <WebCore/FocusController.h>
89 #import <WebCore/Frame.h>
90 #import <WebCore/FrameLoader.h>
91 #import <WebCore/FrameView.h>
92 #import <WebCore/HTMLNames.h>
93 #import <WebCore/HitTestResult.h>
94 #import <WebCore/Image.h>
95 #import <WebCore/KeyboardEvent.h>
96 #import <WebCore/LegacyWebArchive.h>
97 #import <WebCore/MIMETypeRegistry.h>
98 #import <WebCore/Page.h>
99 #import <WebCore/PlatformKeyboardEvent.h>
100 #import <WebCore/PlatformMouseEvent.h>
101 #import <WebCore/Range.h>
102 #import <WebCore/SelectionController.h>
103 #import <WebCore/SharedBuffer.h>
104 #import <WebCore/SimpleFontData.h>
105 #import <WebCore/Text.h>
106 #import <WebCore/WebCoreObjCExtras.h>
107 #import <WebCore/WebCoreTextRenderer.h>
108 #import <WebCore/markup.h>
109 #import <WebKit/DOM.h>
110 #import <WebKit/DOMExtensions.h>
111 #import <WebKit/DOMPrivate.h>
112 #import <WebKitSystemInterface.h>
113 #import <dlfcn.h>
114 #import <limits>
115 #import <runtime/InitializeThreading.h>
116
117 #if USE(ACCELERATED_COMPOSITING)
118 #import <QuartzCore/QuartzCore.h>
119 #endif
120
121 using namespace WebCore;
122 using namespace HTMLNames;
123 using namespace WTF;
124
125 @interface NSWindow (BorderViewAccess)
126 - (NSView*)_web_borderView;
127 @end
128
129 @implementation NSWindow (BorderViewAccess)
130 - (NSView*)_web_borderView
131 {
132     return _borderView;
133 }
134 @end
135
136 @interface WebResponderChainSink : NSResponder {
137     NSResponder* _lastResponderInChain;
138     BOOL _receivedUnhandledCommand;
139 }
140 - (id)initWithResponderChain:(NSResponder *)chain;
141 - (void)detach;
142 - (BOOL)receivedUnhandledCommand;
143 @end
144
145 static IMP oldSetCursorIMP = NULL;
146
147 #ifdef BUILDING_ON_TIGER
148 static IMP oldResetCursorRectsIMP = NULL;
149 static BOOL canSetCursor = YES;
150
151 static void resetCursorRects(NSWindow* self, SEL cmd)
152 {
153     NSPoint point = [self mouseLocationOutsideOfEventStream];
154     NSView* view = [[self _web_borderView] hitTest:point];
155     if ([view isKindOfClass:[WebHTMLView class]]) {
156         WebHTMLView *htmlView = (WebHTMLView*)view;
157         NSPoint localPoint = [htmlView convertPoint:point fromView:nil];
158         NSDictionary *dict = [htmlView elementAtPoint:localPoint allowShadowContent:NO];
159         DOMElement *element = [dict objectForKey:WebElementDOMNodeKey];
160         if (![element isKindOfClass:[DOMHTMLAppletElement class]] && ![element isKindOfClass:[DOMHTMLObjectElement class]] &&
161             ![element isKindOfClass:[DOMHTMLEmbedElement class]])
162             canSetCursor = NO;
163     }
164     oldResetCursorRectsIMP(self, cmd);
165     canSetCursor = YES;
166 }
167
168 static void setCursor(NSCursor* self, SEL cmd)
169 {
170     if (canSetCursor)
171         oldSetCursorIMP(self, cmd);
172 }
173 #else
174 static void setCursor(NSWindow* self, SEL cmd, NSPoint point)
175 {
176     NSView* view = [[self _web_borderView] hitTest:point];
177     if ([view isKindOfClass:[WebHTMLView class]]) {
178         WebHTMLView *htmlView = (WebHTMLView*)view;
179         NSPoint localPoint = [htmlView convertPoint:point fromView:nil];
180         NSDictionary *dict = [htmlView elementAtPoint:localPoint allowShadowContent:NO];
181         DOMElement *element = [dict objectForKey:WebElementDOMNodeKey];
182         if (![element isKindOfClass:[DOMHTMLAppletElement class]] && ![element isKindOfClass:[DOMHTMLObjectElement class]] &&
183             ![element isKindOfClass:[DOMHTMLEmbedElement class]])
184             return;
185     }
186     oldSetCursorIMP(self, cmd, point);
187 }
188 #endif
189
190 #if USE(ACCELERATED_COMPOSITING)
191 @interface WebLayerHostingView : NSView
192 @end
193
194 @implementation WebLayerHostingView
195 // Empty NSViews intercept rightMouseDown: to do context menu handling, but we need the WebLayerHostingView to
196 // let right mouse clicks through.
197 - (void)rightMouseDown:(NSEvent *)theEvent
198 {
199     [[self nextResponder] performSelector:_cmd withObject:theEvent];
200 }
201 @end
202 #endif // USE(ACCELERATED_COMPOSITING)
203
204 extern "C" {
205
206 // Need to declare these attribute names because AppKit exports them but does not make them available in API or SPI headers.
207
208 extern NSString *NSMarkedClauseSegmentAttributeName;
209 extern NSString *NSTextInputReplacementRangeAttributeName;
210 }
211
212 @interface NSView (WebNSViewDetails)
213 - (void)_recursiveDisplayRectIfNeededIgnoringOpacity:(NSRect)rect isVisibleRect:(BOOL)isVisibleRect rectIsVisibleRectForView:(NSView *)visibleView topView:(BOOL)topView;
214 - (void)_recursiveDisplayAllDirtyWithLockFocus:(BOOL)needsLockFocus visRect:(NSRect)visRect;
215 - (void)_recursive:(BOOL)recurse displayRectIgnoringOpacity:(NSRect)displayRect inContext:(NSGraphicsContext *)context topView:(BOOL)topView;
216 - (NSRect)_dirtyRect;
217 - (void)_setDrawsOwnDescendants:(BOOL)drawsOwnDescendants;
218 - (void)_propagateDirtyRectsToOpaqueAncestors;
219 - (void)_windowChangedKeyState;
220 @end
221
222 @interface NSApplication (WebNSApplicationDetails)
223 - (void)speakString:(NSString *)string;
224 @end
225
226 @interface NSWindow (WebNSWindowDetails)
227 - (id)_newFirstResponderAfterResigning;
228 - (void)_setForceActiveControls:(BOOL)flag;
229 @end
230
231 @interface NSAttributedString (WebNSAttributedStringDetails)
232 - (id)_initWithDOMRange:(DOMRange *)range;
233 - (DOMDocumentFragment *)_documentFromRange:(NSRange)range document:(DOMDocument *)document documentAttributes:(NSDictionary *)dict subresources:(NSArray **)subresources;
234 @end
235
236 @interface NSSpellChecker (WebNSSpellCheckerDetails)
237 - (void)learnWord:(NSString *)word;
238 @end
239
240 // By imaging to a width a little wider than the available pixels,
241 // thin pages will be scaled down a little, matching the way they
242 // print in IE and Camino. This lets them use fewer sheets than they
243 // would otherwise, which is presumably why other browsers do this.
244 // Wide pages will be scaled down more than this.
245 #define PrintingMinimumShrinkFactor     1.25f
246
247 // This number determines how small we are willing to reduce the page content
248 // in order to accommodate the widest line. If the page would have to be
249 // reduced smaller to make the widest line fit, we just clip instead (this
250 // behavior matches MacIE and Mozilla, at least)
251 #define PrintingMaximumShrinkFactor     2.0f
252
253 // This number determines how short the last printed page of a multi-page print session
254 // can be before we try to shrink the scale in order to reduce the number of pages, and
255 // thus eliminate the orphan.
256 #define LastPrintedPageOrphanRatio      0.1f
257
258 // This number determines the amount the scale factor is adjusted to try to eliminate orphans.
259 // It has no direct mathematical relationship to LastPrintedPageOrphanRatio, due to variable
260 // numbers of pages, logic to avoid breaking elements, and CSS-supplied hard page breaks.
261 #define PrintingOrphanShrinkAdjustment  1.1f
262
263 #define AUTOSCROLL_INTERVAL             0.1f
264
265 #define DRAG_LABEL_BORDER_X             4.0f
266 //Keep border_y in synch with DragController::LinkDragBorderInset
267 #define DRAG_LABEL_BORDER_Y             2.0f
268 #define DRAG_LABEL_RADIUS               5.0f
269 #define DRAG_LABEL_BORDER_Y_OFFSET              2.0f
270
271 #define MIN_DRAG_LABEL_WIDTH_BEFORE_CLIP        120.0f
272 #define MAX_DRAG_LABEL_WIDTH                    320.0f
273
274 #define DRAG_LINK_LABEL_FONT_SIZE   11.0f
275 #define DRAG_LINK_URL_FONT_SIZE   10.0f
276
277 // Any non-zero value will do, but using something recognizable might help us debug some day.
278 #define TRACKING_RECT_TAG 0xBADFACE
279
280 // FIXME: This constant is copied from AppKit's _NXSmartPaste constant.
281 #define WebSmartPastePboardType @"NeXT smart paste pasteboard type"
282
283 #define STANDARD_WEIGHT 5
284 #define MIN_BOLD_WEIGHT 7
285 #define STANDARD_BOLD_WEIGHT 9
286
287 // Fake URL scheme.
288 #define WebDataProtocolScheme @"webkit-fake-url"
289
290 // <rdar://problem/4985524> References to WebCoreScrollView as a subview of a WebHTMLView may be present
291 // in some NIB files, so NSUnarchiver must be still able to look up this now-unused class.
292 @interface WebCoreScrollView : NSScrollView
293 @end
294
295 @implementation WebCoreScrollView
296 @end
297
298 // if YES, do the standard NSView hit test (which can't give the right result when HTML overlaps a view)
299 static BOOL forceNSViewHitTest;
300
301 // if YES, do the "top WebHTMLView" hit test (which we'd like to do all the time but can't because of Java requirements [see bug 4349721])
302 static BOOL forceWebHTMLViewHitTest;
303
304 static WebHTMLView *lastHitView;
305
306 // We need this to be able to safely reference the CachedImage for the promised drag data
307 static CachedResourceClient* promisedDataClient()
308 {
309     static CachedResourceClient* staticCachedResourceClient = new CachedResourceClient;
310     return staticCachedResourceClient;
311 }
312
313 @interface WebHTMLView (WebHTMLViewFileInternal)
314 - (BOOL)_imageExistsAtPaths:(NSArray *)paths;
315 - (DOMDocumentFragment *)_documentFragmentFromPasteboard:(NSPasteboard *)pasteboard inContext:(DOMRange *)context allowPlainText:(BOOL)allowPlainText;
316 - (NSString *)_plainTextFromPasteboard:(NSPasteboard *)pasteboard;
317 - (void)_pasteWithPasteboard:(NSPasteboard *)pasteboard allowPlainText:(BOOL)allowPlainText;
318 - (void)_pasteAsPlainTextWithPasteboard:(NSPasteboard *)pasteboard;
319 - (void)_removeMouseMovedObserverUnconditionally;
320 - (void)_removeSuperviewObservers;
321 - (void)_removeWindowObservers;
322 - (BOOL)_shouldInsertFragment:(DOMDocumentFragment *)fragment replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action;
323 - (BOOL)_shouldInsertText:(NSString *)text replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action;
324 - (BOOL)_shouldReplaceSelectionWithText:(NSString *)text givenAction:(WebViewInsertAction)action;
325 - (float)_calculatePrintHeight;
326 - (DOMRange *)_selectedRange;
327 - (BOOL)_shouldDeleteRange:(DOMRange *)range;
328 - (NSView *)_hitViewForEvent:(NSEvent *)event;
329 - (void)_writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard cachedAttributedString:(NSAttributedString *)attributedString;
330 - (DOMRange *)_documentRange;
331 - (void)_setMouseDownEvent:(NSEvent *)event;
332 - (WebHTMLView *)_topHTMLView;
333 - (BOOL)_isTopHTMLView;
334 - (void)_web_setPrintingModeRecursive;
335 - (void)_web_setPrintingModeRecursiveAndAdjustViewSize;
336 - (void)_web_clearPrintingModeRecursive;
337 @end
338
339 @interface WebHTMLView (WebForwardDeclaration) // FIXME: Put this in a normal category and stop doing the forward declaration trick.
340 - (void)_setPrinting:(BOOL)printing minimumPageWidth:(float)minPageWidth maximumPageWidth:(float)maxPageWidth adjustViewSize:(BOOL)adjustViewSize;
341 @end
342
343 @class NSTextInputContext;
344 @interface NSResponder (AppKitDetails)
345 - (NSTextInputContext *)inputContext;
346 @end
347
348 @interface NSObject (NSTextInputContextDetails)
349 - (BOOL)wantsToHandleMouseEvents;
350 - (BOOL)handleMouseEvent:(NSEvent *)event;
351 @end
352
353 @interface WebHTMLView (WebNSTextInputSupport) <NSTextInput>
354 - (void)_updateSelectionForInputManager;
355 @end
356
357 @interface WebHTMLView (WebEditingStyleSupport)
358 - (DOMCSSStyleDeclaration *)_emptyStyle;
359 - (NSString *)_colorAsString:(NSColor *)color;
360 @end
361
362 @interface NSView (WebHTMLViewFileInternal)
363 - (void)_web_addDescendantWebHTMLViewsToArray:(NSMutableArray *) array;
364 @end
365
366 @interface NSMutableDictionary (WebHTMLViewFileInternal)
367 - (void)_web_setObjectIfNotNil:(id)object forKey:(id)key;
368 @end
369
370 // Handles the complete: text command
371 @interface WebTextCompleteController : NSObject <NSTableViewDelegate, NSTableViewDataSource> {
372 @private
373     WebHTMLView *_view;
374     NSWindow *_popupWindow;
375     NSTableView *_tableView;
376     NSArray *_completions;
377     NSString *_originalString;
378     int prefixLength;
379 }
380 - (id)initWithHTMLView:(WebHTMLView *)view;
381 - (void)doCompletion;
382 - (void)endRevertingChange:(BOOL)revertChange moveLeft:(BOOL)goLeft;
383 - (BOOL)popupWindowIsOpen;
384 - (BOOL)filterKeyDown:(NSEvent *)event;
385 - (void)_reflectSelection;
386 @end
387
388 struct WebHTMLViewInterpretKeyEventsParameters {
389     KeyboardEvent* event;
390     BOOL eventWasHandled;
391     BOOL shouldSaveCommand;
392     // The Input Method may consume an event and not tell us, in
393     // which case we should not bubble the event up the DOM
394     BOOL consumedByIM;
395 };
396
397 @interface WebHTMLViewPrivate : NSObject {
398 @public
399     BOOL closed;
400     BOOL needsLayout;
401     BOOL needsToApplyStyles;
402     BOOL ignoringMouseDraggedEvents;
403     BOOL printing;
404     BOOL avoidingPrintOrphan;
405     BOOL observingMouseMovedNotifications;
406     BOOL observingSuperviewNotifications;
407     BOOL observingWindowNotifications;
408     BOOL resigningFirstResponder;
409     
410     id savedSubviews;
411     BOOL subviewsSetAside;
412     
413 #if USE(ACCELERATED_COMPOSITING)
414     NSView *layerHostingView;
415 #endif
416
417     NSEvent *mouseDownEvent; // Kept after handling the event.
418     BOOL handlingMouseDownEvent;
419     NSEvent *keyDownEvent; // Kept after handling the event.
420     
421     NSSize lastLayoutSize;
422
423     NSPoint lastScrollPosition;
424
425     WebPluginController *pluginController;
426     
427     NSString *toolTip;
428     NSToolTipTag lastToolTipTag;
429     id trackingRectOwner;
430     void *trackingRectUserData;
431     
432     NSTimer *autoscrollTimer;
433     NSEvent *autoscrollTriggerEvent;
434     
435     NSArray *pageRects;
436
437     NSMutableDictionary *highlighters;
438
439 #ifdef BUILDING_ON_TIGER
440     BOOL nextResponderDisabledOnce;
441 #endif
442     
443     WebTextCompleteController *compController;
444     
445     BOOL transparentBackground;
446
447     WebHTMLViewInterpretKeyEventsParameters* interpretKeyEventsParameters;
448     BOOL receivedNOOP;
449     
450     WebDataSource *dataSource;
451     WebCore::CachedImage* promisedDragTIFFDataSource;
452     
453     CFRunLoopTimerRef updateFocusedAndActiveStateTimer;
454     CFRunLoopTimerRef updateMouseoverTimer;
455
456     SEL selectorForDoCommandBySelector;
457
458 #ifndef NDEBUG
459     BOOL enumeratingSubviews;
460 #endif
461 }
462 - (void)clear;
463 @end
464
465 static NSCellStateValue kit(TriState state)
466 {
467     switch (state) {
468         case FalseTriState:
469             return NSOffState;
470         case TrueTriState:
471             return NSOnState;
472         case MixedTriState:
473             return NSMixedState;
474     }
475     ASSERT_NOT_REACHED();
476     return NSOffState;
477 }
478
479 @implementation WebHTMLViewPrivate
480
481 + (void)initialize
482 {
483     JSC::initializeThreading();
484 #ifndef BUILDING_ON_TIGER
485     WebCoreObjCFinalizeOnMainThread(self);
486 #endif
487
488     if (!oldSetCursorIMP) {
489 #ifdef BUILDING_ON_TIGER
490         Method setCursorMethod = class_getInstanceMethod([NSCursor class], @selector(set));
491 #else
492         Method setCursorMethod = class_getInstanceMethod([NSWindow class], @selector(_setCursorForMouseLocation:));
493 #endif
494         ASSERT(setCursorMethod);
495
496         oldSetCursorIMP = method_setImplementation(setCursorMethod, (IMP)setCursor);
497         ASSERT(oldSetCursorIMP);
498     }
499     
500 #ifdef BUILDING_ON_TIGER
501     if (!oldResetCursorRectsIMP) {
502         Method resetCursorRectsMethod = class_getInstanceMethod([NSWindow class], @selector(resetCursorRects));
503         ASSERT(resetCursorRectsMethod);
504         oldResetCursorRectsIMP = method_setImplementation(resetCursorRectsMethod, (IMP)resetCursorRects);
505         ASSERT(oldResetCursorRectsIMP);
506     }
507 #endif
508
509 }
510
511 - (void)dealloc
512 {
513     if (WebCoreObjCScheduleDeallocateOnMainThread([WebHTMLViewPrivate class], self))
514         return;
515
516     ASSERT(!autoscrollTimer);
517     ASSERT(!autoscrollTriggerEvent);
518     ASSERT(!updateFocusedAndActiveStateTimer);
519     ASSERT(!updateMouseoverTimer);
520     
521     [mouseDownEvent release];
522     [keyDownEvent release];
523     [pluginController release];
524     [toolTip release];
525     [compController release];
526     [dataSource release];
527     [highlighters release];
528     if (promisedDragTIFFDataSource)
529         promisedDragTIFFDataSource->removeClient(promisedDataClient());
530
531     [super dealloc];
532 }
533
534 - (void)finalize
535 {
536     ASSERT_MAIN_THREAD();
537
538     if (promisedDragTIFFDataSource)
539         promisedDragTIFFDataSource->removeClient(promisedDataClient());
540
541     [super finalize];
542 }
543
544 - (void)clear
545 {
546     [mouseDownEvent release];
547     [keyDownEvent release];
548     [pluginController release];
549     [toolTip release];
550     [compController release];
551     [dataSource release];
552     [highlighters release];
553     if (promisedDragTIFFDataSource)
554         promisedDragTIFFDataSource->removeClient(promisedDataClient());
555
556     mouseDownEvent = nil;
557     keyDownEvent = nil;
558     pluginController = nil;
559     toolTip = nil;
560     compController = nil;
561     dataSource = nil;
562     highlighters = nil;
563     promisedDragTIFFDataSource = 0;
564
565 #if USE(ACCELERATED_COMPOSITING)
566     layerHostingView = nil;
567 #endif
568 }
569
570 @end
571
572 @implementation WebHTMLView (WebHTMLViewFileInternal)
573
574 - (DOMRange *)_documentRange
575 {
576     return [[[self _frame] DOMDocument] _documentRange];
577 }
578
579 - (BOOL)_imageExistsAtPaths:(NSArray *)paths
580 {
581     NSEnumerator *enumerator = [paths objectEnumerator];
582     NSString *path;
583     
584     while ((path = [enumerator nextObject]) != nil) {
585         NSString *MIMEType = WKGetMIMETypeForExtension([path pathExtension]);
586         if (MIMETypeRegistry::isSupportedImageResourceMIMEType(MIMEType))
587             return YES;
588     }
589     
590     return NO;
591 }
592
593 - (WebDataSource *)_dataSource
594 {
595     return _private->dataSource;
596 }
597
598 - (WebView *)_webView
599 {
600     return [_private->dataSource _webView];
601 }
602
603 - (WebFrameView *)_frameView
604 {
605     return [[_private->dataSource webFrame] frameView];
606 }
607
608 - (DOMDocumentFragment *)_documentFragmentWithPaths:(NSArray *)paths
609 {
610     DOMDocumentFragment *fragment;
611     NSEnumerator *enumerator = [paths objectEnumerator];
612     NSMutableArray *domNodes = [[NSMutableArray alloc] init];
613     NSString *path;
614     
615     while ((path = [enumerator nextObject]) != nil) {
616         // Non-image file types; _web_userVisibleString is appropriate here because this will
617         // be pasted as visible text.
618         NSString *url = [[[NSURL fileURLWithPath:path] _webkit_canonicalize] _web_userVisibleString];
619         [domNodes addObject:[[[self _frame] DOMDocument] createTextNode: url]];
620     }
621     
622     fragment = [[self _frame] _documentFragmentWithNodesAsParagraphs:domNodes]; 
623     
624     [domNodes release];
625     
626     return [fragment firstChild] != nil ? fragment : nil;
627 }
628
629 + (NSArray *)_excludedElementsForAttributedStringConversion
630 {
631     static NSArray *elements = nil;
632     if (elements == nil) {
633         elements = [[NSArray alloc] initWithObjects:
634             // Omit style since we want style to be inline so the fragment can be easily inserted.
635             @"style",
636             // Omit xml so the result is not XHTML.
637             @"xml", 
638             // Omit tags that will get stripped when converted to a fragment anyway.
639             @"doctype", @"html", @"head", @"body",
640             // Omit deprecated tags.
641             @"applet", @"basefont", @"center", @"dir", @"font", @"isindex", @"menu", @"s", @"strike", @"u",
642             // Omit object so no file attachments are part of the fragment.
643             @"object", nil];
644         CFRetain(elements);
645     }
646     return elements;
647 }
648
649 static NSURL* uniqueURLWithRelativePart(NSString *relativePart)
650 {
651     CFUUIDRef UUIDRef = CFUUIDCreate(kCFAllocatorDefault);
652     NSString *UUIDString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, UUIDRef);
653     CFRelease(UUIDRef);
654     NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@/%@", WebDataProtocolScheme, UUIDString, relativePart]];
655     CFRelease(UUIDString);
656
657     return URL;
658 }
659
660 - (DOMDocumentFragment *)_documentFragmentFromPasteboard:(NSPasteboard *)pasteboard
661                                                inContext:(DOMRange *)context
662                                           allowPlainText:(BOOL)allowPlainText
663 {
664     NSArray *types = [pasteboard types];
665     DOMDocumentFragment *fragment = nil;
666
667     if ([types containsObject:WebArchivePboardType] &&
668         (fragment = [self _documentFragmentFromPasteboard:pasteboard 
669                                                   forType:WebArchivePboardType
670                                                 inContext:context
671                                              subresources:0]))
672         return fragment;
673                                            
674     if ([types containsObject:NSFilenamesPboardType] &&
675         (fragment = [self _documentFragmentFromPasteboard:pasteboard 
676                                                   forType:NSFilenamesPboardType
677                                                 inContext:context
678                                              subresources:0]))
679         return fragment;
680     
681     if ([types containsObject:NSHTMLPboardType] &&
682         (fragment = [self _documentFragmentFromPasteboard:pasteboard 
683                                                   forType:NSHTMLPboardType
684                                                 inContext:context
685                                              subresources:0]))
686         return fragment;
687     
688     if ([types containsObject:NSRTFPboardType] &&
689         (fragment = [self _documentFragmentFromPasteboard:pasteboard 
690                                                   forType:NSRTFPboardType
691                                                 inContext:context
692                                              subresources:0]))
693         return fragment;
694
695     if ([types containsObject:NSRTFDPboardType] &&
696         (fragment = [self _documentFragmentFromPasteboard:pasteboard 
697                                                   forType:NSRTFDPboardType
698                                                 inContext:context
699                                              subresources:0]))
700         return fragment;
701
702     if ([types containsObject:NSTIFFPboardType] &&
703         (fragment = [self _documentFragmentFromPasteboard:pasteboard 
704                                                   forType:NSTIFFPboardType
705                                                 inContext:context
706                                              subresources:0]))
707         return fragment;
708
709 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
710     if ([types containsObject:NSPICTPboardType] &&
711         (fragment = [self _documentFragmentFromPasteboard:pasteboard 
712                                                   forType:NSPICTPboardType
713                                                 inContext:context
714                                              subresources:0]))
715         return fragment;
716 #endif
717
718     // Only 10.5 and higher support setting and retrieving pasteboard types with UTIs, but we don't believe
719     // that any applications on Tiger put types for which we only have a UTI, like PNG, on the pasteboard.
720     if ([types containsObject:(NSString*)kUTTypePNG] &&
721         (fragment = [self _documentFragmentFromPasteboard:pasteboard 
722                                                   forType:(NSString*)kUTTypePNG
723                                                 inContext:context
724                                              subresources:0]))
725         return fragment;
726         
727     if ([types containsObject:NSURLPboardType] &&
728         (fragment = [self _documentFragmentFromPasteboard:pasteboard 
729                                                   forType:NSURLPboardType
730                                                 inContext:context
731                                              subresources:0]))
732         return fragment;
733         
734     if (allowPlainText && [types containsObject:NSStringPboardType] &&
735         (fragment = [self _documentFragmentFromPasteboard:pasteboard
736                                                   forType:NSStringPboardType
737                                                 inContext:context
738                                              subresources:0])) {
739         return fragment;
740     }
741     
742     return nil;
743 }
744
745 - (NSString *)_plainTextFromPasteboard:(NSPasteboard *)pasteboard
746 {
747     NSArray *types = [pasteboard types];
748     
749     if ([types containsObject:NSStringPboardType])
750         return [pasteboard stringForType:NSStringPboardType];
751     
752     NSAttributedString *attributedString = nil;
753     NSString *string;
754
755     if ([types containsObject:NSRTFDPboardType])
756         attributedString = [[NSAttributedString alloc] initWithRTFD:[pasteboard dataForType:NSRTFDPboardType] documentAttributes:NULL];
757     if (attributedString == nil && [types containsObject:NSRTFPboardType])
758         attributedString = [[NSAttributedString alloc] initWithRTF:[pasteboard dataForType:NSRTFPboardType] documentAttributes:NULL];
759     if (attributedString != nil) {
760         string = [[attributedString string] copy];
761         [attributedString release];
762         return [string autorelease];
763     }
764     
765     if ([types containsObject:NSFilenamesPboardType]) {
766         string = [[pasteboard propertyListForType:NSFilenamesPboardType] componentsJoinedByString:@"\n"];
767         if (string != nil)
768             return string;
769     }
770     
771     NSURL *URL;
772     
773     if ((URL = [NSURL URLFromPasteboard:pasteboard])) {
774         string = [URL _web_userVisibleString];
775         if ([string length] > 0)
776             return string;
777     }
778     
779     return nil;
780 }
781
782 - (void)_pasteWithPasteboard:(NSPasteboard *)pasteboard allowPlainText:(BOOL)allowPlainText
783 {
784     WebView *webView = [[self _webView] retain];
785     [webView _setInsertionPasteboard:pasteboard];
786
787     DOMRange *range = [self _selectedRange];
788     DOMDocumentFragment *fragment = [self _documentFragmentFromPasteboard:pasteboard inContext:range allowPlainText:allowPlainText];
789     if (fragment && [self _shouldInsertFragment:fragment replacingDOMRange:range givenAction:WebViewInsertActionPasted])
790         [[self _frame] _replaceSelectionWithFragment:fragment selectReplacement:NO smartReplace:[self _canSmartReplaceWithPasteboard:pasteboard] matchStyle:NO];
791
792     [webView _setInsertionPasteboard:nil];
793     [webView release];
794 }
795
796 - (void)_pasteAsPlainTextWithPasteboard:(NSPasteboard *)pasteboard
797 {
798     WebView *webView = [[self _webView] retain];
799     [webView _setInsertionPasteboard:pasteboard];
800
801     NSString *text = [self _plainTextFromPasteboard:pasteboard];
802     if ([self _shouldReplaceSelectionWithText:text givenAction:WebViewInsertActionPasted])
803         [[self _frame] _replaceSelectionWithText:text selectReplacement:NO smartReplace:[self _canSmartReplaceWithPasteboard:pasteboard]];
804
805     [webView _setInsertionPasteboard:nil];
806     [webView release];
807 }
808
809 - (void)_removeMouseMovedObserverUnconditionally
810 {
811     if (!_private || !_private->observingMouseMovedNotifications)
812         return;
813     
814     [[NSNotificationCenter defaultCenter] removeObserver:self name:WKMouseMovedNotification() object:nil];
815     _private->observingMouseMovedNotifications = false;
816 }
817
818 - (void)_removeSuperviewObservers
819 {
820     if (!_private || !_private->observingSuperviewNotifications)
821         return;
822     
823     NSView *superview = [self superview];
824     if (!superview || ![self window])
825         return;
826     
827     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
828     [notificationCenter removeObserver:self name:NSViewFrameDidChangeNotification object:superview];
829     [notificationCenter removeObserver:self name:NSViewBoundsDidChangeNotification object:superview];
830     
831     _private->observingSuperviewNotifications = false;
832 }
833
834 - (void)_removeWindowObservers
835 {
836     if (!_private->observingWindowNotifications)
837         return;
838     
839     NSWindow *window = [self window];
840     if (!window)
841         return;
842     
843     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
844     [notificationCenter removeObserver:self name:NSWindowDidBecomeKeyNotification object:nil];
845     [notificationCenter removeObserver:self name:NSWindowDidResignKeyNotification object:nil];
846     [notificationCenter removeObserver:self name:NSWindowWillCloseNotification object:window];
847     [notificationCenter removeObserver:self name:WKWindowWillOrderOnScreenNotification() object:window];
848     
849     _private->observingWindowNotifications = false;
850 }
851
852 - (BOOL)_shouldInsertFragment:(DOMDocumentFragment *)fragment replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action
853 {
854     WebView *webView = [self _webView];
855     DOMNode *child = [fragment firstChild];
856     if ([fragment lastChild] == child && [child isKindOfClass:[DOMCharacterData class]])
857         return [[webView _editingDelegateForwarder] webView:webView shouldInsertText:[(DOMCharacterData *)child data] replacingDOMRange:range givenAction:action];
858     return [[webView _editingDelegateForwarder] webView:webView shouldInsertNode:fragment replacingDOMRange:range givenAction:action];
859 }
860
861 - (BOOL)_shouldInsertText:(NSString *)text replacingDOMRange:(DOMRange *)range givenAction:(WebViewInsertAction)action
862 {
863     WebView *webView = [self _webView];
864     return [[webView _editingDelegateForwarder] webView:webView shouldInsertText:text replacingDOMRange:range givenAction:action];
865 }
866
867 - (BOOL)_shouldReplaceSelectionWithText:(NSString *)text givenAction:(WebViewInsertAction)action
868 {
869     return [self _shouldInsertText:text replacingDOMRange:[self _selectedRange] givenAction:action];
870 }
871
872 // Calculate the vertical size of the view that fits on a single page
873 - (float)_calculatePrintHeight
874 {
875     // Obtain the print info object for the current operation
876     NSPrintInfo *pi = [[NSPrintOperation currentOperation] printInfo];
877     
878     // Calculate the page height in points
879     NSSize paperSize = [pi paperSize];
880     return paperSize.height - [pi topMargin] - [pi bottomMargin];
881 }
882
883 - (DOMRange *)_selectedRange
884 {
885     Frame* coreFrame = core([self _frame]);
886     return coreFrame ? kit(coreFrame->selection()->toNormalizedRange().get()) : nil;
887 }
888
889 - (BOOL)_shouldDeleteRange:(DOMRange *)range
890 {
891     Frame* coreFrame = core([self _frame]);
892     return coreFrame && coreFrame->editor()->shouldDeleteRange(core(range));
893 }
894
895 - (NSView *)_hitViewForEvent:(NSEvent *)event
896 {
897     // Usually, we hack AK's hitTest method to catch all events at the topmost WebHTMLView.  
898     // Callers of this method, however, want to query the deepest view instead.
899     forceNSViewHitTest = YES;
900     NSView *hitView = [[[self window] contentView] hitTest:[event locationInWindow]];
901     forceNSViewHitTest = NO;    
902     return hitView;
903 }
904
905 - (void)_writeSelectionWithPasteboardTypes:(NSArray *)types toPasteboard:(NSPasteboard *)pasteboard cachedAttributedString:(NSAttributedString *)attributedString
906 {
907     // Put HTML on the pasteboard.
908     if ([types containsObject:WebArchivePboardType]) {
909         if (RefPtr<LegacyWebArchive> coreArchive = LegacyWebArchive::createFromSelection(core([self _frame]))) {
910             if (RetainPtr<CFDataRef> data = coreArchive ? coreArchive->rawDataRepresentation() : 0)
911                 [pasteboard setData:(NSData *)data.get() forType:WebArchivePboardType];
912         }
913     }
914     
915     // Put the attributed string on the pasteboard (RTF/RTFD format).
916     if ([types containsObject:NSRTFDPboardType]) {
917         if (attributedString == nil) {
918             attributedString = [self selectedAttributedString];
919         }        
920         NSData *RTFDData = [attributedString RTFDFromRange:NSMakeRange(0, [attributedString length]) documentAttributes:nil];
921         [pasteboard setData:RTFDData forType:NSRTFDPboardType];
922     }        
923     if ([types containsObject:NSRTFPboardType]) {
924         if (attributedString == nil) {
925             attributedString = [self selectedAttributedString];
926         }
927         if ([attributedString containsAttachments]) {
928             attributedString = [attributedString _web_attributedStringByStrippingAttachmentCharacters];
929         }
930         NSData *RTFData = [attributedString RTFFromRange:NSMakeRange(0, [attributedString length]) documentAttributes:nil];
931         [pasteboard setData:RTFData forType:NSRTFPboardType];
932     }
933     
934     // Put plain string on the pasteboard.
935     if ([types containsObject:NSStringPboardType]) {
936         // Map &nbsp; to a plain old space because this is better for source code, other browsers do it,
937         // and because HTML forces you to do this any time you want two spaces in a row.
938         NSMutableString *s = [[self selectedString] mutableCopy];
939         const unichar NonBreakingSpaceCharacter = 0xA0;
940         NSString *NonBreakingSpaceString = [NSString stringWithCharacters:&NonBreakingSpaceCharacter length:1];
941         [s replaceOccurrencesOfString:NonBreakingSpaceString withString:@" " options:0 range:NSMakeRange(0, [s length])];
942         [pasteboard setString:s forType:NSStringPboardType];
943         [s release];
944     }
945     
946     if ([self _canSmartCopyOrDelete] && [types containsObject:WebSmartPastePboardType]) {
947         [pasteboard setData:nil forType:WebSmartPastePboardType];
948     }
949 }
950
951 - (void)_setMouseDownEvent:(NSEvent *)event
952 {
953     ASSERT(!event || [event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown);
954
955     if (event == _private->mouseDownEvent)
956         return;
957
958     [event retain];
959     [_private->mouseDownEvent release];
960     _private->mouseDownEvent = event;
961 }
962
963 - (void)_cancelUpdateFocusedAndActiveStateTimer
964 {
965     if (_private->updateFocusedAndActiveStateTimer) {
966         CFRunLoopTimerInvalidate(_private->updateFocusedAndActiveStateTimer);
967         CFRelease(_private->updateFocusedAndActiveStateTimer);
968         _private->updateFocusedAndActiveStateTimer = NULL;
969     }
970 }
971
972 - (void)_cancelUpdateMouseoverTimer
973 {
974     if (_private->updateMouseoverTimer) {
975         CFRunLoopTimerInvalidate(_private->updateMouseoverTimer);
976         CFRelease(_private->updateMouseoverTimer);
977         _private->updateMouseoverTimer = NULL;
978     }
979 }
980
981 - (WebHTMLView *)_topHTMLView
982 {
983     // FIXME: this can fail if the dataSource is nil, which happens when the WebView is tearing down from the window closing.
984     WebHTMLView *view = (WebHTMLView *)[[[[_private->dataSource _webView] mainFrame] frameView] documentView];
985     ASSERT(view);
986     ASSERT([view isKindOfClass:[WebHTMLView class]]);
987     return view;
988 }
989
990 - (BOOL)_isTopHTMLView
991 {
992     // FIXME: this should be a cached boolean that doesn't rely on _topHTMLView since that can fail (see _topHTMLView).
993     return self == [self _topHTMLView];
994 }
995
996 - (void)_web_setPrintingModeRecursive
997 {
998     [self _setPrinting:YES minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:NO];
999
1000 #ifndef NDEBUG
1001     _private->enumeratingSubviews = YES;
1002 #endif
1003
1004     NSMutableArray *descendantWebHTMLViews = [[NSMutableArray alloc] init];
1005
1006     [self _web_addDescendantWebHTMLViewsToArray:descendantWebHTMLViews];
1007
1008     unsigned count = [descendantWebHTMLViews count];
1009     for (unsigned i = 0; i < count; ++i)
1010         [[descendantWebHTMLViews objectAtIndex:i] _setPrinting:YES minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:NO];
1011
1012     [descendantWebHTMLViews release];
1013
1014 #ifndef NDEBUG
1015     _private->enumeratingSubviews = NO;
1016 #endif
1017 }
1018
1019 - (void)_web_clearPrintingModeRecursive
1020 {
1021     [self _setPrinting:NO minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:NO];
1022
1023 #ifndef NDEBUG
1024     _private->enumeratingSubviews = YES;
1025 #endif
1026
1027     NSMutableArray *descendantWebHTMLViews = [[NSMutableArray alloc] init];
1028
1029     [self _web_addDescendantWebHTMLViewsToArray:descendantWebHTMLViews];
1030
1031     unsigned count = [descendantWebHTMLViews count];
1032     for (unsigned i = 0; i < count; ++i)
1033         [[descendantWebHTMLViews objectAtIndex:i] _setPrinting:NO minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:NO];
1034
1035     [descendantWebHTMLViews release];
1036
1037 #ifndef NDEBUG
1038     _private->enumeratingSubviews = NO;
1039 #endif
1040 }
1041
1042 - (void)_web_setPrintingModeRecursiveAndAdjustViewSize
1043 {
1044     [self _setPrinting:YES minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:YES];
1045
1046 #ifndef NDEBUG
1047     _private->enumeratingSubviews = YES;
1048 #endif
1049
1050     NSMutableArray *descendantWebHTMLViews = [[NSMutableArray alloc] init];
1051
1052     [self _web_addDescendantWebHTMLViewsToArray:descendantWebHTMLViews];
1053
1054     unsigned count = [descendantWebHTMLViews count];
1055     for (unsigned i = 0; i < count; ++i)
1056         [[descendantWebHTMLViews objectAtIndex:i] _setPrinting:YES minimumPageWidth:0.0f maximumPageWidth:0.0f adjustViewSize:YES];
1057
1058     [descendantWebHTMLViews release];
1059
1060 #ifndef NDEBUG
1061     _private->enumeratingSubviews = NO;
1062 #endif
1063 }
1064
1065 @end
1066
1067 @implementation WebHTMLView (WebPrivate)
1068
1069 + (NSArray *)supportedMIMETypes
1070 {
1071     return [WebHTMLRepresentation supportedMIMETypes];
1072 }
1073
1074 + (NSArray *)supportedImageMIMETypes
1075 {
1076     return [WebHTMLRepresentation supportedImageMIMETypes];
1077 }
1078
1079 + (NSArray *)supportedNonImageMIMETypes
1080 {
1081     return [WebHTMLRepresentation supportedNonImageMIMETypes];
1082 }
1083
1084 + (NSArray *)unsupportedTextMIMETypes
1085 {
1086     return [NSArray arrayWithObjects:
1087         @"text/calendar",       // iCal
1088         @"text/x-calendar",
1089         @"text/x-vcalendar",
1090         @"text/vcalendar",
1091         @"text/vcard",          // vCard
1092         @"text/x-vcard",
1093         @"text/directory",
1094         @"text/ldif",           // Netscape Address Book
1095         @"text/qif",            // Quicken
1096         @"text/x-qif",
1097         @"text/x-csv",          // CSV (for Address Book and Microsoft Outlook)
1098         @"text/x-vcf",          // vCard type used in Sun affinity app
1099         @"text/rtf",            // Rich Text Format
1100         nil];
1101 }
1102
1103 + (void)_postFlagsChangedEvent:(NSEvent *)flagsChangedEvent
1104 {
1105     // This is a workaround for: <rdar://problem/2981619> NSResponder_Private should include notification for FlagsChanged
1106     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
1107         location:[[flagsChangedEvent window] convertScreenToBase:[NSEvent mouseLocation]]
1108         modifierFlags:[flagsChangedEvent modifierFlags]
1109         timestamp:[flagsChangedEvent timestamp]
1110         windowNumber:[flagsChangedEvent windowNumber]
1111         context:[flagsChangedEvent context]
1112         eventNumber:0 clickCount:0 pressure:0];
1113
1114     // Pretend it's a mouse move.
1115     [[NSNotificationCenter defaultCenter]
1116         postNotificationName:WKMouseMovedNotification() object:self
1117         userInfo:[NSDictionary dictionaryWithObject:fakeEvent forKey:@"NSEvent"]];
1118 }
1119
1120 - (id)_bridge
1121 {
1122     // This method exists to maintain compatibility with Leopard's Dictionary.app, since it
1123     // calls _bridge to get access to convertNSRangeToDOMRange: and convertDOMRangeToNSRange:.
1124     // Return the WebFrame, which implements the compatibility methods. <rdar://problem/6002160>
1125     return [self _frame];
1126 }
1127
1128 - (void)_updateMouseoverWithFakeEvent
1129 {
1130     [self _cancelUpdateMouseoverTimer];
1131     
1132     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved
1133         location:[[self window] convertScreenToBase:[NSEvent mouseLocation]]
1134         modifierFlags:[[NSApp currentEvent] modifierFlags]
1135         timestamp:[NSDate timeIntervalSinceReferenceDate]
1136         windowNumber:[[self window] windowNumber]
1137         context:[[NSApp currentEvent] context]
1138         eventNumber:0 clickCount:0 pressure:0];
1139     
1140     [self _updateMouseoverWithEvent:fakeEvent];
1141 }
1142
1143 static void _updateMouseoverTimerCallback(CFRunLoopTimerRef timer, void *info)
1144 {
1145     WebHTMLView *view = (WebHTMLView *)info;
1146     
1147     [view _updateMouseoverWithFakeEvent];
1148 }
1149
1150 - (void)_frameOrBoundsChanged
1151 {
1152     if (!NSEqualSizes(_private->lastLayoutSize, [(NSClipView *)[self superview] documentVisibleRect].size)) {
1153         [self setNeedsLayout:YES];
1154         [self setNeedsDisplay:YES];
1155         [_private->compController endRevertingChange:NO moveLeft:NO];
1156     }
1157
1158     NSPoint origin = [[self superview] bounds].origin;
1159     if (!NSEqualPoints(_private->lastScrollPosition, origin)) {
1160         if (Frame* coreFrame = core([self _frame]))
1161             coreFrame->eventHandler()->sendScrollEvent();
1162         [_private->compController endRevertingChange:NO moveLeft:NO];
1163         
1164         WebView *webView = [self _webView];
1165         [[webView _UIDelegateForwarder] webView:webView didScrollDocumentInFrameView:[self _frameView]];
1166     }
1167     _private->lastScrollPosition = origin;
1168
1169     if ([self window] && !_private->closed && !_private->updateMouseoverTimer) {
1170         CFRunLoopTimerContext context = { 0, self, NULL, NULL, NULL };
1171         
1172         // Use a 100ms delay so that the synthetic mouse over update doesn't cause cursor thrashing when pages are loading
1173         // and scrolling rapidly back to back.
1174         _private->updateMouseoverTimer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent() + 0.1, 0, 0, 0,
1175                                                               _updateMouseoverTimerCallback, &context);
1176         CFRunLoopAddTimer(CFRunLoopGetCurrent(), _private->updateMouseoverTimer, kCFRunLoopDefaultMode);
1177     }
1178 }
1179
1180 - (void)_setAsideSubviews
1181 {
1182     ASSERT(!_private->subviewsSetAside);
1183     ASSERT(_private->savedSubviews == nil);
1184     _private->savedSubviews = _subviews;
1185 #if USE(ACCELERATED_COMPOSITING)
1186     // We need to keep the layer-hosting view in the subviews, otherwise the layers flash.
1187     if (_private->layerHostingView) {
1188         NSArray* newSubviews = [[NSArray alloc] initWithObjects:_private->layerHostingView, nil];
1189         _subviews = newSubviews;
1190     } else
1191         _subviews = nil;
1192 #else
1193     _subviews = nil;
1194 #endif    
1195     _private->subviewsSetAside = YES;
1196  }
1197  
1198  - (void)_restoreSubviews
1199  {
1200     ASSERT(_private->subviewsSetAside);
1201 #if USE(ACCELERATED_COMPOSITING)
1202     if (_private->layerHostingView) {
1203         [_subviews release];
1204         _subviews = _private->savedSubviews;
1205     } else {
1206         ASSERT(_subviews == nil);
1207         _subviews = _private->savedSubviews;
1208     }
1209 #else
1210     ASSERT(_subviews == nil);
1211     _subviews = _private->savedSubviews;
1212 #endif    
1213     _private->savedSubviews = nil;
1214     _private->subviewsSetAside = NO;
1215 }
1216
1217 #ifndef NDEBUG
1218
1219 - (void)didAddSubview:(NSView *)subview
1220 {
1221     if (_private->enumeratingSubviews)
1222         LOG(View, "A view of class %s was added during subview enumeration for layout or printing mode change. This view might paint without first receiving layout.", object_getClassName([subview class]));
1223 }
1224
1225 - (void)willRemoveSubview:(NSView *)subview
1226 {
1227     // Have to null-check _private, since this can be called via -dealloc when
1228     // cleaning up the the layerHostingView.
1229     if (_private && _private->enumeratingSubviews)
1230         LOG(View, "A view of class %s was removed during subview enumeration for layout or printing mode change. We will still do layout or the printing mode change even though this view is no longer in the view hierarchy.", object_getClassName([subview class]));
1231 }
1232
1233 #endif
1234
1235 #ifdef BUILDING_ON_TIGER
1236
1237 // This is called when we are about to draw, but before our dirty rect is propagated to our ancestors.
1238 // That's the perfect time to do a layout, except that ideally we'd want to be sure that we're dirty
1239 // before doing it. As a compromise, when we're opaque we do the layout only when actually asked to
1240 // draw, but when we're transparent we do the layout at this stage so views behind us know that they
1241 // need to be redrawn (in case the layout causes some things to get dirtied).
1242 - (void)_propagateDirtyRectsToOpaqueAncestors
1243 {
1244     if (![[self _webView] drawsBackground])
1245         [self _web_layoutIfNeededRecursive];
1246     [super _propagateDirtyRectsToOpaqueAncestors];
1247 }
1248
1249 #else
1250
1251 - (void)viewWillDraw
1252 {
1253     // On window close we will be called when the datasource is nil, then hit an assert in _topHTMLView
1254     // So check if the dataSource is nil before calling [self _isTopHTMLView], this can be removed
1255     // once the FIXME in _isTopHTMLView is fixed.
1256     if (_private->dataSource && [self _isTopHTMLView])
1257         [self _web_layoutIfNeededRecursive];
1258     [super viewWillDraw];
1259 }
1260
1261 #endif
1262
1263 // Don't let AppKit even draw subviews. We take care of that.
1264 - (void)_recursiveDisplayRectIfNeededIgnoringOpacity:(NSRect)rect isVisibleRect:(BOOL)isVisibleRect rectIsVisibleRectForView:(NSView *)visibleView topView:(BOOL)topView
1265 {
1266     // This helps when we print as part of a larger print process.
1267     // If the WebHTMLView itself is what we're printing, then we will never have to do this.
1268     BOOL wasInPrintingMode = _private->printing;
1269     BOOL isPrinting = ![NSGraphicsContext currentContextDrawingToScreen];
1270     if (isPrinting) {
1271         if (!wasInPrintingMode)
1272             [self _web_setPrintingModeRecursive];
1273 #ifndef BUILDING_ON_TIGER
1274         else
1275             [self _web_layoutIfNeededRecursive];
1276 #endif
1277     } else if (wasInPrintingMode)
1278         [self _web_clearPrintingModeRecursive];
1279
1280 #ifdef BUILDING_ON_TIGER
1281
1282     // Because Tiger does not have viewWillDraw we need to do layout here.
1283     [self _web_layoutIfNeededRecursive];
1284     [_subviews makeObjectsPerformSelector:@selector(_propagateDirtyRectsToOpaqueAncestors)];
1285
1286 #endif
1287
1288     [self _setAsideSubviews];
1289     [super _recursiveDisplayRectIfNeededIgnoringOpacity:rect isVisibleRect:isVisibleRect rectIsVisibleRectForView:visibleView topView:topView];
1290     [self _restoreSubviews];
1291
1292     if (wasInPrintingMode != isPrinting) {
1293         if (wasInPrintingMode)
1294             [self _web_setPrintingModeRecursive];
1295         else
1296             [self _web_clearPrintingModeRecursive];
1297     }
1298 }
1299
1300 // Don't let AppKit even draw subviews. We take care of that.
1301 - (void)_recursiveDisplayAllDirtyWithLockFocus:(BOOL)needsLockFocus visRect:(NSRect)visRect
1302 {
1303     BOOL needToSetAsideSubviews = !_private->subviewsSetAside;
1304
1305     BOOL wasInPrintingMode = _private->printing;
1306     BOOL isPrinting = ![NSGraphicsContext currentContextDrawingToScreen];
1307
1308     if (needToSetAsideSubviews) {
1309         // This helps when we print as part of a larger print process.
1310         // If the WebHTMLView itself is what we're printing, then we will never have to do this.
1311         if (isPrinting) {
1312             if (!wasInPrintingMode)
1313                 [self _web_setPrintingModeRecursive];
1314 #ifndef BUILDING_ON_TIGER
1315             else
1316                 [self _web_layoutIfNeededRecursive];
1317 #endif
1318         } else if (wasInPrintingMode)
1319             [self _web_clearPrintingModeRecursive];
1320
1321 #ifdef BUILDING_ON_TIGER
1322
1323         // Because Tiger does not have viewWillDraw we need to do layout here.
1324         NSRect boundsBeforeLayout = [self bounds];
1325         if (!NSIsEmptyRect(visRect))
1326             [self _web_layoutIfNeededRecursive];
1327
1328         // If layout changes the view's bounds, then we need to recompute the visRect.
1329         // That's because the visRect passed to us was based on the bounds at the time
1330         // we were called. This method is only displayed to draw "all", so it's safe
1331         // to just call visibleRect to compute the entire rectangle.
1332         if (!NSEqualRects(boundsBeforeLayout, [self bounds]))
1333             visRect = [self visibleRect];
1334
1335 #endif
1336
1337         [self _setAsideSubviews];
1338     }
1339
1340     [super _recursiveDisplayAllDirtyWithLockFocus:needsLockFocus visRect:visRect];
1341
1342     if (needToSetAsideSubviews) {
1343         if (wasInPrintingMode != isPrinting) {
1344             if (wasInPrintingMode)
1345                 [self _web_setPrintingModeRecursive];
1346             else
1347                 [self _web_clearPrintingModeRecursive];
1348         }
1349
1350         [self _restoreSubviews];
1351     }
1352 }
1353
1354 // Don't let AppKit even draw subviews. We take care of that.
1355 - (void)_recursive:(BOOL)recurse displayRectIgnoringOpacity:(NSRect)displayRect inContext:(NSGraphicsContext *)context topView:(BOOL)topView
1356 {
1357 #ifdef BUILDING_ON_TIGER 
1358     // Because Tiger does not have viewWillDraw we need to do layout here.
1359     [self _web_layoutIfNeededRecursive];
1360 #endif
1361
1362     [self _setAsideSubviews];
1363     [super _recursive:recurse displayRectIgnoringOpacity:displayRect inContext:context topView:topView];
1364     [self _restoreSubviews];
1365 }
1366
1367 - (BOOL)_insideAnotherHTMLView
1368 {
1369     return self != [self _topHTMLView];
1370 }
1371
1372 - (NSView *)hitTest:(NSPoint)point
1373 {
1374     // WebHTMLView objects handle all events for objects inside them.
1375     // To get those events, we prevent hit testing from AppKit.
1376
1377     // But there are three exceptions to this:
1378     //   1) For right mouse clicks and control clicks we don't yet have an implementation
1379     //      that works for nested views, so we let the hit testing go through the
1380     //      standard NSView code path (needs to be fixed, see bug 4361618).
1381     //   2) Java depends on doing a hit test inside it's mouse moved handling,
1382     //      so we let the hit testing go through the standard NSView code path
1383     //      when the current event is a mouse move (except when we are calling
1384     //      from _updateMouseoverWithEvent, so we have to use a global,
1385     //      forceWebHTMLViewHitTest, for that)
1386     //   3) The acceptsFirstMouse: and shouldDelayWindowOrderingForEvent: methods
1387     //      both need to figure out which view to check with inside the WebHTMLView.
1388     //      They use a global to change the behavior of hitTest: so they can get the
1389     //      right view. The global is forceNSViewHitTest and the method they use to
1390     //      do the hit testing is _hitViewForEvent:. (But this does not work correctly
1391     //      when there is HTML overlapping the view, see bug 4361626)
1392     //   4) NSAccessibilityHitTest relies on this for checking the cursor position.
1393     //      Our check for that is whether the event is NSFlagsChanged.  This works
1394     //      for VoiceOver's cntl-opt-f5 command (move focus to item under cursor)
1395     //      and Dictionary's cmd-cntl-D (open dictionary popup for item under cursor).
1396     //      This is of course a hack.
1397
1398     BOOL captureHitsOnSubviews;
1399     if (forceNSViewHitTest)
1400         captureHitsOnSubviews = NO;
1401     else if (forceWebHTMLViewHitTest)
1402         captureHitsOnSubviews = YES;
1403     else {
1404         NSEvent *event = [[self window] currentEvent];
1405         captureHitsOnSubviews = !([event type] == NSMouseMoved
1406             || [event type] == NSRightMouseDown
1407             || ([event type] == NSLeftMouseDown && ([event modifierFlags] & NSControlKeyMask) != 0)
1408             || [event type] == NSFlagsChanged);
1409     }
1410
1411     if (!captureHitsOnSubviews)
1412         return [super hitTest:point];
1413     if ([[self superview] mouse:point inRect:[self frame]])
1414         return self;
1415     return nil;
1416 }
1417
1418 - (void)_clearLastHitViewIfSelf
1419 {
1420     if (lastHitView == self)
1421         lastHitView = nil;
1422 }
1423
1424 - (NSTrackingRectTag)addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside
1425 {
1426     ASSERT(_private->trackingRectOwner == nil);
1427     _private->trackingRectOwner = owner;
1428     _private->trackingRectUserData = data;
1429     return TRACKING_RECT_TAG;
1430 }
1431
1432 - (NSTrackingRectTag)_addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside useTrackingNum:(int)tag
1433 {
1434     ASSERT(tag == 0 || tag == TRACKING_RECT_TAG);
1435     ASSERT(_private->trackingRectOwner == nil);
1436     _private->trackingRectOwner = owner;
1437     _private->trackingRectUserData = data;
1438     return TRACKING_RECT_TAG;
1439 }
1440
1441 - (void)_addTrackingRects:(NSRect *)rects owner:(id)owner userDataList:(void **)userDataList assumeInsideList:(BOOL *)assumeInsideList trackingNums:(NSTrackingRectTag *)trackingNums count:(int)count
1442 {
1443     ASSERT(count == 1);
1444     ASSERT(trackingNums[0] == 0 || trackingNums[0] == TRACKING_RECT_TAG);
1445     ASSERT(_private->trackingRectOwner == nil);
1446     _private->trackingRectOwner = owner;
1447     _private->trackingRectUserData = userDataList[0];
1448     trackingNums[0] = TRACKING_RECT_TAG;
1449 }
1450
1451 - (void)removeTrackingRect:(NSTrackingRectTag)tag
1452 {
1453     if (tag == 0)
1454         return;
1455     
1456     if (_private && (tag == TRACKING_RECT_TAG)) {
1457         _private->trackingRectOwner = nil;
1458         return;
1459     }
1460     
1461     if (_private && (tag == _private->lastToolTipTag)) {
1462         [super removeTrackingRect:tag];
1463         _private->lastToolTipTag = 0;
1464         return;
1465     }
1466     
1467     // If any other tracking rect is being removed, we don't know how it was created
1468     // and it's possible there's a leak involved (see 3500217)
1469     ASSERT_NOT_REACHED();
1470 }
1471
1472 - (void)_removeTrackingRects:(NSTrackingRectTag *)tags count:(int)count
1473 {
1474     int i;
1475     for (i = 0; i < count; ++i) {
1476         int tag = tags[i];
1477         if (tag == 0)
1478             continue;
1479         ASSERT(tag == TRACKING_RECT_TAG);
1480         if (_private != nil) {
1481             _private->trackingRectOwner = nil;
1482         }
1483     }
1484 }
1485
1486 - (void)_sendToolTipMouseExited
1487 {
1488     // Nothing matters except window, trackingNumber, and userData.
1489     NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSMouseExited
1490         location:NSMakePoint(0, 0)
1491         modifierFlags:0
1492         timestamp:0
1493         windowNumber:[[self window] windowNumber]
1494         context:NULL
1495         eventNumber:0
1496         trackingNumber:TRACKING_RECT_TAG
1497         userData:_private->trackingRectUserData];
1498     [_private->trackingRectOwner mouseExited:fakeEvent];
1499 }
1500
1501 - (void)_sendToolTipMouseEntered
1502 {
1503     // Nothing matters except window, trackingNumber, and userData.
1504     NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSMouseEntered
1505         location:NSMakePoint(0, 0)
1506         modifierFlags:0
1507         timestamp:0
1508         windowNumber:[[self window] windowNumber]
1509         context:NULL
1510         eventNumber:0
1511         trackingNumber:TRACKING_RECT_TAG
1512         userData:_private->trackingRectUserData];
1513     [_private->trackingRectOwner mouseEntered:fakeEvent];
1514 }
1515
1516 - (void)_setToolTip:(NSString *)string
1517 {
1518     NSString *toolTip = [string length] == 0 ? nil : string;
1519     NSString *oldToolTip = _private->toolTip;
1520     if ((toolTip == nil || oldToolTip == nil) ? toolTip == oldToolTip : [toolTip isEqualToString:oldToolTip]) {
1521         return;
1522     }
1523     if (oldToolTip) {
1524         [self _sendToolTipMouseExited];
1525         [oldToolTip release];
1526     }
1527     _private->toolTip = [toolTip copy];
1528     if (toolTip) {
1529         // See radar 3500217 for why we remove all tooltips rather than just the single one we created.
1530         [self removeAllToolTips];
1531         NSRect wideOpenRect = NSMakeRect(-100000, -100000, 200000, 200000);
1532         _private->lastToolTipTag = [self addToolTipRect:wideOpenRect owner:self userData:NULL];
1533         [self _sendToolTipMouseEntered];
1534     }
1535 }
1536
1537 - (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(NSPoint)point userData:(void *)data
1538 {
1539     return [[_private->toolTip copy] autorelease];
1540 }
1541
1542 - (void)_updateMouseoverWithEvent:(NSEvent *)event
1543 {
1544     if (_private->closed)
1545         return;
1546
1547     NSView *contentView = [[event window] contentView];
1548     NSPoint locationForHitTest = [[contentView superview] convertPoint:[event locationInWindow] fromView:nil];
1549     
1550     forceWebHTMLViewHitTest = YES;
1551     NSView *hitView = [contentView hitTest:locationForHitTest];
1552     forceWebHTMLViewHitTest = NO;
1553     
1554     WebHTMLView *view = nil;
1555     if ([hitView isKindOfClass:[WebHTMLView class]] && ![[(WebHTMLView *)hitView _webView] isHoverFeedbackSuspended])
1556         view = (WebHTMLView *)hitView;    
1557
1558     if (view)
1559         [view retain];
1560
1561     if (lastHitView != view && lastHitView && [lastHitView _frame]) {
1562         // If we are moving out of a view (or frame), let's pretend the mouse moved
1563         // all the way out of that view. But we have to account for scrolling, because
1564         // khtml doesn't understand our clipping.
1565         NSRect visibleRect = [[[[lastHitView _frame] frameView] _scrollView] documentVisibleRect];
1566         float yScroll = visibleRect.origin.y;
1567         float xScroll = visibleRect.origin.x;
1568
1569         event = [NSEvent mouseEventWithType:NSMouseMoved
1570                          location:NSMakePoint(-1 - xScroll, -1 - yScroll )
1571                          modifierFlags:[[NSApp currentEvent] modifierFlags]
1572                          timestamp:[NSDate timeIntervalSinceReferenceDate]
1573                          windowNumber:[[view window] windowNumber]
1574                          context:[[NSApp currentEvent] context]
1575                          eventNumber:0 clickCount:0 pressure:0];
1576         if (Frame* lastHitCoreFrame = core([lastHitView _frame]))
1577             lastHitCoreFrame->eventHandler()->mouseMoved(event);
1578     }
1579
1580     lastHitView = view;
1581
1582     if (view) {
1583         if (Frame* coreFrame = core([view _frame]))
1584             coreFrame->eventHandler()->mouseMoved(event);
1585
1586         [view release];
1587     }
1588 }
1589
1590 // keep in sync with WebPasteboardHelper::insertablePasteboardTypes
1591 + (NSArray *)_insertablePasteboardTypes
1592 {
1593     static NSArray *types = nil;
1594     if (!types) {
1595         types = [[NSArray alloc] initWithObjects:WebArchivePboardType, NSHTMLPboardType, NSFilenamesPboardType, NSTIFFPboardType,
1596 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
1597             NSPICTPboardType,
1598 #endif
1599             NSURLPboardType, NSRTFDPboardType, NSRTFPboardType, NSStringPboardType, NSColorPboardType, kUTTypePNG, nil];
1600         CFRetain(types);
1601     }
1602     return types;
1603 }
1604
1605 + (NSArray *)_selectionPasteboardTypes
1606 {
1607     // FIXME: We should put data for NSHTMLPboardType on the pasteboard but Microsoft Excel doesn't like our format of HTML (3640423).
1608     return [NSArray arrayWithObjects:WebArchivePboardType, NSRTFDPboardType, NSRTFPboardType, NSStringPboardType, nil];
1609 }
1610
1611 - (NSImage *)_dragImageForURL:(NSString*)urlString withLabel:(NSString*)label
1612 {
1613     BOOL drawURLString = YES;
1614     BOOL clipURLString = NO, clipLabelString = NO;
1615     
1616     if (!label) {
1617         drawURLString = NO;
1618         label = urlString;
1619     }
1620     
1621     NSFont *labelFont = [[NSFontManager sharedFontManager] convertFont:[NSFont systemFontOfSize:DRAG_LINK_LABEL_FONT_SIZE]
1622                                                            toHaveTrait:NSBoldFontMask];
1623     NSFont *urlFont = [NSFont systemFontOfSize: DRAG_LINK_URL_FONT_SIZE];
1624     NSSize labelSize;
1625     labelSize.width = [label _web_widthWithFont: labelFont];
1626     labelSize.height = [labelFont ascender] - [labelFont descender];
1627     if (labelSize.width > MAX_DRAG_LABEL_WIDTH){
1628         labelSize.width = MAX_DRAG_LABEL_WIDTH;
1629         clipLabelString = YES;
1630     }
1631     
1632     NSSize imageSize, urlStringSize;
1633     imageSize.width = labelSize.width + DRAG_LABEL_BORDER_X * 2.0f;
1634     imageSize.height = labelSize.height + DRAG_LABEL_BORDER_Y * 2.0f;
1635     if (drawURLString) {
1636         urlStringSize.width = [urlString _web_widthWithFont: urlFont];
1637         urlStringSize.height = [urlFont ascender] - [urlFont descender];
1638         imageSize.height += urlStringSize.height;
1639         if (urlStringSize.width > MAX_DRAG_LABEL_WIDTH) {
1640             imageSize.width = MAX(MAX_DRAG_LABEL_WIDTH + DRAG_LABEL_BORDER_X * 2.0f, MIN_DRAG_LABEL_WIDTH_BEFORE_CLIP);
1641             clipURLString = YES;
1642         } else {
1643             imageSize.width = MAX(labelSize.width + DRAG_LABEL_BORDER_X * 2.0f, urlStringSize.width + DRAG_LABEL_BORDER_X * 2.0f);
1644         }
1645     }
1646     NSImage *dragImage = [[[NSImage alloc] initWithSize: imageSize] autorelease];
1647     [dragImage lockFocus];
1648     
1649     [[NSColor colorWithDeviceRed: 0.7f green: 0.7f blue: 0.7f alpha: 0.8f] set];
1650     
1651     // Drag a rectangle with rounded corners/
1652     NSBezierPath *path = [NSBezierPath bezierPath];
1653     [path appendBezierPathWithOvalInRect: NSMakeRect(0.0f, 0.0f, DRAG_LABEL_RADIUS * 2.0f, DRAG_LABEL_RADIUS * 2.0f)];
1654     [path appendBezierPathWithOvalInRect: NSMakeRect(0, imageSize.height - DRAG_LABEL_RADIUS * 2.0f, DRAG_LABEL_RADIUS * 2.0f, DRAG_LABEL_RADIUS * 2.0f)];
1655     [path appendBezierPathWithOvalInRect: NSMakeRect(imageSize.width - DRAG_LABEL_RADIUS * 2.0f, imageSize.height - DRAG_LABEL_RADIUS * 2.0f, DRAG_LABEL_RADIUS * 2.0f, DRAG_LABEL_RADIUS * 2.0f)];
1656     [path appendBezierPathWithOvalInRect: NSMakeRect(imageSize.width - DRAG_LABEL_RADIUS * 2.0f, 0.0f, DRAG_LABEL_RADIUS * 2.0f, DRAG_LABEL_RADIUS * 2.0f)];
1657     
1658     [path appendBezierPathWithRect: NSMakeRect(DRAG_LABEL_RADIUS, 0.0f, imageSize.width - DRAG_LABEL_RADIUS * 2.0f, imageSize.height)];
1659     [path appendBezierPathWithRect: NSMakeRect(0.0f, DRAG_LABEL_RADIUS, DRAG_LABEL_RADIUS + 10.0f, imageSize.height - 2.0f * DRAG_LABEL_RADIUS)];
1660     [path appendBezierPathWithRect: NSMakeRect(imageSize.width - DRAG_LABEL_RADIUS - 20.0f, DRAG_LABEL_RADIUS, DRAG_LABEL_RADIUS + 20.0f, imageSize.height - 2.0f * DRAG_LABEL_RADIUS)];
1661     [path fill];
1662     
1663     NSColor *topColor = [NSColor colorWithDeviceWhite:0.0f alpha:0.75f];
1664     NSColor *bottomColor = [NSColor colorWithDeviceWhite:1.0f alpha:0.5f];
1665     if (drawURLString) {
1666         if (clipURLString)
1667             urlString = [WebStringTruncator centerTruncateString: urlString toWidth:imageSize.width - (DRAG_LABEL_BORDER_X * 2.0f) withFont:urlFont];
1668         
1669         [urlString _web_drawDoubledAtPoint:NSMakePoint(DRAG_LABEL_BORDER_X, DRAG_LABEL_BORDER_Y - [urlFont descender]) 
1670                               withTopColor:topColor bottomColor:bottomColor font:urlFont];
1671     }
1672     
1673     if (clipLabelString)
1674         label = [WebStringTruncator rightTruncateString: label toWidth:imageSize.width - (DRAG_LABEL_BORDER_X * 2.0f) withFont:labelFont];
1675     [label _web_drawDoubledAtPoint:NSMakePoint (DRAG_LABEL_BORDER_X, imageSize.height - DRAG_LABEL_BORDER_Y_OFFSET - [labelFont pointSize])
1676                       withTopColor:topColor bottomColor:bottomColor font:labelFont];
1677     
1678     [dragImage unlockFocus];
1679     
1680     return dragImage;
1681 }
1682
1683 - (NSImage *)_dragImageForLinkElement:(NSDictionary *)element
1684 {
1685     NSURL *linkURL = [element objectForKey: WebElementLinkURLKey];
1686     
1687     NSString *label = [element objectForKey: WebElementLinkLabelKey];
1688     NSString *urlString = [linkURL _web_userVisibleString];
1689     return [self _dragImageForURL:urlString withLabel:label];
1690 }
1691
1692 - (void)pasteboardChangedOwner:(NSPasteboard *)pasteboard
1693 {
1694     [self setPromisedDragTIFFDataSource:0];
1695 }
1696
1697 - (void)pasteboard:(NSPasteboard *)pasteboard provideDataForType:(NSString *)type
1698 {
1699     if ([type isEqual:NSRTFDPboardType] && [[pasteboard types] containsObject:WebArchivePboardType]) {
1700         WebArchive *archive = [[WebArchive alloc] initWithData:[pasteboard dataForType:WebArchivePboardType]];
1701         [pasteboard _web_writePromisedRTFDFromArchive:archive containsImage:[[pasteboard types] containsObject:NSTIFFPboardType]];
1702         [archive release];
1703     } else if ([type isEqual:NSTIFFPboardType] && [self promisedDragTIFFDataSource]) {
1704         if (Image* image = [self promisedDragTIFFDataSource]->image())
1705             [pasteboard setData:(NSData *)image->getTIFFRepresentation() forType:NSTIFFPboardType];
1706         [self setPromisedDragTIFFDataSource:0];
1707     }
1708 }
1709
1710 - (void)_handleAutoscrollForMouseDragged:(NSEvent *)event 
1711
1712     [self autoscroll:event]; 
1713     [self _startAutoscrollTimer:event]; 
1714
1715
1716 - (WebPluginController *)_pluginController
1717 {
1718     return _private->pluginController;
1719 }
1720
1721 - (void)_layoutForPrinting
1722 {
1723     // Set printing mode temporarily so we can adjust the size of the view. This will allow
1724     // AppKit's pagination code to use the correct height for the page content. Leaving printing
1725     // mode on indefinitely would interfere with Mail's printing mechanism (at least), so we just
1726     // turn it off again after adjusting the size.
1727     [self _web_setPrintingModeRecursiveAndAdjustViewSize];
1728     [self _web_clearPrintingModeRecursive];
1729 }
1730
1731 - (void)_smartInsertForString:(NSString *)pasteString replacingRange:(DOMRange *)rangeToReplace beforeString:(NSString **)beforeString afterString:(NSString **)afterString
1732 {
1733     if (!pasteString || !rangeToReplace || ![[self _webView] smartInsertDeleteEnabled]) {
1734         if (beforeString)
1735             *beforeString = nil;
1736         if (afterString)
1737             *afterString = nil;
1738         return;
1739     }
1740     
1741     [[self _frame] _smartInsertForString:pasteString replacingRange:rangeToReplace beforeString:beforeString afterString:afterString];
1742 }
1743
1744 - (BOOL)_canSmartReplaceWithPasteboard:(NSPasteboard *)pasteboard
1745 {
1746     return [[self _webView] smartInsertDeleteEnabled] && [[pasteboard types] containsObject:WebSmartPastePboardType];
1747 }
1748
1749 - (void)_startAutoscrollTimer: (NSEvent *)triggerEvent
1750 {
1751     if (_private->autoscrollTimer == nil) {
1752         _private->autoscrollTimer = [[NSTimer scheduledTimerWithTimeInterval:AUTOSCROLL_INTERVAL
1753             target:self selector:@selector(_autoscroll) userInfo:nil repeats:YES] retain];
1754         _private->autoscrollTriggerEvent = [triggerEvent retain];
1755     }
1756 }
1757
1758 // FIXME: _selectionRect is deprecated in favor of selectionRect, which is in protocol WebDocumentSelection.
1759 // We can't remove this yet because it's still in use by Mail.
1760 - (NSRect)_selectionRect
1761 {
1762     return [self selectionRect];
1763 }
1764
1765 - (void)_stopAutoscrollTimer
1766 {
1767     NSTimer *timer = _private->autoscrollTimer;
1768     _private->autoscrollTimer = nil;
1769     [_private->autoscrollTriggerEvent release];
1770     _private->autoscrollTriggerEvent = nil;
1771     [timer invalidate];
1772     [timer release];
1773 }
1774
1775 - (void)_autoscroll
1776 {
1777     // Guarantee that the autoscroll timer is invalidated, even if we don't receive
1778     // a mouse up event.
1779     BOOL isStillDown = CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState, kCGMouseButtonLeft);   
1780     if (!isStillDown){
1781         [self _stopAutoscrollTimer];
1782         return;
1783     }
1784
1785     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseDragged
1786         location:[[self window] convertScreenToBase:[NSEvent mouseLocation]]
1787         modifierFlags:[[NSApp currentEvent] modifierFlags]
1788         timestamp:[NSDate timeIntervalSinceReferenceDate]
1789         windowNumber:[[self window] windowNumber]
1790         context:[[NSApp currentEvent] context]
1791         eventNumber:0 clickCount:0 pressure:0];
1792     [self mouseDragged:fakeEvent];
1793 }
1794
1795 - (BOOL)_canEdit
1796 {
1797     Frame* coreFrame = core([self _frame]);
1798     return coreFrame && coreFrame->editor()->canEdit();
1799 }
1800
1801 - (BOOL)_canEditRichly
1802 {
1803     Frame* coreFrame = core([self _frame]);
1804     return coreFrame && coreFrame->editor()->canEditRichly();
1805 }
1806
1807 - (BOOL)_canAlterCurrentSelection
1808 {
1809     return [self _hasSelectionOrInsertionPoint] && [self _isEditable];
1810 }
1811
1812 - (BOOL)_hasSelection
1813 {
1814     Frame* coreFrame = core([self _frame]);
1815     return coreFrame && coreFrame->selection()->isRange();
1816 }
1817
1818 - (BOOL)_hasSelectionOrInsertionPoint
1819 {
1820     Frame* coreFrame = core([self _frame]);
1821     return coreFrame && coreFrame->selection()->isCaretOrRange();
1822 }
1823
1824 - (BOOL)_hasInsertionPoint
1825 {
1826     Frame* coreFrame = core([self _frame]);
1827     return coreFrame && coreFrame->selection()->isCaret();
1828 }
1829
1830 - (BOOL)_isEditable
1831 {
1832     Frame* coreFrame = core([self _frame]);
1833     return coreFrame && coreFrame->selection()->isContentEditable();
1834 }
1835
1836 - (BOOL)_transparentBackground
1837 {
1838     return _private->transparentBackground;
1839 }
1840
1841 - (void)_setTransparentBackground:(BOOL)f
1842 {
1843     _private->transparentBackground = f;
1844 }
1845
1846 - (NSImage *)_selectionDraggingImage
1847 {
1848     if ([self _hasSelection]) {
1849         NSImage *dragImage = core([self _frame])->selectionImage();
1850         [dragImage _web_dissolveToFraction:WebDragImageAlpha];
1851         return dragImage;
1852     }
1853     return nil;
1854 }
1855
1856 - (NSRect)_selectionDraggingRect
1857 {
1858     // Mail currently calls this method. We can eliminate it when Mail no longer calls it.
1859     return [self selectionRect];
1860 }
1861
1862 - (DOMNode *)_insertOrderedList
1863 {
1864     Frame* coreFrame = core([self _frame]);
1865     return coreFrame ? kit(coreFrame->editor()->insertOrderedList().get()) : nil;
1866 }
1867
1868 - (DOMNode *)_insertUnorderedList
1869 {
1870     Frame* coreFrame = core([self _frame]);
1871     return coreFrame ? kit(coreFrame->editor()->insertUnorderedList().get()) : nil;
1872 }
1873
1874 - (BOOL)_canIncreaseSelectionListLevel
1875 {
1876     Frame* coreFrame = core([self _frame]);
1877     return coreFrame && coreFrame->editor()->canIncreaseSelectionListLevel();
1878 }
1879
1880 - (BOOL)_canDecreaseSelectionListLevel
1881 {
1882     Frame* coreFrame = core([self _frame]);
1883     return coreFrame && coreFrame->editor()->canDecreaseSelectionListLevel();
1884 }
1885
1886 - (DOMNode *)_increaseSelectionListLevel
1887 {
1888     Frame* coreFrame = core([self _frame]);
1889     return coreFrame ? kit(coreFrame->editor()->increaseSelectionListLevel().get()) : nil;
1890 }
1891
1892 - (DOMNode *)_increaseSelectionListLevelOrdered
1893 {
1894     Frame* coreFrame = core([self _frame]);
1895     return coreFrame ? kit(coreFrame->editor()->increaseSelectionListLevelOrdered().get()) : nil;
1896 }
1897
1898 - (DOMNode *)_increaseSelectionListLevelUnordered
1899 {
1900     Frame* coreFrame = core([self _frame]);
1901     return coreFrame ? kit(coreFrame->editor()->increaseSelectionListLevelUnordered().get()) : nil;
1902 }
1903
1904 - (void)_decreaseSelectionListLevel
1905 {
1906     Frame* coreFrame = core([self _frame]);
1907     if (coreFrame)
1908         coreFrame->editor()->decreaseSelectionListLevel();
1909 }
1910
1911 - (void)_setHighlighter:(id<WebHTMLHighlighter>)highlighter ofType:(NSString*)type
1912 {
1913     if (!_private->highlighters)
1914         _private->highlighters = [[NSMutableDictionary alloc] init];
1915     [_private->highlighters setObject:highlighter forKey:type];
1916 }
1917
1918 - (void)_removeHighlighterOfType:(NSString*)type
1919 {
1920     [_private->highlighters removeObjectForKey:type];
1921 }
1922
1923 - (void)_updateFocusedAndActiveState
1924 {
1925     [self _cancelUpdateFocusedAndActiveStateTimer];
1926
1927     [[self _webView] _updateFocusedAndActiveStateForFrame:[self _frame]];
1928 }
1929
1930 - (void)_writeSelectionToPasteboard:(NSPasteboard *)pasteboard
1931 {
1932     ASSERT([self _hasSelection]);
1933     NSArray *types = [self pasteboardTypesForSelection];
1934
1935     // Don't write RTFD to the pasteboard when the copied attributed string has no attachments.
1936     NSAttributedString *attributedString = [self selectedAttributedString];
1937     NSMutableArray *mutableTypes = nil;
1938     if (![attributedString containsAttachments]) {
1939         mutableTypes = [types mutableCopy];
1940         [mutableTypes removeObject:NSRTFDPboardType];
1941         types = mutableTypes;
1942     }
1943
1944     [pasteboard declareTypes:types owner:[self _topHTMLView]];
1945     [self _writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard cachedAttributedString:attributedString];
1946     [mutableTypes release];
1947 }
1948
1949 - (void)close
1950 {
1951     // Check for a nil _private here in case we were created with initWithCoder. In that case, the WebView is just throwing
1952     // out the archived WebHTMLView and recreating a new one if needed. So close doesn't need to do anything in that case.
1953     if (!_private || _private->closed)
1954         return;
1955
1956     _private->closed = YES;
1957
1958     [self _cancelUpdateMouseoverTimer];
1959     [self _cancelUpdateFocusedAndActiveStateTimer];
1960     [self _clearLastHitViewIfSelf];
1961     [self _removeMouseMovedObserverUnconditionally];
1962     [self _removeWindowObservers];
1963     [self _removeSuperviewObservers];
1964     [_private->pluginController destroyAllPlugins];
1965     [_private->pluginController setDataSource:nil];
1966     // remove tooltips before clearing _private so removeTrackingRect: will work correctly
1967     [self removeAllToolTips];
1968
1969 #if USE(ACCELERATED_COMPOSITING)
1970     if (_private->layerHostingView)
1971         [[self _webView] _stoppedAcceleratedCompositingForFrame:[self _frame]];
1972 #endif
1973
1974     [_private clear];
1975
1976     Page* page = core([self _webView]);
1977     if (page)
1978         page->dragController()->setDraggingImageURL(KURL());
1979 }
1980
1981 - (BOOL)_hasHTMLDocument
1982 {
1983     Frame* coreFrame = core([self _frame]);
1984     if (!coreFrame)
1985         return NO;
1986     Document* document = coreFrame->document();
1987     return document && document->isHTMLDocument();
1988 }
1989
1990 - (DOMDocumentFragment *)_documentFragmentFromPasteboard:(NSPasteboard *)pasteboard
1991                                                  forType:(NSString *)pboardType
1992                                                inContext:(DOMRange *)context
1993                                             subresources:(NSArray **)subresources
1994 {
1995     if (pboardType == WebArchivePboardType) {
1996         WebArchive *archive = [[WebArchive alloc] initWithData:[pasteboard dataForType:WebArchivePboardType]];
1997         if (subresources)
1998             *subresources = [archive subresources];
1999         DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithArchive:archive];
2000         [archive release];
2001         return fragment;
2002     }
2003     if (pboardType == NSFilenamesPboardType)
2004         return [self _documentFragmentWithPaths:[pasteboard propertyListForType:NSFilenamesPboardType]];
2005         
2006     if (pboardType == NSHTMLPboardType) {
2007         NSString *HTMLString = [pasteboard stringForType:NSHTMLPboardType];
2008         // This is a hack to make Microsoft's HTML pasteboard data work. See 3778785.
2009         if ([HTMLString hasPrefix:@"Version:"]) {
2010             NSRange range = [HTMLString rangeOfString:@"<html" options:NSCaseInsensitiveSearch];
2011             if (range.location != NSNotFound)
2012                 HTMLString = [HTMLString substringFromIndex:range.location];
2013         }
2014         if ([HTMLString length] == 0)
2015             return nil;
2016         
2017         return [[self _frame] _documentFragmentWithMarkupString:HTMLString baseURLString:nil];
2018     }
2019
2020     // The _hasHTMLDocument clause here is a workaround for a bug in NSAttributedString: Radar 5052369.
2021     // If we call _documentFromRange on an XML document we'll get "setInnerHTML: method not found".
2022     // FIXME: Remove this once bug 5052369 is fixed.
2023     if ([self _hasHTMLDocument] && pboardType == NSRTFPboardType || pboardType == NSRTFDPboardType) {
2024         NSAttributedString *string = nil;
2025         if (pboardType == NSRTFDPboardType)
2026             string = [[NSAttributedString alloc] initWithRTFD:[pasteboard dataForType:NSRTFDPboardType] documentAttributes:NULL];
2027         if (string == nil)
2028             string = [[NSAttributedString alloc] initWithRTF:[pasteboard dataForType:NSRTFPboardType] documentAttributes:NULL];
2029         if (string == nil)
2030             return nil;
2031             
2032         NSDictionary *documentAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:
2033             [[self class] _excludedElementsForAttributedStringConversion], NSExcludedElementsDocumentAttribute,
2034             self, @"WebResourceHandler", nil];
2035         NSArray *s;
2036         
2037         BOOL wasDeferringCallbacks = [[self _webView] defersCallbacks];
2038         if (!wasDeferringCallbacks)
2039             [[self _webView] setDefersCallbacks:YES];
2040             
2041         DOMDocumentFragment *fragment = [string _documentFromRange:NSMakeRange(0, [string length]) 
2042                                                           document:[[self _frame] DOMDocument] 
2043                                                 documentAttributes:documentAttributes
2044                                                       subresources:&s];
2045         if (subresources)
2046             *subresources = s;
2047         
2048         NSEnumerator *e = [s objectEnumerator];
2049         WebResource *r;
2050         while ((r = [e nextObject]))
2051             [[self _dataSource] addSubresource:r];
2052         
2053         if (!wasDeferringCallbacks)
2054             [[self _webView] setDefersCallbacks:NO];
2055         
2056         [documentAttributes release];
2057         [string release];
2058         return fragment;
2059     }
2060     if (pboardType == NSTIFFPboardType) {
2061         WebResource *resource = [[WebResource alloc] initWithData:[pasteboard dataForType:NSTIFFPboardType]
2062                                                               URL:uniqueURLWithRelativePart(@"image.tiff")
2063                                                          MIMEType:@"image/tiff" 
2064                                                  textEncodingName:nil
2065                                                         frameName:nil];
2066         DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithImageResource:resource];
2067         [resource release];
2068         return fragment;
2069     }
2070 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
2071     if (pboardType == NSPICTPboardType) {
2072         WebResource *resource = [[WebResource alloc] initWithData:[pasteboard dataForType:NSPICTPboardType]
2073                                                               URL:uniqueURLWithRelativePart(@"image.pict")
2074                                                          MIMEType:@"image/pict" 
2075                                                  textEncodingName:nil
2076                                                         frameName:nil];
2077         DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithImageResource:resource];
2078         [resource release];
2079         return fragment;
2080     }
2081 #endif
2082     // Only 10.5 and higher support setting and retrieving pasteboard types with UTIs, but we don't believe
2083     // that any applications on Tiger put types for which we only have a UTI, like PNG, on the pasteboard.
2084     if ([pboardType isEqualToString:(NSString*)kUTTypePNG]) {
2085         WebResource *resource = [[WebResource alloc] initWithData:[pasteboard dataForType:(NSString*)kUTTypePNG]
2086                                                               URL:uniqueURLWithRelativePart(@"image.png")
2087                                                          MIMEType:@"image/png" 
2088                                                  textEncodingName:nil
2089                                                         frameName:nil];
2090         DOMDocumentFragment *fragment = [[self _dataSource] _documentFragmentWithImageResource:resource];
2091         [resource release];
2092         return fragment;
2093     }
2094     if (pboardType == NSURLPboardType) {
2095         NSURL *URL = [NSURL URLFromPasteboard:pasteboard];
2096         DOMDocument* document = [[self _frame] DOMDocument];
2097         ASSERT(document);
2098         if (!document)
2099             return nil;
2100         DOMHTMLAnchorElement *anchor = (DOMHTMLAnchorElement *)[document createElement:@"a"];
2101         NSString *URLString = [URL _web_originalDataAsString]; // Original data is ASCII-only, so there is no need to precompose.
2102         if ([URLString length] == 0)
2103             return nil;
2104         NSString *URLTitleString = [[pasteboard stringForType:WebURLNamePboardType] precomposedStringWithCanonicalMapping];
2105         DOMText *text = [document createTextNode:URLTitleString];
2106         [anchor setHref:URLString];
2107         [anchor appendChild:text];
2108         DOMDocumentFragment *fragment = [document createDocumentFragment];
2109         [fragment appendChild:anchor];
2110         return fragment;
2111     }
2112     if (pboardType == NSStringPboardType)
2113         return kit(createFragmentFromText(core(context), [[pasteboard stringForType:NSStringPboardType] precomposedStringWithCanonicalMapping]).get());
2114     return nil;
2115 }
2116
2117 #if ENABLE(NETSCAPE_PLUGIN_API) 
2118 - (void)_pauseNullEventsForAllNetscapePlugins 
2119
2120     NSArray *subviews = [self subviews]; 
2121     unsigned int subviewCount = [subviews count]; 
2122     unsigned int subviewIndex; 
2123     
2124     for (subviewIndex = 0; subviewIndex < subviewCount; subviewIndex++) { 
2125         NSView *subview = [subviews objectAtIndex:subviewIndex]; 
2126         if ([subview isKindOfClass:[WebBaseNetscapePluginView class]]) 
2127             [(WebBaseNetscapePluginView *)subview stopTimers];
2128     } 
2129
2130 #endif 
2131
2132 #if ENABLE(NETSCAPE_PLUGIN_API) 
2133 - (void)_resumeNullEventsForAllNetscapePlugins 
2134
2135     NSArray *subviews = [self subviews]; 
2136     unsigned int subviewCount = [subviews count]; 
2137     unsigned int subviewIndex; 
2138     
2139     for (subviewIndex = 0; subviewIndex < subviewCount; subviewIndex++) { 
2140         NSView *subview = [subviews objectAtIndex:subviewIndex]; 
2141         if ([subview isKindOfClass:[WebBaseNetscapePluginView class]]) 
2142             [(WebBaseNetscapePluginView *)subview restartTimers]; 
2143     } 
2144
2145 #endif 
2146
2147 - (BOOL)_isUsingAcceleratedCompositing
2148 {
2149 #if USE(ACCELERATED_COMPOSITING)
2150     return _private->layerHostingView != nil;
2151 #else
2152     return NO;
2153 #endif
2154 }
2155
2156 @end
2157
2158 @implementation NSView (WebHTMLViewFileInternal)
2159
2160 - (void)_web_addDescendantWebHTMLViewsToArray:(NSMutableArray *)array
2161 {
2162     unsigned count = [_subviews count];
2163     for (unsigned i = 0; i < count; ++i) {
2164         NSView *child = [_subviews objectAtIndex:i];
2165         if ([child isKindOfClass:[WebHTMLView class]])
2166             [array addObject:child];
2167         [child _web_addDescendantWebHTMLViewsToArray:array];
2168     }
2169 }
2170
2171 @end
2172
2173 @implementation NSMutableDictionary (WebHTMLViewFileInternal)
2174
2175 - (void)_web_setObjectIfNotNil:(id)object forKey:(id)key
2176 {
2177     if (object == nil) {
2178         [self removeObjectForKey:key];
2179     } else {
2180         [self setObject:object forKey:key];
2181     }
2182 }
2183
2184 @end
2185
2186 @interface NSString (WebHTMLViewFileInternal)
2187 - (BOOL)matchesExtensionEquivalent:(NSString *)extension;
2188 @end
2189
2190 @implementation NSString (WebHTMLViewFileInternal)
2191
2192 - (BOOL)matchesExtensionEquivalent:(NSString *)extension
2193 {
2194     if ([self hasSuffix:extension])
2195         return YES;
2196     else if ([extension isEqualToString:@"jpeg"] && [self hasSuffix:@"jpg"])
2197         return YES;
2198     return NO;
2199 }
2200
2201 @end
2202
2203 #ifdef BUILDING_ON_TIGER
2204
2205 // The following is a workaround for
2206 // <rdar://problem/3429631> window stops getting mouse moved events after first tooltip appears
2207 // The trick is to define a category on NSToolTipPanel that implements setAcceptsMouseMovedEvents:.
2208 // Since the category will be searched before the real class, we'll prevent the flag from being
2209 // set on the tool tip panel.
2210
2211 @interface NSToolTipPanel : NSPanel
2212 @end
2213
2214 @interface NSToolTipPanel (WebHTMLViewFileInternal)
2215 @end
2216
2217 @implementation NSToolTipPanel (WebHTMLViewFileInternal)
2218
2219 - (void)setAcceptsMouseMovedEvents:(BOOL)flag
2220 {
2221     // Do nothing, preventing the tool tip panel from trying to accept mouse-moved events.
2222 }
2223
2224 @end
2225
2226 #endif
2227
2228 @interface NSArray (WebHTMLView)
2229 - (void)_web_makePluginViewsPerformSelector:(SEL)selector withObject:(id)object;
2230 @end
2231
2232 @implementation WebHTMLView
2233
2234 + (void)initialize
2235 {
2236     [NSApp registerServicesMenuSendTypes:[[self class] _selectionPasteboardTypes] 
2237                              returnTypes:[[self class] _insertablePasteboardTypes]];
2238     JSC::initializeThreading();
2239 #ifndef BUILDING_ON_TIGER
2240     WebCoreObjCFinalizeOnMainThread(self);
2241 #endif
2242 }
2243
2244 - (id)initWithFrame:(NSRect)frame
2245 {
2246     self = [super initWithFrame:frame];
2247     if (!self)
2248         return nil;
2249     
2250     [self setFocusRingType:NSFocusRingTypeNone];
2251     
2252     // Make all drawing go through us instead of subviews.
2253     [self _setDrawsOwnDescendants:YES];
2254     
2255     _private = [[WebHTMLViewPrivate alloc] init];
2256
2257     _private->pluginController = [[WebPluginController alloc] initWithDocumentView:self];
2258     _private->needsLayout = YES;
2259     
2260     return self;
2261 }
2262
2263 - (void)dealloc
2264 {
2265     if (WebCoreObjCScheduleDeallocateOnMainThread([WebHTMLView class], self))
2266         return;
2267
2268     // We can't assert that close has already been called because
2269     // this view can be removed from it's superview, even though
2270     // it could be needed later, so close if needed.
2271     [self close];
2272     [_private release];
2273     _private = nil;
2274     [super dealloc];
2275 }
2276
2277 - (void)finalize
2278 {
2279     ASSERT_MAIN_THREAD();
2280     // We can't assert that close has already been called because
2281     // this view can be removed from it's superview, even though
2282     // it could be needed later, so close if needed.
2283     [self close];
2284     [super finalize];
2285 }
2286
2287 // Returns YES if the delegate returns YES (so we should do no more work).
2288 - (BOOL)callDelegateDoCommandBySelectorIfNeeded:(SEL)selector
2289 {
2290     BOOL callerAlreadyCalledDelegate = _private->selectorForDoCommandBySelector == selector;
2291     _private->selectorForDoCommandBySelector = 0;
2292     if (callerAlreadyCalledDelegate)
2293         return NO;
2294     WebView *webView = [self _webView];
2295     return [[webView _editingDelegateForwarder] webView:webView doCommandBySelector:selector];
2296 }
2297
2298 static String commandNameForSelector(SEL selector)
2299 {
2300     // Change a few command names into ones supported by WebCore::Editor.
2301     // If this list gets too long we might decide we need to use a hash table.
2302     if (selector == @selector(insertParagraphSeparator:) || selector == @selector(insertNewlineIgnoringFieldEditor:))
2303         return "InsertNewline";
2304     if (selector == @selector(insertTabIgnoringFieldEditor:))
2305         return "InsertTab";
2306     if (selector == @selector(pageDown:))
2307         return "MovePageDown";
2308     if (selector == @selector(pageDownAndModifySelection:))
2309         return "MovePageDownAndModifySelection";
2310     if (selector == @selector(pageUp:))
2311         return "MovePageUp";
2312     if (selector == @selector(pageUpAndModifySelection:))
2313         return "MovePageUpAndModifySelection";
2314
2315     // Remove the trailing colon.
2316     const char* selectorName = sel_getName(selector);
2317     size_t selectorNameLength = strlen(selectorName);
2318     if (selectorNameLength < 2 || selectorName[selectorNameLength - 1] != ':')
2319         return String();
2320     return String(selectorName, selectorNameLength - 1);
2321 }
2322
2323 - (Editor::Command)coreCommandBySelector:(SEL)selector
2324 {
2325     Frame* coreFrame = core([self _frame]);
2326     if (!coreFrame)
2327         return Editor::Command();
2328     return coreFrame->editor()->command(commandNameForSelector(selector));
2329 }
2330
2331 - (Editor::Command)coreCommandByName:(const char*)name
2332 {
2333     Frame* coreFrame = core([self _frame]);
2334     if (!coreFrame)
2335         return Editor::Command();
2336     return coreFrame->editor()->command(name);
2337 }
2338
2339 - (void)executeCoreCommandBySelector:(SEL)selector
2340 {
2341     if ([self callDelegateDoCommandBySelectorIfNeeded:selector])
2342         return;
2343     [self coreCommandBySelector:selector].execute();
2344 }
2345
2346 - (void)executeCoreCommandByName:(const char*)name
2347 {
2348     [self coreCommandByName:name].execute();
2349 }
2350
2351 // These commands are forwarded to the Editor object in WebCore.
2352 // Ideally we'd do this for all editing commands; more of the code
2353 // should be moved from here to there, and more commands should be
2354 // added to this list.
2355
2356 // FIXME: Maybe we should set things up so that all these share a single method implementation function.
2357 // The functions are identical.
2358
2359 #define WEBCORE_COMMAND(command) - (void)command:(id)sender { [self executeCoreCommandBySelector:_cmd]; }
2360
2361 WEBCORE_COMMAND(alignCenter)
2362 WEBCORE_COMMAND(alignJustified)
2363 WEBCORE_COMMAND(alignLeft)
2364 WEBCORE_COMMAND(alignRight)
2365 WEBCORE_COMMAND(copy)
2366 WEBCORE_COMMAND(cut)
2367 WEBCORE_COMMAND(delete)
2368 WEBCORE_COMMAND(deleteBackward)
2369 WEBCORE_COMMAND(deleteBackwardByDecomposingPreviousCharacter)
2370 WEBCORE_COMMAND(deleteForward)
2371 WEBCORE_COMMAND(deleteToBeginningOfLine)
2372 WEBCORE_COMMAND(deleteToBeginningOfParagraph)
2373 WEBCORE_COMMAND(deleteToEndOfLine)
2374 WEBCORE_COMMAND(deleteToEndOfParagraph)
2375 WEBCORE_COMMAND(deleteToMark)
2376 WEBCORE_COMMAND(deleteWordBackward)
2377 WEBCORE_COMMAND(deleteWordForward)
2378 WEBCORE_COMMAND(ignoreSpelling)
2379 WEBCORE_COMMAND(indent)
2380 WEBCORE_COMMAND(insertBacktab)
2381 WEBCORE_COMMAND(insertLineBreak)
2382 WEBCORE_COMMAND(insertNewline)
2383 WEBCORE_COMMAND(insertNewlineIgnoringFieldEditor)
2384 WEBCORE_COMMAND(insertParagraphSeparator)
2385 WEBCORE_COMMAND(insertTab)
2386 WEBCORE_COMMAND(insertTabIgnoringFieldEditor)
2387 WEBCORE_COMMAND(makeTextWritingDirectionLeftToRight)
2388 WEBCORE_COMMAND(makeTextWritingDirectionNatural)
2389 WEBCORE_COMMAND(makeTextWritingDirectionRightToLeft)
2390 WEBCORE_COMMAND(moveBackward)
2391 WEBCORE_COMMAND(moveBackwardAndModifySelection)
2392 WEBCORE_COMMAND(moveDown)
2393 WEBCORE_COMMAND(moveDownAndModifySelection)
2394 WEBCORE_COMMAND(moveForward)
2395 WEBCORE_COMMAND(moveForwardAndModifySelection)
2396 WEBCORE_COMMAND(moveLeft)
2397 WEBCORE_COMMAND(moveLeftAndModifySelection)
2398 WEBCORE_COMMAND(moveParagraphBackwardAndModifySelection)
2399 WEBCORE_COMMAND(moveParagraphForwardAndModifySelection)
2400 WEBCORE_COMMAND(moveRight)
2401 WEBCORE_COMMAND(moveRightAndModifySelection)
2402 WEBCORE_COMMAND(moveToBeginningOfDocument)
2403 WEBCORE_COMMAND(moveToBeginningOfDocumentAndModifySelection)
2404 WEBCORE_COMMAND(moveToBeginningOfLine)
2405 WEBCORE_COMMAND(moveToBeginningOfLineAndModifySelection)
2406 WEBCORE_COMMAND(moveToBeginningOfParagraph)
2407 WEBCORE_COMMAND(moveToBeginningOfParagraphAndModifySelection)
2408 WEBCORE_COMMAND(moveToBeginningOfSentence)
2409 WEBCORE_COMMAND(moveToBeginningOfSentenceAndModifySelection)
2410 WEBCORE_COMMAND(moveToEndOfDocument)
2411 WEBCORE_COMMAND(moveToEndOfDocumentAndModifySelection)
2412 WEBCORE_COMMAND(moveToEndOfLine)
2413 WEBCORE_COMMAND(moveToEndOfLineAndModifySelection)
2414 WEBCORE_COMMAND(moveToEndOfParagraph)
2415 WEBCORE_COMMAND(moveToEndOfParagraphAndModifySelection)
2416 WEBCORE_COMMAND(moveToEndOfSentence)
2417 WEBCORE_COMMAND(moveToEndOfSentenceAndModifySelection)
2418 WEBCORE_COMMAND(moveToLeftEndOfLine)
2419 WEBCORE_COMMAND(moveToLeftEndOfLineAndModifySelection)
2420 WEBCORE_COMMAND(moveToRightEndOfLine)
2421 WEBCORE_COMMAND(moveToRightEndOfLineAndModifySelection)
2422 WEBCORE_COMMAND(moveUp)
2423 WEBCORE_COMMAND(moveUpAndModifySelection)
2424 WEBCORE_COMMAND(moveWordBackward)
2425 WEBCORE_COMMAND(moveWordBackwardAndModifySelection)
2426 WEBCORE_COMMAND(moveWordForward)
2427 WEBCORE_COMMAND(moveWordForwardAndModifySelection)
2428 WEBCORE_COMMAND(moveWordLeft)
2429 WEBCORE_COMMAND(moveWordLeftAndModifySelection)
2430 WEBCORE_COMMAND(moveWordRight)
2431 WEBCORE_COMMAND(moveWordRightAndModifySelection)
2432 WEBCORE_COMMAND(outdent)
2433 WEBCORE_COMMAND(pageDown)
2434 WEBCORE_COMMAND(pageDownAndModifySelection)
2435 WEBCORE_COMMAND(pageUp)
2436 WEBCORE_COMMAND(pageUpAndModifySelection)
2437 WEBCORE_COMMAND(selectAll)
2438 WEBCORE_COMMAND(selectLine)
2439 WEBCORE_COMMAND(selectParagraph)
2440 WEBCORE_COMMAND(selectSentence)
2441 WEBCORE_COMMAND(selectToMark)
2442 WEBCORE_COMMAND(selectWord)
2443 WEBCORE_COMMAND(setMark)
2444 WEBCORE_COMMAND(subscript)
2445 WEBCORE_COMMAND(superscript)
2446 WEBCORE_COMMAND(swapWithMark)
2447 WEBCORE_COMMAND(transpose)
2448 WEBCORE_COMMAND(underline)
2449 WEBCORE_COMMAND(unscript)
2450 WEBCORE_COMMAND(yank)
2451 WEBCORE_COMMAND(yankAndSelect)
2452
2453 #undef WEBCORE_COMMAND
2454
2455 #define COMMAND_PROLOGUE if ([self callDelegateDoCommandBySelectorIfNeeded:_cmd]) return;
2456
2457 - (IBAction)takeFindStringFromSelection:(id)sender
2458 {
2459     COMMAND_PROLOGUE
2460
2461     if (![self _hasSelection]) {
2462         NSBeep();
2463         return;
2464     }
2465
2466     [NSPasteboard _web_setFindPasteboardString:[self selectedString] withOwner:self];
2467 }
2468
2469 - (BOOL)writeSelectionToPasteboard:(NSPasteboard *)pasteboard types:(NSArray *)types
2470 {
2471     [pasteboard declareTypes:types owner:[self _topHTMLView]];
2472     [self writeSelectionWithPasteboardTypes:types toPasteboard:pasteboard];
2473     return YES;
2474 }
2475
2476 - (BOOL)readSelectionFromPasteboard:(NSPasteboard *)pasteboard
2477 {
2478     Frame* coreFrame = core([self _frame]);
2479     if (!coreFrame)
2480         return NO;
2481     if (coreFrame->selection()->isContentRichlyEditable())
2482         [self _pasteWithPasteboard:pasteboard allowPlainText:YES];
2483     else
2484         [self _pasteAsPlainTextWithPasteboard:pasteboard];
2485     return YES;
2486 }
2487
2488 - (id)validRequestorForSendType:(NSString *)sendType returnType:(NSString *)returnType
2489 {
2490     BOOL isSendTypeOK = !sendType || ([[self pasteboardTypesForSelection] containsObject:sendType] && [self _hasSelection]);
2491     BOOL isReturnTypeOK = !returnType || ([[[self class] _insertablePasteboardTypes] containsObject:returnType] && [self _isEditable]);
2492     if (isSendTypeOK && isReturnTypeOK)
2493         return self;
2494     return [[self nextResponder] validRequestorForSendType:sendType returnType:returnType];
2495 }
2496
2497 // jumpToSelection is the old name for what AppKit now calls centerSelectionInVisibleArea. Safari
2498 // was using the old jumpToSelection selector in its menu. Newer versions of Safari will use the
2499 // selector centerSelectionInVisibleArea. We'll leave the old selector in place for two reasons:
2500 // (1) Compatibility between older Safari and newer WebKit; (2) other WebKit-based applications
2501 // might be using the selector, and we don't want to break them.
2502 - (void)jumpToSelection:(id)sender
2503 {
2504     COMMAND_PROLOGUE
2505
2506     if (Frame* coreFrame = core([self _frame]))
2507         coreFrame->revealSelection(ScrollAlignment::alignCenterAlways);
2508 }
2509
2510 - (NSCellStateValue)selectionHasStyle:(CSSStyleDeclaration*)style
2511 {
2512     Frame* coreFrame = core([self _frame]);
2513     if (!coreFrame)
2514         return NSOffState;
2515     return kit(coreFrame->editor()->selectionHasStyle(style));
2516 }
2517
2518 - (BOOL)validateUserInterfaceItemWithoutDelegate:(id <NSValidatedUserInterfaceItem>)item
2519 {
2520     SEL action = [item action];
2521     RefPtr<Frame> frame = core([self _frame]);
2522
2523     if (!frame)
2524         return NO;
2525     
2526     if (Document* doc = frame->document()) {
2527         if (doc->isPluginDocument())
2528             return NO;
2529         if (doc->isImageDocument()) {            
2530             if (action == @selector(copy:))
2531                 return frame->loader()->isComplete();
2532             return NO;
2533         }
2534     }
2535
2536     if (action == @selector(changeSpelling:)
2537             || action == @selector(_changeSpellingFromMenu:)
2538             || action == @selector(checkSpelling:)
2539             || action == @selector(complete:)
2540             || action == @selector(pasteFont:))
2541         return [self _canEdit];
2542
2543     if (action == @selector(showGuessPanel:)) {
2544 #ifndef BUILDING_ON_TIGER
2545         // Match OS X AppKit behavior for post-Tiger. Don't change Tiger behavior.
2546         NSMenuItem *menuItem = (NSMenuItem *)item;
2547         if ([menuItem isKindOfClass:[NSMenuItem class]]) {
2548             BOOL panelShowing = [[[NSSpellChecker sharedSpellChecker] spellingPanel] isVisible];
2549             [menuItem setTitle:panelShowing
2550                 ? UI_STRING("Hide Spelling and Grammar", "menu item title")
2551                 : UI_STRING("Show Spelling and Grammar", "menu item title")];
2552         }
2553 #endif
2554         return [self _canEdit];
2555     }
2556     
2557     if (action == @selector(changeBaseWritingDirection:)
2558             || action == @selector(makeBaseWritingDirectionLeftToRight:)
2559             || action == @selector(makeBaseWritingDirectionRightToLeft:)) {
2560         NSWritingDirection writingDirection;
2561
2562         if (action == @selector(changeBaseWritingDirection:)) {
2563             writingDirection = static_cast<NSWritingDirection>([item tag]);
2564             if (writingDirection == NSWritingDirectionNatural)
2565                 return NO;
2566         } else if (action == @selector(makeBaseWritingDirectionLeftToRight:))
2567             writingDirection = NSWritingDirectionLeftToRight;
2568         else
2569             writingDirection = NSWritingDirectionRightToLeft;
2570
2571         NSMenuItem *menuItem = (NSMenuItem *)item;
2572         if ([menuItem isKindOfClass:[NSMenuItem class]]) {
2573             RefPtr<CSSStyleDeclaration> style = CSSMutableStyleDeclaration::create();
2574             ExceptionCode ec;
2575             style->setProperty("direction", writingDirection == NSWritingDirectionLeftToRight ? "LTR" : "RTL", ec);
2576             [menuItem setState:frame->editor()->selectionHasStyle(style.get())];
2577         }
2578         return [self _canEdit];
2579     }
2580
2581     if (action == @selector(makeBaseWritingDirectionNatural:)) {
2582         NSMenuItem *menuItem = (NSMenuItem *)item;
2583         if ([menuItem isKindOfClass:[NSMenuItem class]])
2584             [menuItem setState:NSOffState];
2585         return NO;
2586     }
2587
2588     if (action == @selector(toggleBaseWritingDirection:)) {
2589         NSMenuItem *menuItem = (NSMenuItem *)item;
2590         if ([menuItem isKindOfClass:[NSMenuItem class]]) {
2591             RefPtr<CSSStyleDeclaration> style = CSSMutableStyleDeclaration::create();
2592             ExceptionCode ec;
2593             style->setProperty("direction", "RTL", ec);
2594             // Take control of the title of the menu item instead of just checking/unchecking it because
2595             // a check would be ambiguous.
2596             [menuItem setTitle:frame->editor()->selectionHasStyle(style.get())
2597                 ? UI_STRING("Left to Right", "Left to Right context menu item")
2598                 : UI_STRING("Right to Left", "Right to Left context menu item")];
2599         }
2600         return [self _canEdit];
2601     } 
2602     
2603     if (action == @selector(changeAttributes:)
2604             || action == @selector(changeColor:)        
2605             || action == @selector(changeFont:))
2606         return [self _canEditRichly];
2607     
2608     if (action == @selector(capitalizeWord:)
2609                || action == @selector(lowercaseWord:)
2610                || action == @selector(uppercaseWord:))
2611         return [self _hasSelection] && [self _isEditable];
2612
2613     if (action == @selector(centerSelectionInVisibleArea:)
2614                || action == @selector(jumpToSelection:)
2615                || action == @selector(copyFont:))
2616         return [self _hasSelection] || ([self _isEditable] && [self _hasInsertionPoint]);
2617     
2618     if (action == @selector(changeDocumentBackgroundColor:))
2619         return [[self _webView] isEditable] && [self _canEditRichly];
2620     
2621     if (action == @selector(_ignoreSpellingFromMenu:)
2622             || action == @selector(_learnSpellingFromMenu:)
2623             || action == @selector(takeFindStringFromSelection:))
2624         return [self _hasSelection];
2625     
2626     if (action == @selector(paste:) || action == @selector(pasteAsPlainText:))
2627         return frame && (frame->editor()->canDHTMLPaste() || frame->editor()->canPaste());
2628     
2629     if (action == @selector(pasteAsRichText:))
2630         return frame && (frame->editor()->canDHTMLPaste()
2631             || (frame->editor()->canPaste() && frame->selection()->isContentRichlyEditable()));
2632     
2633     if (action == @selector(performFindPanelAction:))
2634         return NO;
2635     
2636     if (action == @selector(_lookUpInDictionaryFromMenu:))
2637         return [self _hasSelection];
2638     
2639 #ifndef BUILDING_ON_TIGER
2640     if (action == @selector(toggleGrammarChecking:)) {
2641         // FIXME 4799134: WebView is the bottleneck for this grammar-checking logic, but we must validate 
2642         // the selector here because we implement it here, and we must implement it here because the AppKit 
2643         // code checks the first responder.
2644         NSMenuItem *menuItem = (NSMenuItem *)item;
2645         if ([menuItem isKindOfClass:[NSMenuItem class]])
2646             [menuItem setState:[self isGrammarCheckingEnabled] ? NSOnState : NSOffState];
2647         return YES;
2648     }
2649 #endif
2650     
2651     Editor::Command command = [self coreCommandBySelector:action];
2652     if (command.isSupported()) {
2653         NSMenuItem *menuItem = (NSMenuItem *)item;
2654         if ([menuItem isKindOfClass:[NSMenuItem class]])
2655             [menuItem setState:kit(command.state())];
2656         return command.isEnabled();
2657     }
2658
2659     return YES;
2660 }
2661
2662 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
2663 {
2664     // This can be called during teardown when _webView is nil. Return NO when this happens, because CallUIDelegateReturningBoolean
2665     // assumes the WebVIew is non-nil.
2666     if (![self _webView])
2667         return NO;
2668     BOOL result = [self validateUserInterfaceItemWithoutDelegate:item];
2669     return CallUIDelegateReturningBoolean(result, [self _webView], @selector(webView:validateUserInterfaceItem:defaultValidation:), item, result);
2670 }
2671
2672 - (BOOL)acceptsFirstResponder
2673 {
2674     // Don't accept first responder when we first click on this view.
2675     // We have to pass the event down through WebCore first to be sure we don't hit a subview.
2676     // Do accept first responder at any other time, for example from keyboard events,
2677     // or from calls back from WebCore once we begin mouse-down event handling.
2678     NSEvent *event = [NSApp currentEvent];
2679     if ([event type] == NSLeftMouseDown
2680             && !_private->handlingMouseDownEvent
2681             && NSPointInRect([event locationInWindow], [self convertRect:[self visibleRect] toView:nil])) {
2682         return NO;
2683     }
2684     return YES;
2685 }
2686
2687 - (BOOL)maintainsInactiveSelection
2688 {
2689     // This method helps to determine whether the WebHTMLView should maintain
2690     // an inactive selection when it's not first responder.
2691     // Traditionally, these views have not maintained such selections,
2692     // clearing them when the view was not first responder. However,
2693     // to fix bugs like this one:
2694     // <rdar://problem/3672088>: "Editable WebViews should maintain a selection even 
2695     //                            when they're not firstResponder"
2696     // it was decided to add a switch to act more like an NSTextView.
2697
2698     if ([[self _webView] maintainsInactiveSelection])
2699         return YES;
2700
2701     // Predict the case where we are losing first responder status only to
2702     // gain it back again. Want to keep the selection in that case.
2703     id nextResponder = [[self window] _newFirstResponderAfterResigning];
2704     if ([nextResponder isKindOfClass:[NSScrollView class]]) {
2705         id contentView = [nextResponder contentView];
2706         if (contentView)
2707             nextResponder = contentView;
2708     }
2709     if ([nextResponder isKindOfClass:[NSClipView class]]) {
2710         id documentView = [nextResponder documentView];
2711         if (documentView)
2712             nextResponder = documentView;
2713     }
2714     if (nextResponder == self)
2715         return YES;
2716
2717     Frame* coreFrame = core([self _frame]);
2718     bool selectionIsEditable = coreFrame && coreFrame->selection()->isContentEditable();
2719     bool nextResponderIsInWebView = [nextResponder isKindOfClass:[NSView class]]
2720         && [nextResponder isDescendantOf:[[[self _webView] mainFrame] frameView]];
2721
2722     return selectionIsEditable && nextResponderIsInWebView;
2723 }
2724
2725 - (void)addMouseMovedObserver
2726 {
2727     if (!_private->dataSource || ![self _isTopHTMLView] || _private->observingMouseMovedNotifications)
2728         return;
2729
2730     // Unless the Dashboard asks us to do this for all windows, keep an observer going only for the key window.
2731     if (!([[self window] isKeyWindow] 
2732 #if ENABLE(DASHBOARD_SUPPORT)
2733             || [[self _webView] _dashboardBehavior:WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows]
2734 #endif
2735         ))
2736         return;
2737
2738     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mouseMovedNotification:)
2739         name:WKMouseMovedNotification() object:nil];
2740     [self _frameOrBoundsChanged];
2741     _private->observingMouseMovedNotifications = true;
2742 }
2743
2744 - (void)removeMouseMovedObserver
2745 {
2746 #if ENABLE(DASHBOARD_SUPPORT)
2747     // Don't remove the observer if we're running the Dashboard.
2748     if ([[self _webView] _dashboardBehavior:WebDashboardBehaviorAlwaysSendMouseEventsToAllWindows])
2749         return;
2750 #endif
2751
2752     [[self _webView] _mouseDidMoveOverElement:nil modifierFlags:0];
2753     [self _removeMouseMovedObserverUnconditionally];
2754 }
2755
2756 - (void)addSuperviewObservers
2757 {
2758     // We watch the bounds of our superview, so that we can do a layout when the size
2759     // of the superview changes. This is different from other scrollable things that don't
2760     // need this kind of thing because their layout doesn't change.
2761     
2762     // We need to pay attention to both height and width because our "layout" has to change
2763     // to extend the background the full height of the space and because some elements have
2764     // sizes that are based on the total size of the view.
2765     
2766     if (_private->observingSuperviewNotifications)
2767         return;
2768
2769     NSView *superview = [self superview];
2770     if (!superview || ![self window])
2771         return;
2772     
2773     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
2774     [notificationCenter addObserver:self selector:@selector(_frameOrBoundsChanged) name:NSViewFrameDidChangeNotification object:superview];
2775     [notificationCenter addObserver:self selector:@selector(_frameOrBoundsChanged) name:NSViewBoundsDidChangeNotification object:superview];
2776     
2777     // In addition to registering for frame/bounds change notifications, call -_frameOrBoundsChanged.
2778     // It will check the current size/scroll against the previous layout's size/scroll.  We need to
2779     // do this here to catch the case where the WebView is laid out at one size, removed from its
2780     // window, resized, and inserted into another window.  Our frame/bounds changed notifications
2781     // will not be sent in that situation, since we only watch for changes while in the view hierarchy.
2782     [self _frameOrBoundsChanged];
2783     
2784     _private->observingSuperviewNotifications = true;
2785 }
2786
2787 - (void)addWindowObservers
2788 {
2789     if (_private->observingWindowNotifications)
2790         return;
2791     
2792     NSWindow *window = [self window];
2793     if (!window)
2794         return;
2795     
2796     NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
2797     [notificationCenter addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:nil];
2798     [notificationCenter addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:nil];
2799     [notificationCenter addObserver:self selector:@selector(windowWillClose:) name:NSWindowWillCloseNotification object:window];
2800     [notificationCenter addObserver:self selector:@selector(windowWillOrderOnScreen:) name:WKWindowWillOrderOnScreenNotification() object:window];
2801     
2802     _private->observingWindowNotifications = true;
2803 }
2804
2805 - (void)viewWillMoveToSuperview:(NSView *)newSuperview
2806 {
2807     [self _removeSuperviewObservers];
2808 }
2809
2810 - (void)viewDidMoveToSuperview
2811 {
2812     if ([self superview] != nil)
2813         [self addSuperviewObservers];
2814 }
2815
2816 static void _updateFocusedAndActiveStateTimerCallback(CFRunLoopTimerRef timer, void *info)
2817 {
2818     WebHTMLView *view = (WebHTMLView *)info;
2819     [view _updateFocusedAndActiveState];
2820 }
2821
2822 - (void)viewWillMoveToWindow:(NSWindow *)window
2823 {
2824     // Don't do anything if we aren't initialized.  This happens
2825     // when decoding a WebView.  When WebViews are decoded their subviews
2826     // are created by initWithCoder: and so won't be normally
2827     // initialized.  The stub views are discarded by WebView.
2828     if (!_private)
2829         return;
2830
2831     // FIXME: Some of these calls may not work because this view may be already removed from it's superview.
2832     [self _removeMouseMovedObserverUnconditionally];
2833     [self _removeWindowObservers];
2834     [self _removeSuperviewObservers];
2835     [self _cancelUpdateMouseoverTimer];
2836     [self _cancelUpdateFocusedAndActiveStateTimer];
2837     
2838     [[self _pluginController] stopAllPlugins];
2839 }
2840
2841 - (void)viewDidMoveToWindow
2842 {
2843     // Don't do anything if we aren't initialized.  This happens
2844     // when decoding a WebView.  When WebViews are decoded their subviews
2845     // are created by initWithCoder: and so won't be normally
2846     // initialized.  The stub views are discarded by WebView.
2847     if (!_private || _private->closed)
2848         return;
2849         
2850     [self _stopAutoscrollTimer];
2851     if ([self window]) {
2852         _private->lastScrollPosition = [[self superview] bounds].origin;
2853         [self addWindowObservers];
2854         [self addSuperviewObservers];
2855         [self addMouseMovedObserver];
2856
2857         // Schedule this update, rather than making the call right now.
2858         // The reason is that placing the caret in the just-installed view requires
2859         // the HTML/XML document to be available on the WebCore side, but it is not
2860         // at the time this code is running. However, it will be there on the next
2861         // crank of the run loop. Doing this helps to make a blinking caret appear 
2862         // in a new, empty window "automatic".
2863         if (!_private->updateFocusedAndActiveStateTimer) {
2864             CFRunLoopTimerContext context = { 0, self, NULL, NULL, NULL };
2865             _private->updateFocusedAndActiveStateTimer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent(), 0, 0, 0,
2866                                                                     _updateFocusedAndActiveStateTimerCallback, &context);
2867             CFRunLoopAddTimer(CFRunLoopGetCurrent(), _private->updateFocusedAndActiveStateTimer, kCFRunLoopDefaultMode);
2868         }
2869         
2870         [[self _pluginController] startAllPlugins];
2871
2872         _private->lastScrollPosition = NSZeroPoint;
2873     }
2874 }
2875
2876 - (void)viewWillMoveToHostWindow:(NSWindow *)hostWindow
2877 {
2878     [[self subviews] _web_makePluginViewsPerformSelector:@selector(viewWillMoveToHostWindow:) withObject:hostWindow];
2879 }
2880
2881 - (void)viewDidMoveToHostWindow
2882 {
2883     [[self subviews] _web_makePluginViewsPerformSelector:@selector(viewDidMoveToHostWindow) withObject:nil];
2884 }
2885
2886
2887 - (void)addSubview:(NSView *)view
2888 {
2889     [super addSubview:view];
2890
2891     if ([WebPluginController isPlugInView:view])
2892         [[self _pluginController] addPlugin:view];
2893 }
2894
2895 - (void)willRemoveSubview:(NSView *)subview
2896 {
2897     if ([WebPluginController isPlugInView:subview])
2898         [[self _pluginController] destroyPlugin:subview];
2899
2900     [super willRemoveSubview:subview];
2901 }
2902
2903 - (void)reapplyStyles
2904 {
2905     if (!_private->needsToApplyStyles)
2906         return;
2907     
2908 #ifdef LOG_TIMES
2909     double start = CFAbsoluteTimeGetCurrent();
2910 #endif
2911
2912     if (Frame* coreFrame = core([self _frame])) {
2913         if (FrameView* coreView = coreFrame->view())
2914             coreView->setMediaType(_private->printing ? "print" : "screen");
2915         if (Document* document = coreFrame->document())
2916             document->setPrinting(_private->printing);
2917         coreFrame->reapplyStyles();
2918     }
2919     
2920 #ifdef LOG_TIMES        
2921     double thisTime = CFAbsoluteTimeGetCurrent() - start;
2922     LOG(Timing, "%s apply style seconds = %f", [self URL], thisTime);
2923 #endif
2924
2925     _private->needsToApplyStyles = NO;
2926 }
2927
2928 // Do a layout, but set up a new fixed width for the purposes of doing printing layout.
2929 // minPageWidth==0 implies a non-printing layout
2930 - (void)layoutToMinimumPageWidth:(float)minPageWidth maximumPageWidth:(float)maxPageWidth adjustingViewSize:(BOOL)adjustViewSize
2931 {
2932     [self reapplyStyles];
2933     
2934     if (!_private->needsLayout && ![[self _frame] _needsLayout])
2935         return;
2936
2937 #ifdef LOG_TIMES        
2938     double start = CFAbsoluteTimeGetCurrent();
2939 #endif
2940
2941     LOG(View, "%@ doing layout", self);
2942
2943     Frame* coreFrame = core([self _frame]);
2944     if (!coreFrame) {
2945         _private->needsLayout = NO;
2946         return;
2947     }
2948
2949     if (FrameView* coreView = coreFrame->view()) {
2950         if (minPageWidth > 0.0)
2951             coreView->forceLayoutWithPageWidthRange(minPageWidth, maxPageWidth, adjustViewSize);
2952         else {
2953             coreView->forceLayout(!adjustViewSize);
2954             if (adjustViewSize)
2955                 coreView->adjustViewSize();
2956         }
2957     }
2958     _private->needsLayout = NO;
2959     
2960     if (!_private->printing)
2961         _private->lastLayoutSize = [(NSClipView *)[self superview] documentVisibleRect].size;
2962
2963 #ifdef LOG_TIMES        
2964     double thisTime = CFAbsoluteTimeGetCurrent() - start;
2965     LOG(Timing, "%s layout seconds = %f", [self URL], thisTime);
2966 #endif
2967 }
2968
2969 - (void)layout
2970 {
2971     [self layoutToMinimumPageWidth:0.0f maximumPageWidth:0.0f adjustingViewSize:NO];
2972 }
2973
2974 // Deliver mouseup events to the DOM for button 2.
2975 - (void)rightMouseUp:(NSEvent *)event
2976 {
2977     [super rightMouseUp:event];
2978     if (Frame* coreframe = core([self _frame]))
2979         coreframe->eventHandler()->mouseUp(event);
2980 }
2981
2982 - (NSMenu *)menuForEvent:(NSEvent *)event
2983 {
2984     [_private->compController endRevertingChange:NO moveLeft:NO];
2985
2986     _private->handlingMouseDownEvent = YES;
2987     BOOL handledEvent = NO;
2988     Frame* coreFrame = core([self _frame]);
2989
2990     if (!coreFrame) {
2991         _private->handlingMouseDownEvent = NO;
2992         return nil;
2993     }
2994
2995     Page* page = coreFrame->page();
2996     if (!page)
2997         return nil;
2998
2999     page->contextMenuController()->clearContextMenu();
3000     // Match behavior of other browsers by sending an onmousedown event for right clicks.
3001     coreFrame->eventHandler()->mouseDown(event);
3002     handledEvent = coreFrame->eventHandler()->sendContextMenuEvent(PlatformMouseEvent(event));
3003     _private->handlingMouseDownEvent = NO;
3004
3005     if (!handledEvent)
3006         return nil;
3007
3008     ContextMenu* coreMenu = page->contextMenuController()->contextMenu();
3009     if (!coreMenu)
3010         return nil;
3011
3012     NSArray* menuItems = coreMenu->platformDescription();
3013     NSMenu* menu = nil;
3014     if (menuItems && [menuItems count] > 0) {
3015         menu = [[[NSMenu alloc] init] autorelease];
3016         for (unsigned i = 0; i < [menuItems count]; i++)
3017             [menu addItem:[menuItems objectAtIndex:i]];
3018     }
3019
3020     return menu;
3021 }
3022
3023 - (BOOL)searchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag
3024 {
3025     return [self searchFor:string direction:forward caseSensitive:caseFlag wrap:wrapFlag startInSelection:NO];
3026 }
3027
3028 - (void)clearFocus
3029 {
3030     Frame* coreFrame = core([self _frame]);
3031     if (!coreFrame)
3032         return;
3033     Document* document = coreFrame->document();
3034     if (!document)
3035         return;
3036     
3037     document->setFocusedNode(0);
3038 }
3039
3040 - (BOOL)isOpaque
3041 {
3042     return [[self _webView] drawsBackground];
3043 }
3044
3045 - (void)setNeedsDisplay:(BOOL)flag
3046 {
3047     LOG(View, "%@ setNeedsDisplay:%@", self, flag ? @"YES" : @"NO");
3048     [super setNeedsDisplay:flag];
3049 }
3050
3051 - (void)setNeedsLayout: (BOOL)flag
3052 {
3053     LOG(View, "%@ setNeedsLayout:%@", self, flag ? @"YES" : @"NO");
3054     _private->needsLayout = flag;
3055 }
3056
3057 - (void)setNeedsToApplyStyles: (BOOL)flag
3058 {
3059     LOG(View, "%@ setNeedsToApplyStyles:%@", self, flag ? @"YES" : @"NO");
3060     _private->needsToApplyStyles = flag;
3061 }
3062
3063 - (void)drawSingleRect:(NSRect)rect
3064 {
3065     [NSGraphicsContext saveGraphicsState];
3066     NSRectClip(rect);
3067         
3068     ASSERT([[self superview] isKindOfClass:[WebClipView class]]);
3069
3070     [(WebClipView *)[self superview] setAdditionalClip:rect];
3071
3072     @try {
3073         if ([self _transparentBackground]) {
3074             [[NSColor clearColor] set];
3075             NSRectFill (rect);
3076         }
3077
3078         [[self _frame] _drawRect:rect contentsOnly:YES];
3079
3080         WebView *webView = [self _webView];
3081
3082         // This hack is needed for <rdar://problem/5023545>. We can hit a race condition where drawRect will be
3083         // called after the WebView has closed. If the client did not properly close the WebView and set the 
3084         // UIDelegate to nil, then the UIDelegate will be stale and this code will crash. 
3085         static BOOL version3OrLaterClient = WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITHOUT_QUICKBOOKS_QUIRK);
3086         if (version3OrLaterClient)
3087             [[webView _UIDelegateForwarder] webView:webView didDrawRect:[webView convertRect:rect fromView:self]];
3088
3089         if (WebNodeHighlight *currentHighlight = [webView currentNodeHighlight])
3090             [currentHighlight setNeedsUpdateInTargetViewRect:[self convertRect:rect toView:[currentHighlight targetView]]];
3091
3092         [(WebClipView *)[self superview] resetAdditionalClip];
3093
3094         [NSGraphicsContext restoreGraphicsState];
3095     } @catch (NSException *localException) {
3096         [(WebClipView *)[self superview] resetAdditionalClip];
3097         [NSGraphicsContext restoreGraphicsState];
3098         LOG_ERROR("Exception caught while drawing: %@", localException);
3099         [localException raise];
3100     }
3101 }
3102
3103 - (void)drawRect:(NSRect)rect
3104 {
3105     ASSERT_MAIN_THREAD();
3106     LOG(View, "%@ drawing", self);
3107
3108     const NSRect *rects;
3109     NSInteger count;
3110     [self getRectsBeingDrawn:&rects count:&count];
3111
3112     BOOL subviewsWereSetAside = _private->subviewsSetAside;
3113     if (subviewsWereSetAside)
3114         [self _restoreSubviews];
3115
3116 #ifdef LOG_TIMES
3117     double start = CFAbsoluteTimeGetCurrent();
3118 #endif
3119
3120     if ([[self _webView] _mustDrawUnionedRect:rect singleRects:rects count:count])
3121         [self drawSingleRect:rect];
3122     else
3123         for (int i = 0; i < count; ++i)
3124             [self drawSingleRect:rects[i]];
3125
3126 #ifdef LOG_TIMES
3127     double thisTime = CFAbsoluteTimeGetCurrent() - start;
3128     LOG(Timing, "%s draw seconds = %f", widget->part()->baseURL().URL().latin1(), thisTime);
3129 #endif
3130
3131     if (subviewsWereSetAside)
3132         [self _setAsideSubviews];
3133         
3134 #if USE(ACCELERATED_COMPOSITING)
3135     if ([[self _webView] _needsOneShotDrawingSynchronization]) {
3136         // Disable screen updates so that drawing into the NSView and
3137         // CALayer updates appear on the screen at the same time.
3138         [[self window] disableScreenUpdatesUntilFlush];
3139         [CATransaction flush];
3140         [[self _webView] _setNeedsOneShotDrawingSynchronization:NO];
3141     }
3142 #endif
3143 }
3144
3145 // Turn off the additional clip while computing our visibleRect.
3146 - (NSRect)visibleRect
3147 {
3148     if (!([[self superview] isKindOfClass:[WebClipView class]]))
3149         return [super visibleRect];
3150         
3151     WebClipView *clipView = (WebClipView *)[self superview];
3152
3153     BOOL hasAdditionalClip = [clipView hasAdditionalClip];
3154     if (!hasAdditionalClip) {
3155         return [super visibleRect];
3156     }
3157     
3158     NSRect additionalClip = [clipView additionalClip];
3159     [clipView resetAdditionalClip];
3160     NSRect visibleRect = [super visibleRect];
3161     [clipView setAdditionalClip:additionalClip];
3162     return visibleRect;
3163 }
3164
3165 - (BOOL)isFlipped 
3166 {
3167     return YES;
3168 }
3169
3170 - (void)windowDidBecomeKey:(NSNotification *)notification
3171 {
3172     NSWindow *keyWindow = [notification object];
3173
3174     if (keyWindow == [self window])
3175         [self addMouseMovedObserver];
3176
3177     if (keyWindow == [self window] || keyWindow == [[self window] attachedSheet])
3178         [self _updateFocusedAndActiveState];
3179 }
3180
3181 - (void)windowDidResignKey:(NSNotification *)notification
3182 {
3183     NSWindow *formerKeyWindow = [notification object];
3184
3185     if (formerKeyWindow == [self window])
3186         [self removeMouseMovedObserver];
3187
3188     if (formerKeyWindow == [self window] || formerKeyWindow == [[self window] attachedSheet]) {
3189         [self _updateFocusedAndActiveState];
3190         [_private->compController endRevertingChange:NO moveLeft:NO];
3191     }
3192 }
3193
3194 - (void)windowWillClose:(NSNotification *)notification
3195 {
3196     [_private->compController endRevertingChange:NO moveLeft:NO];
3197     [[self _pluginController] destroyAllPlugins];
3198 }
3199
3200 - (void)windowWillOrderOnScreen:(NSNotification *)notification
3201 {
3202     if (![[self _webView] shouldUpdateWhileOffscreen])
3203         [self setNeedsDisplay:YES];
3204 }
3205
3206 - (void)scrollWheel:(NSEvent *)event
3207 {
3208     [self retain];
3209     Frame* frame = core([self _frame]);
3210     if (!frame || !frame->eventHandler()->wheelEvent(event))
3211         [super scrollWheel:event];
3212     [self release];
3213 }
3214
3215 - (BOOL)_isSelectionEvent:(NSEvent *)event
3216 {
3217     NSPoint point = [self convertPoint:[event locationInWindow] fromView:nil];
3218     return [[[self elementAtPoint:point allowShadowContent:YES] objectForKey:WebElementIsSelectedKey] boolValue];
3219 }
3220
3221 - (BOOL)acceptsFirstMouse:(NSEvent *)event
3222 {
3223     NSView *hitView = [self _hitViewForEvent:event];
3224     WebHTMLView *hitHTMLView = [hitView isKindOfClass:[self class]] ? (WebHTMLView *)hitView : nil;
3225     
3226 #if ENABLE(DASHBOARD_SUPPORT)
3227     if ([[self _webView] _dashboardBehavior:WebDashboardBehaviorAlwaysAcceptsFirstMouse])
3228         return YES;
3229 #endif
3230     
3231     if (hitHTMLView) {
3232         bool result = false;
3233         if (Frame* coreFrame = core([hitHTMLView _frame])) {
3234             coreFrame->eventHandler()->setActivationEventNumber([event eventNumber]);
3235             [hitHTMLView _setMouseDownEvent:event];
3236             if ([hitHTMLView _isSelectionEvent:event])
3237                 result = coreFrame->eventHandler()->eventMayStartDrag(event);
3238             [hitHTMLView _setMouseDownEvent:nil];
3239         }
3240         return result;
3241     }
3242     return [hitView acceptsFirstMouse:event];
3243 }
3244
3245 - (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)event
3246 {
3247     NSView *hitView = [self _hitViewForEvent:event];
3248     WebHTMLView *hitHTMLView = [hitView isKindOfClass:[self class]] ? (WebHTMLView *)hitView : nil;
3249     if (hitHTMLView) {
3250         bool result = false;
3251         if ([hitHTMLView _isSelectionEvent:event])
3252             if (Frame* coreFrame = core([hitHTMLView _frame])) {
3253                 [hitHTMLView _setMouseDownEvent:event];
3254                 result = coreFrame->eventHandler()->eventMayStartDrag(event);
3255                 [hitHTMLView _setMouseDownEvent:nil];
3256             }
3257         return result;
3258     }
3259     return [hitView shouldDelayWindowOrderingForEvent:event];
3260 }
3261
3262 - (void)mouseDown:(NSEvent *)event
3263 {
3264     RetainPtr<WebHTMLView> protector = self;
3265     if ([[self inputContext] wantsToHandleMouseEvents] && [[self inputContext] handleMouseEvent:event])
3266         return;
3267
3268     _private->handlingMouseDownEvent = YES;
3269
3270     // Record the mouse down position so we can determine drag hysteresis.
3271     [self _setMouseDownEvent:event];
3272
3273     NSInputManager *currentInputManager = [NSInputManager currentInputManager];
3274     if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event])
3275         goto done;
3276
3277     [_private->compController endRevertingChange:NO moveLeft:NO];
3278
3279     // If the web page handles the context menu event and menuForEvent: returns nil, we'll get control click events here.
3280     // We don't want to pass them along to KHTML a second time.
3281     if (!([event modifierFlags] & NSControlKeyMask)) {
3282         _private->ignoringMouseDraggedEvents = NO;
3283
3284         // Don't do any mouseover while the mouse is down.
3285         [self _cancelUpdateMouseoverTimer];
3286
3287         // Let WebCore get a chance to deal with the event. This will call back to us
3288         // to start the autoscroll timer if appropriate.
3289         if (Frame* coreframe = core([self _frame]))
3290             coreframe->eventHandler()->mouseDown(event);
3291     }
3292
3293 done:
3294     _private->handlingMouseDownEvent = NO;
3295 }
3296
3297 - (void)dragImage:(NSImage *)dragImage
3298                at:(NSPoint)at
3299            offset:(NSSize)offset
3300             event:(NSEvent *)event
3301        pasteboard:(NSPasteboard *)pasteboard
3302            source:(id)source
3303         slideBack:(BOOL)slideBack
3304 {
3305     ASSERT(self == [self _topHTMLView]);
3306     [super dragImage:dragImage at:at offset:offset event:event pasteboard:pasteboard source:source slideBack:slideBack];
3307 }
3308
3309 - (void)mouseDragged:(NSEvent *)event
3310 {
3311     NSInputManager *currentInputManager = [NSInputManager currentInputManager];
3312     if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event])
3313         return;
3314
3315     [self retain];
3316
3317     if (!_private->ignoringMouseDraggedEvents)
3318         if (Frame* coreframe = core([self _frame]))
3319             coreframe->eventHandler()->mouseDragged(event);
3320
3321     [self release];
3322 }
3323
3324 - (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
3325 {
3326     ASSERT(![self _webView] || [self _isTopHTMLView]);
3327     
3328     Page *page = core([self _webView]);
3329     
3330     if (!page)
3331         return NSDragOperationNone;
3332     
3333     if (page->dragController()->dragOperation() == DragOperationNone)
3334         return NSDragOperationGeneric | NSDragOperationCopy;
3335     
3336     return (NSDragOperation)page->dragController()->dragOperation();
3337 }
3338
3339 - (void)draggedImage:(NSImage *)image movedTo:(NSPoint)screenLoc
3340 {
3341     ASSERT(![self _webView] || [self _isTopHTMLView]);
3342     
3343     NSPoint windowImageLoc = [[self window] convertScreenToBase:screenLoc];
3344     NSPoint windowMouseLoc = windowImageLoc;
3345     
3346     if (Page* page = core([self _webView])) {
3347         DragController* dragController = page->dragController();
3348         NSPoint windowMouseLoc = NSMakePoint(windowImageLoc.x + dragController->dragOffset().x(), windowImageLoc.y + dragController->dragOffset().y());
3349     }
3350     
3351     [[self _frame] _dragSourceMovedTo:windowMouseLoc];
3352 }
3353
3354 - (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
3355 {
3356     ASSERT(![self _webView] || [self _isTopHTMLView]);
3357     
3358     NSPoint windowImageLoc = [[self window] convertScreenToBase:aPoint];
3359     NSPoint windowMouseLoc = windowImageLoc;
3360     
3361     if (Page* page = core([self _webView])) {
3362         DragController* dragController = page->dragController();
3363         windowMouseLoc = NSMakePoint(windowImageLoc.x + dragController->dragOffset().x(), windowImageLoc.y + dragController->dragOffset().y());
3364         dragController->dragEnded();
3365     }
3366     
3367     [[self _frame] _dragSourceEndedAt:windowMouseLoc operation:operation];
3368     
3369     // Prevent queued mouseDragged events from coming after the drag and fake mouseUp event.
3370     _private->ignoringMouseDraggedEvents = YES;
3371     
3372     // Once the dragging machinery kicks in, we no longer get mouse drags or the up event.
3373     // WebCore expects to get balanced down/up's, so we must fake up a mouseup.
3374     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseUp
3375                                             location:windowMouseLoc
3376                                        modifierFlags:[[NSApp currentEvent] modifierFlags]
3377                                            timestamp:[NSDate timeIntervalSinceReferenceDate]
3378                                         windowNumber:[[self window] windowNumber]
3379                                              context:[[NSApp currentEvent] context]
3380                                          eventNumber:0 clickCount:0 pressure:0];
3381     [self mouseUp:fakeEvent]; // This will also update the mouseover state.
3382 }
3383
3384 - (NSArray *)namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination
3385 {
3386     NSFileWrapper *wrapper = nil;
3387     NSURL *draggingImageURL = nil;
3388     
3389     if (WebCore::CachedImage* tiffResource = [self promisedDragTIFFDataSource]) {
3390         
3391         SharedBuffer *buffer = static_cast<CachedResource*>(tiffResource)->data();
3392         if (!buffer)
3393             goto noPromisedData;
3394         
3395         NSData *data = buffer->createNSData();
3396         NSURLResponse *response = tiffResource->response().nsURLResponse();
3397         draggingImageURL = [response URL];
3398         wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:data] autorelease];
3399         NSString* filename = [response suggestedFilename];
3400         NSString* trueExtension(tiffResource->image()->filenameExtension());
3401         if (![filename matchesExtensionEquivalent:trueExtension])
3402             filename = [[filename stringByAppendingString:@"."] stringByAppendingString:trueExtension];
3403         [wrapper setPreferredFilename:filename];
3404     }
3405     
3406 noPromisedData:
3407     
3408     if (!wrapper) {
3409         ASSERT(![self _webView] || [self _isTopHTMLView]);
3410         Page* page = core([self _webView]);
3411         
3412         //If a load occurs midway through a drag, the view may be detached, which gives
3413         //us no ability to get to the original Page, so we cannot access any drag state
3414         //FIXME: is there a way to recover?
3415         if (!page) 
3416             return nil; 
3417         
3418         const KURL& imageURL = page->dragController()->draggingImageURL();
3419         ASSERT(!imageURL.isEmpty());
3420         draggingImageURL = imageURL;
3421
3422         wrapper = [[self _dataSource] _fileWrapperForURL:draggingImageURL];
3423     }
3424     
3425     if (wrapper == nil) {
3426         LOG_ERROR("Failed to create image file.");
3427         return nil;
3428     }
3429
3430     // FIXME: Report an error if we fail to create a file.
3431     NSString *path = [[dropDestination path] stringByAppendingPathComponent:[wrapper preferredFilename]];
3432     path = [[NSFileManager defaultManager] _webkit_pathWithUniqueFilenameForPath:path];
3433     if (![wrapper writeToFile:path atomically:NO updateFilenames:YES])
3434         LOG_ERROR("Failed to create image file via -[NSFileWrapper writeToFile:atomically:updateFilenames:]");
3435     
3436     if (draggingImageURL)
3437         [[NSFileManager defaultManager] _webkit_setMetadataURL:[draggingImageURL absoluteString] referrer:nil atPath:path];
3438     
3439     return [NSArray arrayWithObject:[path lastPathComponent]];
3440 }
3441
3442 - (void)mouseUp:(NSEvent *)event
3443 {
3444     [self _setMouseDownEvent:nil];
3445
3446     NSInputManager *currentInputManager = [NSInputManager currentInputManager];
3447     if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event])
3448         return;
3449
3450     [self retain];
3451
3452     [self _stopAutoscrollTimer];
3453     if (Frame* coreframe = core([self _frame]))
3454         coreframe->eventHandler()->mouseUp(event);
3455     [self _updateMouseoverWithFakeEvent];
3456
3457     [self release];
3458 }
3459
3460 - (void)mouseMovedNotification:(NSNotification *)notification
3461 {
3462     [self _updateMouseoverWithEvent:[[notification userInfo] objectForKey:@"NSEvent"]];
3463 }
3464
3465 // returning YES from this method is the way we tell AppKit that it is ok for this view
3466 // to be in the key loop even when "tab to all controls" is not on.
3467 - (BOOL)needsPanelToBecomeKey
3468 {
3469     return YES;
3470 }
3471
3472 - (BOOL)becomeFirstResponder
3473 {
3474     NSSelectionDirection direction = NSDirectSelection;
3475     if (![[self _webView] _isPerformingProgrammaticFocus])
3476         direction = [[self window] keyViewSelectionDirection];
3477
3478     [self _updateFocusedAndActiveState];
3479     [self _updateFontPanel];
3480     
3481     Frame* frame = core([self _frame]);
3482     if (!frame)
3483         return YES;
3484     
3485     frame->editor()->setStartNewKillRingSequence(true);
3486
3487     if (direction == NSDirectSelection)
3488         return YES;
3489
3490     Page* page = frame->page();
3491     if (!page)
3492         return YES;
3493
3494     page->focusController()->setFocusedFrame(frame);
3495     if (Document* document = frame->document())
3496         document->setFocusedNode(0);
3497     page->focusController()->setInitialFocus(direction == NSSelectingNext ? FocusDirectionForward : FocusDirectionBackward,
3498                                              frame->eventHandler()->currentKeyboardEvent().get());
3499     return YES;
3500 }
3501
3502 - (BOOL)resignFirstResponder
3503 {
3504     BOOL resign = [super resignFirstResponder];
3505     if (resign) {
3506         _private->resigningFirstResponder = YES;
3507         [_private->compController endRevertingChange:NO moveLeft:NO];
3508         if (![self maintainsInactiveSelection]) { 
3509             [self deselectAll];
3510             if (![[self _webView] _isPerformingProgrammaticFocus])
3511                 [self clearFocus];
3512         }
3513         [self _updateFocusedAndActiveState];
3514         _private->resigningFirstResponder = NO;
3515     }
3516     return resign;
3517 }
3518
3519 - (void)setDataSource:(WebDataSource *)dataSource 
3520 {
3521     ASSERT(dataSource);
3522     if (_private->dataSource != dataSource) {
3523         ASSERT(!_private->closed);
3524         BOOL hadDataSource = _private->dataSource != nil;
3525
3526         [dataSource retain];
3527         [_private->dataSource release];
3528         _private->dataSource = dataSource;
3529         [_private->pluginController setDataSource:dataSource];
3530
3531         if (!hadDataSource)
3532             [self addMouseMovedObserver];
3533     }
3534 }
3535
3536 - (void)dataSourceUpdated:(WebDataSource *)dataSource
3537 {
3538 }