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