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