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