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