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