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