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