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