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