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