Clicking "Go Back" from a safe browsing warning from an iframe should navigate the...
[WebKit-https.git] / Source / WebKit / UIProcess / Cocoa / WebViewImpl.mm
1 /*
2  * Copyright (C) 2015-2019 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "WebViewImpl.h"
28
29 #if PLATFORM(MAC)
30
31 #import "APIAttachment.h"
32 #import "APILegacyContextHistoryClient.h"
33 #import "APINavigation.h"
34 #import "AppKitSPI.h"
35 #import "AttributedString.h"
36 #import "ColorSpaceData.h"
37 #import "FullscreenClient.h"
38 #import "GenericCallback.h"
39 #import "Logging.h"
40 #import "NativeWebGestureEvent.h"
41 #import "NativeWebKeyboardEvent.h"
42 #import "NativeWebMouseEvent.h"
43 #import "NativeWebWheelEvent.h"
44 #import "PageClient.h"
45 #import "PageClientImplMac.h"
46 #import "PasteboardTypes.h"
47 #import "PlaybackSessionManagerProxy.h"
48 #import "RemoteLayerTreeDrawingAreaProxy.h"
49 #import "RemoteObjectRegistry.h"
50 #import "RemoteObjectRegistryMessages.h"
51 #import "StringUtilities.h"
52 #import "TextChecker.h"
53 #import "TextCheckerState.h"
54 #import "TiledCoreAnimationDrawingAreaProxy.h"
55 #import "UIGamepadProvider.h"
56 #import "UndoOrRedo.h"
57 #import "ViewGestureController.h"
58 #import "WKBrowsingContextControllerInternal.h"
59 #import "WKEditCommand.h"
60 #import "WKErrorInternal.h"
61 #import "WKFullScreenWindowController.h"
62 #import "WKImmediateActionController.h"
63 #import "WKPrintingView.h"
64 #import "WKSafeBrowsingWarning.h"
65 #import "WKShareSheet.h"
66 #import "WKTextInputWindowController.h"
67 #import "WKViewLayoutStrategy.h"
68 #import "WKWebViewInternal.h"
69 #import "WKWebViewPrivate.h"
70 #import "WebBackForwardList.h"
71 #import "WebEditCommandProxy.h"
72 #import "WebEventFactory.h"
73 #import "WebInspectorProxy.h"
74 #import "WebPageProxy.h"
75 #import "WebProcessPool.h"
76 #import "WebProcessProxy.h"
77 #import "_WKRemoteObjectRegistryInternal.h"
78 #import "_WKThumbnailViewInternal.h"
79 #import <Carbon/Carbon.h>
80 #import <WebCore/AXObjectCache.h>
81 #import <WebCore/ActivityState.h>
82 #import <WebCore/ColorMac.h>
83 #import <WebCore/DictionaryLookup.h>
84 #import <WebCore/DragData.h>
85 #import <WebCore/DragItem.h>
86 #import <WebCore/Editor.h>
87 #import <WebCore/FontAttributeChanges.h>
88 #import <WebCore/FontAttributes.h>
89 #import <WebCore/KeypressCommand.h>
90 #import <WebCore/LegacyNSPasteboardTypes.h>
91 #import <WebCore/LoaderNSURLExtras.h>
92 #import <WebCore/LocalizedStrings.h>
93 #import <WebCore/PlatformEventFactoryMac.h>
94 #import <WebCore/PromisedAttachmentInfo.h>
95 #import <WebCore/TextAlternativeWithRange.h>
96 #import <WebCore/TextUndoInsertionMarkupMac.h>
97 #import <WebCore/WebActionDisablingCALayerDelegate.h>
98 #import <WebCore/WebCoreCALayerExtras.h>
99 #import <WebCore/WebCoreFullScreenPlaceholderView.h>
100 #import <WebCore/WebCoreFullScreenWindow.h>
101 #import <WebCore/WebCoreNSFontManagerExtras.h>
102 #import <WebCore/WebPlaybackControlsManager.h>
103 #import <pal/spi/cg/CoreGraphicsSPI.h>
104 #import <pal/spi/cocoa/AVKitSPI.h>
105 #import <pal/spi/cocoa/NSTouchBarSPI.h>
106 #import <pal/spi/mac/DataDetectorsSPI.h>
107 #import <pal/spi/mac/LookupSPI.h>
108 #import <pal/spi/mac/NSAccessibilitySPI.h>
109 #import <pal/spi/mac/NSApplicationSPI.h>
110 #import <pal/spi/mac/NSImmediateActionGestureRecognizerSPI.h>
111 #import <pal/spi/mac/NSScrollerImpSPI.h>
112 #import <pal/spi/mac/NSSpellCheckerSPI.h>
113 #import <pal/spi/mac/NSTextFinderSPI.h>
114 #import <pal/spi/mac/NSViewSPI.h>
115 #import <pal/spi/mac/NSWindowSPI.h>
116 #import <sys/stat.h>
117 #import <wtf/FileSystem.h>
118 #import <wtf/NeverDestroyed.h>
119 #import <wtf/ProcessPrivilege.h>
120 #import <wtf/SetForScope.h>
121 #import <wtf/SoftLinking.h>
122 #import <wtf/cf/TypeCastsCF.h>
123 #import <wtf/text/StringConcatenate.h>
124
125 #if HAVE(TOUCH_BAR) && ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
126 SOFT_LINK_FRAMEWORK(AVKit)
127 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
128 SOFT_LINK_CLASS(AVKit, AVTouchBarPlaybackControlsProvider)
129 SOFT_LINK_CLASS(AVKit, AVTouchBarScrubber)
130 #else
131 SOFT_LINK_CLASS(AVKit, AVFunctionBarPlaybackControlsProvider)
132 SOFT_LINK_CLASS(AVKit, AVFunctionBarScrubber)
133 #endif // __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
134
135 static NSString * const WKMediaExitFullScreenItem = @"WKMediaExitFullScreenItem";
136 #endif // HAVE(TOUCH_BAR) && ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
137
138 WTF_DECLARE_CF_TYPE_TRAIT(CGImage);
139
140 @interface NSApplication ()
141 - (BOOL)isSpeaking;
142 - (void)speakString:(NSString *)string;
143 - (void)stopSpeaking:(id)sender;
144 @end
145
146 // FIXME: Move to an SPI header.
147 @interface NSTextInputContext (WKNSTextInputContextDetails)
148 - (void)handleEvent:(NSEvent *)event completionHandler:(void(^)(BOOL handled))completionHandler;
149 - (void)handleEventByInputMethod:(NSEvent *)event completionHandler:(void(^)(BOOL handled))completionHandler;
150 - (BOOL)handleEventByKeyboardLayout:(NSEvent *)event;
151 @end
152
153 #if HAVE(TOUCH_BAR) && ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
154 // FIXME: Remove this once -setCanShowMediaSelectionButton: is declared in an SDK used by Apple's buildbot.
155 @interface AVTouchBarScrubber ()
156 - (void)setCanShowMediaSelectionButton:(BOOL)canShowMediaSelectionButton;
157 @end
158 #endif
159
160 @interface WKAccessibilitySettingsObserver : NSObject {
161     WebKit::WebViewImpl *_impl;
162 }
163
164 - (instancetype)initWithImpl:(WebKit::WebViewImpl&)impl;
165 @end
166
167 @implementation WKAccessibilitySettingsObserver
168
169 - (instancetype)initWithImpl:(WebKit::WebViewImpl&)impl
170 {
171     self = [super init];
172     if (!self)
173         return nil;
174
175     _impl = &impl;
176
177     NSNotificationCenter* workspaceNotificationCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
178     [workspaceNotificationCenter addObserver:self selector:@selector(_settingsDidChange:) name:NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification object:nil];
179
180     return self;
181 }
182
183 - (void)dealloc
184 {
185     NSNotificationCenter *workspaceNotificationCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
186     [workspaceNotificationCenter removeObserver:self name:NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification object:nil];
187
188     [super dealloc];
189 }
190
191 - (void)_settingsDidChange:(NSNotification *)notification
192 {
193     _impl->accessibilitySettingsDidChange();
194 }
195
196 @end
197
198 @interface WKWindowVisibilityObserver : NSObject {
199     NSView *_view;
200     WebKit::WebViewImpl *_impl;
201
202     BOOL _didRegisterForLookupPopoverCloseNotifications;
203 }
204
205 - (instancetype)initWithView:(NSView *)view impl:(WebKit::WebViewImpl&)impl;
206 - (void)startObserving:(NSWindow *)window;
207 - (void)stopObserving:(NSWindow *)window;
208 - (void)startObservingFontPanel;
209 - (void)startObservingLookupDismissalIfNeeded;
210 @end
211
212 @implementation WKWindowVisibilityObserver
213
214 - (instancetype)initWithView:(NSView *)view impl:(WebKit::WebViewImpl&)impl
215 {
216     self = [super init];
217     if (!self)
218         return nil;
219
220     _view = view;
221     _impl = &impl;
222
223     NSNotificationCenter* workspaceNotificationCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
224     [workspaceNotificationCenter addObserver:self selector:@selector(_activeSpaceDidChange:) name:NSWorkspaceActiveSpaceDidChangeNotification object:nil];
225
226     return self;
227 }
228
229 - (void)dealloc
230 {
231 #if !ENABLE(REVEAL)
232     if (_didRegisterForLookupPopoverCloseNotifications && PAL::canLoad_Lookup_LUNotificationPopoverWillClose())
233         [[NSNotificationCenter defaultCenter] removeObserver:self name:PAL::get_Lookup_LUNotificationPopoverWillClose() object:nil];
234 #endif // !ENABLE(REVEAL)
235
236     NSNotificationCenter *workspaceNotificationCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
237     [workspaceNotificationCenter removeObserver:self name:NSWorkspaceActiveSpaceDidChangeNotification object:nil];
238
239     [super dealloc];
240 }
241
242 static void* keyValueObservingContext = &keyValueObservingContext;
243
244 - (void)startObserving:(NSWindow *)window
245 {
246     if (!window)
247         return;
248
249     NSNotificationCenter *defaultNotificationCenter = [NSNotificationCenter defaultCenter];
250
251     // An NSView derived object such as WKView cannot observe these notifications, because NSView itself observes them.
252     [defaultNotificationCenter addObserver:self selector:@selector(_windowDidOrderOffScreen:) name:@"NSWindowDidOrderOffScreenNotification" object:window];
253     [defaultNotificationCenter addObserver:self selector:@selector(_windowDidOrderOnScreen:) name:@"_NSWindowDidBecomeVisible" object:window];
254
255     [defaultNotificationCenter addObserver:self selector:@selector(_windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:nil];
256     [defaultNotificationCenter addObserver:self selector:@selector(_windowDidResignKey:) name:NSWindowDidResignKeyNotification object:nil];
257     [defaultNotificationCenter addObserver:self selector:@selector(_windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:window];
258     [defaultNotificationCenter addObserver:self selector:@selector(_windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:window];
259     [defaultNotificationCenter addObserver:self selector:@selector(_windowDidMove:) name:NSWindowDidMoveNotification object:window];
260     [defaultNotificationCenter addObserver:self selector:@selector(_windowDidResize:) name:NSWindowDidResizeNotification object:window];
261     [defaultNotificationCenter addObserver:self selector:@selector(_windowDidChangeBackingProperties:) name:NSWindowDidChangeBackingPropertiesNotification object:window];
262     [defaultNotificationCenter addObserver:self selector:@selector(_windowDidChangeScreen:) name:NSWindowDidChangeScreenNotification object:window];
263     [defaultNotificationCenter addObserver:self selector:@selector(_windowDidChangeLayerHosting:) name:@"_NSWindowDidChangeContentsHostedInLayerSurfaceNotification" object:window];
264     [defaultNotificationCenter addObserver:self selector:@selector(_windowDidChangeOcclusionState:) name:NSWindowDidChangeOcclusionStateNotification object:window];
265
266     [window addObserver:self forKeyPath:@"contentLayoutRect" options:NSKeyValueObservingOptionInitial context:keyValueObservingContext];
267     [window addObserver:self forKeyPath:@"titlebarAppearsTransparent" options:NSKeyValueObservingOptionInitial context:keyValueObservingContext];
268 }
269
270 - (void)stopObserving:(NSWindow *)window
271 {
272     if (!window)
273         return;
274
275     NSNotificationCenter *defaultNotificationCenter = [NSNotificationCenter defaultCenter];
276
277     [defaultNotificationCenter removeObserver:self name:@"NSWindowDidOrderOffScreenNotification" object:window];
278     [defaultNotificationCenter removeObserver:self name:@"_NSWindowDidBecomeVisible" object:window];
279
280     [defaultNotificationCenter removeObserver:self name:NSWindowDidBecomeKeyNotification object:nil];
281     [defaultNotificationCenter removeObserver:self name:NSWindowDidResignKeyNotification object:nil];
282     [defaultNotificationCenter removeObserver:self name:NSWindowDidMiniaturizeNotification object:window];
283     [defaultNotificationCenter removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window];
284     [defaultNotificationCenter removeObserver:self name:NSWindowDidMoveNotification object:window];
285     [defaultNotificationCenter removeObserver:self name:NSWindowDidResizeNotification object:window];
286     [defaultNotificationCenter removeObserver:self name:NSWindowDidChangeBackingPropertiesNotification object:window];
287     [defaultNotificationCenter removeObserver:self name:NSWindowDidChangeScreenNotification object:window];
288     [defaultNotificationCenter removeObserver:self name:@"_NSWindowDidChangeContentsHostedInLayerSurfaceNotification" object:window];
289     [defaultNotificationCenter removeObserver:self name:NSWindowDidChangeOcclusionStateNotification object:window];
290
291     if (_impl->isEditable())
292         [[NSFontPanel sharedFontPanel] removeObserver:self forKeyPath:@"visible" context:keyValueObservingContext];
293     [window removeObserver:self forKeyPath:@"contentLayoutRect" context:keyValueObservingContext];
294     [window removeObserver:self forKeyPath:@"titlebarAppearsTransparent" context:keyValueObservingContext];
295 }
296
297 - (void)startObservingFontPanel
298 {
299     [[NSFontPanel sharedFontPanel] addObserver:self forKeyPath:@"visible" options:0 context:keyValueObservingContext];
300 }
301
302 - (void)startObservingLookupDismissalIfNeeded
303 {
304     if (_didRegisterForLookupPopoverCloseNotifications)
305         return;
306
307     _didRegisterForLookupPopoverCloseNotifications = YES;
308 #if !ENABLE(REVEAL)
309     if (PAL::canLoad_Lookup_LUNotificationPopoverWillClose())
310         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_dictionaryLookupPopoverWillClose:) name:PAL::get_Lookup_LUNotificationPopoverWillClose() object:nil];
311 #endif
312 }
313
314 - (void)_windowDidOrderOnScreen:(NSNotification *)notification
315 {
316     _impl->windowDidOrderOnScreen();
317 }
318
319 - (void)_windowDidOrderOffScreen:(NSNotification *)notification
320 {
321     _impl->windowDidOrderOffScreen();
322 }
323
324 - (void)_windowDidBecomeKey:(NSNotification *)notification
325 {
326     _impl->windowDidBecomeKey([notification object]);
327 }
328
329 - (void)_windowDidResignKey:(NSNotification *)notification
330 {
331     _impl->windowDidResignKey([notification object]);
332 }
333
334 - (void)_windowDidMiniaturize:(NSNotification *)notification
335 {
336     _impl->windowDidMiniaturize();
337 }
338
339 - (void)_windowDidDeminiaturize:(NSNotification *)notification
340 {
341     _impl->windowDidDeminiaturize();
342 }
343
344 - (void)_windowDidMove:(NSNotification *)notification
345 {
346     _impl->windowDidMove();
347 }
348
349 - (void)_windowDidResize:(NSNotification *)notification
350 {
351     _impl->windowDidResize();
352 }
353
354 - (void)_windowDidChangeBackingProperties:(NSNotification *)notification
355 {
356     CGFloat oldBackingScaleFactor = [[notification.userInfo objectForKey:NSBackingPropertyOldScaleFactorKey] doubleValue];
357     _impl->windowDidChangeBackingProperties(oldBackingScaleFactor);
358 }
359
360 - (void)_windowDidChangeScreen:(NSNotification *)notification
361 {
362     _impl->windowDidChangeScreen();
363 }
364
365 - (void)_windowDidChangeLayerHosting:(NSNotification *)notification
366 {
367     _impl->windowDidChangeLayerHosting();
368 }
369
370 - (void)_windowDidChangeOcclusionState:(NSNotification *)notification
371 {
372     _impl->windowDidChangeOcclusionState();
373 }
374
375 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
376 {
377     if (context != keyValueObservingContext) {
378         [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
379         return;
380     }
381
382     if ([keyPath isEqualToString:@"visible"] && [NSFontPanel sharedFontPanelExists] && object == [NSFontPanel sharedFontPanel]) {
383         _impl->updateFontManagerIfNeeded();
384         return;
385     }
386     if ([keyPath isEqualToString:@"contentLayoutRect"] || [keyPath isEqualToString:@"titlebarAppearsTransparent"])
387         _impl->updateContentInsetsIfAutomatic();
388 }
389
390 #if !ENABLE(REVEAL)
391 - (void)_dictionaryLookupPopoverWillClose:(NSNotification *)notification
392 {
393     _impl->clearTextIndicatorWithAnimation(WebCore::TextIndicatorWindowDismissalAnimation::None);
394 }
395 #endif
396
397 - (void)_activeSpaceDidChange:(NSNotification *)notification
398 {
399     _impl->activeSpaceDidChange();
400 }
401
402 @end
403
404 @interface WKFlippedView : NSView
405 @end
406
407 @implementation WKFlippedView
408
409 - (BOOL)isFlipped
410 {
411     return YES;
412 }
413
414 @end
415
416 @interface WKResponderChainSink : NSResponder {
417     NSResponder *_lastResponderInChain;
418     bool _didReceiveUnhandledCommand;
419 }
420
421 - (id)initWithResponderChain:(NSResponder *)chain;
422 - (void)detach;
423 - (bool)didReceiveUnhandledCommand;
424 @end
425
426 @implementation WKResponderChainSink
427
428 - (id)initWithResponderChain:(NSResponder *)chain
429 {
430     self = [super init];
431     if (!self)
432         return nil;
433     _lastResponderInChain = chain;
434     while (NSResponder *next = [_lastResponderInChain nextResponder])
435         _lastResponderInChain = next;
436     [_lastResponderInChain setNextResponder:self];
437     return self;
438 }
439
440 - (void)detach
441 {
442     // This assumes that the responder chain was either unmodified since
443     // -initWithResponderChain: was called, or was modified in such a way
444     // that _lastResponderInChain is still in the chain, and self was not
445     // moved earlier in the chain than _lastResponderInChain.
446     NSResponder *responderBeforeSelf = _lastResponderInChain;
447     NSResponder *next = [responderBeforeSelf nextResponder];
448     for (; next && next != self; next = [next nextResponder])
449         responderBeforeSelf = next;
450
451     // Nothing to be done if we are no longer in the responder chain.
452     if (next != self)
453         return;
454
455     [responderBeforeSelf setNextResponder:[self nextResponder]];
456     _lastResponderInChain = nil;
457 }
458
459 - (bool)didReceiveUnhandledCommand
460 {
461     return _didReceiveUnhandledCommand;
462 }
463
464 - (void)noResponderFor:(SEL)selector
465 {
466     _didReceiveUnhandledCommand = true;
467 }
468
469 - (void)doCommandBySelector:(SEL)selector
470 {
471     _didReceiveUnhandledCommand = true;
472 }
473
474 - (BOOL)tryToPerform:(SEL)action with:(id)object
475 {
476     _didReceiveUnhandledCommand = true;
477     return YES;
478 }
479
480 @end
481
482 #if HAVE(TOUCH_BAR)
483
484 @interface WKTextListTouchBarViewController : NSViewController {
485 @private
486     WebKit::WebViewImpl* _webViewImpl;
487     WebKit::ListType _currentListType;
488 }
489
490 @property (nonatomic) WebKit::ListType currentListType;
491
492 - (instancetype)initWithWebViewImpl:(WebKit::WebViewImpl*)webViewImpl;
493
494 @end
495
496 @implementation WKTextListTouchBarViewController
497
498 @synthesize currentListType=_currentListType;
499
500 static const CGFloat listControlSegmentWidth = 67;
501 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER) && ENABLE(FULLSCREEN_API)
502 static const CGFloat exitFullScreenButtonWidth = 64;
503 #endif
504
505 static const NSUInteger noListSegment = 0;
506 static const NSUInteger unorderedListSegment = 1;
507 static const NSUInteger orderedListSegment = 2;
508
509 - (instancetype)initWithWebViewImpl:(WebKit::WebViewImpl*)webViewImpl
510 {
511     if (!(self = [super init]))
512         return nil;
513
514     _webViewImpl = webViewImpl;
515
516     NSSegmentedControl *insertListControl = [NSSegmentedControl segmentedControlWithLabels:@[ WebCore::insertListTypeNone(), WebCore::insertListTypeBulleted(), WebCore::insertListTypeNumbered() ] trackingMode:NSSegmentSwitchTrackingSelectOne target:self action:@selector(_selectList:)];
517     [insertListControl setWidth:listControlSegmentWidth forSegment:noListSegment];
518     [insertListControl setWidth:listControlSegmentWidth forSegment:unorderedListSegment];
519     [insertListControl setWidth:listControlSegmentWidth forSegment:orderedListSegment];
520     insertListControl.font = [NSFont systemFontOfSize:15];
521
522     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
523     id segmentElement = NSAccessibilityUnignoredDescendant(insertListControl);
524     NSArray *segments = [segmentElement accessibilityAttributeValue:NSAccessibilityChildrenAttribute];
525     ASSERT(segments.count == 3);
526     [segments[noListSegment] accessibilitySetOverrideValue:WebCore::insertListTypeNone() forAttribute:NSAccessibilityDescriptionAttribute];
527     [segments[unorderedListSegment] accessibilitySetOverrideValue:WebCore::insertListTypeBulletedAccessibilityTitle() forAttribute:NSAccessibilityDescriptionAttribute];
528     [segments[orderedListSegment] accessibilitySetOverrideValue:WebCore::insertListTypeNumberedAccessibilityTitle() forAttribute:NSAccessibilityDescriptionAttribute];
529     ALLOW_DEPRECATED_DECLARATIONS_END
530
531     self.view = insertListControl;
532
533     return self;
534 }
535
536 - (void)didDestroyView
537 {
538     _webViewImpl = nullptr;
539 }
540
541 - (void)_selectList:(id)sender
542 {
543     if (!_webViewImpl)
544         return;
545
546     NSSegmentedControl *insertListControl = (NSSegmentedControl *)self.view;
547     switch (insertListControl.selectedSegment) {
548     case noListSegment:
549         // There is no "remove list" edit command, but InsertOrderedList and InsertUnorderedList both
550         // behave as toggles, so we can invoke the appropriate edit command depending on our _currentListType
551         // to remove an existing list. We don't have to do anything if _currentListType is NoList.
552         if (_currentListType == WebKit::OrderedList)
553             _webViewImpl->page().executeEditCommand(@"InsertOrderedList", @"");
554         else if (_currentListType == WebKit::UnorderedList)
555             _webViewImpl->page().executeEditCommand(@"InsertUnorderedList", @"");
556         break;
557     case unorderedListSegment:
558         _webViewImpl->page().executeEditCommand(@"InsertUnorderedList", @"");
559         break;
560     case orderedListSegment:
561         _webViewImpl->page().executeEditCommand(@"InsertOrderedList", @"");
562         break;
563     }
564
565     _webViewImpl->dismissTextTouchBarPopoverItemWithIdentifier(NSTouchBarItemIdentifierTextList);
566 }
567
568 - (void)setCurrentListType:(WebKit::ListType)listType
569 {
570     NSSegmentedControl *insertListControl = (NSSegmentedControl *)self.view;
571     switch (listType) {
572     case WebKit::NoList:
573         [insertListControl setSelected:YES forSegment:noListSegment];
574         break;
575     case WebKit::OrderedList:
576         [insertListControl setSelected:YES forSegment:orderedListSegment];
577         break;
578     case WebKit::UnorderedList:
579         [insertListControl setSelected:YES forSegment:unorderedListSegment];
580         break;
581     }
582
583     _currentListType = listType;
584 }
585
586 @end
587
588 @interface WKTextTouchBarItemController : NSTextTouchBarItemController <NSCandidateListTouchBarItemDelegate, NSTouchBarDelegate> {
589 @private
590     BOOL _textIsBold;
591     BOOL _textIsItalic;
592     BOOL _textIsUnderlined;
593     NSTextAlignment _currentTextAlignment;
594     RetainPtr<NSColor> _textColor;
595     RetainPtr<WKTextListTouchBarViewController> _textListTouchBarViewController;
596
597 @private
598     WebKit::WebViewImpl* _webViewImpl;
599 }
600
601 @property (nonatomic) BOOL textIsBold;
602 @property (nonatomic) BOOL textIsItalic;
603 @property (nonatomic) BOOL textIsUnderlined;
604 @property (nonatomic) NSTextAlignment currentTextAlignment;
605 @property (nonatomic, retain, readwrite) NSColor *textColor;
606
607 - (instancetype)initWithWebViewImpl:(WebKit::WebViewImpl*)webViewImpl;
608 @end
609
610 @implementation WKTextTouchBarItemController
611
612 @synthesize textIsBold=_textIsBold;
613 @synthesize textIsItalic=_textIsItalic;
614 @synthesize textIsUnderlined=_textIsUnderlined;
615 @synthesize currentTextAlignment=_currentTextAlignment;
616
617 - (instancetype)initWithWebViewImpl:(WebKit::WebViewImpl*)webViewImpl
618 {
619     if (!(self = [super init]))
620         return nil;
621
622     _webViewImpl = webViewImpl;
623
624     return self;
625 }
626
627 - (void)didDestroyView
628 {
629     [[NSNotificationCenter defaultCenter] removeObserver:self];
630     _webViewImpl = nullptr;
631     [_textListTouchBarViewController didDestroyView];
632 }
633
634 #pragma mark NSTouchBarDelegate
635
636 - (NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar makeItemForIdentifier:(NSString *)identifier
637 {
638     return [self itemForIdentifier:identifier];
639 }
640
641 - (NSTouchBarItem *)itemForIdentifier:(NSString *)identifier
642 {
643     NSTouchBarItem *item = [super itemForIdentifier:identifier];
644     BOOL isTextFormatItem = [identifier isEqualToString:NSTouchBarItemIdentifierTextFormat];
645
646     if (isTextFormatItem || [identifier isEqualToString:NSTouchBarItemIdentifierTextStyle])
647         self.textStyle.action = @selector(_wkChangeTextStyle:);
648
649     if (isTextFormatItem || [identifier isEqualToString:NSTouchBarItemIdentifierTextAlignment])
650         self.textAlignments.action = @selector(_wkChangeTextAlignment:);
651
652     NSColorPickerTouchBarItem *colorPickerItem = nil;
653     if ([identifier isEqualToString:NSTouchBarItemIdentifierTextColorPicker] && [item isKindOfClass:[NSColorPickerTouchBarItem class]])
654         colorPickerItem = (NSColorPickerTouchBarItem *)item;
655     if (isTextFormatItem)
656         colorPickerItem = self.colorPickerItem;
657     if (colorPickerItem) {
658         colorPickerItem.target = self;
659         colorPickerItem.action = @selector(_wkChangeColor:);
660         colorPickerItem.showsAlpha = NO;
661 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
662         colorPickerItem.allowedColorSpaces = @[ [NSColorSpace sRGBColorSpace] ];
663 #endif
664     }
665
666     return item;
667 }
668
669 #pragma mark NSCandidateListTouchBarItemDelegate
670
671 - (void)candidateListTouchBarItem:(NSCandidateListTouchBarItem *)anItem endSelectingCandidateAtIndex:(NSInteger)index
672 {
673     if (index == NSNotFound)
674         return;
675
676     if (!_webViewImpl)
677         return;
678
679     NSArray *candidates = anItem.candidates;
680     if ((NSUInteger)index >= candidates.count)
681         return;
682
683     NSTextCheckingResult *candidate = candidates[index];
684     ASSERT([candidate isKindOfClass:[NSTextCheckingResult class]]);
685
686     _webViewImpl->handleAcceptedCandidate(candidate);
687 }
688
689 - (void)candidateListTouchBarItem:(NSCandidateListTouchBarItem *)anItem changedCandidateListVisibility:(BOOL)isVisible
690 {
691     if (!_webViewImpl)
692         return;
693
694     if (isVisible)
695         _webViewImpl->requestCandidatesForSelectionIfNeeded();
696
697     _webViewImpl->updateTouchBar();
698 }
699
700 #pragma mark NSNotificationCenter observers
701
702 - (void)touchBarDidExitCustomization:(NSNotification *)notification
703 {
704     if (!_webViewImpl)
705         return;
706
707     _webViewImpl->setIsCustomizingTouchBar(false);
708     _webViewImpl->updateTouchBar();
709 }
710
711 - (void)touchBarWillEnterCustomization:(NSNotification *)notification
712 {
713     if (!_webViewImpl)
714         return;
715
716     _webViewImpl->setIsCustomizingTouchBar(true);
717 }
718
719 - (void)didChangeAutomaticTextCompletion:(NSNotification *)notification
720 {
721     if (!_webViewImpl)
722         return;
723
724     _webViewImpl->updateTouchBarAndRefreshTextBarIdentifiers();
725 }
726
727
728 #pragma mark NSTextTouchBarItemController
729
730 - (WKTextListTouchBarViewController *)textListTouchBarViewController
731 {
732     return (WKTextListTouchBarViewController *)self.textListViewController;
733 }
734
735 - (void)setTextIsBold:(BOOL)bold
736 {
737     _textIsBold = bold;
738     if ([self.textStyle isSelectedForSegment:0] != _textIsBold)
739         [self.textStyle setSelected:_textIsBold forSegment:0];
740 }
741
742 - (void)setTextIsItalic:(BOOL)italic
743 {
744     _textIsItalic = italic;
745     if ([self.textStyle isSelectedForSegment:1] != _textIsItalic)
746         [self.textStyle setSelected:_textIsItalic forSegment:1];
747 }
748
749 - (void)setTextIsUnderlined:(BOOL)underlined
750 {
751     _textIsUnderlined = underlined;
752     if ([self.textStyle isSelectedForSegment:2] != _textIsUnderlined)
753         [self.textStyle setSelected:_textIsUnderlined forSegment:2];
754 }
755
756 - (void)_wkChangeTextStyle:(id)sender
757 {
758     if (!_webViewImpl)
759         return;
760
761     if ([self.textStyle isSelectedForSegment:0] != _textIsBold) {
762         _textIsBold = !_textIsBold;
763         _webViewImpl->page().executeEditCommand(@"ToggleBold", @"");
764     }
765
766     if ([self.textStyle isSelectedForSegment:1] != _textIsItalic) {
767         _textIsItalic = !_textIsItalic;
768         _webViewImpl->page().executeEditCommand("ToggleItalic", @"");
769     }
770
771     if ([self.textStyle isSelectedForSegment:2] != _textIsUnderlined) {
772         _textIsUnderlined = !_textIsUnderlined;
773         _webViewImpl->page().executeEditCommand("ToggleUnderline", @"");
774     }
775 }
776
777 - (void)setCurrentTextAlignment:(NSTextAlignment)alignment
778 {
779     _currentTextAlignment = alignment;
780     [self.textAlignments selectSegmentWithTag:_currentTextAlignment];
781 }
782
783 - (void)_wkChangeTextAlignment:(id)sender
784 {
785     if (!_webViewImpl)
786         return;
787
788     NSTextAlignment alignment = (NSTextAlignment)[self.textAlignments.cell tagForSegment:self.textAlignments.selectedSegment];
789     switch (alignment) {
790     case NSTextAlignmentLeft:
791         _currentTextAlignment = NSTextAlignmentLeft;
792         _webViewImpl->page().executeEditCommand("AlignLeft", @"");
793         break;
794     case NSTextAlignmentRight:
795         _currentTextAlignment = NSTextAlignmentRight;
796         _webViewImpl->page().executeEditCommand("AlignRight", @"");
797         break;
798     case NSTextAlignmentCenter:
799         _currentTextAlignment = NSTextAlignmentCenter;
800         _webViewImpl->page().executeEditCommand("AlignCenter", @"");
801         break;
802     case NSTextAlignmentJustified:
803         _currentTextAlignment = NSTextAlignmentJustified;
804         _webViewImpl->page().executeEditCommand("AlignJustified", @"");
805         break;
806     default:
807         break;
808     }
809
810     _webViewImpl->dismissTextTouchBarPopoverItemWithIdentifier(NSTouchBarItemIdentifierTextAlignment);
811 }
812
813 - (NSColor *)textColor
814 {
815     return _textColor.get();
816 }
817
818 - (void)setTextColor:(NSColor *)color
819 {
820     _textColor = color;
821     self.colorPickerItem.color = _textColor.get();
822 }
823
824 - (void)_wkChangeColor:(id)sender
825 {
826     if (!_webViewImpl)
827         return;
828
829     _textColor = self.colorPickerItem.color;
830     _webViewImpl->page().executeEditCommand("ForeColor", WebCore::colorFromNSColor(_textColor.get()).serialized());
831 }
832
833 - (NSViewController *)textListViewController
834 {
835     if (!_textListTouchBarViewController)
836         _textListTouchBarViewController = adoptNS([[WKTextListTouchBarViewController alloc] initWithWebViewImpl:_webViewImpl]);
837     return _textListTouchBarViewController.get();
838 }
839
840 @end
841
842 @interface WKPromisedAttachmentContext : NSObject {
843 @private
844     RetainPtr<NSURL> _blobURL;
845     RetainPtr<NSString> _fileName;
846     RetainPtr<NSString> _attachmentIdentifier;
847 }
848
849 - (instancetype)initWithIdentifier:(NSString *)identifier blobURL:(NSURL *)url fileName:(NSString *)fileName;
850
851 @property (nonatomic, readonly) NSURL *blobURL;
852 @property (nonatomic, readonly) NSString *fileName;
853 @property (nonatomic, readonly) NSString *attachmentIdentifier;
854
855 @end
856
857 @implementation WKPromisedAttachmentContext
858
859 - (instancetype)initWithIdentifier:(NSString *)identifier blobURL:(NSURL *)blobURL fileName:(NSString *)fileName
860 {
861     if (!(self = [super init]))
862         return nil;
863
864     _blobURL = blobURL;
865     _fileName = fileName;
866     _attachmentIdentifier = identifier;
867     return self;
868 }
869
870 - (NSURL *)blobURL
871 {
872     return _blobURL.get();
873 }
874
875 - (NSString *)fileName
876 {
877     return _fileName.get();
878 }
879
880 - (NSString *)attachmentIdentifier
881 {
882     return _attachmentIdentifier.get();
883 }
884
885 @end
886
887 namespace WebKit {
888
889 NSTouchBar *WebViewImpl::makeTouchBar()
890 {
891     if (!m_canCreateTouchBars) {
892         m_canCreateTouchBars = true;
893         updateTouchBar();
894     }
895     return m_currentTouchBar.get();
896 }
897
898 void WebViewImpl::updateTouchBar()
899 {
900     if (!m_canCreateTouchBars)
901         return;
902
903     NSTouchBar *touchBar = nil;
904     bool userActionRequirementsHaveBeenMet = m_requiresUserActionForEditingControlsManager ? m_page->hasHadSelectionChangesFromUserInteraction() : true;
905     if (m_page->editorState().isContentEditable && !m_page->isTouchBarUpdateSupressedForHiddenContentEditable()) {
906         updateTextTouchBar();
907         if (userActionRequirementsHaveBeenMet)
908             touchBar = textTouchBar();
909     }
910 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
911     else if (m_page->hasActiveVideoForControlsManager()) {
912         updateMediaTouchBar();
913         // If useMediaPlaybackControlsView() is true, then we are relying on the API client to display a popover version
914         // of the media timeline in their own function bar. If it is false, then we will display the media timeline in our
915         // function bar.
916         if (!useMediaPlaybackControlsView())
917             touchBar = [m_mediaTouchBarProvider respondsToSelector:@selector(touchBar)] ? [(id)m_mediaTouchBarProvider.get() touchBar] : [(id)m_mediaTouchBarProvider.get() touchBar];
918     } else if ([m_mediaTouchBarProvider playbackControlsController]) {
919         if (m_clientWantsMediaPlaybackControlsView) {
920             if ([m_view respondsToSelector:@selector(_web_didRemoveMediaControlsManager)] && m_view.getAutoreleased() == [m_view window].firstResponder)
921                 [m_view _web_didRemoveMediaControlsManager];
922         }
923         [m_mediaTouchBarProvider setPlaybackControlsController:nil];
924         [m_mediaPlaybackControlsView setPlaybackControlsController:nil];
925     }
926 #endif
927
928     if (touchBar == m_currentTouchBar)
929         return;
930
931     // If m_editableElementIsFocused is true, then we may have a non-editable selection right now just because
932     // the user is clicking or tabbing between editable fields.
933     if (m_editableElementIsFocused && touchBar != textTouchBar())
934         return;
935
936     m_currentTouchBar = touchBar;
937     [m_view willChangeValueForKey:@"touchBar"];
938     [m_view setTouchBar:m_currentTouchBar.get()];
939     [m_view didChangeValueForKey:@"touchBar"];
940 }
941
942 NSCandidateListTouchBarItem *WebViewImpl::candidateListTouchBarItem() const
943 {
944     if (m_page->editorState().isInPasswordField)
945         return m_passwordTextCandidateListTouchBarItem.get();
946     return isRichlyEditableForTouchBar() ? m_richTextCandidateListTouchBarItem.get() : m_plainTextCandidateListTouchBarItem.get();
947 }
948
949 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
950 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
951 AVTouchBarScrubber *WebViewImpl::mediaPlaybackControlsView() const
952 #else
953 AVFunctionBarScrubber *WebViewImpl::mediaPlaybackControlsView() const
954 #endif
955 {
956     if (m_page->hasActiveVideoForControlsManager())
957         return m_mediaPlaybackControlsView.get();
958     return nil;
959 }
960 #endif
961
962 bool WebViewImpl::useMediaPlaybackControlsView() const
963 {
964 #if ENABLE(FULLSCREEN_API)
965     if (hasFullScreenWindowController())
966         return ![m_fullScreenWindowController isFullScreen];
967 #endif
968     return m_clientWantsMediaPlaybackControlsView;
969 }
970
971 void WebViewImpl::dismissTextTouchBarPopoverItemWithIdentifier(NSString *identifier)
972 {
973     NSTouchBarItem *foundItem = nil;
974     for (NSTouchBarItem *item in textTouchBar().items) {
975         if ([item.identifier isEqualToString:identifier]) {
976             foundItem = item;
977             break;
978         }
979
980         if ([item.identifier isEqualToString:NSTouchBarItemIdentifierTextFormat]) {
981             for (NSTouchBarItem *childItem in ((NSGroupTouchBarItem *)item).groupTouchBar.items) {
982                 if ([childItem.identifier isEqualToString:identifier]) {
983                     foundItem = childItem;
984                     break;
985                 }
986             }
987             break;
988         }
989     }
990
991     if ([foundItem isKindOfClass:[NSPopoverTouchBarItem class]])
992         [(NSPopoverTouchBarItem *)foundItem dismissPopover:nil];
993 }
994
995 static NSArray<NSString *> *textTouchBarCustomizationAllowedIdentifiers()
996 {
997     return @[ NSTouchBarItemIdentifierCharacterPicker, NSTouchBarItemIdentifierTextColorPicker, NSTouchBarItemIdentifierTextStyle, NSTouchBarItemIdentifierTextAlignment, NSTouchBarItemIdentifierTextList, NSTouchBarItemIdentifierFlexibleSpace ];
998 }
999
1000 static NSArray<NSString *> *plainTextTouchBarDefaultItemIdentifiers()
1001 {
1002     return @[ NSTouchBarItemIdentifierCharacterPicker, NSTouchBarItemIdentifierCandidateList ];
1003 }
1004
1005 static NSArray<NSString *> *richTextTouchBarDefaultItemIdentifiers()
1006 {
1007     return @[ NSTouchBarItemIdentifierCharacterPicker, NSTouchBarItemIdentifierTextFormat, NSTouchBarItemIdentifierCandidateList ];
1008 }
1009
1010 static NSArray<NSString *> *passwordTextTouchBarDefaultItemIdentifiers()
1011 {
1012     return @[ NSTouchBarItemIdentifierCandidateList ];
1013 }
1014
1015 void WebViewImpl::updateTouchBarAndRefreshTextBarIdentifiers()
1016 {
1017     if (m_richTextTouchBar)
1018         setUpTextTouchBar(m_richTextTouchBar.get());
1019
1020     if (m_plainTextTouchBar)
1021         setUpTextTouchBar(m_plainTextTouchBar.get());
1022
1023     if (m_passwordTextTouchBar)
1024         setUpTextTouchBar(m_passwordTextTouchBar.get());
1025
1026     updateTouchBar();
1027 }
1028
1029 void WebViewImpl::setUpTextTouchBar(NSTouchBar *touchBar)
1030 {
1031     NSSet<NSTouchBarItem *> *templateItems = nil;
1032     NSArray<NSTouchBarItemIdentifier> *defaultItemIdentifiers = nil;
1033     NSArray<NSTouchBarItemIdentifier> *customizationAllowedItemIdentifiers = nil;
1034
1035     if (touchBar == m_passwordTextTouchBar.get()) {
1036         templateItems = [NSMutableSet setWithObject:m_passwordTextCandidateListTouchBarItem.get()];
1037         defaultItemIdentifiers = passwordTextTouchBarDefaultItemIdentifiers();
1038     } else if (touchBar == m_richTextTouchBar.get()) {
1039         templateItems = [NSMutableSet setWithObject:m_richTextCandidateListTouchBarItem.get()];
1040         defaultItemIdentifiers = richTextTouchBarDefaultItemIdentifiers();
1041         customizationAllowedItemIdentifiers = textTouchBarCustomizationAllowedIdentifiers();
1042     } else if (touchBar == m_plainTextTouchBar.get()) {
1043         templateItems = [NSMutableSet setWithObject:m_plainTextCandidateListTouchBarItem.get()];
1044         defaultItemIdentifiers = plainTextTouchBarDefaultItemIdentifiers();
1045         customizationAllowedItemIdentifiers = textTouchBarCustomizationAllowedIdentifiers();
1046     }
1047
1048     [touchBar setDelegate:m_textTouchBarItemController.get()];
1049     [touchBar setTemplateItems:templateItems];
1050     [touchBar setDefaultItemIdentifiers:defaultItemIdentifiers];
1051     [touchBar setCustomizationAllowedItemIdentifiers:customizationAllowedItemIdentifiers];
1052
1053     if (NSGroupTouchBarItem *textFormatItem = (NSGroupTouchBarItem *)[touchBar itemForIdentifier:NSTouchBarItemIdentifierTextFormat])
1054         textFormatItem.groupTouchBar.customizationIdentifier = @"WKTextFormatTouchBar";
1055 }
1056
1057 bool WebViewImpl::isRichlyEditableForTouchBar() const
1058 {
1059     return m_page->editorState().isContentRichlyEditable && !m_page->isNeverRichlyEditableForTouchBar();
1060 }
1061
1062 NSTouchBar *WebViewImpl::textTouchBar() const
1063 {
1064     if (m_page->editorState().isInPasswordField)
1065         return m_passwordTextTouchBar.get();
1066     return isRichlyEditableForTouchBar() ? m_richTextTouchBar.get() : m_plainTextTouchBar.get();
1067 }
1068
1069 static NSTextAlignment nsTextAlignmentFromTextAlignment(TextAlignment textAlignment)
1070 {
1071     NSTextAlignment nsTextAlignment;
1072     switch (textAlignment) {
1073     case NoAlignment:
1074         nsTextAlignment = NSTextAlignmentNatural;
1075         break;
1076     case LeftAlignment:
1077         nsTextAlignment = NSTextAlignmentLeft;
1078         break;
1079     case RightAlignment:
1080         nsTextAlignment = NSTextAlignmentRight;
1081         break;
1082     case CenterAlignment:
1083         nsTextAlignment = NSTextAlignmentCenter;
1084         break;
1085     case JustifiedAlignment:
1086         nsTextAlignment = NSTextAlignmentJustified;
1087         break;
1088     default:
1089         ASSERT_NOT_REACHED();
1090     }
1091     
1092     return nsTextAlignment;
1093 }
1094
1095 void WebViewImpl::updateTextTouchBar()
1096 {
1097     if (!m_page->editorState().isContentEditable)
1098         return;
1099
1100     if (m_isUpdatingTextTouchBar)
1101         return;
1102
1103     SetForScope<bool> isUpdatingTextFunctionBar(m_isUpdatingTextTouchBar, true);
1104
1105     if (!m_textTouchBarItemController)
1106         m_textTouchBarItemController = adoptNS([[WKTextTouchBarItemController alloc] initWithWebViewImpl:this]);
1107
1108     if (!m_startedListeningToCustomizationEvents) {
1109         [[NSNotificationCenter defaultCenter] addObserver:m_textTouchBarItemController.get() selector:@selector(touchBarDidExitCustomization:) name:NSTouchBarDidExitCustomization object:nil];
1110         [[NSNotificationCenter defaultCenter] addObserver:m_textTouchBarItemController.get() selector:@selector(touchBarWillEnterCustomization:) name:NSTouchBarWillEnterCustomization object:nil];
1111         [[NSNotificationCenter defaultCenter] addObserver:m_textTouchBarItemController.get() selector:@selector(didChangeAutomaticTextCompletion:) name:NSSpellCheckerDidChangeAutomaticTextCompletionNotification object:nil];
1112
1113         m_startedListeningToCustomizationEvents = true;
1114     }
1115
1116     if (!m_richTextCandidateListTouchBarItem || !m_plainTextCandidateListTouchBarItem || !m_passwordTextCandidateListTouchBarItem) {
1117         m_richTextCandidateListTouchBarItem = adoptNS([[NSCandidateListTouchBarItem alloc] initWithIdentifier:NSTouchBarItemIdentifierCandidateList]);
1118         [m_richTextCandidateListTouchBarItem setDelegate:m_textTouchBarItemController.get()];
1119         m_plainTextCandidateListTouchBarItem = adoptNS([[NSCandidateListTouchBarItem alloc] initWithIdentifier:NSTouchBarItemIdentifierCandidateList]);
1120         [m_plainTextCandidateListTouchBarItem setDelegate:m_textTouchBarItemController.get()];
1121         m_passwordTextCandidateListTouchBarItem = adoptNS([[NSCandidateListTouchBarItem alloc] initWithIdentifier:NSTouchBarItemIdentifierCandidateList]);
1122         [m_passwordTextCandidateListTouchBarItem setDelegate:m_textTouchBarItemController.get()];
1123         requestCandidatesForSelectionIfNeeded();
1124     }
1125
1126     if (!m_richTextTouchBar) {
1127         m_richTextTouchBar = adoptNS([[NSTouchBar alloc] init]);
1128         setUpTextTouchBar(m_richTextTouchBar.get());
1129         [m_richTextTouchBar setCustomizationIdentifier:@"WKRichTextTouchBar"];
1130     }
1131
1132     if (!m_plainTextTouchBar) {
1133         m_plainTextTouchBar = adoptNS([[NSTouchBar alloc] init]);
1134         setUpTextTouchBar(m_plainTextTouchBar.get());
1135         [m_plainTextTouchBar setCustomizationIdentifier:@"WKPlainTextTouchBar"];
1136     }
1137
1138     if ([NSSpellChecker isAutomaticTextCompletionEnabled] && !m_isCustomizingTouchBar) {
1139         BOOL showCandidatesList = !m_page->editorState().selectionIsRange || m_isHandlingAcceptedCandidate;
1140         [candidateListTouchBarItem() updateWithInsertionPointVisibility:showCandidatesList];
1141         [m_view _didUpdateCandidateListVisibility:showCandidatesList];
1142     }
1143
1144     if (m_page->editorState().isInPasswordField) {
1145         if (!m_passwordTextTouchBar) {
1146             m_passwordTextTouchBar = adoptNS([[NSTouchBar alloc] init]);
1147             setUpTextTouchBar(m_passwordTextTouchBar.get());
1148         }
1149         [m_passwordTextCandidateListTouchBarItem setCandidates:@[ ] forSelectedRange:NSMakeRange(0, 0) inString:nil];
1150     }
1151
1152     NSTouchBar *textTouchBar = this->textTouchBar();
1153     BOOL isShowingCombinedTextFormatItem = [textTouchBar.defaultItemIdentifiers containsObject:NSTouchBarItemIdentifierTextFormat];
1154     [textTouchBar setPrincipalItemIdentifier:isShowingCombinedTextFormatItem ? NSTouchBarItemIdentifierTextFormat : nil];
1155
1156     // Set current typing attributes for rich text. This will ensure that the buttons reflect the state of
1157     // the text when changing selection throughout the document.
1158     if (isRichlyEditableForTouchBar()) {
1159         const EditorState& editorState = m_page->editorState();
1160         if (!editorState.isMissingPostLayoutData) {
1161             [m_textTouchBarItemController setTextIsBold:(bool)(m_page->editorState().postLayoutData().typingAttributes & AttributeBold)];
1162             [m_textTouchBarItemController setTextIsItalic:(bool)(m_page->editorState().postLayoutData().typingAttributes & AttributeItalics)];
1163             [m_textTouchBarItemController setTextIsUnderlined:(bool)(m_page->editorState().postLayoutData().typingAttributes & AttributeUnderline)];
1164             [m_textTouchBarItemController setTextColor:nsColor(editorState.postLayoutData().textColor)];
1165             [[m_textTouchBarItemController textListTouchBarViewController] setCurrentListType:(ListType)m_page->editorState().postLayoutData().enclosingListType];
1166             [m_textTouchBarItemController setCurrentTextAlignment:nsTextAlignmentFromTextAlignment((TextAlignment)editorState.postLayoutData().textAlignment)];
1167         }
1168         BOOL isShowingCandidateListItem = [textTouchBar.defaultItemIdentifiers containsObject:NSTouchBarItemIdentifierCandidateList] && [NSSpellChecker isAutomaticTextReplacementEnabled];
1169         [m_textTouchBarItemController setUsesNarrowTextStyleItem:isShowingCombinedTextFormatItem && isShowingCandidateListItem];
1170     }
1171 }
1172
1173 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
1174
1175 bool WebViewImpl::isPictureInPictureActive()
1176 {
1177     return [m_playbackControlsManager isPictureInPictureActive];
1178 }
1179
1180 void WebViewImpl::togglePictureInPicture()
1181 {
1182     [m_playbackControlsManager togglePictureInPicture];
1183 }
1184
1185 void WebViewImpl::updateMediaPlaybackControlsManager()
1186 {
1187     if (!m_page->hasActiveVideoForControlsManager())
1188         return;
1189
1190     if (!m_playbackControlsManager) {
1191         m_playbackControlsManager = adoptNS([[WebPlaybackControlsManager alloc] init]);
1192         [m_playbackControlsManager setAllowsPictureInPicturePlayback:m_page->preferences().allowsPictureInPictureMediaPlayback()];
1193         [m_playbackControlsManager setCanTogglePictureInPicture:NO];
1194     }
1195
1196     if (PlatformPlaybackSessionInterface* interface = m_page->playbackSessionManager()->controlsManagerInterface()) {
1197         [m_playbackControlsManager setPlaybackSessionInterfaceMac:interface];
1198         interface->updatePlaybackControlsManagerCanTogglePictureInPicture();
1199     }
1200 }
1201
1202 #endif // ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
1203
1204 void WebViewImpl::updateMediaTouchBar()
1205 {
1206 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER) && ENABLE(VIDEO_PRESENTATION_MODE)
1207     if (!m_mediaTouchBarProvider) {
1208 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
1209         m_mediaTouchBarProvider = adoptNS([allocAVTouchBarPlaybackControlsProviderInstance() init]);
1210 #else
1211         m_mediaTouchBarProvider = adoptNS([allocAVFunctionBarPlaybackControlsProviderInstance() init]);
1212 #endif // __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
1213     }
1214
1215     if (!m_mediaPlaybackControlsView) {
1216 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
1217         m_mediaPlaybackControlsView = adoptNS([allocAVTouchBarScrubberInstance() init]);
1218         // FIXME: Remove this once setCanShowMediaSelectionButton: is declared in an SDK used by Apple's buildbot.
1219         if ([m_mediaPlaybackControlsView respondsToSelector:@selector(setCanShowMediaSelectionButton:)])
1220             [m_mediaPlaybackControlsView setCanShowMediaSelectionButton:YES];
1221 #else
1222         m_mediaPlaybackControlsView = adoptNS([allocAVFunctionBarScrubberInstance() init]);
1223 #endif // __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
1224     }
1225
1226     updateMediaPlaybackControlsManager();
1227
1228     [m_mediaTouchBarProvider setPlaybackControlsController:m_playbackControlsManager.get()];
1229     [m_mediaPlaybackControlsView setPlaybackControlsController:m_playbackControlsManager.get()];
1230
1231     if (!useMediaPlaybackControlsView()) {
1232 #if ENABLE(FULLSCREEN_API)
1233         // If we can't have a media popover function bar item, it might be because we are in full screen.
1234         // If so, customize the escape key.
1235         NSTouchBar *touchBar = [m_mediaTouchBarProvider respondsToSelector:@selector(touchBar)] ? [(id)m_mediaTouchBarProvider.get() touchBar] : [(id)m_mediaTouchBarProvider.get() touchBar];
1236         if (hasFullScreenWindowController() && [m_fullScreenWindowController isFullScreen]) {
1237             if (!m_exitFullScreenButton) {
1238                 m_exitFullScreenButton = adoptNS([[NSCustomTouchBarItem alloc] initWithIdentifier:WKMediaExitFullScreenItem]);
1239
1240                 NSImage *image = [NSImage imageNamed:NSImageNameTouchBarExitFullScreenTemplate];
1241                 [image setTemplate:YES];
1242
1243                 NSButton *exitFullScreenButton = [NSButton buttonWithTitle:image ? @"" : @"Exit" image:image target:m_fullScreenWindowController.get() action:@selector(requestExitFullScreen)];
1244                 [exitFullScreenButton setAccessibilityTitle:WebCore::exitFullScreenButtonAccessibilityTitle()];
1245
1246                 [[exitFullScreenButton.widthAnchor constraintLessThanOrEqualToConstant:exitFullScreenButtonWidth] setActive:YES];
1247                 [m_exitFullScreenButton setView:exitFullScreenButton];
1248             }
1249             touchBar.escapeKeyReplacementItem = m_exitFullScreenButton.get();
1250         } else
1251             touchBar.escapeKeyReplacementItem = nil;
1252 #endif
1253         // The rest of the work to update the media function bar only applies to the popover version, so return early.
1254         return;
1255     }
1256
1257     if (m_playbackControlsManager && m_view.getAutoreleased() == [m_view window].firstResponder && [m_view respondsToSelector:@selector(_web_didAddMediaControlsManager:)])
1258         [m_view _web_didAddMediaControlsManager:m_mediaPlaybackControlsView.get()];
1259 #endif
1260 }
1261
1262 #if HAVE(TOUCH_BAR)
1263
1264 bool WebViewImpl::canTogglePictureInPicture()
1265 {
1266 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
1267     return [m_playbackControlsManager canTogglePictureInPicture];
1268 #else
1269     return NO;
1270 #endif
1271 }
1272
1273 #endif // HAVE(TOUCH_BAR)
1274
1275 void WebViewImpl::forceRequestCandidatesForTesting()
1276 {
1277     m_canCreateTouchBars = true;
1278 #if HAVE(TOUCH_BAR)
1279     updateTouchBar();
1280 #endif
1281 }
1282
1283 bool WebViewImpl::shouldRequestCandidates() const
1284 {
1285     return !m_page->editorState().isInPasswordField && candidateListTouchBarItem().candidateListVisible;
1286 }
1287
1288 void WebViewImpl::setEditableElementIsFocused(bool editableElementIsFocused)
1289 {
1290     m_editableElementIsFocused = editableElementIsFocused;
1291
1292 #if HAVE(TOUCH_BAR)
1293     // If the editable elements have blurred, then we might need to get rid of the editing function bar.
1294     if (!m_editableElementIsFocused)
1295         updateTouchBar();
1296 #endif
1297 }
1298
1299 } // namespace WebKit
1300 #else // !HAVE(TOUCH_BAR)
1301 namespace WebKit {
1302
1303 void WebViewImpl::forceRequestCandidatesForTesting()
1304 {
1305 }
1306
1307 bool WebViewImpl::shouldRequestCandidates() const
1308 {
1309     return false;
1310 }
1311
1312 void WebViewImpl::setEditableElementIsFocused(bool editableElementIsFocused)
1313 {
1314     m_editableElementIsFocused = editableElementIsFocused;
1315 }
1316
1317 } // namespace WebKit
1318 #endif // HAVE(TOUCH_BAR)
1319
1320 namespace WebKit {
1321
1322 static NSTrackingAreaOptions trackingAreaOptions()
1323 {
1324     // Legacy style scrollbars have design details that rely on tracking the mouse all the time.
1325     NSTrackingAreaOptions options = NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited | NSTrackingInVisibleRect | NSTrackingCursorUpdate;
1326     if (_NSRecommendedScrollerStyle() == NSScrollerStyleLegacy)
1327         options |= NSTrackingActiveAlways;
1328     else
1329         options |= NSTrackingActiveInKeyWindow;
1330     return options;
1331 }
1332
1333 WebViewImpl::WebViewImpl(NSView <WebViewImplDelegate> *view, WKWebView *outerWebView, WebProcessPool& processPool, Ref<API::PageConfiguration>&& configuration)
1334     : m_view(view)
1335     , m_pageClient(std::make_unique<PageClientImpl>(view, outerWebView))
1336     , m_page(processPool.createWebPage(*m_pageClient, WTFMove(configuration)))
1337     , m_needsViewFrameInWindowCoordinates(m_page->preferences().pluginsEnabled())
1338     , m_intrinsicContentSize(CGSizeMake(NSViewNoIntrinsicMetric, NSViewNoIntrinsicMetric))
1339     , m_layoutStrategy([WKViewLayoutStrategy layoutStrategyWithPage:m_page view:view viewImpl:*this mode:kWKLayoutModeViewSize])
1340     , m_undoTarget(adoptNS([[WKEditorUndoTarget alloc] init]))
1341     , m_windowVisibilityObserver(adoptNS([[WKWindowVisibilityObserver alloc] initWithView:view impl:*this]))
1342     , m_accessibilitySettingsObserver(adoptNS([[WKAccessibilitySettingsObserver alloc] initWithImpl:*this]))
1343     , m_primaryTrackingArea(adoptNS([[NSTrackingArea alloc] initWithRect:view.frame options:trackingAreaOptions() owner:view userInfo:nil]))
1344 {
1345     static_cast<PageClientImpl&>(*m_pageClient).setImpl(*this);
1346
1347     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer));
1348     [NSApp registerServicesMenuSendTypes:PasteboardTypes::forSelection() returnTypes:PasteboardTypes::forEditing()];
1349
1350     [view addTrackingArea:m_primaryTrackingArea.get()];
1351
1352     m_page->setIntrinsicDeviceScaleFactor(intrinsicDeviceScaleFactor());
1353
1354     if (Class gestureClass = NSClassFromString(@"NSImmediateActionGestureRecognizer")) {
1355         m_immediateActionGestureRecognizer = adoptNS([(NSImmediateActionGestureRecognizer *)[gestureClass alloc] init]);
1356         m_immediateActionController = adoptNS([[WKImmediateActionController alloc] initWithPage:m_page view:view viewImpl:*this recognizer:m_immediateActionGestureRecognizer.get()]);
1357         [m_immediateActionGestureRecognizer setDelegate:m_immediateActionController.get()];
1358         [m_immediateActionGestureRecognizer setDelaysPrimaryMouseButtonEvents:NO];
1359     }
1360
1361     m_page->setAddsVisitedLinks(processPool.historyClient().addsVisitedLinks());
1362
1363     m_page->initializeWebPage();
1364
1365     registerDraggedTypes();
1366
1367     view.wantsLayer = YES;
1368
1369     // Explicitly set the layer contents placement so AppKit will make sure that our layer has masksToBounds set to YES.
1370     view.layerContentsPlacement = NSViewLayerContentsPlacementTopLeft;
1371
1372 #if ENABLE(FULLSCREEN_API)
1373     m_page->setFullscreenClient(std::make_unique<WebKit::FullscreenClient>(view));
1374 #endif
1375
1376     WebProcessPool::statistics().wkViewCount++;
1377 }
1378
1379 WebViewImpl::~WebViewImpl()
1380 {
1381     if (m_remoteObjectRegistry) {
1382         m_page->process().processPool().removeMessageReceiver(Messages::RemoteObjectRegistry::messageReceiverName(), m_page->pageID());
1383         [m_remoteObjectRegistry _invalidate];
1384         m_remoteObjectRegistry = nil;
1385     }
1386
1387     ASSERT(!m_inSecureInputState);
1388     ASSERT(!m_thumbnailView);
1389
1390     [m_layoutStrategy invalidate];
1391
1392     [m_immediateActionController willDestroyView:m_view.getAutoreleased()];
1393
1394 #if HAVE(TOUCH_BAR)
1395     [m_textTouchBarItemController didDestroyView];
1396 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
1397     [m_mediaTouchBarProvider setPlaybackControlsController:nil];
1398     [m_mediaPlaybackControlsView setPlaybackControlsController:nil];
1399 #endif
1400 #endif
1401
1402     m_page->close();
1403
1404     WebProcessPool::statistics().wkViewCount--;
1405
1406 }
1407
1408 NSWindow *WebViewImpl::window()
1409 {
1410     return [m_view window];
1411 }
1412
1413 void WebViewImpl::handleProcessSwapOrExit()
1414 {
1415     dismissContentRelativeChildWindowsWithAnimation(true);
1416
1417     notifyInputContextAboutDiscardedComposition();
1418
1419     updateRemoteAccessibilityRegistration(false);
1420     flushPendingMouseEventCallbacks();
1421 }
1422
1423 void WebViewImpl::processWillSwap()
1424 {
1425     handleProcessSwapOrExit();
1426     if (m_gestureController)
1427         m_gestureController->disconnectFromProcess();
1428 }
1429
1430 void WebViewImpl::processDidExit()
1431 {
1432     handleProcessSwapOrExit();
1433     m_gestureController = nullptr;
1434 }
1435
1436 void WebViewImpl::pageClosed()
1437 {
1438     updateRemoteAccessibilityRegistration(false);
1439 }
1440
1441 void WebViewImpl::didRelaunchProcess()
1442 {
1443     if (m_gestureController)
1444         m_gestureController->connectToProcess();
1445
1446     accessibilityRegisterUIProcessTokens();
1447     windowDidChangeScreen(); // Make sure DisplayID is set.
1448 }
1449
1450 void WebViewImpl::setDrawsBackground(bool drawsBackground)
1451 {
1452     Optional<WebCore::Color> backgroundColor;
1453     if (!drawsBackground)
1454         backgroundColor = WebCore::Color(WebCore::Color::transparent);
1455     m_page->setBackgroundColor(backgroundColor);
1456
1457     // Make sure updateLayer gets called on the web view.
1458     [m_view setNeedsDisplay:YES];
1459 }
1460
1461 bool WebViewImpl::drawsBackground() const
1462 {
1463     auto& backgroundColor = m_page->backgroundColor();
1464     return !backgroundColor || backgroundColor.value().isVisible();
1465 }
1466
1467 void WebViewImpl::setBackgroundColor(NSColor *backgroundColor)
1468 {
1469     m_backgroundColor = backgroundColor;
1470
1471     // Make sure updateLayer gets called on the web view.
1472     [m_view setNeedsDisplay:YES];
1473 }
1474
1475 NSColor *WebViewImpl::backgroundColor() const
1476 {
1477     if (!m_backgroundColor)
1478 #if ENABLE(DARK_MODE_CSS)
1479         return [NSColor controlBackgroundColor];
1480 #else
1481         return [NSColor whiteColor];
1482 #endif
1483     return m_backgroundColor.get();
1484 }
1485
1486 bool WebViewImpl::isOpaque() const
1487 {
1488     return drawsBackground();
1489 }
1490
1491 void WebViewImpl::setShouldSuppressFirstResponderChanges(bool shouldSuppress)
1492 {   
1493     m_pageClient->setShouldSuppressFirstResponderChanges(shouldSuppress);
1494 }
1495
1496 bool WebViewImpl::acceptsFirstResponder()
1497 {
1498     return true;
1499 }
1500
1501 bool WebViewImpl::becomeFirstResponder()
1502 {
1503     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer));
1504     // If we just became first responder again, there is no need to do anything,
1505     // since resignFirstResponder has correctly detected this situation.
1506     if (m_willBecomeFirstResponderAgain) {
1507         m_willBecomeFirstResponderAgain = false;
1508         return true;
1509     }
1510
1511     NSSelectionDirection direction = [[m_view window] keyViewSelectionDirection];
1512
1513     m_inBecomeFirstResponder = true;
1514
1515     updateSecureInputState();
1516     m_page->activityStateDidChange(WebCore::ActivityState::IsFocused);
1517     // Restore the selection in the editable region if resigning first responder cleared selection.
1518     m_page->restoreSelectionInFocusedEditableElement();
1519
1520     m_inBecomeFirstResponder = false;
1521
1522 #if HAVE(TOUCH_BAR)
1523     updateTouchBar();
1524 #endif
1525
1526     if (direction != NSDirectSelection) {
1527         NSEvent *event = [NSApp currentEvent];
1528         NSEvent *keyboardEvent = nil;
1529         if ([event type] == NSEventTypeKeyDown || [event type] == NSEventTypeKeyUp)
1530             keyboardEvent = event;
1531         m_page->setInitialFocus(direction == NSSelectingNext, keyboardEvent != nil, NativeWebKeyboardEvent(keyboardEvent, false, false, { }), [](WebKit::CallbackBase::Error) { });
1532     }
1533     return true;
1534 }
1535
1536 bool WebViewImpl::resignFirstResponder()
1537 {
1538     // Predict the case where we are losing first responder status only to
1539     // gain it back again. We want resignFirstResponder to do nothing in that case.
1540     id nextResponder = [[m_view window] _newFirstResponderAfterResigning];
1541
1542     // FIXME: This will probably need to change once WKWebView doesn't contain a WKView.
1543     if ([nextResponder isKindOfClass:[WKWebView class]] && [m_view superview] == nextResponder) {
1544         m_willBecomeFirstResponderAgain = true;
1545         return true;
1546     }
1547
1548     m_willBecomeFirstResponderAgain = false;
1549     m_inResignFirstResponder = true;
1550
1551     m_page->confirmCompositionAsync();
1552
1553     notifyInputContextAboutDiscardedComposition();
1554
1555     resetSecureInputState();
1556
1557     if (!m_page->maintainsInactiveSelection())
1558         m_page->clearSelection();
1559
1560     m_page->activityStateDidChange(WebCore::ActivityState::IsFocused);
1561     
1562     m_inResignFirstResponder = false;
1563     
1564     return true;
1565 }
1566
1567 void WebViewImpl::takeFocus(WebCore::FocusDirection direction)
1568 {
1569     NSView *webView = m_view.getAutoreleased();
1570
1571     if (direction == FocusDirectionForward) {
1572         // Since we're trying to move focus out of m_webView, and because
1573         // m_webView may contain subviews within it, we ask it for the next key
1574         // view of the last view in its key view loop. This makes m_webView
1575         // behave as if it had no subviews, which is the behavior we want.
1576         [webView.window selectKeyViewFollowingView:[webView _findLastViewInKeyViewLoop]];
1577     } else
1578         [webView.window selectKeyViewPrecedingView:webView];
1579 }
1580
1581 void WebViewImpl::showSafeBrowsingWarning(const SafeBrowsingWarning& warning, CompletionHandler<void(Variant<ContinueUnsafeLoad, URL>&&)>&& completionHandler)
1582 {
1583     if (!m_view)
1584         return completionHandler(ContinueUnsafeLoad::Yes);
1585
1586     m_safeBrowsingWarning = adoptNS([[WKSafeBrowsingWarning alloc] initWithFrame:[m_view bounds] safeBrowsingWarning:warning completionHandler:[weakThis = makeWeakPtr(*this), completionHandler = WTFMove(completionHandler)] (auto&& result) mutable {
1587         completionHandler(WTFMove(result));
1588         if (!weakThis)
1589             return;
1590         bool navigatesFrame = WTF::switchOn(result,
1591             [] (ContinueUnsafeLoad continueUnsafeLoad) { return continueUnsafeLoad == ContinueUnsafeLoad::Yes; },
1592             [] (const URL&) { return true; }
1593         );
1594         bool forMainFrameNavigation = [weakThis->m_safeBrowsingWarning forMainFrameNavigation];
1595         if (navigatesFrame && forMainFrameNavigation) {
1596             // The safe browsing warning will be hidden once the next page is shown.
1597             return;
1598         }
1599         if (!navigatesFrame && weakThis->m_safeBrowsingWarning && !forMainFrameNavigation) {
1600             weakThis->m_page->goBack();
1601             return;
1602         }
1603         [std::exchange(weakThis->m_safeBrowsingWarning, nullptr) removeFromSuperview];
1604     }]);
1605     [m_view addSubview:m_safeBrowsingWarning.get()];
1606 }
1607
1608 void WebViewImpl::clearSafeBrowsingWarning()
1609 {
1610     [std::exchange(m_safeBrowsingWarning, nullptr) removeFromSuperview];
1611 }
1612
1613 void WebViewImpl::clearSafeBrowsingWarningIfForMainFrameNavigation()
1614 {
1615     if ([m_safeBrowsingWarning forMainFrameNavigation])
1616         clearSafeBrowsingWarning();
1617 }
1618
1619 bool WebViewImpl::isFocused() const
1620 {
1621     if (m_inBecomeFirstResponder)
1622         return true;
1623     if (m_inResignFirstResponder)
1624         return false;
1625     return [m_view window].firstResponder == m_view.getAutoreleased();
1626 }
1627
1628 void WebViewImpl::viewWillStartLiveResize()
1629 {
1630     m_page->viewWillStartLiveResize();
1631
1632     [m_layoutStrategy willStartLiveResize];
1633 }
1634
1635 void WebViewImpl::viewDidEndLiveResize()
1636 {
1637     m_page->viewWillEndLiveResize();
1638
1639     [m_layoutStrategy didEndLiveResize];
1640 }
1641
1642 void WebViewImpl::renewGState()
1643 {
1644     if (m_textIndicatorWindow)
1645         dismissContentRelativeChildWindowsWithAnimation(false);
1646
1647     // Update the view frame.
1648     if ([m_view window])
1649         updateWindowAndViewFrames();
1650
1651     updateContentInsetsIfAutomatic();
1652 }
1653
1654 void WebViewImpl::setFrameSize(CGSize)
1655 {
1656     [m_layoutStrategy didChangeFrameSize];
1657     [m_safeBrowsingWarning setFrame:[m_view bounds]];
1658 }
1659
1660 void WebViewImpl::disableFrameSizeUpdates()
1661 {
1662     [m_layoutStrategy disableFrameSizeUpdates];
1663 }
1664
1665 void WebViewImpl::enableFrameSizeUpdates()
1666 {
1667     [m_layoutStrategy enableFrameSizeUpdates];
1668 }
1669
1670 bool WebViewImpl::frameSizeUpdatesDisabled() const
1671 {
1672     return [m_layoutStrategy frameSizeUpdatesDisabled];
1673 }
1674
1675 void WebViewImpl::setFrameAndScrollBy(CGRect frame, CGSize scrollDelta)
1676 {
1677     if (!CGSizeEqualToSize(scrollDelta, CGSizeZero))
1678         m_scrollOffsetAdjustment = scrollDelta;
1679
1680     [m_view frame] = NSRectFromCGRect(frame);
1681 }
1682
1683 void WebViewImpl::updateWindowAndViewFrames()
1684 {
1685     if (clipsToVisibleRect())
1686         updateViewExposedRect();
1687
1688     if (m_didScheduleWindowAndViewFrameUpdate)
1689         return;
1690
1691     m_didScheduleWindowAndViewFrameUpdate = true;
1692
1693     auto weakThis = makeWeakPtr(*this);
1694     dispatch_async(dispatch_get_main_queue(), [weakThis] {
1695         if (!weakThis)
1696             return;
1697
1698         weakThis->m_didScheduleWindowAndViewFrameUpdate = false;
1699
1700         NSRect viewFrameInWindowCoordinates = NSZeroRect;
1701         NSPoint accessibilityPosition = NSZeroPoint;
1702
1703         if (weakThis->m_needsViewFrameInWindowCoordinates)
1704             viewFrameInWindowCoordinates = [weakThis->m_view convertRect:[weakThis->m_view frame] toView:nil];
1705
1706             ALLOW_DEPRECATED_DECLARATIONS_BEGIN
1707         if (WebCore::AXObjectCache::accessibilityEnabled())
1708             accessibilityPosition = [[weakThis->m_view accessibilityAttributeValue:NSAccessibilityPositionAttribute] pointValue];
1709             ALLOW_DEPRECATED_DECLARATIONS_END
1710         
1711         weakThis->m_page->windowAndViewFramesChanged(viewFrameInWindowCoordinates, accessibilityPosition);
1712     });
1713 }
1714
1715 void WebViewImpl::setFixedLayoutSize(CGSize fixedLayoutSize)
1716 {
1717     m_lastRequestedFixedLayoutSize = fixedLayoutSize;
1718
1719     if (supportsArbitraryLayoutModes())
1720         m_page->setFixedLayoutSize(WebCore::expandedIntSize(WebCore::FloatSize(fixedLayoutSize)));
1721 }
1722
1723 CGSize WebViewImpl::fixedLayoutSize() const
1724 {
1725     return m_page->fixedLayoutSize();
1726 }
1727
1728 std::unique_ptr<WebKit::DrawingAreaProxy> WebViewImpl::createDrawingAreaProxy(WebProcessProxy& process)
1729 {
1730     if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"WebKit2UseRemoteLayerTreeDrawingArea"] boolValue])
1731         return std::make_unique<RemoteLayerTreeDrawingAreaProxy>(m_page, process);
1732
1733     return std::make_unique<TiledCoreAnimationDrawingAreaProxy>(m_page, process);
1734 }
1735
1736 bool WebViewImpl::isUsingUISideCompositing() const
1737 {
1738     auto* drawingArea = m_page->drawingArea();
1739     return drawingArea && drawingArea->type() == DrawingAreaTypeRemoteLayerTree;
1740 }
1741
1742 void WebViewImpl::setDrawingAreaSize(CGSize size)
1743 {
1744     if (!m_page->drawingArea())
1745         return;
1746
1747     m_page->drawingArea()->setSize(WebCore::IntSize(size), WebCore::IntSize(m_scrollOffsetAdjustment));
1748     m_scrollOffsetAdjustment = CGSizeZero;
1749 }
1750
1751 void WebViewImpl::updateLayer()
1752 {
1753     [m_view layer].backgroundColor = drawsBackground() ? [backgroundColor() CGColor] : CGColorGetConstantColor(kCGColorClear);
1754 }
1755
1756 void WebViewImpl::drawRect(CGRect rect)
1757 {
1758     LOG(Printing, "drawRect: x:%g, y:%g, width:%g, height:%g", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
1759     m_page->endPrinting();
1760 }
1761
1762 bool WebViewImpl::canChangeFrameLayout(WebFrameProxy& frame)
1763 {
1764     // PDF documents are already paginated, so we can't change them to add headers and footers.
1765     return !frame.isDisplayingPDFDocument();
1766 }
1767
1768 NSPrintOperation *WebViewImpl::printOperationWithPrintInfo(NSPrintInfo *printInfo, WebFrameProxy& frame)
1769 {
1770     LOG(Printing, "Creating an NSPrintOperation for frame '%s'", frame.url().string().utf8().data());
1771
1772     // FIXME: If the frame cannot be printed (e.g. if it contains an encrypted PDF that disallows
1773     // printing), this function should return nil.
1774     RetainPtr<WKPrintingView> printingView = adoptNS([[WKPrintingView alloc] initWithFrameProxy:frame view:m_view.getAutoreleased()]);
1775     // NSPrintOperation takes ownership of the view.
1776     NSPrintOperation *printOperation = [NSPrintOperation printOperationWithView:printingView.get() printInfo:printInfo];
1777     [printOperation setCanSpawnSeparateThread:YES];
1778     [printOperation setJobTitle:frame.title()];
1779     printingView->_printOperation = printOperation;
1780     return printOperation;
1781 }
1782
1783 void WebViewImpl::setAutomaticallyAdjustsContentInsets(bool automaticallyAdjustsContentInsets)
1784 {
1785     m_automaticallyAdjustsContentInsets = automaticallyAdjustsContentInsets;
1786     updateContentInsetsIfAutomatic();
1787 }
1788
1789 void WebViewImpl::updateContentInsetsIfAutomatic()
1790 {
1791     if (!m_automaticallyAdjustsContentInsets)
1792         return;
1793
1794     NSWindow *window = [m_view window];
1795     if ((window.styleMask & NSWindowStyleMaskFullSizeContentView) && !window.titlebarAppearsTransparent && ![m_view enclosingScrollView]) {
1796         NSRect contentLayoutRect = [m_view convertRect:window.contentLayoutRect fromView:nil];
1797         CGFloat newTopContentInset = NSMaxY(contentLayoutRect) - NSHeight(contentLayoutRect);
1798         if (m_page->topContentInset() != newTopContentInset)
1799             setTopContentInset(newTopContentInset);
1800     } else
1801         setTopContentInset(0);
1802 }
1803
1804 CGFloat WebViewImpl::topContentInset() const
1805 {
1806     if (m_didScheduleSetTopContentInset)
1807         return m_pendingTopContentInset;
1808     return m_page->topContentInset();
1809 }
1810
1811 void WebViewImpl::setTopContentInset(CGFloat contentInset)
1812 {
1813     m_pendingTopContentInset = contentInset;
1814
1815     if (m_didScheduleSetTopContentInset)
1816         return;
1817
1818     m_didScheduleSetTopContentInset = true;
1819
1820     auto weakThis = makeWeakPtr(*this);
1821     dispatch_async(dispatch_get_main_queue(), [weakThis] {
1822         if (!weakThis)
1823             return;
1824         weakThis->dispatchSetTopContentInset();
1825     });
1826 }
1827
1828 void WebViewImpl::dispatchSetTopContentInset()
1829 {
1830     if (!m_didScheduleSetTopContentInset)
1831         return;
1832
1833     m_didScheduleSetTopContentInset = false;
1834     m_page->setTopContentInset(m_pendingTopContentInset);
1835 }
1836
1837 void WebViewImpl::prepareContentInRect(CGRect rect)
1838 {
1839     m_contentPreparationRect = rect;
1840     m_useContentPreparationRectForVisibleRect = true;
1841
1842     updateViewExposedRect();
1843 }
1844
1845 void WebViewImpl::updateViewExposedRect()
1846 {
1847     CGRect exposedRect = NSRectToCGRect([m_view visibleRect]);
1848
1849     if (m_useContentPreparationRectForVisibleRect)
1850         exposedRect = CGRectUnion(m_contentPreparationRect, exposedRect);
1851
1852     if (auto drawingArea = m_page->drawingArea())
1853         drawingArea->setViewExposedRect(m_clipsToVisibleRect ? Optional<WebCore::FloatRect>(exposedRect) : WTF::nullopt);
1854 }
1855
1856 void WebViewImpl::setClipsToVisibleRect(bool clipsToVisibleRect)
1857 {
1858     m_clipsToVisibleRect = clipsToVisibleRect;
1859     updateViewExposedRect();
1860 }
1861
1862 void WebViewImpl::setMinimumSizeForAutoLayout(CGSize minimumSizeForAutoLayout)
1863 {
1864     bool expandsToFit = minimumSizeForAutoLayout.width > 0;
1865
1866     m_page->setViewLayoutSize(WebCore::IntSize(minimumSizeForAutoLayout));
1867     m_page->setMainFrameIsScrollable(!expandsToFit);
1868
1869     setClipsToVisibleRect(expandsToFit);
1870 }
1871
1872 CGSize WebViewImpl::minimumSizeForAutoLayout() const
1873 {
1874     return m_page->viewLayoutSize();
1875 }
1876
1877 void WebViewImpl::setShouldExpandToViewHeightForAutoLayout(bool shouldExpandToViewHeightForAutoLayout)
1878 {
1879     m_page->setAutoSizingShouldExpandToViewHeight(shouldExpandToViewHeightForAutoLayout);
1880 }
1881
1882 bool WebViewImpl::shouldExpandToViewHeightForAutoLayout() const
1883 {
1884     return m_page->autoSizingShouldExpandToViewHeight();
1885 }
1886
1887 void WebViewImpl::setIntrinsicContentSize(CGSize intrinsicContentSize)
1888 {
1889     // If the intrinsic content size is less than the minimum layout width, the content flowed to fit,
1890     // so we can report that that dimension is flexible. If not, we need to report our intrinsic width
1891     // so that autolayout will know to provide space for us.
1892
1893     CGSize intrinsicContentSizeAcknowledgingFlexibleWidth = intrinsicContentSize;
1894     if (intrinsicContentSize.width < m_page->viewLayoutSize().width())
1895         intrinsicContentSizeAcknowledgingFlexibleWidth.width = NSViewNoIntrinsicMetric;
1896
1897     m_intrinsicContentSize = intrinsicContentSizeAcknowledgingFlexibleWidth;
1898     [m_view invalidateIntrinsicContentSize];
1899 }
1900
1901 CGSize WebViewImpl::intrinsicContentSize() const
1902 {
1903     return m_intrinsicContentSize;
1904 }
1905
1906 void WebViewImpl::setViewScale(CGFloat viewScale)
1907 {
1908     m_lastRequestedViewScale = viewScale;
1909
1910     if (!supportsArbitraryLayoutModes() && viewScale != 1)
1911         return;
1912
1913     m_page->scaleView(viewScale);
1914     [m_layoutStrategy didChangeViewScale];
1915 }
1916
1917 CGFloat WebViewImpl::viewScale() const
1918 {
1919     return m_page->viewScaleFactor();
1920 }
1921
1922 WKLayoutMode WebViewImpl::layoutMode() const
1923 {
1924     return [m_layoutStrategy layoutMode];
1925 }
1926
1927 void WebViewImpl::setLayoutMode(WKLayoutMode layoutMode)
1928 {
1929     m_lastRequestedLayoutMode = layoutMode;
1930
1931     if (!supportsArbitraryLayoutModes() && layoutMode != kWKLayoutModeViewSize)
1932         return;
1933
1934     if (layoutMode == [m_layoutStrategy layoutMode])
1935         return;
1936
1937     [m_layoutStrategy willChangeLayoutStrategy];
1938     m_layoutStrategy = [WKViewLayoutStrategy layoutStrategyWithPage:m_page view:m_view.getAutoreleased() viewImpl:*this mode:layoutMode];
1939 }
1940
1941 bool WebViewImpl::supportsArbitraryLayoutModes() const
1942 {
1943     if ([m_fullScreenWindowController isFullScreen])
1944         return false;
1945
1946     WebFrameProxy* frame = m_page->mainFrame();
1947     if (!frame)
1948         return true;
1949
1950     // If we have a plugin document in the main frame, avoid using custom WKLayoutModes
1951     // and fall back to the defaults, because there's a good chance that it won't work (e.g. with PDFPlugin).
1952     if (frame->containsPluginDocument())
1953         return false;
1954
1955     return true;
1956 }
1957
1958 void WebViewImpl::updateSupportsArbitraryLayoutModes()
1959 {
1960     if (!supportsArbitraryLayoutModes()) {
1961         WKLayoutMode oldRequestedLayoutMode = m_lastRequestedLayoutMode;
1962         CGFloat oldRequestedViewScale = m_lastRequestedViewScale;
1963         CGSize oldRequestedFixedLayoutSize = m_lastRequestedFixedLayoutSize;
1964         setViewScale(1);
1965         setLayoutMode(kWKLayoutModeViewSize);
1966         setFixedLayoutSize(CGSizeZero);
1967
1968         // The 'last requested' parameters will have been overwritten by setting them above, but we don't
1969         // want this to count as a request (only changes from the client count), so reset them.
1970         m_lastRequestedLayoutMode = oldRequestedLayoutMode;
1971         m_lastRequestedViewScale = oldRequestedViewScale;
1972         m_lastRequestedFixedLayoutSize = oldRequestedFixedLayoutSize;
1973     } else if (m_lastRequestedLayoutMode != [m_layoutStrategy layoutMode]) {
1974         setViewScale(m_lastRequestedViewScale);
1975         setLayoutMode(m_lastRequestedLayoutMode);
1976         setFixedLayoutSize(m_lastRequestedFixedLayoutSize);
1977     }
1978 }
1979
1980 void WebViewImpl::setOverrideDeviceScaleFactor(CGFloat deviceScaleFactor)
1981 {
1982     m_overrideDeviceScaleFactor = deviceScaleFactor;
1983     m_page->setIntrinsicDeviceScaleFactor(intrinsicDeviceScaleFactor());
1984 }
1985
1986 float WebViewImpl::intrinsicDeviceScaleFactor() const
1987 {
1988     if (m_overrideDeviceScaleFactor)
1989         return m_overrideDeviceScaleFactor;
1990     if (m_targetWindowForMovePreparation)
1991         return m_targetWindowForMovePreparation.backingScaleFactor;
1992     if (NSWindow *window = [m_view window])
1993         return window.backingScaleFactor;
1994     return [NSScreen mainScreen].backingScaleFactor;
1995 }
1996
1997 void WebViewImpl::windowDidOrderOffScreen()
1998 {
1999     LOG(ActivityState, "WebViewImpl %p (page %llu) windowDidOrderOffScreen", this, m_page->pageID());
2000     m_page->activityStateDidChange({ WebCore::ActivityState::IsVisible, WebCore::ActivityState::WindowIsActive });
2001 }
2002
2003 void WebViewImpl::windowDidOrderOnScreen()
2004 {
2005     LOG(ActivityState, "WebViewImpl %p (page %llu) windowDidOrderOnScreen", this, m_page->pageID());
2006     m_page->activityStateDidChange({ WebCore::ActivityState::IsVisible, WebCore::ActivityState::WindowIsActive });
2007 }
2008
2009 void WebViewImpl::windowDidBecomeKey(NSWindow *keyWindow)
2010 {
2011     if (keyWindow == [m_view window] || keyWindow == [m_view window].attachedSheet) {
2012 #if ENABLE(GAMEPAD)
2013         UIGamepadProvider::singleton().viewBecameActive(m_page.get());
2014 #endif
2015         updateSecureInputState();
2016         m_page->activityStateDidChange(WebCore::ActivityState::WindowIsActive);
2017     }
2018 }
2019
2020 void WebViewImpl::windowDidResignKey(NSWindow *formerKeyWindow)
2021 {
2022     if (formerKeyWindow == [m_view window] || formerKeyWindow == [m_view window].attachedSheet) {
2023 #if ENABLE(GAMEPAD)
2024         UIGamepadProvider::singleton().viewBecameInactive(m_page.get());
2025 #endif
2026         updateSecureInputState();
2027         m_page->activityStateDidChange(WebCore::ActivityState::WindowIsActive);
2028     }
2029 }
2030
2031 void WebViewImpl::windowDidMiniaturize()
2032 {
2033     m_page->activityStateDidChange(WebCore::ActivityState::IsVisible);
2034 }
2035
2036 void WebViewImpl::windowDidDeminiaturize()
2037 {
2038     m_page->activityStateDidChange(WebCore::ActivityState::IsVisible);
2039 }
2040
2041 void WebViewImpl::windowDidMove()
2042 {
2043     updateWindowAndViewFrames();
2044 }
2045
2046 void WebViewImpl::windowDidResize()
2047 {
2048     updateWindowAndViewFrames();
2049 }
2050
2051 void WebViewImpl::windowDidChangeBackingProperties(CGFloat oldBackingScaleFactor)
2052 {
2053     CGFloat newBackingScaleFactor = intrinsicDeviceScaleFactor();
2054     if (oldBackingScaleFactor == newBackingScaleFactor)
2055         return;
2056
2057     m_page->setIntrinsicDeviceScaleFactor(newBackingScaleFactor);
2058 }
2059
2060 void WebViewImpl::windowDidChangeScreen()
2061 {
2062     NSWindow *window = m_targetWindowForMovePreparation ? m_targetWindowForMovePreparation : [m_view window];
2063     m_page->windowScreenDidChange([[[[window screen] deviceDescription] objectForKey:@"NSScreenNumber"] intValue]);
2064 }
2065
2066 void WebViewImpl::windowDidChangeLayerHosting()
2067 {
2068     m_page->layerHostingModeDidChange();
2069 }
2070
2071 void WebViewImpl::windowDidChangeOcclusionState()
2072 {
2073     LOG(ActivityState, "WebViewImpl %p (page %llu) windowDidChangeOcclusionState", this, m_page->pageID());
2074     m_page->activityStateDidChange(WebCore::ActivityState::IsVisible);
2075 }
2076
2077 bool WebViewImpl::mightBeginDragWhileInactive()
2078 {
2079     if ([m_view window].isKeyWindow)
2080         return false;
2081
2082     if (m_page->editorState().selectionIsNone || !m_page->editorState().selectionIsRange)
2083         return false;
2084
2085     return true;
2086 }
2087
2088 bool WebViewImpl::mightBeginScrollWhileInactive()
2089 {
2090     // Legacy style scrollbars have design details that rely on tracking the mouse all the time.
2091     if (_NSRecommendedScrollerStyle() == NSScrollerStyleLegacy)
2092         return true;
2093
2094     return false;
2095 }
2096
2097 void WebViewImpl::accessibilitySettingsDidChange()
2098 {
2099     m_page->accessibilitySettingsDidChange();
2100 }
2101
2102 bool WebViewImpl::acceptsFirstMouse(NSEvent *event)
2103 {
2104     if (!mightBeginDragWhileInactive() && !mightBeginScrollWhileInactive())
2105         return false;
2106
2107     // There's a chance that responding to this event will run a nested event loop, and
2108     // fetching a new event might release the old one. Retaining and then autoreleasing
2109     // the current event prevents that from causing a problem inside WebKit or AppKit code.
2110     CFRetain((__bridge CFTypeRef)event);
2111     CFAutorelease((__bridge CFTypeRef)event);
2112
2113     if (![m_view hitTest:event.locationInWindow])
2114         return false;
2115
2116     setLastMouseDownEvent(event);
2117     bool result = m_page->acceptsFirstMouse(event.eventNumber, WebEventFactory::createWebMouseEvent(event, m_lastPressureEvent.get(), m_view.getAutoreleased()));
2118     setLastMouseDownEvent(nil);
2119     return result;
2120 }
2121
2122 bool WebViewImpl::shouldDelayWindowOrderingForEvent(NSEvent *event)
2123 {
2124     if (!mightBeginDragWhileInactive())
2125         return false;
2126
2127     // There's a chance that responding to this event will run a nested event loop, and
2128     // fetching a new event might release the old one. Retaining and then autoreleasing
2129     // the current event prevents that from causing a problem inside WebKit or AppKit code.
2130     CFRetain((__bridge CFTypeRef)event);
2131     CFAutorelease((__bridge CFTypeRef)event);
2132
2133     if (![m_view hitTest:event.locationInWindow])
2134         return false;
2135
2136     setLastMouseDownEvent(event);
2137     bool result = m_page->shouldDelayWindowOrderingForEvent(WebEventFactory::createWebMouseEvent(event, m_lastPressureEvent.get(), m_view.getAutoreleased()));
2138     setLastMouseDownEvent(nil);
2139     return result;
2140 }
2141
2142 bool WebViewImpl::windowResizeMouseLocationIsInVisibleScrollerThumb(CGPoint point)
2143 {
2144     NSPoint localPoint = [m_view convertPoint:NSPointFromCGPoint(point) fromView:nil];
2145     NSRect visibleThumbRect = NSRect(m_page->visibleScrollerThumbRect());
2146     return NSMouseInRect(localPoint, visibleThumbRect, [m_view isFlipped]);
2147 }
2148
2149 void WebViewImpl::viewWillMoveToWindow(NSWindow *window)
2150 {
2151     // If we're in the middle of preparing to move to a window, we should only be moved to that window.
2152     ASSERT(!m_targetWindowForMovePreparation || (m_targetWindowForMovePreparation == window));
2153
2154     NSWindow *currentWindow = [m_view window];
2155     if (window == currentWindow)
2156         return;
2157
2158     clearAllEditCommands();
2159
2160     NSWindow *stopObservingWindow = m_targetWindowForMovePreparation ? m_targetWindowForMovePreparation : [m_view window];
2161     [m_windowVisibilityObserver stopObserving:stopObservingWindow];
2162     [m_windowVisibilityObserver startObserving:window];
2163 }
2164
2165 void WebViewImpl::viewDidMoveToWindow()
2166 {
2167     NSWindow *window = m_targetWindowForMovePreparation ? m_targetWindowForMovePreparation : [m_view window];
2168
2169     LOG(ActivityState, "WebViewImpl %p viewDidMoveToWindow %p", this, window);
2170
2171     if (window) {
2172         windowDidChangeScreen();
2173
2174         OptionSet<WebCore::ActivityState::Flag> activityStateChanges { WebCore::ActivityState::WindowIsActive, WebCore::ActivityState::IsVisible };
2175         if (m_shouldDeferViewInWindowChanges)
2176             m_viewInWindowChangeWasDeferred = true;
2177         else
2178             activityStateChanges.add(WebCore::ActivityState::IsInWindow);
2179         m_page->activityStateDidChange(activityStateChanges);
2180
2181         updateWindowAndViewFrames();
2182
2183         // FIXME(135509) This call becomes unnecessary once 135509 is fixed; remove.
2184         m_page->layerHostingModeDidChange();
2185
2186         if (!m_flagsChangedEventMonitor) {
2187             auto weakThis = makeWeakPtr(*this);
2188             m_flagsChangedEventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskFlagsChanged handler:[weakThis] (NSEvent *flagsChangedEvent) {
2189                 if (weakThis)
2190                     weakThis->postFakeMouseMovedEventForFlagsChangedEvent(flagsChangedEvent);
2191                 return flagsChangedEvent;
2192             }];
2193         }
2194
2195         accessibilityRegisterUIProcessTokens();
2196
2197         if (m_immediateActionGestureRecognizer && ![[m_view gestureRecognizers] containsObject:m_immediateActionGestureRecognizer.get()] && !m_ignoresNonWheelEvents && m_allowsLinkPreview)
2198             [m_view addGestureRecognizer:m_immediateActionGestureRecognizer.get()];
2199     } else {
2200         OptionSet<WebCore::ActivityState::Flag> activityStateChanges { WebCore::ActivityState::WindowIsActive, WebCore::ActivityState::IsVisible };
2201         if (m_shouldDeferViewInWindowChanges)
2202             m_viewInWindowChangeWasDeferred = true;
2203         else
2204             activityStateChanges.add(WebCore::ActivityState::IsInWindow);
2205         m_page->activityStateDidChange(activityStateChanges);
2206
2207         [NSEvent removeMonitor:m_flagsChangedEventMonitor];
2208         m_flagsChangedEventMonitor = nil;
2209
2210         dismissContentRelativeChildWindowsWithAnimation(false);
2211
2212         if (m_immediateActionGestureRecognizer) {
2213             // Work around <rdar://problem/22646404> by explicitly cancelling the animation.
2214             cancelImmediateActionAnimation();
2215             [m_view removeGestureRecognizer:m_immediateActionGestureRecognizer.get()];
2216         }
2217     }
2218
2219     m_page->setIntrinsicDeviceScaleFactor(intrinsicDeviceScaleFactor());
2220     m_page->webViewDidMoveToWindow();
2221 }
2222
2223 void WebViewImpl::viewDidChangeBackingProperties()
2224 {
2225     NSColorSpace *colorSpace = [m_view window].colorSpace;
2226     if ([colorSpace isEqualTo:m_colorSpace.get()])
2227         return;
2228
2229     m_colorSpace = nullptr;
2230     if (DrawingAreaProxy *drawingArea = m_page->drawingArea())
2231         drawingArea->colorSpaceDidChange();
2232 }
2233
2234 void WebViewImpl::viewDidHide()
2235 {
2236     LOG(ActivityState, "WebViewImpl %p (page %llu) viewDidHide", this, m_page->pageID());
2237     m_page->activityStateDidChange(WebCore::ActivityState::IsVisible);
2238 }
2239
2240 void WebViewImpl::viewDidUnhide()
2241 {
2242     LOG(ActivityState, "WebViewImpl %p (page %llu) viewDidUnhide", this, m_page->pageID());
2243     m_page->activityStateDidChange(WebCore::ActivityState::IsVisible);
2244 }
2245
2246 void WebViewImpl::activeSpaceDidChange()
2247 {
2248     LOG(ActivityState, "WebViewImpl %p (page %llu) activeSpaceDidChange", this, m_page->pageID());
2249     m_page->activityStateDidChange(WebCore::ActivityState::IsVisible);
2250 }
2251
2252 NSView *WebViewImpl::hitTest(CGPoint point)
2253 {
2254     NSView *hitView = [m_view _web_superHitTest:NSPointFromCGPoint(point)];
2255     if (hitView && hitView == m_layerHostingView)
2256         hitView = m_view.getAutoreleased();
2257
2258     return hitView;
2259 }
2260
2261 void WebViewImpl::postFakeMouseMovedEventForFlagsChangedEvent(NSEvent *flagsChangedEvent)
2262 {
2263     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSEventTypeMouseMoved location:flagsChangedEvent.window.mouseLocationOutsideOfEventStream
2264         modifierFlags:flagsChangedEvent.modifierFlags timestamp:flagsChangedEvent.timestamp windowNumber:flagsChangedEvent.windowNumber
2265         context:nullptr eventNumber:0 clickCount:0 pressure:0];
2266     NativeWebMouseEvent webEvent(fakeEvent, m_lastPressureEvent.get(), m_view.getAutoreleased());
2267     m_page->handleMouseEvent(webEvent);
2268 }
2269
2270 ColorSpaceData WebViewImpl::colorSpace()
2271 {
2272     if (!m_colorSpace) {
2273         if (m_targetWindowForMovePreparation)
2274             m_colorSpace = m_targetWindowForMovePreparation.colorSpace;
2275         else if (NSWindow *window = [m_view window])
2276             m_colorSpace = window.colorSpace;
2277         else
2278             m_colorSpace = [NSScreen mainScreen].colorSpace;
2279     }
2280
2281     ColorSpaceData colorSpaceData;
2282     colorSpaceData.cgColorSpace = [m_colorSpace CGColorSpace];
2283     
2284     return colorSpaceData;
2285 }
2286
2287 void WebViewImpl::setUnderlayColor(NSColor *underlayColor)
2288 {
2289     m_page->setUnderlayColor(WebCore::colorFromNSColor(underlayColor));
2290 }
2291
2292 NSColor *WebViewImpl::underlayColor() const
2293 {
2294     WebCore::Color webColor = m_page->underlayColor();
2295     if (!webColor.isValid())
2296         return nil;
2297
2298     return WebCore::nsColor(webColor);
2299 }
2300
2301 NSColor *WebViewImpl::pageExtendedBackgroundColor() const
2302 {
2303     WebCore::Color color = m_page->pageExtendedBackgroundColor();
2304     if (!color.isValid())
2305         return nil;
2306
2307     return WebCore::nsColor(color);
2308 }
2309
2310 void WebViewImpl::setOverlayScrollbarStyle(Optional<WebCore::ScrollbarOverlayStyle> scrollbarStyle)
2311 {
2312     m_page->setOverlayScrollbarStyle(scrollbarStyle);
2313 }
2314
2315 Optional<WebCore::ScrollbarOverlayStyle> WebViewImpl::overlayScrollbarStyle() const
2316 {
2317     return m_page->overlayScrollbarStyle();
2318 }
2319
2320 void WebViewImpl::beginDeferringViewInWindowChanges()
2321 {
2322     if (m_shouldDeferViewInWindowChanges) {
2323         NSLog(@"beginDeferringViewInWindowChanges was called while already deferring view-in-window changes!");
2324         return;
2325     }
2326
2327     m_shouldDeferViewInWindowChanges = true;
2328 }
2329
2330 void WebViewImpl::endDeferringViewInWindowChanges()
2331 {
2332     if (!m_shouldDeferViewInWindowChanges) {
2333         NSLog(@"endDeferringViewInWindowChanges was called without beginDeferringViewInWindowChanges!");
2334         return;
2335     }
2336
2337     m_shouldDeferViewInWindowChanges = false;
2338
2339     if (m_viewInWindowChangeWasDeferred) {
2340         dispatchSetTopContentInset();
2341         m_page->activityStateDidChange(WebCore::ActivityState::IsInWindow);
2342         m_viewInWindowChangeWasDeferred = false;
2343     }
2344 }
2345
2346 void WebViewImpl::endDeferringViewInWindowChangesSync()
2347 {
2348     if (!m_shouldDeferViewInWindowChanges) {
2349         NSLog(@"endDeferringViewInWindowChangesSync was called without beginDeferringViewInWindowChanges!");
2350         return;
2351     }
2352
2353     m_shouldDeferViewInWindowChanges = false;
2354
2355     if (m_viewInWindowChangeWasDeferred) {
2356         dispatchSetTopContentInset();
2357         m_page->activityStateDidChange(WebCore::ActivityState::IsInWindow);
2358         m_viewInWindowChangeWasDeferred = false;
2359     }
2360 }
2361
2362 void WebViewImpl::prepareForMoveToWindow(NSWindow *targetWindow, WTF::Function<void()>&& completionHandler)
2363 {
2364     m_shouldDeferViewInWindowChanges = true;
2365     viewWillMoveToWindow(targetWindow);
2366     m_targetWindowForMovePreparation = targetWindow;
2367     viewDidMoveToWindow();
2368
2369     m_shouldDeferViewInWindowChanges = false;
2370
2371     auto weakThis = makeWeakPtr(*this);
2372     m_page->installActivityStateChangeCompletionHandler([weakThis, completionHandler = WTFMove(completionHandler)]() {
2373         completionHandler();
2374
2375         if (!weakThis)
2376             return;
2377
2378         ASSERT([weakThis->m_view window] == weakThis->m_targetWindowForMovePreparation);
2379         weakThis->m_targetWindowForMovePreparation = nil;
2380     });
2381
2382     dispatchSetTopContentInset();
2383     m_page->activityStateDidChange(WebCore::ActivityState::IsInWindow, false, WebPageProxy::ActivityStateChangeDispatchMode::Immediate);
2384     m_viewInWindowChangeWasDeferred = false;
2385 }
2386
2387 void WebViewImpl::updateSecureInputState()
2388 {
2389     if (![[m_view window] isKeyWindow] || !isFocused()) {
2390         if (m_inSecureInputState) {
2391             DisableSecureEventInput();
2392             m_inSecureInputState = false;
2393         }
2394         return;
2395     }
2396     // WKView has a single input context for all editable areas (except for plug-ins).
2397     NSTextInputContext *context = [m_view _web_superInputContext];
2398     bool isInPasswordField = m_page->editorState().isInPasswordField;
2399
2400     if (isInPasswordField) {
2401         if (!m_inSecureInputState)
2402             EnableSecureEventInput();
2403         static NSArray *romanInputSources = [[NSArray alloc] initWithObjects:&NSAllRomanInputSourcesLocaleIdentifier count:1];
2404         LOG(TextInput, "-> setAllowedInputSourceLocales:romanInputSources");
2405         [context setAllowedInputSourceLocales:romanInputSources];
2406     } else {
2407         if (m_inSecureInputState)
2408             DisableSecureEventInput();
2409         LOG(TextInput, "-> setAllowedInputSourceLocales:nil");
2410         [context setAllowedInputSourceLocales:nil];
2411     }
2412     m_inSecureInputState = isInPasswordField;
2413 }
2414
2415 void WebViewImpl::resetSecureInputState()
2416 {
2417     if (m_inSecureInputState) {
2418         DisableSecureEventInput();
2419         m_inSecureInputState = false;
2420     }
2421 }
2422
2423 void WebViewImpl::notifyInputContextAboutDiscardedComposition()
2424 {
2425     // <rdar://problem/9359055>: -discardMarkedText can only be called for active contexts.
2426     // FIXME: We fail to ever notify the input context if something (e.g. a navigation) happens while the window is not key.
2427     // This is not a problem when the window is key, because we discard marked text on resigning first responder.
2428     if (![[m_view window] isKeyWindow] || m_view.getAutoreleased() != [[m_view window] firstResponder])
2429         return;
2430
2431     LOG(TextInput, "-> discardMarkedText");
2432
2433     [[m_view _web_superInputContext] discardMarkedText]; // Inform the input method that we won't have an inline input area despite having been asked to.
2434 }
2435
2436 void WebViewImpl::setPluginComplexTextInputState(PluginComplexTextInputState pluginComplexTextInputState)
2437 {
2438     m_pluginComplexTextInputState = pluginComplexTextInputState;
2439
2440     if (m_pluginComplexTextInputState != PluginComplexTextInputDisabled)
2441         return;
2442
2443     // Send back an empty string to the plug-in. This will disable text input.
2444     m_page->sendComplexTextInputToPlugin(m_pluginComplexTextInputIdentifier, String());
2445 }
2446
2447 void WebViewImpl::setPluginComplexTextInputStateAndIdentifier(PluginComplexTextInputState pluginComplexTextInputState, uint64_t pluginComplexTextInputIdentifier)
2448 {
2449     if (pluginComplexTextInputIdentifier != m_pluginComplexTextInputIdentifier) {
2450         // We're asked to update the state for a plug-in that doesn't have focus.
2451         return;
2452     }
2453
2454     setPluginComplexTextInputState(pluginComplexTextInputState);
2455 }
2456
2457 void WebViewImpl::disableComplexTextInputIfNecessary()
2458 {
2459     if (!m_pluginComplexTextInputIdentifier)
2460         return;
2461
2462     if (m_pluginComplexTextInputState != PluginComplexTextInputEnabled)
2463         return;
2464
2465     // Check if the text input window has been dismissed.
2466     if (![[WKTextInputWindowController sharedTextInputWindowController] hasMarkedText])
2467         setPluginComplexTextInputState(PluginComplexTextInputDisabled);
2468 }
2469
2470 bool WebViewImpl::handlePluginComplexTextInputKeyDown(NSEvent *event)
2471 {
2472     ASSERT(m_pluginComplexTextInputIdentifier);
2473     ASSERT(m_pluginComplexTextInputState != PluginComplexTextInputDisabled);
2474
2475     BOOL usingLegacyCocoaTextInput = m_pluginComplexTextInputState == PluginComplexTextInputEnabledLegacy;
2476
2477     NSString *string = nil;
2478     BOOL didHandleEvent = [[WKTextInputWindowController sharedTextInputWindowController] interpretKeyEvent:event usingLegacyCocoaTextInput:usingLegacyCocoaTextInput string:&string];
2479
2480     if (string) {
2481         m_page->sendComplexTextInputToPlugin(m_pluginComplexTextInputIdentifier, string);
2482
2483         if (!usingLegacyCocoaTextInput)
2484             m_pluginComplexTextInputState = PluginComplexTextInputDisabled;
2485     }
2486
2487     return didHandleEvent;
2488 }
2489
2490 bool WebViewImpl::tryHandlePluginComplexTextInputKeyDown(NSEvent *event)
2491 {
2492     if (!m_pluginComplexTextInputIdentifier || m_pluginComplexTextInputState == PluginComplexTextInputDisabled)
2493         return NO;
2494
2495     // Check if the text input window has been dismissed and let the plug-in process know.
2496     // This is only valid with the updated Cocoa text input spec.
2497     disableComplexTextInputIfNecessary();
2498
2499     // Try feeding the keyboard event directly to the plug-in.
2500     if (m_pluginComplexTextInputState == PluginComplexTextInputEnabledLegacy)
2501         return handlePluginComplexTextInputKeyDown(event);
2502
2503     return NO;
2504 }
2505
2506 void WebViewImpl::pluginFocusOrWindowFocusChanged(bool pluginHasFocusAndWindowHasFocus, uint64_t pluginComplexTextInputIdentifier)
2507 {
2508     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer));
2509     BOOL inputSourceChanged = m_pluginComplexTextInputIdentifier;
2510
2511     if (pluginHasFocusAndWindowHasFocus) {
2512         // Check if we're already allowing text input for this plug-in.
2513         if (pluginComplexTextInputIdentifier == m_pluginComplexTextInputIdentifier)
2514             return;
2515
2516         m_pluginComplexTextInputIdentifier = pluginComplexTextInputIdentifier;
2517
2518     } else {
2519         // Check if we got a request to unfocus a plug-in that isn't focused.
2520         if (pluginComplexTextInputIdentifier != m_pluginComplexTextInputIdentifier)
2521             return;
2522
2523         m_pluginComplexTextInputIdentifier = 0;
2524     }
2525
2526     if (inputSourceChanged) {
2527         // The input source changed; discard any entered text.
2528         [[WKTextInputWindowController sharedTextInputWindowController] unmarkText];
2529     }
2530     
2531     // This will force the current input context to be updated to its correct value.
2532     [NSApp updateWindows];
2533 }
2534
2535 bool WebViewImpl::tryPostProcessPluginComplexTextInputKeyDown(NSEvent *event)
2536 {
2537     if (!m_pluginComplexTextInputIdentifier || m_pluginComplexTextInputState == PluginComplexTextInputDisabled)
2538         return NO;
2539
2540     // In the legacy text input model, the event has already been sent to the input method.
2541     if (m_pluginComplexTextInputState == PluginComplexTextInputEnabledLegacy)
2542         return NO;
2543
2544     return handlePluginComplexTextInputKeyDown(event);
2545 }
2546
2547 void WebViewImpl::handleAcceptedAlternativeText(const String& acceptedAlternative)
2548 {
2549     m_page->handleAlternativeTextUIResult(acceptedAlternative);
2550 }
2551
2552
2553 NSInteger WebViewImpl::spellCheckerDocumentTag()
2554 {
2555     if (!m_spellCheckerDocumentTag)
2556         m_spellCheckerDocumentTag = [NSSpellChecker uniqueSpellDocumentTag];
2557     return m_spellCheckerDocumentTag.value();
2558 }
2559
2560 void WebViewImpl::pressureChangeWithEvent(NSEvent *event)
2561 {
2562     if (event == m_lastPressureEvent)
2563         return;
2564
2565     if (m_ignoresNonWheelEvents)
2566         return;
2567
2568     if (event.phase != NSEventPhaseChanged && event.phase != NSEventPhaseBegan && event.phase != NSEventPhaseEnded)
2569         return;
2570
2571     NativeWebMouseEvent webEvent(event, m_lastPressureEvent.get(), m_view.getAutoreleased());
2572     m_page->handleMouseEvent(webEvent);
2573
2574     m_lastPressureEvent = event;
2575 }
2576
2577 #if ENABLE(FULLSCREEN_API)
2578 bool WebViewImpl::hasFullScreenWindowController() const
2579 {
2580     return !!m_fullScreenWindowController;
2581 }
2582
2583 WKFullScreenWindowController *WebViewImpl::fullScreenWindowController()
2584 {
2585     if (!m_fullScreenWindowController)
2586         m_fullScreenWindowController = adoptNS([[WKFullScreenWindowController alloc] initWithWindow:fullScreenWindow() webView:m_view.getAutoreleased() page:m_page]);
2587
2588     return m_fullScreenWindowController.get();
2589 }
2590
2591 void WebViewImpl::closeFullScreenWindowController()
2592 {
2593     if (!m_fullScreenWindowController)
2594         return;
2595
2596     [m_fullScreenWindowController close];
2597     m_fullScreenWindowController = nullptr;
2598 }
2599 #endif
2600
2601 NSView *WebViewImpl::fullScreenPlaceholderView()
2602 {
2603 #if ENABLE(FULLSCREEN_API)
2604     if (m_fullScreenWindowController && [m_fullScreenWindowController isFullScreen])
2605         return [m_fullScreenWindowController webViewPlaceholder];
2606 #endif
2607     return nil;
2608 }
2609
2610 NSWindow *WebViewImpl::fullScreenWindow()
2611 {
2612 #if ENABLE(FULLSCREEN_API)
2613     return [[[WebCoreFullScreenWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame] styleMask:(NSWindowStyleMaskBorderless | NSWindowStyleMaskResizable) backing:NSBackingStoreBuffered defer:NO] autorelease];
2614 #else
2615     return nil;
2616 #endif
2617 }
2618
2619 bool WebViewImpl::isEditable() const
2620 {
2621     return m_page->isEditable();
2622 }
2623
2624 typedef HashMap<SEL, String> SelectorNameMap;
2625
2626 // Map selectors into Editor command names.
2627 // This is not needed for any selectors that have the same name as the Editor command.
2628 static const SelectorNameMap& selectorExceptionMap()
2629 {
2630     static NeverDestroyed<SelectorNameMap> map;
2631
2632     struct SelectorAndCommandName {
2633         SEL selector;
2634         ASCIILiteral commandName;
2635     };
2636
2637     static const SelectorAndCommandName names[] = {
2638         { @selector(insertNewlineIgnoringFieldEditor:), "InsertNewline"_s },
2639         { @selector(insertParagraphSeparator:), "InsertNewline"_s },
2640         { @selector(insertTabIgnoringFieldEditor:), "InsertTab"_s },
2641         { @selector(pageDown:), "MovePageDown"_s },
2642         { @selector(pageDownAndModifySelection:), "MovePageDownAndModifySelection"_s },
2643         { @selector(pageUp:), "MovePageUp"_s },
2644         { @selector(pageUpAndModifySelection:), "MovePageUpAndModifySelection"_s },
2645         { @selector(scrollPageDown:), "ScrollPageForward"_s },
2646         { @selector(scrollPageUp:), "ScrollPageBackward"_s },
2647         { @selector(_pasteAsQuotation:), "PasteAsQuotation"_s },
2648     };
2649
2650     for (auto& name : names)
2651         map.get().add(name.selector, name.commandName);
2652
2653     return map;
2654 }
2655
2656 static String commandNameForSelector(SEL selector)
2657 {
2658     // Check the exception map first.
2659     static const SelectorNameMap& exceptionMap = selectorExceptionMap();
2660     SelectorNameMap::const_iterator it = exceptionMap.find(selector);
2661     if (it != exceptionMap.end())
2662         return it->value;
2663
2664     // Remove the trailing colon.
2665     // No need to capitalize the command name since Editor command names are
2666     // not case sensitive.
2667     const char* selectorName = sel_getName(selector);
2668     size_t selectorNameLength = strlen(selectorName);
2669     if (selectorNameLength < 2 || selectorName[selectorNameLength - 1] != ':')
2670         return String();
2671     return String(selectorName, selectorNameLength - 1);
2672 }
2673
2674 bool WebViewImpl::executeSavedCommandBySelector(SEL selector)
2675 {
2676     LOG(TextInput, "Executing previously saved command %s", sel_getName(selector));
2677     // The sink does two things: 1) Tells us if the responder went unhandled, and
2678     // 2) prevents any NSBeep; we don't ever want to beep here.
2679     RetainPtr<WKResponderChainSink> sink = adoptNS([[WKResponderChainSink alloc] initWithResponderChain:m_view.getAutoreleased()]);
2680     [m_view _web_superDoCommandBySelector:selector];
2681     [sink detach];
2682     return ![sink didReceiveUnhandledCommand];
2683 }
2684
2685 void WebViewImpl::executeEditCommandForSelector(SEL selector, const String& argument)
2686 {
2687     m_page->executeEditCommand(commandNameForSelector(selector), argument);
2688 }
2689
2690 void WebViewImpl::registerEditCommand(Ref<WebEditCommandProxy>&& command, UndoOrRedo undoOrRedo)
2691 {
2692     auto actionName = command->label();
2693     auto commandObjC = adoptNS([[WKEditCommand alloc] initWithWebEditCommandProxy:WTFMove(command)]);
2694
2695     NSUndoManager *undoManager = [m_view undoManager];
2696     [undoManager registerUndoWithTarget:m_undoTarget.get() selector:((undoOrRedo == UndoOrRedo::Undo) ? @selector(undoEditing:) : @selector(redoEditing:)) object:commandObjC.get()];
2697     if (!actionName.isEmpty())
2698         [undoManager setActionName:(NSString *)actionName];
2699 }
2700
2701 void WebViewImpl::clearAllEditCommands()
2702 {
2703     [[m_view undoManager] removeAllActionsWithTarget:m_undoTarget.get()];
2704 }
2705
2706 bool WebViewImpl::writeSelectionToPasteboard(NSPasteboard *pasteboard, NSArray *types)
2707 {
2708     size_t numTypes = types.count;
2709     [pasteboard declareTypes:types owner:nil];
2710     for (size_t i = 0; i < numTypes; ++i) {
2711         if ([[types objectAtIndex:i] isEqualTo:WebCore::legacyStringPasteboardType()])
2712             [pasteboard setString:m_page->stringSelectionForPasteboard() forType:WebCore::legacyStringPasteboardType()];
2713         else {
2714             RefPtr<WebCore::SharedBuffer> buffer = m_page->dataSelectionForPasteboard([types objectAtIndex:i]);
2715             [pasteboard setData:buffer ? buffer->createNSData().get() : nil forType:[types objectAtIndex:i]];
2716         }
2717     }
2718     return true;
2719 }
2720
2721 bool WebViewImpl::readSelectionFromPasteboard(NSPasteboard *pasteboard)
2722 {
2723     return m_page->readSelectionFromPasteboard([pasteboard name]);
2724 }
2725
2726 id WebViewImpl::validRequestorForSendAndReturnTypes(NSString *sendType, NSString *returnType)
2727 {
2728     EditorState editorState = m_page->editorState();
2729     bool isValidSendType = false;
2730
2731     if (sendType && !editorState.selectionIsNone) {
2732         if (editorState.isInPlugin)
2733             isValidSendType = [sendType isEqualToString:WebCore::legacyStringPasteboardType()];
2734         else
2735             isValidSendType = [PasteboardTypes::forSelection() containsObject:sendType];
2736     }
2737
2738     bool isValidReturnType = false;
2739     if (!returnType)
2740         isValidReturnType = true;
2741     else if ([PasteboardTypes::forEditing() containsObject:returnType] && editorState.isContentEditable) {
2742         // We can insert strings in any editable context.  We can insert other types, like images, only in rich edit contexts.
2743         isValidReturnType = editorState.isContentRichlyEditable || [returnType isEqualToString:WebCore::legacyStringPasteboardType()];
2744     }
2745     if (isValidSendType && isValidReturnType)
2746         return m_view.getAutoreleased();
2747     return [[m_view nextResponder] validRequestorForSendType:sendType returnType:returnType];
2748 }
2749
2750 void WebViewImpl::centerSelectionInVisibleArea()
2751 {
2752     m_page->centerSelectionInVisibleArea();
2753 }
2754
2755 void WebViewImpl::selectionDidChange()
2756 {
2757     updateFontManagerIfNeeded();
2758     if (!m_isHandlingAcceptedCandidate)
2759         m_softSpaceRange = NSMakeRange(NSNotFound, 0);
2760 #if HAVE(TOUCH_BAR)
2761     updateTouchBar();
2762     if (!m_page->editorState().isMissingPostLayoutData)
2763         requestCandidatesForSelectionIfNeeded();
2764 #endif
2765
2766     NSWindow *window = [m_view window];
2767     if (window.firstResponder == m_view.get().get()) {
2768         NSInspectorBar *inspectorBar = window.inspectorBar;
2769         if (inspectorBar.visible)
2770             [inspectorBar _update];
2771     }
2772
2773     [m_view _web_editorStateDidChange];
2774 }
2775
2776 void WebViewImpl::showShareSheet(const WebCore::ShareDataWithParsedURL& data, WTF::CompletionHandler<void(bool)>&& completionHandler, WKWebView *view)
2777 {
2778     if (_shareSheet)
2779         [_shareSheet dismiss];
2780     
2781     ASSERT([view respondsToSelector:@selector(shareSheetDidDismiss:)]);
2782     _shareSheet = adoptNS([[WKShareSheet alloc] initWithView:view]);
2783     [_shareSheet setDelegate:view];
2784     
2785     [_shareSheet presentWithParameters:data completionHandler:WTFMove(completionHandler)];
2786 }
2787     
2788 void WebViewImpl::shareSheetDidDismiss(WKShareSheet *shareSheet)
2789 {
2790     ASSERT(_shareSheet == shareSheet);
2791     
2792     [_shareSheet setDelegate:nil];
2793     _shareSheet = nil;
2794 }
2795
2796 void WebViewImpl::didBecomeEditable()
2797 {
2798     [m_windowVisibilityObserver startObservingFontPanel];
2799
2800     dispatch_async(dispatch_get_main_queue(), [] {
2801         [[NSSpellChecker sharedSpellChecker] _preflightChosenSpellServer];
2802     });
2803 }
2804
2805 void WebViewImpl::updateFontManagerIfNeeded()
2806 {
2807     BOOL fontPanelIsVisible = NSFontPanel.sharedFontPanelExists && NSFontPanel.sharedFontPanel.visible;
2808     if (!fontPanelIsVisible && !m_page->editorState().isContentRichlyEditable)
2809         return;
2810
2811     m_page->fontAtSelection([](const String& fontName, double fontSize, bool selectionHasMultipleFonts, WebKit::CallbackBase::Error error) {
2812         if (NSFont *font = [NSFont fontWithName:fontName size:fontSize])
2813             [NSFontManager.sharedFontManager setSelectedFont:font isMultiple:selectionHasMultipleFonts];
2814     });
2815 }
2816
2817 void WebViewImpl::typingAttributesWithCompletionHandler(void(^completion)(NSDictionary<NSString *, id> *))
2818 {
2819     if (auto attributes = m_page->cachedFontAttributesAtSelectionStart()) {
2820         auto attributesAsDictionary = attributes->createDictionary();
2821         completion(attributesAsDictionary.get());
2822         return;
2823     }
2824
2825     m_page->requestFontAttributesAtSelectionStart([completion = makeBlockPtr(completion)] (const WebCore::FontAttributes& attributes, CallbackBase::Error error) {
2826         if (error != CallbackBase::Error::None) {
2827             completion(nil);
2828             return;
2829         }
2830
2831         auto attributesAsDictionary = attributes.createDictionary();
2832         completion(attributesAsDictionary.get());
2833     });
2834 }
2835
2836 void WebViewImpl::changeFontColorFromSender(id sender)
2837 {
2838     if (![sender respondsToSelector:@selector(color)])
2839         return;
2840
2841     id color = [sender color];
2842     if (![color isKindOfClass:NSColor.class])
2843         return;
2844
2845     auto& editorState = m_page->editorState();
2846     if (!editorState.isContentEditable || editorState.selectionIsNone)
2847         return;
2848
2849     WebCore::FontAttributeChanges changes;
2850     changes.setForegroundColor(WebCore::colorFromNSColor((NSColor *)color));
2851     m_page->changeFontAttributes(WTFMove(changes));
2852 }
2853
2854 void WebViewImpl::changeFontAttributesFromSender(id sender)
2855 {
2856     auto& editorState = m_page->editorState();
2857     if (!editorState.isContentEditable || editorState.selectionIsNone)
2858         return;
2859
2860     m_page->changeFontAttributes(WebCore::computedFontAttributeChanges(NSFontManager.sharedFontManager, sender));
2861     updateFontManagerIfNeeded();
2862 }
2863
2864 void WebViewImpl::changeFontFromFontManager()
2865 {
2866     auto& editorState = m_page->editorState();
2867     if (!editorState.isContentEditable || editorState.selectionIsNone)
2868         return;
2869
2870     m_page->changeFont(WebCore::computedFontChanges(NSFontManager.sharedFontManager));
2871     updateFontManagerIfNeeded();
2872 }
2873
2874 static NSMenuItem *menuItem(id <NSValidatedUserInterfaceItem> item)
2875 {
2876     if (![(NSObject *)item isKindOfClass:[NSMenuItem class]])
2877         return nil;
2878     return (NSMenuItem *)item;
2879 }
2880
2881 static NSToolbarItem *toolbarItem(id <NSValidatedUserInterfaceItem> item)
2882 {
2883     if (![(NSObject *)item isKindOfClass:[NSToolbarItem class]])
2884         return nil;
2885     return (NSToolbarItem *)item;
2886 }
2887
2888 bool WebViewImpl::validateUserInterfaceItem(id <NSValidatedUserInterfaceItem> item)
2889 {
2890     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer));
2891     SEL action = [item action];
2892
2893     if (action == @selector(showGuessPanel:)) {
2894         if (NSMenuItem *menuItem = WebKit::menuItem(item))
2895             [menuItem setTitle:WebCore::contextMenuItemTagShowSpellingPanel(![[[NSSpellChecker sharedSpellChecker] spellingPanel] isVisible])];
2896         return m_page->editorState().isContentEditable;
2897     }
2898
2899     if (action == @selector(checkSpelling:) || action == @selector(changeSpelling:))
2900         return m_page->editorState().isContentEditable;
2901
2902     if (action == @selector(toggleContinuousSpellChecking:)) {
2903         bool enabled = TextChecker::isContinuousSpellCheckingAllowed();
2904         bool checked = enabled && TextChecker::state().isContinuousSpellCheckingEnabled;
2905         [menuItem(item) setState:checked ? NSControlStateValueOn : NSControlStateValueOff];
2906         return enabled;
2907     }
2908
2909     if (action == @selector(toggleGrammarChecking:)) {
2910         bool checked = TextChecker::state().isGrammarCheckingEnabled;
2911         [menuItem(item) setState:checked ? NSControlStateValueOn : NSControlStateValueOff];
2912         return true;
2913     }
2914
2915     if (action == @selector(toggleAutomaticSpellingCorrection:)) {
2916         bool checked = TextChecker::state().isAutomaticSpellingCorrectionEnabled;
2917         [menuItem(item) setState:checked ? NSControlStateValueOn : NSControlStateValueOff];
2918         return m_page->editorState().isContentEditable;
2919     }
2920
2921     if (action == @selector(orderFrontSubstitutionsPanel:)) {
2922         if (NSMenuItem *menuItem = WebKit::menuItem(item))
2923             [menuItem setTitle:WebCore::contextMenuItemTagShowSubstitutions(![[[NSSpellChecker sharedSpellChecker] substitutionsPanel] isVisible])];
2924         return m_page->editorState().isContentEditable;
2925     }
2926
2927     if (action == @selector(toggleSmartInsertDelete:)) {
2928         bool checked = m_page->isSmartInsertDeleteEnabled();
2929         [menuItem(item) setState:checked ? NSControlStateValueOn : NSControlStateValueOff];
2930         return m_page->editorState().isContentEditable;
2931     }
2932
2933     if (action == @selector(toggleAutomaticQuoteSubstitution:)) {
2934         bool checked = TextChecker::state().isAutomaticQuoteSubstitutionEnabled;
2935         [menuItem(item) setState:checked ? NSControlStateValueOn : NSControlStateValueOff];
2936         return m_page->editorState().isContentEditable;
2937     }
2938
2939     if (action == @selector(toggleAutomaticDashSubstitution:)) {
2940         bool checked = TextChecker::state().isAutomaticDashSubstitutionEnabled;
2941         [menuItem(item) setState:checked ? NSControlStateValueOn : NSControlStateValueOff];
2942         return m_page->editorState().isContentEditable;
2943     }
2944
2945     if (action == @selector(toggleAutomaticLinkDetection:)) {
2946         bool checked = TextChecker::state().isAutomaticLinkDetectionEnabled;
2947         [menuItem(item) setState:checked ? NSControlStateValueOn : NSControlStateValueOff];
2948         return m_page->editorState().isContentEditable;
2949     }
2950
2951     if (action == @selector(toggleAutomaticTextReplacement:)) {
2952         bool checked = TextChecker::state().isAutomaticTextReplacementEnabled;
2953         [menuItem(item) setState:checked ? NSControlStateValueOn : NSControlStateValueOff];
2954         return m_page->editorState().isContentEditable;
2955     }
2956
2957     if (action == @selector(uppercaseWord:) || action == @selector(lowercaseWord:) || action == @selector(capitalizeWord:))
2958         return m_page->editorState().selectionIsRange && m_page->editorState().isContentEditable;
2959
2960     if (action == @selector(stopSpeaking:))
2961         return [NSApp isSpeaking];
2962
2963     // The centerSelectionInVisibleArea: selector is enabled if there's a selection range or if there's an insertion point in an editable area.
2964     if (action == @selector(centerSelectionInVisibleArea:))
2965         return m_page->editorState().selectionIsRange || (m_page->editorState().isContentEditable && !m_page->editorState().selectionIsNone);
2966
2967     // Next, handle editor commands. Start by returning true for anything that is not an editor command.
2968     // Returning true is the default thing to do in an AppKit validate method for any selector that is not recognized.
2969     String commandName = commandNameForSelector([item action]);
2970     if (!WebCore::Editor::commandIsSupportedFromMenuOrKeyBinding(commandName))
2971         return true;
2972
2973     // Add this item to the vector of items for a given command that are awaiting validation.
2974     ValidationMap::AddResult addResult = m_validationMap.add(commandName, ValidationVector());
2975     addResult.iterator->value.append(item);
2976     if (addResult.isNewEntry) {
2977         // If we are not already awaiting validation for this command, start the asynchronous validation process.
2978         // FIXME: Theoretically, there is a race here; when we get the answer it might be old, from a previous time
2979         // we asked for the same command; there is no guarantee the answer is still valid.
2980         auto weakThis = makeWeakPtr(*this);
2981         m_page->validateCommand(commandName, [weakThis](const String& commandName, bool isEnabled, int32_t state, WebKit::CallbackBase::Error error) {
2982             if (!weakThis)
2983                 return;
2984
2985             // If the process exits before the command can be validated, we'll be called back with an error.
2986             if (error != WebKit::CallbackBase::Error::None)
2987                 return;
2988
2989             weakThis->setUserInterfaceItemState(commandName, isEnabled, state);
2990         });
2991     }
2992
2993     // Treat as enabled until we get the result back from the web process and _setUserInterfaceItemState is called.
2994     // FIXME <rdar://problem/8803459>: This means disabled items will flash enabled at first for a moment.
2995     // But returning NO here would be worse; that would make keyboard commands such as command-C fail.
2996     return true;
2997 }
2998
2999 void WebViewImpl::setUserInterfaceItemState(NSString *commandName, bool enabled, int state)
3000 {
3001     ValidationVector items = m_validationMap.take(commandName);
3002     for (auto& item : items) {
3003         [menuItem(item.get()) setState:state];
3004         [menuItem(item.get()) setEnabled:enabled];
3005         [toolbarItem(item.get()) setEnabled:enabled];
3006         // FIXME <rdar://problem/8803392>: If the item is neither a menu nor toolbar item, it will be left enabled.
3007     }
3008 }
3009
3010 void WebViewImpl::startSpeaking()
3011 {
3012     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer));
3013     m_page->getSelectionOrContentsAsString([](const String& string, WebKit::CallbackBase::Error error) {
3014         if (error != WebKit::CallbackBase::Error::None)
3015             return;
3016         if (!string)
3017             return;
3018
3019         [NSApp speakString:string];
3020     });
3021 }
3022
3023 void WebViewImpl::stopSpeaking(id sender)
3024 {
3025     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer));
3026     [NSApp stopSpeaking:sender];
3027 }
3028
3029 void WebViewImpl::showGuessPanel(id sender)
3030 {
3031     NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
3032     if (!checker) {
3033         LOG_ERROR("No NSSpellChecker");
3034         return;
3035     }
3036
3037     NSPanel *spellingPanel = [checker spellingPanel];
3038     if ([spellingPanel isVisible]) {
3039         [spellingPanel orderOut:sender];
3040         return;
3041     }
3042
3043     m_page->advanceToNextMisspelling(true);
3044     [spellingPanel orderFront:sender];
3045 }
3046
3047 void WebViewImpl::checkSpelling()
3048 {
3049     m_page->advanceToNextMisspelling(false);
3050 }
3051
3052 void WebViewImpl::changeSpelling(id sender)
3053 {
3054     NSString *word = [[sender selectedCell] stringValue];
3055
3056     m_page->changeSpellingToWord(word);
3057 }
3058
3059 void WebViewImpl::toggleContinuousSpellChecking()
3060 {
3061     bool spellCheckingEnabled = !TextChecker::state().isContinuousSpellCheckingEnabled;
3062     TextChecker::setContinuousSpellCheckingEnabled(spellCheckingEnabled);
3063
3064     m_page->process().updateTextCheckerState();
3065 }
3066
3067 bool WebViewImpl::isGrammarCheckingEnabled()
3068 {
3069     return TextChecker::state().isGrammarCheckingEnabled;
3070 }
3071
3072 void WebViewImpl::setGrammarCheckingEnabled(bool flag)
3073 {
3074     if (static_cast<bool>(flag) == TextChecker::state().isGrammarCheckingEnabled)
3075         return;
3076
3077     TextChecker::setGrammarCheckingEnabled(flag);
3078     m_page->process().updateTextCheckerState();
3079 }
3080
3081 void WebViewImpl::toggleGrammarChecking()
3082 {
3083     bool grammarCheckingEnabled = !TextChecker::state().isGrammarCheckingEnabled;
3084     TextChecker::setGrammarCheckingEnabled(grammarCheckingEnabled);
3085
3086     m_page->process().updateTextCheckerState();
3087 }
3088
3089 void WebViewImpl::toggleAutomaticSpellingCorrection()
3090 {
3091     TextChecker::setAutomaticSpellingCorrectionEnabled(!TextChecker::state().isAutomaticSpellingCorrectionEnabled);
3092
3093     m_page->process().updateTextCheckerState();
3094 }
3095
3096 void WebViewImpl::orderFrontSubstitutionsPanel(id sender)
3097 {
3098     NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
3099     if (!checker) {
3100         LOG_ERROR("No NSSpellChecker");
3101         return;
3102     }
3103
3104     NSPanel *substitutionsPanel = [checker substitutionsPanel];
3105     if ([substitutionsPanel isVisible]) {
3106         [substitutionsPanel orderOut:sender];
3107         return;
3108     }
3109     [substitutionsPanel orderFront:sender];
3110 }
3111
3112 void WebViewImpl::toggleSmartInsertDelete()
3113 {
3114     m_page->setSmartInsertDeleteEnabled(!m_page->isSmartInsertDeleteEnabled());
3115 }
3116
3117 bool WebViewImpl::isAutomaticQuoteSubstitutionEnabled()
3118 {
3119     return TextChecker::state().isAutomaticQuoteSubstitutionEnabled;
3120 }
3121
3122 void WebViewImpl::setAutomaticQuoteSubstitutionEnabled(bool flag)
3123 {
3124     if (static_cast<bool>(flag) == TextChecker::state().isAutomaticQuoteSubstitutionEnabled)
3125         return;
3126
3127     TextChecker::setAutomaticQuoteSubstitutionEnabled(flag);
3128     m_page->process().updateTextCheckerState();
3129 }
3130
3131 void WebViewImpl::toggleAutomaticQuoteSubstitution()
3132 {
3133     TextChecker::setAutomaticQuoteSubstitutionEnabled(!TextChecker::state().isAutomaticQuoteSubstitutionEnabled);
3134     m_page->process().updateTextCheckerState();
3135 }
3136
3137 bool WebViewImpl::isAutomaticDashSubstitutionEnabled()
3138 {
3139     return TextChecker::state().isAutomaticDashSubstitutionEnabled;
3140 }
3141
3142 void WebViewImpl::setAutomaticDashSubstitutionEnabled(bool flag)
3143 {
3144     if (static_cast<bool>(flag) == TextChecker::state().isAutomaticDashSubstitutionEnabled)
3145         return;
3146
3147     TextChecker::setAutomaticDashSubstitutionEnabled(flag);
3148     m_page->process().updateTextCheckerState();
3149 }
3150
3151 void WebViewImpl::toggleAutomaticDashSubstitution()
3152 {
3153     TextChecker::setAutomaticDashSubstitutionEnabled(!TextChecker::state().isAutomaticDashSubstitutionEnabled);
3154     m_page->process().updateTextCheckerState();
3155 }
3156
3157 bool WebViewImpl::isAutomaticLinkDetectionEnabled()
3158 {
3159     return TextChecker::state().isAutomaticLinkDetectionEnabled;
3160 }
3161
3162 void WebViewImpl::setAutomaticLinkDetectionEnabled(bool flag)
3163 {
3164     if (static_cast<bool>(flag) == TextChecker::state().isAutomaticLinkDetectionEnabled)
3165         return;
3166
3167     TextChecker::setAutomaticLinkDetectionEnabled(flag);
3168     m_page->process().updateTextCheckerState();
3169 }
3170
3171 void WebViewImpl::toggleAutomaticLinkDetection()
3172 {
3173     TextChecker::setAutomaticLinkDetectionEnabled(!TextChecker::state().isAutomaticLinkDetectionEnabled);
3174     m_page->process().updateTextCheckerState();
3175 }
3176
3177 bool WebViewImpl::isAutomaticTextReplacementEnabled()
3178 {
3179     return TextChecker::state().isAutomaticTextReplacementEnabled;
3180 }
3181
3182 void WebViewImpl::setAutomaticTextReplacementEnabled(bool flag)
3183 {
3184     if (static_cast<bool>(flag) == TextChecker::state().isAutomaticTextReplacementEnabled)
3185         return;
3186     
3187     TextChecker::setAutomaticTextReplacementEnabled(flag);
3188     m_page->process().updateTextCheckerState();
3189 }
3190
3191 void WebViewImpl::toggleAutomaticTextReplacement()
3192 {
3193     TextChecker::setAutomaticTextReplacementEnabled(!TextChecker::state().isAutomaticTextReplacementEnabled);
3194     m_page->process().updateTextCheckerState();
3195 }
3196
3197 void WebViewImpl::uppercaseWord()
3198 {
3199     m_page->uppercaseWord();
3200 }
3201
3202 void WebViewImpl::lowercaseWord()
3203 {
3204     m_page->lowercaseWord();
3205 }
3206
3207 void WebViewImpl::capitalizeWord()
3208 {
3209     m_page->capitalizeWord();
3210 }
3211
3212 void WebViewImpl::requestCandidatesForSelectionIfNeeded()
3213 {
3214     if (!shouldRequestCandidates())
3215         return;
3216
3217     const EditorState& editorState = m_page->editorState();
3218     if (!editorState.isContentEditable)
3219         return;
3220
3221     if (editorState.isMissingPostLayoutData)
3222         return;
3223
3224     auto& postLayoutData = editorState.postLayoutData();
3225     m_lastStringForCandidateRequest = postLayoutData.stringForCandidateRequest;
3226
3227     NSRange selectedRange = NSMakeRange(postLayoutData.candidateRequestStartPosition, postLayoutData.selectedTextLength);
3228     NSTextCheckingTypes checkingTypes = NSTextCheckingTypeSpelling | NSTextCheckingTypeReplacement | NSTextCheckingTypeCorrection;
3229     auto weakThis = makeWeakPtr(*this);
3230     m_lastCandidateRequestSequenceNumber = [[NSSpellChecker sharedSpellChecker] requestCandidatesForSelectedRange:selectedRange inString:postLayoutData.paragraphContextForCandidateRequest types:checkingTypes options:nil inSpellDocumentWithTag:spellCheckerDocumentTag() completionHandler:[weakThis](NSInteger sequenceNumber, NSArray<NSTextCheckingResult *> *candidates) {
3231         dispatch_async(dispatch_get_main_queue(), ^{
3232             if (!weakThis)
3233                 return;
3234             weakThis->handleRequestedCandidates(sequenceNumber, candidates);
3235         });
3236     }];
3237 }
3238
3239 void WebViewImpl::handleRequestedCandidates(NSInteger sequenceNumber, NSArray<NSTextCheckingResult *> *candidates)
3240 {
3241     if (!shouldRequestCandidates())
3242         return;
3243
3244     if (m_lastCandidateRequestSequenceNumber != sequenceNumber)
3245         return;
3246
3247     const EditorState& editorState = m_page->editorState();
3248     if (!editorState.isContentEditable)
3249         return;
3250
3251     // FIXME: It's pretty lame that we have to depend on the most recent EditorState having post layout data,
3252     // and that we just bail if it is missing.
3253     if (editorState.isMissingPostLayoutData)
3254         return;
3255
3256     auto& postLayoutData = editorState.postLayoutData();
3257     if (m_lastStringForCandidateRequest != postLayoutData.stringForCandidateRequest)
3258         return;
3259
3260 #if HAVE(TOUCH_BAR)
3261     NSRange selectedRange = NSMakeRange(postLayoutData.candidateRequestStartPosition, postLayoutData.selectedTextLength);
3262     WebCore::IntRect offsetSelectionRect = postLayoutData.focusedElementRect;
3263     offsetSelectionRect.move(0, offsetSelectionRect.height());
3264
3265     [candidateListTouchBarItem() setCandidates:candidates forSelectedRange:selectedRange inString:postLayoutData.paragraphContextForCandidateRequest rect:offsetSelectionRect view:m_view.getAutoreleased() completionHandler:nil];
3266 #else
3267     UNUSED_PARAM(candidates);
3268 #endif
3269 }
3270
3271 static constexpr WebCore::TextCheckingType coreTextCheckingType(NSTextCheckingType type)
3272 {
3273     switch (type) {
3274     case NSTextCheckingTypeCorrection:
3275         return WebCore::TextCheckingType::Correction;
3276     case NSTextCheckingTypeReplacement:
3277         return WebCore::TextCheckingType::Replacement;
3278     case NSTextCheckingTypeSpelling:
3279         return WebCore::TextCheckingType::Spelling;
3280     default:
3281         return WebCore::TextCheckingType::None;
3282     }
3283 }
3284
3285 static WebCore::TextCheckingResult textCheckingResultFromNSTextCheckingResult(NSTextCheckingResult *nsResult)
3286 {
3287     NSRange resultRange = [nsResult range];
3288
3289     WebCore::TextCheckingResult result;
3290     result.type = coreTextCheckingType(nsResult.resultType);
3291     result.location = resultRange.location;
3292     result.length = resultRange.length;
3293     result.replacement = nsResult.replacementString;
3294     return result;
3295 }
3296
3297 void WebViewImpl::handleAcceptedCandidate(NSTextCheckingResult *acceptedCandidate)
3298 {
3299     const EditorState& editorState = m_page->editorState();
3300     if (!editorState.isContentEditable)
3301         return;
3302
3303     // FIXME: It's pretty lame that we have to depend on the most recent EditorState having post layout data,
3304     // and that we just bail if it is missing.
3305     if (editorState.isMissingPostLayoutData)
3306         return;
3307
3308     auto& postLayoutData = editorState.postLayoutData();
3309     if (m_lastStringForCandidateRequest != postLayoutData.stringForCandidateRequest)
3310         return;
3311
3312     m_isHandlingAcceptedCandidate = true;
3313     NSRange range = [acceptedCandidate range];
3314     if (acceptedCandidate.replacementString && [acceptedCandidate.replacementString length] > 0) {
3315         NSRange replacedRange = NSMakeRange(range.location, [acceptedCandidate.replacementString length]);
3316         NSRange softSpaceRange = NSMakeRange(NSMaxRange(replacedRange) - 1, 1);
3317         if ([acceptedCandidate.replacementString hasSuffix:@" "])
3318             m_softSpaceRange = softSpaceRange;
3319     }
3320
3321     m_page->handleAcceptedCandidate(textCheckingResultFromNSTextCheckingResult(acceptedCandidate));
3322 }
3323
3324 void WebViewImpl::doAfterProcessingAllPendingMouseEvents(dispatch_block_t action)
3325 {
3326     if (!m_page->isProcessingMouseEvents()) {
3327         action();
3328         return;
3329     }
3330
3331     m_callbackHandlersAfterProcessingPendingMouseEvents.append(makeBlockPtr(action));
3332 }
3333
3334 void WebViewImpl::didFinishProcessingAllPendingMouseEvents()
3335 {
3336     flushPendingMouseEventCallbacks();
3337 }
3338
3339 void WebViewImpl::flushPendingMouseEventCallbacks()
3340 {
3341     for (auto& callback : m_callbackHandlersAfterProcessingPendingMouseEvents)
3342         callback();
3343
3344     m_callbackHandlersAfterProcessingPendingMouseEvents.clear();
3345 }
3346
3347 void WebViewImpl::preferencesDidChange()
3348 {
3349     BOOL needsViewFrameInWindowCoordinates = m_page->preferences().pluginsEnabled();
3350
3351     if (!!needsViewFrameInWindowCoordinates == !!m_needsViewFrameInWindowCoordinates)
3352         return;
3353
3354     m_needsViewFrameInWindowCoordinates = needsViewFrameInWindowCoordinates;
3355     if ([m_view window])
3356         updateWindowAndViewFrames();
3357 }
3358
3359 void WebViewImpl::setTextIndicator(WebCore::TextIndicator& textIndicator, WebCore::TextIndicatorWindowLifetime lifetime)
3360 {
3361     if (!m_textIndicatorWindow)
3362         m_textIndicatorWindow = std::make_unique<WebCore::TextIndicatorWindow>(m_view.getAutoreleased());
3363
3364     NSRect textBoundingRectInScreenCoordinates = [[m_view window] convertRectToScreen:[m_view convertRect:textIndicator.textBoundingRectInRootViewCoordinates() toView:nil]];
3365     m_textIndicatorWindow->setTextIndicator(textIndicator, NSRectToCGRect(textBoundingRectInScreenCoordinates), lifetime);
3366 }
3367
3368 void WebViewImpl::clearTextIndicatorWithAnimation(WebCore::TextIndicatorWindowDismissalAnimation animation)
3369 {
3370     if (m_textIndicatorWindow)
3371         m_textIndicatorWindow->clearTextIndicator(animation);
3372     m_textIndicatorWindow = nullptr;
3373 }
3374
3375 void WebViewImpl::setTextIndicatorAnimationProgress(float progress)
3376 {
3377     if (m_textIndicatorWindow)
3378         m_textIndicatorWindow->setAnimationProgress(progress);
3379 }
3380
3381 void WebViewImpl::dismissContentRelativeChildWindowsWithAnimation(bool animate)
3382 {
3383     [m_view _web_dismissContentRelativeChildWindowsWithAnimation:animate];
3384 }
3385
3386 void WebViewImpl::dismissContentRelativeChildWindowsWithAnimationFromViewOnly(bool animate)
3387 {
3388     // Calling _clearTextIndicatorWithAnimation here will win out over the animated clear in dismissContentRelativeChildWindowsFromViewOnly.
3389     // We can't invert these because clients can override (and have overridden) _dismissContentRelativeChildWindows, so it needs to be called.
3390     // For this same reason, this can't be moved to WebViewImpl without care.
3391     clearTextIndicatorWithAnimation(animate ? WebCore::TextIndicatorWindowDismissalAnimation::FadeOut : WebCore::TextIndicatorWindowDismissalAnimation::None);
3392     [m_view _web_dismissContentRelativeChildWindows];
3393 }
3394
3395 void WebViewImpl::dismissContentRelativeChildWindowsFromViewOnly()
3396 {
3397     bool hasActiveImmediateAction = false;
3398     hasActiveImmediateAction = [m_immediateActionController hasActiveImmediateAction];
3399
3400     // FIXME: We don't know which panel we are dismissing, it may not even be in the current page (see <rdar://problem/13875766>).
3401     if ([m_view window].isKeyWindow || hasActiveImmediateAction) {
3402         WebCore::DictionaryLookup::hidePopup();
3403
3404         if (DataDetectorsLibrary())
3405             [[getDDActionsManagerClass() sharedManager] requestBubbleClosureUnanchorOnFailure:YES];
3406     }
3407
3408     clearTextIndicatorWithAnimation(WebCore::TextIndicatorWindowDismissalAnimation::FadeOut);
3409
3410     [m_immediateActionController dismissContentRelativeChildWindows];
3411
3412     m_pageClient->dismissCorrectionPanel(WebCore::ReasonForDismissingAlternativeTextIgnored);
3413 }
3414
3415 void WebViewImpl::hideWordDefinitionWindow()
3416 {
3417     WebCore::DictionaryLookup::hidePopup();
3418 }
3419
3420 void WebViewImpl::quickLookWithEvent(NSEvent *event)
3421 {
3422     if (ignoresNonWheelEvents())
3423         return;
3424
3425     if (m_immediateActionGestureRecognizer) {
3426         [m_view _web_superQuickLookWithEvent:event];
3427         return;
3428     }
3429
3430     NSPoint locationInViewCoordinates = [m_view convertPoint:[event locationInWindow] fromView:nil];
3431     m_page->performDictionaryLookupAtLocation(WebCore::FloatPoint(locationInViewCoordinates));
3432 }
3433
3434 void WebViewImpl::prepareForDictionaryLookup()
3435 {
3436     [m_windowVisibilityObserver startObservingLookupDismissalIfNeeded];
3437 }
3438
3439 void WebViewImpl::setAllowsLinkPreview(bool allowsLinkPreview)
3440 {
3441     if (m_allowsLinkPreview == allowsLinkPreview)
3442         return;
3443
3444     m_allowsLinkPreview = allowsLinkPreview;
3445
3446     if (!allowsLinkPreview)
3447         [m_view removeGestureRecognizer:m_immediateActionGestureRecognizer.get()];
3448     else if (NSGestureRecognizer *immediateActionRecognizer = m_immediateActionGestureRecognizer.get())
3449         [m_view addGestureRecognizer:immediateActionRecognizer];
3450 }
3451
3452 NSObject *WebViewImpl::immediateActionAnimationControllerForHitTestResult(API::HitTestResult* hitTestResult, uint32_t type, API::Object* userData)
3453 {
3454     return [m_view _web_immediateActionAnimationControllerForHitTestResultInternal:hitTestResult withType:type userData:userData];
3455 }
3456
3457 void WebViewImpl::didPerformImmediateActionHitTest(const WebHitTestResultData& result, bool contentPreventsDefault, API::Object* userData)
3458 {
3459     [m_immediateActionController didPerformImmediateActionHitTest:result contentPreventsDefault:contentPreventsDefault userData:userData];
3460 }
3461
3462 void WebViewImpl::prepareForImmediateActionAnimation()
3463 {
3464     [m_view _web_prepareForImmediateActionAnimation];
3465 }
3466
3467 void WebViewImpl::cancelImmediateActionAnimation()
3468 {
3469     [m_view _web_cancelImmediateActionAnimation];
3470 }
3471
3472 void WebViewImpl::completeImmediateActionAnimation()
3473 {
3474     [m_view _web_completeImmediateActionAnimation];
3475 }
3476
3477 void WebViewImpl::didChangeContentSize(CGSize newSize)
3478 {
3479     [m_view _web_didChangeContentSize:NSSizeFromCGSize(newSize)];
3480 }
3481
3482 void WebViewImpl::didHandleAcceptedCandidate()
3483 {
3484     m_isHandlingAcceptedCandidate = false;
3485
3486     [m_view _didHandleAcceptedCandidate];
3487 }
3488
3489 void WebViewImpl::videoControlsManagerDidChange()
3490 {
3491 #if HAVE(TOUCH_BAR)
3492     updateTouchBar();
3493 #endif
3494
3495 #if ENABLE(FULLSCREEN_API)
3496     if (hasFullScreenWindowController())
3497         [fullScreenWindowController() videoControlsManagerDidChange];
3498 #endif
3499 }
3500
3501 void WebViewImpl::setIgnoresNonWheelEvents(bool ignoresNonWheelEvents)
3502 {
3503     if (m_ignoresNonWheelEvents == ignoresNonWheelEvents)
3504         return;
3505
3506     m_ignoresNonWheelEvents = ignoresNonWheelEvents;
3507     m_page->setShouldDispatchFakeMouseMoveEvents(!ignoresNonWheelEvents);
3508
3509     if (ignoresNonWheelEvents)
3510         [m_view removeGestureRecognizer:m_immediateActionGestureRecognizer.get()];
3511     else if (NSGestureRecognizer *immediateActionRecognizer = m_immediateActionGestureRecognizer.get()) {
3512         if (m_allowsLinkPreview)
3513             [m_view addGestureRecognizer:immediateActionRecognizer];
3514     }
3515 }
3516
3517 void WebViewImpl::setIgnoresAllEvents(bool ignoresAllEvents)
3518 {
3519     m_ignoresAllEvents = ignoresAllEvents;
3520     setIgnoresNonWheelEvents(ignoresAllEvents);
3521 }
3522
3523 void WebViewImpl::setIgnoresMouseDraggedEvents(bool ignoresMouseDraggedEvents)
3524 {
3525     m_ignoresMouseDraggedEvents = ignoresMouseDraggedEvents;
3526 }
3527
3528 void WebViewImpl::setAccessibilityWebProcessToken(NSData *data)
3529 {
3530     m_remoteAccessibilityChild = data.length ? adoptNS([[NSAccessibilityRemoteUIElement alloc] initWithRemoteToken:data]) : nil;
3531     updateRemoteAccessibilityRegistration(true);
3532 }
3533
3534 void WebViewImpl::updateRemoteAccessibilityRegistration(bool registerProcess)
3535 {
3536     // When the tree is connected/disconnected, the remote accessibility registration
3537     // needs to be updated with the pid of the remote process. If the process is going
3538     // away, that information is not present in WebProcess
3539     pid_t pid = 0;
3540     if (registerProcess)
3541         pid = m_page->process().processIdentifier();
3542     else if (!registerProcess) {
3543         pid = [m_remoteAccessibilityChild processIdentifier];
3544         m_remoteAccessibilityChild = nil;
3545     }
3546     if (!pid)
3547         return;