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