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