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