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