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