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