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