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