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