07994e7dc133eaa2a41721be10de8891e4e2b5e0
[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->needsHiddenContentEditableQuirk()) {
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 isRichlyEditable() ? 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::isRichlyEditable() const
1058 {
1059     return m_page->editorState().isContentRichlyEditable && !m_page->needsPlainTextQuirk();
1060 }
1061
1062 NSTouchBar *WebViewImpl::textTouchBar() const
1063 {
1064     if (m_page->editorState().isInPasswordField)
1065         return m_passwordTextTouchBar.get();
1066     return isRichlyEditable() ? 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 (isRichlyEditable()) {
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) && WK_API_ENABLED
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 WK_API_ENABLED
1382     if (m_remoteObjectRegistry) {
1383         m_page->process().processPool().removeMessageReceiver(Messages::RemoteObjectRegistry::messageReceiverName(), m_page->pageID());
1384         [m_remoteObjectRegistry _invalidate];
1385         m_remoteObjectRegistry = nil;
1386     }
1387 #endif
1388
1389     ASSERT(!m_inSecureInputState);
1390
1391 #if WK_API_ENABLED
1392     ASSERT(!m_thumbnailView);
1393 #endif
1394
1395     [m_layoutStrategy invalidate];
1396
1397     [m_immediateActionController willDestroyView:m_view.getAutoreleased()];
1398
1399 #if HAVE(TOUCH_BAR)
1400     [m_textTouchBarItemController didDestroyView];
1401 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
1402     [m_mediaTouchBarProvider setPlaybackControlsController:nil];
1403     [m_mediaPlaybackControlsView setPlaybackControlsController:nil];
1404 #endif
1405 #endif
1406
1407     m_page->close();
1408
1409     WebProcessPool::statistics().wkViewCount--;
1410
1411 }
1412
1413 NSWindow *WebViewImpl::window()
1414 {
1415     return [m_view window];
1416 }
1417
1418 void WebViewImpl::handleProcessSwapOrExit()
1419 {
1420     dismissContentRelativeChildWindowsWithAnimation(true);
1421
1422     notifyInputContextAboutDiscardedComposition();
1423
1424     updateRemoteAccessibilityRegistration(false);
1425     flushPendingMouseEventCallbacks();
1426 }
1427
1428 void WebViewImpl::processWillSwap()
1429 {
1430     handleProcessSwapOrExit();
1431     if (m_gestureController)
1432         m_gestureController->disconnectFromProcess();
1433 }
1434
1435 void WebViewImpl::processDidExit()
1436 {
1437     handleProcessSwapOrExit();
1438     m_gestureController = nullptr;
1439 }
1440
1441 void WebViewImpl::pageClosed()
1442 {
1443     updateRemoteAccessibilityRegistration(false);
1444 }
1445
1446 void WebViewImpl::didRelaunchProcess()
1447 {
1448     if (m_gestureController)
1449         m_gestureController->connectToProcess();
1450
1451     accessibilityRegisterUIProcessTokens();
1452     windowDidChangeScreen(); // Make sure DisplayID is set.
1453 }
1454
1455 void WebViewImpl::setDrawsBackground(bool drawsBackground)
1456 {
1457     Optional<WebCore::Color> backgroundColor;
1458     if (!drawsBackground)
1459         backgroundColor = WebCore::Color(WebCore::Color::transparent);
1460     m_page->setBackgroundColor(backgroundColor);
1461
1462     // Make sure updateLayer gets called on the web view.
1463     [m_view setNeedsDisplay:YES];
1464 }
1465
1466 bool WebViewImpl::drawsBackground() const
1467 {
1468     auto& backgroundColor = m_page->backgroundColor();
1469     return !backgroundColor || backgroundColor.value().isVisible();
1470 }
1471
1472 void WebViewImpl::setBackgroundColor(NSColor *backgroundColor)
1473 {
1474     m_backgroundColor = backgroundColor;
1475
1476     // Make sure updateLayer gets called on the web view.
1477     [m_view setNeedsDisplay:YES];
1478 }
1479
1480 NSColor *WebViewImpl::backgroundColor() const
1481 {
1482     if (!m_backgroundColor)
1483 #if ENABLE(DARK_MODE_CSS)
1484         return [NSColor controlBackgroundColor];
1485 #else
1486         return [NSColor whiteColor];
1487 #endif
1488     return m_backgroundColor.get();
1489 }
1490
1491 bool WebViewImpl::isOpaque() const
1492 {
1493     return drawsBackground();
1494 }
1495
1496 void WebViewImpl::setShouldSuppressFirstResponderChanges(bool shouldSuppress)
1497 {   
1498     m_pageClient->setShouldSuppressFirstResponderChanges(shouldSuppress);
1499 }
1500
1501 bool WebViewImpl::acceptsFirstResponder()
1502 {
1503     return true;
1504 }
1505
1506 bool WebViewImpl::becomeFirstResponder()
1507 {
1508     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer));
1509     // If we just became first responder again, there is no need to do anything,
1510     // since resignFirstResponder has correctly detected this situation.
1511     if (m_willBecomeFirstResponderAgain) {
1512         m_willBecomeFirstResponderAgain = false;
1513         return true;
1514     }
1515
1516     NSSelectionDirection direction = [[m_view window] keyViewSelectionDirection];
1517
1518     m_inBecomeFirstResponder = true;
1519
1520     updateSecureInputState();
1521     m_page->activityStateDidChange(WebCore::ActivityState::IsFocused);
1522     // Restore the selection in the editable region if resigning first responder cleared selection.
1523     m_page->restoreSelectionInFocusedEditableElement();
1524
1525     m_inBecomeFirstResponder = false;
1526
1527 #if HAVE(TOUCH_BAR)
1528     updateTouchBar();
1529 #endif
1530
1531     if (direction != NSDirectSelection) {
1532         NSEvent *event = [NSApp currentEvent];
1533         NSEvent *keyboardEvent = nil;
1534         if ([event type] == NSEventTypeKeyDown || [event type] == NSEventTypeKeyUp)
1535             keyboardEvent = event;
1536         m_page->setInitialFocus(direction == NSSelectingNext, keyboardEvent != nil, NativeWebKeyboardEvent(keyboardEvent, false, false, { }), [](WebKit::CallbackBase::Error) { });
1537     }
1538     return true;
1539 }
1540
1541 bool WebViewImpl::resignFirstResponder()
1542 {
1543 #if WK_API_ENABLED
1544     // Predict the case where we are losing first responder status only to
1545     // gain it back again. We want resignFirstResponder to do nothing in that case.
1546     id nextResponder = [[m_view window] _newFirstResponderAfterResigning];
1547
1548     // FIXME: This will probably need to change once WKWebView doesn't contain a WKView.
1549     if ([nextResponder isKindOfClass:[WKWebView class]] && [m_view superview] == nextResponder) {
1550         m_willBecomeFirstResponderAgain = true;
1551         return true;
1552     }
1553 #endif
1554
1555     m_willBecomeFirstResponderAgain = false;
1556     m_inResignFirstResponder = true;
1557
1558     m_page->confirmCompositionAsync();
1559
1560     notifyInputContextAboutDiscardedComposition();
1561
1562     resetSecureInputState();
1563
1564     if (!m_page->maintainsInactiveSelection())
1565         m_page->clearSelection();
1566
1567     m_page->activityStateDidChange(WebCore::ActivityState::IsFocused);
1568     
1569     m_inResignFirstResponder = false;
1570     
1571     return true;
1572 }
1573
1574 void WebViewImpl::takeFocus(WebCore::FocusDirection direction)
1575 {
1576     NSView *webView = m_view.getAutoreleased();
1577
1578     if (direction == FocusDirectionForward) {
1579         // Since we're trying to move focus out of m_webView, and because
1580         // m_webView may contain subviews within it, we ask it for the next key
1581         // view of the last view in its key view loop. This makes m_webView
1582         // behave as if it had no subviews, which is the behavior we want.
1583         [webView.window selectKeyViewFollowingView:[webView _findLastViewInKeyViewLoop]];
1584     } else
1585         [webView.window selectKeyViewPrecedingView:webView];
1586 }
1587
1588 void WebViewImpl::showSafeBrowsingWarning(const SafeBrowsingWarning& warning, CompletionHandler<void(Variant<ContinueUnsafeLoad, URL>&&)>&& completionHandler)
1589 {
1590     if (!m_view)
1591         return completionHandler(ContinueUnsafeLoad::Yes);
1592
1593     m_safeBrowsingWarning = adoptNS([[WKSafeBrowsingWarning alloc] initWithFrame:[m_view bounds] safeBrowsingWarning:warning completionHandler:[weakThis = makeWeakPtr(*this), completionHandler = WTFMove(completionHandler)] (auto&& result) mutable {
1594         completionHandler(WTFMove(result));
1595         if (!weakThis)
1596             return;
1597         bool navigatesMainFrame = WTF::switchOn(result,
1598             [] (ContinueUnsafeLoad continueUnsafeLoad) { return continueUnsafeLoad == ContinueUnsafeLoad::Yes; },
1599             [] (const URL&) { return true; }
1600         );
1601         if (navigatesMainFrame && [weakThis->m_safeBrowsingWarning forMainFrameNavigation])
1602             return;
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 }
2221
2222 void WebViewImpl::viewDidChangeBackingProperties()
2223 {
2224     NSColorSpace *colorSpace = [m_view window].colorSpace;
2225     if ([colorSpace isEqualTo:m_colorSpace.get()])
2226         return;
2227
2228     m_colorSpace = nullptr;
2229     if (DrawingAreaProxy *drawingArea = m_page->drawingArea())
2230         drawingArea->colorSpaceDidChange();
2231 }
2232
2233 void WebViewImpl::viewDidHide()
2234 {
2235     LOG(ActivityState, "WebViewImpl %p (page %llu) viewDidHide", this, m_page->pageID());
2236     m_page->activityStateDidChange(WebCore::ActivityState::IsVisible);
2237 }
2238
2239 void WebViewImpl::viewDidUnhide()
2240 {
2241     LOG(ActivityState, "WebViewImpl %p (page %llu) viewDidUnhide", this, m_page->pageID());
2242     m_page->activityStateDidChange(WebCore::ActivityState::IsVisible);
2243 }
2244
2245 void WebViewImpl::activeSpaceDidChange()
2246 {
2247     LOG(ActivityState, "WebViewImpl %p (page %llu) activeSpaceDidChange", this, m_page->pageID());
2248     m_page->activityStateDidChange(WebCore::ActivityState::IsVisible);
2249 }
2250
2251 NSView *WebViewImpl::hitTest(CGPoint point)
2252 {
2253     NSView *hitView = [m_view _web_superHitTest:NSPointFromCGPoint(point)];
2254     if (hitView && hitView == m_layerHostingView)
2255         hitView = m_view.getAutoreleased();
2256
2257     return hitView;
2258 }
2259
2260 void WebViewImpl::postFakeMouseMovedEventForFlagsChangedEvent(NSEvent *flagsChangedEvent)
2261 {
2262     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSEventTypeMouseMoved location:flagsChangedEvent.window.mouseLocationOutsideOfEventStream
2263         modifierFlags:flagsChangedEvent.modifierFlags timestamp:flagsChangedEvent.timestamp windowNumber:flagsChangedEvent.windowNumber
2264         context:nullptr eventNumber:0 clickCount:0 pressure:0];
2265     NativeWebMouseEvent webEvent(fakeEvent, m_lastPressureEvent.get(), m_view.getAutoreleased());
2266     m_page->handleMouseEvent(webEvent);
2267 }
2268
2269 ColorSpaceData WebViewImpl::colorSpace()
2270 {
2271     if (!m_colorSpace) {
2272         if (m_targetWindowForMovePreparation)
2273             m_colorSpace = m_targetWindowForMovePreparation.colorSpace;
2274         else if (NSWindow *window = [m_view window])
2275             m_colorSpace = window.colorSpace;
2276         else
2277             m_colorSpace = [NSScreen mainScreen].colorSpace;
2278     }
2279
2280     ColorSpaceData colorSpaceData;
2281     colorSpaceData.cgColorSpace = [m_colorSpace CGColorSpace];
2282     
2283     return colorSpaceData;
2284 }
2285
2286 void WebViewImpl::setUnderlayColor(NSColor *underlayColor)
2287 {
2288     m_page->setUnderlayColor(WebCore::colorFromNSColor(underlayColor));
2289 }
2290
2291 NSColor *WebViewImpl::underlayColor() const
2292 {
2293     WebCore::Color webColor = m_page->underlayColor();
2294     if (!webColor.isValid())
2295         return nil;
2296
2297     return WebCore::nsColor(webColor);
2298 }
2299
2300 NSColor *WebViewImpl::pageExtendedBackgroundColor() const
2301 {
2302     WebCore::Color color = m_page->pageExtendedBackgroundColor();
2303     if (!color.isValid())
2304         return nil;
2305
2306     return WebCore::nsColor(color);
2307 }
2308
2309 void WebViewImpl::setOverlayScrollbarStyle(Optional<WebCore::ScrollbarOverlayStyle> scrollbarStyle)
2310 {
2311     m_page->setOverlayScrollbarStyle(scrollbarStyle);
2312 }
2313
2314 Optional<WebCore::ScrollbarOverlayStyle> WebViewImpl::overlayScrollbarStyle() const
2315 {
2316     return m_page->overlayScrollbarStyle();
2317 }
2318
2319 void WebViewImpl::beginDeferringViewInWindowChanges()
2320 {
2321     if (m_shouldDeferViewInWindowChanges) {
2322         NSLog(@"beginDeferringViewInWindowChanges was called while already deferring view-in-window changes!");
2323         return;
2324     }
2325
2326     m_shouldDeferViewInWindowChanges = true;
2327 }
2328
2329 void WebViewImpl::endDeferringViewInWindowChanges()
2330 {
2331     if (!m_shouldDeferViewInWindowChanges) {
2332         NSLog(@"endDeferringViewInWindowChanges was called without beginDeferringViewInWindowChanges!");
2333         return;
2334     }
2335
2336     m_shouldDeferViewInWindowChanges = false;
2337
2338     if (m_viewInWindowChangeWasDeferred) {
2339         dispatchSetTopContentInset();
2340         m_page->activityStateDidChange(WebCore::ActivityState::IsInWindow);
2341         m_viewInWindowChangeWasDeferred = false;
2342     }
2343 }
2344
2345 void WebViewImpl::endDeferringViewInWindowChangesSync()
2346 {
2347     if (!m_shouldDeferViewInWindowChanges) {
2348         NSLog(@"endDeferringViewInWindowChangesSync was called without beginDeferringViewInWindowChanges!");
2349         return;
2350     }
2351
2352     m_shouldDeferViewInWindowChanges = false;
2353
2354     if (m_viewInWindowChangeWasDeferred) {
2355         dispatchSetTopContentInset();
2356         m_page->activityStateDidChange(WebCore::ActivityState::IsInWindow);
2357         m_viewInWindowChangeWasDeferred = false;
2358     }
2359 }
2360
2361 void WebViewImpl::prepareForMoveToWindow(NSWindow *targetWindow, WTF::Function<void()>&& completionHandler)
2362 {
2363     m_shouldDeferViewInWindowChanges = true;
2364     viewWillMoveToWindow(targetWindow);
2365     m_targetWindowForMovePreparation = targetWindow;
2366     viewDidMoveToWindow();
2367
2368     m_shouldDeferViewInWindowChanges = false;
2369
2370     auto weakThis = makeWeakPtr(*this);
2371     m_page->installActivityStateChangeCompletionHandler([weakThis, completionHandler = WTFMove(completionHandler)]() {
2372         completionHandler();
2373
2374         if (!weakThis)
2375             return;
2376
2377         ASSERT([weakThis->m_view window] == weakThis->m_targetWindowForMovePreparation);
2378         weakThis->m_targetWindowForMovePreparation = nil;
2379     });
2380
2381     dispatchSetTopContentInset();
2382     m_page->activityStateDidChange(WebCore::ActivityState::IsInWindow, false, WebPageProxy::ActivityStateChangeDispatchMode::Immediate);
2383     m_viewInWindowChangeWasDeferred = false;
2384 }
2385
2386 void WebViewImpl::updateSecureInputState()
2387 {
2388     if (![[m_view window] isKeyWindow] || !isFocused()) {
2389         if (m_inSecureInputState) {
2390             DisableSecureEventInput();
2391             m_inSecureInputState = false;
2392         }
2393         return;
2394     }
2395     // WKView has a single input context for all editable areas (except for plug-ins).
2396     NSTextInputContext *context = [m_view _web_superInputContext];
2397     bool isInPasswordField = m_page->editorState().isInPasswordField;
2398
2399     if (isInPasswordField) {
2400         if (!m_inSecureInputState)
2401             EnableSecureEventInput();
2402         static NSArray *romanInputSources = [[NSArray alloc] initWithObjects:&NSAllRomanInputSourcesLocaleIdentifier count:1];
2403         LOG(TextInput, "-> setAllowedInputSourceLocales:romanInputSources");
2404         [context setAllowedInputSourceLocales:romanInputSources];
2405     } else {
2406         if (m_inSecureInputState)
2407             DisableSecureEventInput();
2408         LOG(TextInput, "-> setAllowedInputSourceLocales:nil");
2409         [context setAllowedInputSourceLocales:nil];
2410     }
2411     m_inSecureInputState = isInPasswordField;
2412 }
2413
2414 void WebViewImpl::resetSecureInputState()
2415 {
2416     if (m_inSecureInputState) {
2417         DisableSecureEventInput();
2418         m_inSecureInputState = false;
2419     }
2420 }
2421
2422 void WebViewImpl::notifyInputContextAboutDiscardedComposition()
2423 {
2424     // <rdar://problem/9359055>: -discardMarkedText can only be called for active contexts.
2425     // FIXME: We fail to ever notify the input context if something (e.g. a navigation) happens while the window is not key.
2426     // This is not a problem when the window is key, because we discard marked text on resigning first responder.
2427     if (![[m_view window] isKeyWindow] || m_view.getAutoreleased() != [[m_view window] firstResponder])
2428         return;
2429
2430     LOG(TextInput, "-> discardMarkedText");
2431
2432     [[m_view _web_superInputContext] discardMarkedText]; // Inform the input method that we won't have an inline input area despite having been asked to.
2433 }
2434
2435 void WebViewImpl::setPluginComplexTextInputState(PluginComplexTextInputState pluginComplexTextInputState)
2436 {
2437     m_pluginComplexTextInputState = pluginComplexTextInputState;
2438
2439     if (m_pluginComplexTextInputState != PluginComplexTextInputDisabled)
2440         return;
2441
2442     // Send back an empty string to the plug-in. This will disable text input.
2443     m_page->sendComplexTextInputToPlugin(m_pluginComplexTextInputIdentifier, String());
2444 }
2445
2446 void WebViewImpl::setPluginComplexTextInputStateAndIdentifier(PluginComplexTextInputState pluginComplexTextInputState, uint64_t pluginComplexTextInputIdentifier)
2447 {
2448     if (pluginComplexTextInputIdentifier != m_pluginComplexTextInputIdentifier) {
2449         // We're asked to update the state for a plug-in that doesn't have focus.
2450         return;
2451     }
2452
2453     setPluginComplexTextInputState(pluginComplexTextInputState);
2454 }
2455
2456 void WebViewImpl::disableComplexTextInputIfNecessary()
2457 {
2458     if (!m_pluginComplexTextInputIdentifier)
2459         return;
2460
2461     if (m_pluginComplexTextInputState != PluginComplexTextInputEnabled)
2462         return;
2463
2464     // Check if the text input window has been dismissed.
2465     if (![[WKTextInputWindowController sharedTextInputWindowController] hasMarkedText])
2466         setPluginComplexTextInputState(PluginComplexTextInputDisabled);
2467 }
2468
2469 bool WebViewImpl::handlePluginComplexTextInputKeyDown(NSEvent *event)
2470 {
2471     ASSERT(m_pluginComplexTextInputIdentifier);
2472     ASSERT(m_pluginComplexTextInputState != PluginComplexTextInputDisabled);
2473
2474     BOOL usingLegacyCocoaTextInput = m_pluginComplexTextInputState == PluginComplexTextInputEnabledLegacy;
2475
2476     NSString *string = nil;
2477     BOOL didHandleEvent = [[WKTextInputWindowController sharedTextInputWindowController] interpretKeyEvent:event usingLegacyCocoaTextInput:usingLegacyCocoaTextInput string:&string];
2478
2479     if (string) {
2480         m_page->sendComplexTextInputToPlugin(m_pluginComplexTextInputIdentifier, string);
2481
2482         if (!usingLegacyCocoaTextInput)
2483             m_pluginComplexTextInputState = PluginComplexTextInputDisabled;
2484     }
2485
2486     return didHandleEvent;
2487 }
2488
2489 bool WebViewImpl::tryHandlePluginComplexTextInputKeyDown(NSEvent *event)
2490 {
2491     if (!m_pluginComplexTextInputIdentifier || m_pluginComplexTextInputState == PluginComplexTextInputDisabled)
2492         return NO;
2493
2494     // Check if the text input window has been dismissed and let the plug-in process know.
2495     // This is only valid with the updated Cocoa text input spec.
2496     disableComplexTextInputIfNecessary();
2497
2498     // Try feeding the keyboard event directly to the plug-in.
2499     if (m_pluginComplexTextInputState == PluginComplexTextInputEnabledLegacy)
2500         return handlePluginComplexTextInputKeyDown(event);
2501
2502     return NO;
2503 }
2504
2505 void WebViewImpl::pluginFocusOrWindowFocusChanged(bool pluginHasFocusAndWindowHasFocus, uint64_t pluginComplexTextInputIdentifier)
2506 {
2507     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer));
2508     BOOL inputSourceChanged = m_pluginComplexTextInputIdentifier;
2509
2510     if (pluginHasFocusAndWindowHasFocus) {
2511         // Check if we're already allowing text input for this plug-in.
2512         if (pluginComplexTextInputIdentifier == m_pluginComplexTextInputIdentifier)
2513             return;
2514
2515         m_pluginComplexTextInputIdentifier = pluginComplexTextInputIdentifier;
2516
2517     } else {
2518         // Check if we got a request to unfocus a plug-in that isn't focused.
2519         if (pluginComplexTextInputIdentifier != m_pluginComplexTextInputIdentifier)
2520             return;
2521
2522         m_pluginComplexTextInputIdentifier = 0;
2523     }
2524
2525     if (inputSourceChanged) {
2526         // The input source changed; discard any entered text.
2527         [[WKTextInputWindowController sharedTextInputWindowController] unmarkText];
2528     }
2529     
2530     // This will force the current input context to be updated to its correct value.
2531     [NSApp updateWindows];
2532 }
2533
2534 bool WebViewImpl::tryPostProcessPluginComplexTextInputKeyDown(NSEvent *event)
2535 {
2536     if (!m_pluginComplexTextInputIdentifier || m_pluginComplexTextInputState == PluginComplexTextInputDisabled)
2537         return NO;
2538
2539     // In the legacy text input model, the event has already been sent to the input method.
2540     if (m_pluginComplexTextInputState == PluginComplexTextInputEnabledLegacy)
2541         return NO;
2542
2543     return handlePluginComplexTextInputKeyDown(event);
2544 }
2545
2546 void WebViewImpl::handleAcceptedAlternativeText(const String& acceptedAlternative)
2547 {
2548     m_page->handleAlternativeTextUIResult(acceptedAlternative);
2549 }
2550
2551
2552 NSInteger WebViewImpl::spellCheckerDocumentTag()
2553 {
2554     if (!m_spellCheckerDocumentTag)
2555         m_spellCheckerDocumentTag = [NSSpellChecker uniqueSpellDocumentTag];
2556     return m_spellCheckerDocumentTag.value();
2557 }
2558
2559 void WebViewImpl::pressureChangeWithEvent(NSEvent *event)
2560 {
2561     if (event == m_lastPressureEvent)
2562         return;
2563
2564     if (m_ignoresNonWheelEvents)
2565         return;
2566
2567     if (event.phase != NSEventPhaseChanged && event.phase != NSEventPhaseBegan && event.phase != NSEventPhaseEnded)
2568         return;
2569
2570     NativeWebMouseEvent webEvent(event, m_lastPressureEvent.get(), m_view.getAutoreleased());
2571     m_page->handleMouseEvent(webEvent);
2572
2573     m_lastPressureEvent = event;
2574 }
2575
2576 #if ENABLE(FULLSCREEN_API)
2577 bool WebViewImpl::hasFullScreenWindowController() const
2578 {
2579     return !!m_fullScreenWindowController;
2580 }
2581
2582 WKFullScreenWindowController *WebViewImpl::fullScreenWindowController()
2583 {
2584     if (!m_fullScreenWindowController)
2585         m_fullScreenWindowController = adoptNS([[WKFullScreenWindowController alloc] initWithWindow:fullScreenWindow() webView:m_view.getAutoreleased() page:m_page]);
2586
2587     return m_fullScreenWindowController.get();
2588 }
2589
2590 void WebViewImpl::closeFullScreenWindowController()
2591 {
2592     if (!m_fullScreenWindowController)
2593         return;
2594
2595     [m_fullScreenWindowController close];
2596     m_fullScreenWindowController = nullptr;
2597 }
2598 #endif
2599
2600 NSView *WebViewImpl::fullScreenPlaceholderView()
2601 {
2602 #if ENABLE(FULLSCREEN_API)
2603     if (m_fullScreenWindowController && [m_fullScreenWindowController isFullScreen])
2604         return [m_fullScreenWindowController webViewPlaceholder];
2605 #endif
2606     return nil;
2607 }
2608
2609 NSWindow *WebViewImpl::fullScreenWindow()
2610 {
2611 #if ENABLE(FULLSCREEN_API)
2612     return [[[WebCoreFullScreenWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame] styleMask:(NSWindowStyleMaskBorderless | NSWindowStyleMaskResizable) backing:NSBackingStoreBuffered defer:NO] autorelease];
2613 #else
2614     return nil;
2615 #endif
2616 }
2617
2618 bool WebViewImpl::isEditable() const
2619 {
2620     return m_page->isEditable();
2621 }
2622
2623 typedef HashMap<SEL, String> SelectorNameMap;
2624
2625 // Map selectors into Editor command names.
2626 // This is not needed for any selectors that have the same name as the Editor command.
2627 static const SelectorNameMap& selectorExceptionMap()
2628 {
2629     static NeverDestroyed<SelectorNameMap> map;
2630
2631     struct SelectorAndCommandName {
2632         SEL selector;
2633         ASCIILiteral commandName;
2634     };
2635
2636     static const SelectorAndCommandName names[] = {
2637         { @selector(insertNewlineIgnoringFieldEditor:), "InsertNewline"_s },
2638         { @selector(insertParagraphSeparator:), "InsertNewline"_s },
2639         { @selector(insertTabIgnoringFieldEditor:), "InsertTab"_s },
2640         { @selector(pageDown:), "MovePageDown"_s },
2641         { @selector(pageDownAndModifySelection:), "MovePageDownAndModifySelection"_s },
2642         { @selector(pageUp:), "MovePageUp"_s },
2643         { @selector(pageUpAndModifySelection:), "MovePageUpAndModifySelection"_s },
2644         { @selector(scrollPageDown:), "ScrollPageForward"_s },
2645         { @selector(scrollPageUp:), "ScrollPageBackward"_s },
2646 #if WK_API_ENABLED
2647         { @selector(_pasteAsQuotation:), "PasteAsQuotation"_s },
2648 #endif
2649     };
2650
2651     for (auto& name : names)
2652         map.get().add(name.selector, name.commandName);
2653
2654     return map;
2655 }
2656
2657 static String commandNameForSelector(SEL selector)
2658 {
2659     // Check the exception map first.
2660     static const SelectorNameMap& exceptionMap = selectorExceptionMap();
2661     SelectorNameMap::const_iterator it = exceptionMap.find(selector);
2662     if (it != exceptionMap.end())
2663         return it->value;
2664
2665     // Remove the trailing colon.
2666     // No need to capitalize the command name since Editor command names are
2667     // not case sensitive.
2668     const char* selectorName = sel_getName(selector);
2669     size_t selectorNameLength = strlen(selectorName);
2670     if (selectorNameLength < 2 || selectorName[selectorNameLength - 1] != ':')
2671         return String();
2672     return String(selectorName, selectorNameLength - 1);
2673 }
2674
2675 bool WebViewImpl::executeSavedCommandBySelector(SEL selector)
2676 {
2677     LOG(TextInput, "Executing previously saved command %s", sel_getName(selector));
2678     // The sink does two things: 1) Tells us if the responder went unhandled, and
2679     // 2) prevents any NSBeep; we don't ever want to beep here.
2680     RetainPtr<WKResponderChainSink> sink = adoptNS([[WKResponderChainSink alloc] initWithResponderChain:m_view.getAutoreleased()]);
2681     [m_view _web_superDoCommandBySelector:selector];
2682     [sink detach];
2683     return ![sink didReceiveUnhandledCommand];
2684 }
2685
2686 void WebViewImpl::executeEditCommandForSelector(SEL selector, const String& argument)
2687 {
2688     m_page->executeEditCommand(commandNameForSelector(selector), argument);
2689 }
2690
2691 void WebViewImpl::registerEditCommand(Ref<WebEditCommandProxy>&& command, UndoOrRedo undoOrRedo)
2692 {
2693     auto actionName = command->label();
2694     auto commandObjC = adoptNS([[WKEditCommand alloc] initWithWebEditCommandProxy:WTFMove(command)]);
2695
2696     NSUndoManager *undoManager = [m_view undoManager];
2697     [undoManager registerUndoWithTarget:m_undoTarget.get() selector:((undoOrRedo == UndoOrRedo::Undo) ? @selector(undoEditing:) : @selector(redoEditing:)) object:commandObjC.get()];
2698     if (!actionName.isEmpty())
2699         [undoManager setActionName:(NSString *)actionName];
2700 }
2701
2702 void WebViewImpl::clearAllEditCommands()
2703 {
2704     [[m_view undoManager] removeAllActionsWithTarget:m_undoTarget.get()];
2705 }
2706
2707 bool WebViewImpl::writeSelectionToPasteboard(NSPasteboard *pasteboard, NSArray *types)
2708 {
2709     size_t numTypes = types.count;
2710     [pasteboard declareTypes:types owner:nil];
2711     for (size_t i = 0; i < numTypes; ++i) {
2712         if ([[types objectAtIndex:i] isEqualTo:WebCore::legacyStringPasteboardType()])
2713             [pasteboard setString:m_page->stringSelectionForPasteboard() forType:WebCore::legacyStringPasteboardType()];
2714         else {
2715             RefPtr<WebCore::SharedBuffer> buffer = m_page->dataSelectionForPasteboard([types objectAtIndex:i]);
2716             [pasteboard setData:buffer ? buffer->createNSData().get() : nil forType:[types objectAtIndex:i]];
2717         }
2718     }
2719     return true;
2720 }
2721
2722 bool WebViewImpl::readSelectionFromPasteboard(NSPasteboard *pasteboard)
2723 {
2724     return m_page->readSelectionFromPasteboard([pasteboard name]);
2725 }
2726
2727 id WebViewImpl::validRequestorForSendAndReturnTypes(NSString *sendType, NSString *returnType)
2728 {
2729     EditorState editorState = m_page->editorState();
2730     bool isValidSendType = false;
2731
2732     if (sendType && !editorState.selectionIsNone) {
2733         if (editorState.isInPlugin)
2734             isValidSendType = [sendType isEqualToString:WebCore::legacyStringPasteboardType()];
2735         else
2736             isValidSendType = [PasteboardTypes::forSelection() containsObject:sendType];
2737     }
2738
2739     bool isValidReturnType = false;
2740     if (!returnType)
2741         isValidReturnType = true;
2742     else if ([PasteboardTypes::forEditing() containsObject:returnType] && editorState.isContentEditable) {
2743         // We can insert strings in any editable context.  We can insert other types, like images, only in rich edit contexts.
2744         isValidReturnType = editorState.isContentRichlyEditable || [returnType isEqualToString:WebCore::legacyStringPasteboardType()];
2745     }
2746     if (isValidSendType && isValidReturnType)
2747         return m_view.getAutoreleased();
2748     return [[m_view nextResponder] validRequestorForSendType:sendType returnType:returnType];
2749 }
2750
2751 void WebViewImpl::centerSelectionInVisibleArea()
2752 {
2753     m_page->centerSelectionInVisibleArea();
2754 }
2755
2756 void WebViewImpl::selectionDidChange()
2757 {
2758     updateFontManagerIfNeeded();
2759     if (!m_isHandlingAcceptedCandidate)
2760         m_softSpaceRange = NSMakeRange(NSNotFound, 0);
2761 #if HAVE(TOUCH_BAR)
2762     updateTouchBar();
2763     if (!m_page->editorState().isMissingPostLayoutData)
2764         requestCandidatesForSelectionIfNeeded();
2765 #endif
2766
2767     NSWindow *window = [m_view window];
2768     if (window.firstResponder == m_view.get().get()) {
2769         NSInspectorBar *inspectorBar = window.inspectorBar;
2770         if (inspectorBar.visible)
2771             [inspectorBar _update];
2772     }
2773
2774     [m_view _web_editorStateDidChange];
2775 }
2776
2777 #if WK_API_ENABLED
2778 void WebViewImpl::showShareSheet(const WebCore::ShareDataWithParsedURL& data, WTF::CompletionHandler<void(bool)>&& completionHandler, WKWebView *view)
2779 {
2780     if (_shareSheet)
2781         [_shareSheet dismiss];
2782     
2783     ASSERT([view respondsToSelector:@selector(shareSheetDidDismiss:)]);
2784     _shareSheet = adoptNS([[WKShareSheet alloc] initWithView:view]);
2785     [_shareSheet setDelegate:view];
2786     
2787     [_shareSheet presentWithParameters:data completionHandler:WTFMove(completionHandler)];
2788 }
2789     
2790 void WebViewImpl::shareSheetDidDismiss(WKShareSheet *shareSheet)
2791 {
2792     ASSERT(_shareSheet == shareSheet);
2793     
2794     [_shareSheet setDelegate:nil];
2795     _shareSheet = nil;
2796 }
2797 #endif
2798
2799 void WebViewImpl::didBecomeEditable()
2800 {
2801     [m_windowVisibilityObserver startObservingFontPanel];
2802
2803     dispatch_async(dispatch_get_main_queue(), [] {
2804         [[NSSpellChecker sharedSpellChecker] _preflightChosenSpellServer];
2805     });
2806 }
2807
2808 void WebViewImpl::updateFontManagerIfNeeded()
2809 {
2810     BOOL fontPanelIsVisible = NSFontPanel.sharedFontPanelExists && NSFontPanel.sharedFontPanel.visible;
2811     if (!fontPanelIsVisible && !m_page->editorState().isContentRichlyEditable)
2812         return;
2813
2814     m_page->fontAtSelection([](const String& fontName, double fontSize, bool selectionHasMultipleFonts, WebKit::CallbackBase::Error error) {
2815         if (NSFont *font = [NSFont fontWithName:fontName size:fontSize])
2816             [NSFontManager.sharedFontManager setSelectedFont:font isMultiple:selectionHasMultipleFonts];
2817     });
2818 }
2819
2820 void WebViewImpl::typingAttributesWithCompletionHandler(void(^completion)(NSDictionary<NSString *, id> *))
2821 {
2822     if (auto attributes = m_page->cachedFontAttributesAtSelectionStart()) {
2823         auto attributesAsDictionary = attributes->createDictionary();
2824         completion(attributesAsDictionary.get());
2825         return;
2826     }
2827
2828     m_page->requestFontAttributesAtSelectionStart([completion = makeBlockPtr(completion)] (const WebCore::FontAttributes& attributes, CallbackBase::Error error) {
2829         if (error != CallbackBase::Error::None) {
2830             completion(nil);
2831             return;
2832         }
2833
2834         auto attributesAsDictionary = attributes.createDictionary();
2835         completion(attributesAsDictionary.get());
2836     });
2837 }
2838
2839 void WebViewImpl::changeFontColorFromSender(id sender)
2840 {
2841     if (![sender respondsToSelector:@selector(color)])
2842         return;
2843
2844     id color = [sender color];
2845     if (![color isKindOfClass:NSColor.class])
2846         return;
2847
2848     auto& editorState = m_page->editorState();
2849     if (!editorState.isContentEditable || editorState.selectionIsNone)
2850         return;
2851
2852     WebCore::FontAttributeChanges changes;
2853     changes.setForegroundColor(WebCore::colorFromNSColor((NSColor *)color));
2854     m_page->changeFontAttributes(WTFMove(changes));
2855 }
2856
2857 void WebViewImpl::changeFontAttributesFromSender(id sender)
2858 {
2859     auto& editorState = m_page->editorState();
2860     if (!editorState.isContentEditable || editorState.selectionIsNone)
2861         return;
2862
2863     m_page->changeFontAttributes(WebCore::computedFontAttributeChanges(NSFontManager.sharedFontManager, sender));
2864     updateFontManagerIfNeeded();
2865 }
2866
2867 void WebViewImpl::changeFontFromFontManager()
2868 {
2869     auto& editorState = m_page->editorState();
2870     if (!editorState.isContentEditable || editorState.selectionIsNone)
2871         return;
2872
2873     m_page->changeFont(WebCore::computedFontChanges(NSFontManager.sharedFontManager));
2874     updateFontManagerIfNeeded();
2875 }
2876
2877 static NSMenuItem *menuItem(id <NSValidatedUserInterfaceItem> item)
2878 {
2879     if (![(NSObject *)item isKindOfClass:[NSMenuItem class]])
2880         return nil;
2881     return (NSMenuItem *)item;
2882 }
2883
2884 static NSToolbarItem *toolbarItem(id <NSValidatedUserInterfaceItem> item)
2885 {
2886     if (![(NSObject *)item isKindOfClass:[NSToolbarItem class]])
2887         return nil;
2888     return (NSToolbarItem *)item;
2889 }
2890
2891 bool WebViewImpl::validateUserInterfaceItem(id <NSValidatedUserInterfaceItem> item)
2892 {
2893     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer));
2894     SEL action = [item action];
2895
2896     if (action == @selector(showGuessPanel:)) {
2897         if (NSMenuItem *menuItem = WebKit::menuItem(item))
2898             [menuItem setTitle:WebCore::contextMenuItemTagShowSpellingPanel(![[[NSSpellChecker sharedSpellChecker] spellingPanel] isVisible])];
2899         return m_page->editorState().isContentEditable;
2900     }
2901
2902     if (action == @selector(checkSpelling:) || action == @selector(changeSpelling:))
2903         return m_page->editorState().isContentEditable;
2904
2905     if (action == @selector(toggleContinuousSpellChecking:)) {
2906         bool enabled = TextChecker::isContinuousSpellCheckingAllowed();
2907         bool checked = enabled && TextChecker::state().isContinuousSpellCheckingEnabled;
2908         [menuItem(item) setState:checked ? NSControlStateValueOn : NSControlStateValueOff];
2909         return enabled;
2910     }
2911
2912     if (action == @selector(toggleGrammarChecking:)) {
2913         bool checked = TextChecker::state().isGrammarCheckingEnabled;
2914         [menuItem(item) setState:checked ? NSControlStateValueOn : NSControlStateValueOff];
2915         return true;
2916     }
2917
2918     if (action == @selector(toggleAutomaticSpellingCorrection:)) {
2919         bool checked = TextChecker::state().isAutomaticSpellingCorrectionEnabled;
2920         [menuItem(item) setState:checked ? NSControlStateValueOn : NSControlStateValueOff];
2921         return m_page->editorState().isContentEditable;
2922     }
2923
2924     if (action == @selector(orderFrontSubstitutionsPanel:)) {
2925         if (NSMenuItem *menuItem = WebKit::menuItem(item))
2926             [menuItem setTitle:WebCore::contextMenuItemTagShowSubstitutions(![[[NSSpellChecker sharedSpellChecker] substitutionsPanel] isVisible])];
2927         return m_page->editorState().isContentEditable;
2928     }
2929
2930     if (action == @selector(toggleSmartInsertDelete:)) {
2931         bool checked = m_page->isSmartInsertDeleteEnabled();
2932         [menuItem(item) setState:checked ? NSControlStateValueOn : NSControlStateValueOff];
2933         return m_page->editorState().isContentEditable;
2934     }
2935
2936     if (action == @selector(toggleAutomaticQuoteSubstitution:)) {
2937         bool checked = TextChecker::state().isAutomaticQuoteSubstitutionEnabled;
2938         [menuItem(item) setState:checked ? NSControlStateValueOn : NSControlStateValueOff];
2939         return m_page->editorState().isContentEditable;
2940     }
2941
2942     if (action == @selector(toggleAutomaticDashSubstitution:)) {
2943         bool checked = TextChecker::state().isAutomaticDashSubstitutionEnabled;
2944         [menuItem(item) setState:checked ? NSControlStateValueOn : NSControlStateValueOff];
2945         return m_page->editorState().isContentEditable;
2946     }
2947
2948     if (action == @selector(toggleAutomaticLinkDetection:)) {
2949         bool checked = TextChecker::state().isAutomaticLinkDetectionEnabled;
2950         [menuItem(item) setState:checked ? NSControlStateValueOn : NSControlStateValueOff];
2951         return m_page->editorState().isContentEditable;
2952     }
2953
2954     if (action == @selector(toggleAutomaticTextReplacement:)) {
2955         bool checked = TextChecker::state().isAutomaticTextReplacementEnabled;
2956         [menuItem(item) setState:checked ? NSControlStateValueOn : NSControlStateValueOff];
2957         return m_page->editorState().isContentEditable;
2958     }
2959
2960     if (action == @selector(uppercaseWord:) || action == @selector(lowercaseWord:) || action == @selector(capitalizeWord:))
2961         return m_page->editorState().selectionIsRange && m_page->editorState().isContentEditable;
2962
2963     if (action == @selector(stopSpeaking:))
2964         return [NSApp isSpeaking];
2965
2966     // The centerSelectionInVisibleArea: selector is enabled if there's a selection range or if there's an insertion point in an editable area.
2967     if (action == @selector(centerSelectionInVisibleArea:))
2968         return m_page->editorState().selectionIsRange || (m_page->editorState().isContentEditable && !m_page->editorState().selectionIsNone);
2969
2970     // Next, handle editor commands. Start by returning true for anything that is not an editor command.
2971     // Returning true is the default thing to do in an AppKit validate method for any selector that is not recognized.
2972     String commandName = commandNameForSelector([item action]);
2973     if (!WebCore::Editor::commandIsSupportedFromMenuOrKeyBinding(commandName))
2974         return true;
2975
2976     // Add this item to the vector of items for a given command that are awaiting validation.
2977     ValidationMap::AddResult addResult = m_validationMap.add(commandName, ValidationVector());
2978     addResult.iterator->value.append(item);
2979     if (addResult.isNewEntry) {
2980         // If we are not already awaiting validation for this command, start the asynchronous validation process.
2981         // FIXME: Theoretically, there is a race here; when we get the answer it might be old, from a previous time
2982         // we asked for the same command; there is no guarantee the answer is still valid.
2983         auto weakThis = makeWeakPtr(*this);
2984         m_page->validateCommand(commandName, [weakThis](const String& commandName, bool isEnabled, int32_t state, WebKit::CallbackBase::Error error) {
2985             if (!weakThis)
2986                 return;
2987
2988             // If the process exits before the command can be validated, we'll be called back with an error.
2989             if (error != WebKit::CallbackBase::Error::None)
2990                 return;
2991
2992             weakThis->setUserInterfaceItemState(commandName, isEnabled, state);
2993         });
2994     }
2995
2996     // Treat as enabled until we get the result back from the web process and _setUserInterfaceItemState is called.
2997     // FIXME <rdar://problem/8803459>: This means disabled items will flash enabled at first for a moment.
2998     // But returning NO here would be worse; that would make keyboard commands such as command-C fail.
2999     return true;
3000 }
3001
3002 void WebViewImpl::setUserInterfaceItemState(NSString *commandName, bool enabled, int state)
3003 {
3004     ValidationVector items = m_validationMap.take(commandName);
3005     for (auto& item : items) {
3006         [menuItem(item.get()) setState:state];
3007         [menuItem(item.get()) setEnabled:enabled];
3008         [toolbarItem(item.get()) setEnabled:enabled];
3009         // FIXME <rdar://problem/8803392>: If the item is neither a menu nor toolbar item, it will be left enabled.
3010     }
3011 }
3012
3013 void WebViewImpl::startSpeaking()
3014 {
3015     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer));
3016     m_page->getSelectionOrContentsAsString([](const String& string, WebKit::CallbackBase::Error error) {
3017         if (error != WebKit::CallbackBase::Error::None)
3018             return;
3019         if (!string)
3020             return;
3021
3022         [NSApp speakString:string];
3023     });
3024 }
3025
3026 void WebViewImpl::stopSpeaking(id sender)
3027 {
3028     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer));
3029     [NSApp stopSpeaking:sender];
3030 }
3031
3032 void WebViewImpl::showGuessPanel(id sender)
3033 {
3034     NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
3035     if (!checker) {
3036         LOG_ERROR("No NSSpellChecker");
3037         return;
3038     }
3039
3040     NSPanel *spellingPanel = [checker spellingPanel];
3041     if ([spellingPanel isVisible]) {
3042         [spellingPanel orderOut:sender];
3043         return;
3044     }
3045
3046     m_page->advanceToNextMisspelling(true);
3047     [spellingPanel orderFront:sender];
3048 }
3049
3050 void WebViewImpl::checkSpelling()
3051 {
3052     m_page->advanceToNextMisspelling(false);
3053 }
3054
3055 void WebViewImpl::changeSpelling(id sender)
3056 {
3057     NSString *word = [[sender selectedCell] stringValue];
3058
3059     m_page->changeSpellingToWord(word);
3060 }
3061
3062 void WebViewImpl::toggleContinuousSpellChecking()
3063 {
3064     bool spellCheckingEnabled = !TextChecker::state().isContinuousSpellCheckingEnabled;
3065     TextChecker::setContinuousSpellCheckingEnabled(spellCheckingEnabled);
3066
3067     m_page->process().updateTextCheckerState();
3068 }
3069
3070 bool WebViewImpl::isGrammarCheckingEnabled()
3071 {
3072     return TextChecker::state().isGrammarCheckingEnabled;
3073 }
3074
3075 void WebViewImpl::setGrammarCheckingEnabled(bool flag)
3076 {
3077     if (static_cast<bool>(flag) == TextChecker::state().isGrammarCheckingEnabled)
3078         return;
3079
3080     TextChecker::setGrammarCheckingEnabled(flag);
3081     m_page->process().updateTextCheckerState();
3082 }
3083
3084 void WebViewImpl::toggleGrammarChecking()
3085 {
3086     bool grammarCheckingEnabled = !TextChecker::state().isGrammarCheckingEnabled;
3087     TextChecker::setGrammarCheckingEnabled(grammarCheckingEnabled);
3088
3089     m_page->process().updateTextCheckerState();
3090 }
3091
3092 void WebViewImpl::toggleAutomaticSpellingCorrection()
3093 {
3094     TextChecker::setAutomaticSpellingCorrectionEnabled(!TextChecker::state().isAutomaticSpellingCorrectionEnabled);
3095
3096     m_page->process().updateTextCheckerState();
3097 }
3098
3099 void WebViewImpl::orderFrontSubstitutionsPanel(id sender)
3100 {
3101     NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker];
3102     if (!checker) {
3103         LOG_ERROR("No NSSpellChecker");
3104         return;
3105     }
3106
3107     NSPanel *substitutionsPanel = [checker substitutionsPanel];
3108     if ([substitutionsPanel isVisible]) {
3109         [substitutionsPanel orderOut:sender];
3110         return;
3111     }
3112     [substitutionsPanel orderFront:sender];
3113 }
3114
3115 void WebViewImpl::toggleSmartInsertDelete()
3116 {
3117     m_page->setSmartInsertDeleteEnabled(!m_page->isSmartInsertDeleteEnabled());
3118 }
3119
3120 bool WebViewImpl::isAutomaticQuoteSubstitutionEnabled()
3121 {
3122     return TextChecker::state().isAutomaticQuoteSubstitutionEnabled;
3123 }
3124
3125 void WebViewImpl::setAutomaticQuoteSubstitutionEnabled(bool flag)
3126 {
3127     if (static_cast<bool>(flag) == TextChecker::state().isAutomaticQuoteSubstitutionEnabled)
3128         return;
3129
3130     TextChecker::setAutomaticQuoteSubstitutionEnabled(flag);
3131     m_page->process().updateTextCheckerState();
3132 }
3133
3134 void WebViewImpl::toggleAutomaticQuoteSubstitution()
3135 {
3136     TextChecker::setAutomaticQuoteSubstitutionEnabled(!TextChecker::state().isAutomaticQuoteSubstitutionEnabled);
3137     m_page->process().updateTextCheckerState();
3138 }
3139
3140 bool WebViewImpl::isAutomaticDashSubstitutionEnabled()
3141 {
3142     return TextChecker::state().isAutomaticDashSubstitutionEnabled;
3143 }
3144
3145 void WebViewImpl::setAutomaticDashSubstitutionEnabled(bool flag)
3146 {
3147     if (static_cast<bool>(flag) == TextChecker::state().isAutomaticDashSubstitutionEnabled)
3148         return;
3149
3150     TextChecker::setAutomaticDashSubstitutionEnabled(flag);
3151     m_page->process().updateTextCheckerState();
3152 }
3153
3154 void WebViewImpl::toggleAutomaticDashSubstitution()
3155 {
3156     TextChecker::setAutomaticDashSubstitutionEnabled(!TextChecker::state().isAutomaticDashSubstitutionEnabled);
3157     m_page->process().updateTextCheckerState();
3158 }
3159
3160 bool WebViewImpl::isAutomaticLinkDetectionEnabled()
3161 {
3162     return TextChecker::state().isAutomaticLinkDetectionEnabled;
3163 }
3164
3165 void WebViewImpl::setAutomaticLinkDetectionEnabled(bool flag)
3166 {
3167     if (static_cast<bool>(flag) == TextChecker::state().isAutomaticLinkDetectionEnabled)
3168         return;
3169
3170     TextChecker::setAutomaticLinkDetectionEnabled(flag);
3171     m_page->process().updateTextCheckerState();
3172 }
3173
3174 void WebViewImpl::toggleAutomaticLinkDetection()
3175 {
3176     TextChecker::setAutomaticLinkDetectionEnabled(!TextChecker::state().isAutomaticLinkDetectionEnabled);
3177     m_page->process().updateTextCheckerState();
3178 }
3179
3180 bool WebViewImpl::isAutomaticTextReplacementEnabled()
3181 {
3182     return TextChecker::state().isAutomaticTextReplacementEnabled;
3183 }
3184
3185 void WebViewImpl::setAutomaticTextReplacementEnabled(bool flag)
3186 {
3187     if (static_cast<bool>(flag) == TextChecker::state().isAutomaticTextReplacementEnabled)
3188         return;
3189     
3190     TextChecker::setAutomaticTextReplacementEnabled(flag);
3191     m_page->process().updateTextCheckerState();
3192 }
3193
3194 void WebViewImpl::toggleAutomaticTextReplacement()
3195 {
3196     TextChecker::setAutomaticTextReplacementEnabled(!TextChecker::state().isAutomaticTextReplacementEnabled);
3197     m_page->process().updateTextCheckerState();
3198 }
3199
3200 void WebViewImpl::uppercaseWord()
3201 {
3202     m_page->uppercaseWord();
3203 }
3204
3205 void WebViewImpl::lowercaseWord()
3206 {
3207     m_page->lowercaseWord();
3208 }
3209
3210 void WebViewImpl::capitalizeWord()
3211 {
3212     m_page->capitalizeWord();
3213 }
3214
3215 void WebViewImpl::requestCandidatesForSelectionIfNeeded()
3216 {
3217     if (!shouldRequestCandidates())
3218         return;
3219
3220     const EditorState& editorState = m_page->editorState();
3221     if (!editorState.isContentEditable)
3222         return;
3223
3224     if (editorState.isMissingPostLayoutData)
3225         return;
3226
3227     auto& postLayoutData = editorState.postLayoutData();
3228     m_lastStringForCandidateRequest = postLayoutData.stringForCandidateRequest;
3229
3230     NSRange selectedRange = NSMakeRange(postLayoutData.candidateRequestStartPosition, postLayoutData.selectedTextLength);
3231     NSTextCheckingTypes checkingTypes = NSTextCheckingTypeSpelling | NSTextCheckingTypeReplacement | NSTextCheckingTypeCorrection;
3232     auto weakThis = makeWeakPtr(*this);
3233     m_lastCandidateRequestSequenceNumber = [[NSSpellChecker sharedSpellChecker] requestCandidatesForSelectedRange:selectedRange inString:postLayoutData.paragraphContextForCandidateRequest types:checkingTypes options:nil inSpellDocumentWithTag:spellCheckerDocumentTag() completionHandler:[weakThis](NSInteger sequenceNumber, NSArray<NSTextCheckingResult *> *candidates) {
3234         dispatch_async(dispatch_get_main_queue(), ^{
3235             if (!weakThis)
3236                 return;
3237             weakThis->handleRequestedCandidates(sequenceNumber, candidates);
3238         });
3239     }];
3240 }
3241
3242 void WebViewImpl::handleRequestedCandidates(NSInteger sequenceNumber, NSArray<NSTextCheckingResult *> *candidates)
3243 {
3244     if (!shouldRequestCandidates())
3245         return;
3246
3247     if (m_lastCandidateRequestSequenceNumber != sequenceNumber)
3248         return;
3249
3250     const EditorState& editorState = m_page->editorState();
3251     if (!editorState.isContentEditable)
3252         return;
3253
3254     // FIXME: It's pretty lame that we have to depend on the most recent EditorState having post layout data,
3255     // and that we just bail if it is missing.
3256     if (editorState.isMissingPostLayoutData)
3257         return;
3258
3259     auto& postLayoutData = editorState.postLayoutData();
3260     if (m_lastStringForCandidateRequest != postLayoutData.stringForCandidateRequest)
3261         return;
3262
3263 #if HAVE(TOUCH_BAR)
3264     NSRange selectedRange = NSMakeRange(postLayoutData.candidateRequestStartPosition, postLayoutData.selectedTextLength);
3265     WebCore::IntRect offsetSelectionRect = postLayoutData.focusedElementRect;
3266     offsetSelectionRect.move(0, offsetSelectionRect.height());
3267
3268     [candidateListTouchBarItem() setCandidates:candidates forSelectedRange:selectedRange inString:postLayoutData.paragraphContextForCandidateRequest rect:offsetSelectionRect view:m_view.getAutoreleased() completionHandler:nil];
3269 #else
3270     UNUSED_PARAM(candidates);
3271 #endif
3272 }
3273
3274 static constexpr WebCore::TextCheckingType coreTextCheckingType(NSTextCheckingType type)
3275 {
3276     switch (type) {
3277     case NSTextCheckingTypeCorrection:
3278         return WebCore::TextCheckingType::Correction;
3279     case NSTextCheckingTypeReplacement:
3280         return WebCore::TextCheckingType::Replacement;
3281     case NSTextCheckingTypeSpelling:
3282         return WebCore::TextCheckingType::Spelling;
3283     default:
3284         return WebCore::TextCheckingType::None;
3285     }
3286 }
3287
3288 static WebCore::TextCheckingResult textCheckingResultFromNSTextCheckingResult(NSTextCheckingResult *nsResult)
3289 {
3290     NSRange resultRange = [nsResult range];
3291
3292     WebCore::TextCheckingResult result;
3293     result.type = coreTextCheckingType(nsResult.resultType);
3294     result.location = resultRange.location;
3295     result.length = resultRange.length;
3296     result.replacement = nsResult.replacementString;
3297     return result;
3298 }
3299
3300 void WebViewImpl::handleAcceptedCandidate(NSTextCheckingResult *acceptedCandidate)
3301 {
3302     const EditorState& editorState = m_page->editorState();
3303     if (!editorState.isContentEditable)
3304         return;
3305
3306     // FIXME: It's pretty lame that we have to depend on the most recent EditorState having post layout data,
3307     // and that we just bail if it is missing.
3308     if (editorState.isMissingPostLayoutData)
3309         return;
3310
3311     auto& postLayoutData = editorState.postLayoutData();
3312     if (m_lastStringForCandidateRequest != postLayoutData.stringForCandidateRequest)
3313         return;
3314
3315     m_isHandlingAcceptedCandidate = true;
3316     NSRange range = [acceptedCandidate range];
3317     if (acceptedCandidate.replacementString && [acceptedCandidate.replacementString length] > 0) {
3318         NSRange replacedRange = NSMakeRange(range.location, [acceptedCandidate.replacementString length]);
3319         NSRange softSpaceRange = NSMakeRange(NSMaxRange(replacedRange) - 1, 1);
3320         if ([acceptedCandidate.replacementString hasSuffix:@" "])
3321             m_softSpaceRange = softSpaceRange;
3322     }
3323
3324     m_page->handleAcceptedCandidate(textCheckingResultFromNSTextCheckingResult(acceptedCandidate));
3325 }
3326
3327 void WebViewImpl::doAfterProcessingAllPendingMouseEvents(dispatch_block_t action)
3328 {
3329     if (!m_page->isProcessingMouseEvents()) {
3330         action();
3331         return;
3332     }
3333
3334     m_callbackHandlersAfterProcessingPendingMouseEvents.append(makeBlockPtr(action));
3335 }
3336
3337 void WebViewImpl::didFinishProcessingAllPendingMouseEvents()
3338 {
3339     flushPendingMouseEventCallbacks();
3340 }
3341
3342 void WebViewImpl::flushPendingMouseEventCallbacks()
3343 {
3344     for (auto& callback : m_callbackHandlersAfterProcessingPendingMouseEvents)
3345         callback();
3346
3347     m_callbackHandlersAfterProcessingPendingMouseEvents.clear();
3348 }
3349
3350 void WebViewImpl::preferencesDidChange()
3351 {
3352     BOOL needsViewFrameInWindowCoordinates = m_page->preferences().pluginsEnabled();
3353
3354     if (!!needsViewFrameInWindowCoordinates == !!m_needsViewFrameInWindowCoordinates)
3355         return;
3356
3357     m_needsViewFrameInWindowCoordinates = needsViewFrameInWindowCoordinates;
3358     if ([m_view window])
3359         updateWindowAndViewFrames();
3360 }
3361
3362 void WebViewImpl::setTextIndicator(WebCore::TextIndicator& textIndicator, WebCore::TextIndicatorWindowLifetime lifetime)
3363 {
3364     if (!m_textIndicatorWindow)
3365         m_textIndicatorWindow = std::make_unique<WebCore::TextIndicatorWindow>(m_view.getAutoreleased());
3366
3367     NSRect textBoundingRectInScreenCoordinates = [[m_view window] convertRectToScreen:[m_view convertRect:textIndicator.textBoundingRectInRootViewCoordinates() toView:nil]];
3368     m_textIndicatorWindow->setTextIndicator(textIndicator, NSRectToCGRect(textBoundingRectInScreenCoordinates), lifetime);
3369 }
3370
3371 void WebViewImpl::clearTextIndicatorWithAnimation(WebCore::TextIndicatorWindowDismissalAnimation animation)
3372 {
3373     if (m_textIndicatorWindow)
3374         m_textIndicatorWindow->clearTextIndicator(animation);
3375     m_textIndicatorWindow = nullptr;
3376 }
3377
3378 void WebViewImpl::setTextIndicatorAnimationProgress(float progress)
3379 {
3380     if (m_textIndicatorWindow)
3381         m_textIndicatorWindow->setAnimationProgress(progress);
3382 }
3383
3384 void WebViewImpl::dismissContentRelativeChildWindowsWithAnimation(bool animate)
3385 {
3386     [m_view _web_dismissContentRelativeChildWindowsWithAnimation:animate];
3387 }
3388
3389 void WebViewImpl::dismissContentRelativeChildWindowsWithAnimationFromViewOnly(bool animate)
3390 {
3391     // Calling _clearTextIndicatorWithAnimation here will win out over the animated clear in dismissContentRelativeChildWindowsFromViewOnly.
3392     // We can't invert these because clients can override (and have overridden) _dismissContentRelativeChildWindows, so it needs to be called.
3393     // For this same reason, this can't be moved to WebViewImpl without care.
3394     clearTextIndicatorWithAnimation(animate ? WebCore::TextIndicatorWindowDismissalAnimation::FadeOut : WebCore::TextIndicatorWindowDismissalAnimation::None);
3395     [m_view _web_dismissContentRelativeChildWindows];
3396 }
3397
3398 void WebViewImpl::dismissContentRelativeChildWindowsFromViewOnly()
3399 {
3400     bool hasActiveImmediateAction = false;
3401     hasActiveImmediateAction = [m_immediateActionController hasActiveImmediateAction];
3402
3403     // FIXME: We don't know which panel we are dismissing, it may not even be in the current page (see <rdar://problem/13875766>).
3404     if ([m_view window].isKeyWindow || hasActiveImmediateAction) {
3405         WebCore::DictionaryLookup::hidePopup();
3406
3407         if (DataDetectorsLibrary())
3408             [[getDDActionsManagerClass() sharedManager] requestBubbleClosureUnanchorOnFailure:YES];
3409     }
3410
3411     clearTextIndicatorWithAnimation(WebCore::TextIndicatorWindowDismissalAnimation::FadeOut);
3412
3413     [m_immediateActionController dismissContentRelativeChildWindows];
3414
3415     m_pageClient->dismissCorrectionPanel(WebCore::ReasonForDismissingAlternativeTextIgnored);
3416 }
3417
3418 void WebViewImpl::hideWordDefinitionWindow()
3419 {
3420     WebCore::DictionaryLookup::hidePopup();
3421 }
3422
3423 void WebViewImpl::quickLookWithEvent(NSEvent *event)
3424 {
3425     if (ignoresNonWheelEvents())
3426         return;
3427
3428     if (m_immediateActionGestureRecognizer) {
3429         [m_view _web_superQuickLookWithEvent:event];
3430         return;
3431     }
3432
3433     NSPoint locationInViewCoordinates = [m_view convertPoint:[event locationInWindow] fromView:nil];
3434     m_page->performDictionaryLookupAtLocation(WebCore::FloatPoint(locationInViewCoordinates));
3435 }
3436
3437 void WebViewImpl::prepareForDictionaryLookup()
3438 {
3439     [m_windowVisibilityObserver startObservingLookupDismissalIfNeeded];
3440 }
3441
3442 void WebViewImpl::setAllowsLinkPreview(bool allowsLinkPreview)
3443 {
3444     if (m_allowsLinkPreview == allowsLinkPreview)
3445         return;
3446
3447     m_allowsLinkPreview = allowsLinkPreview;
3448
3449     if (!allowsLinkPreview)
3450         [m_view removeGestureRecognizer:m_immediateActionGestureRecognizer.get()];
3451     else if (NSGestureRecognizer *immediateActionRecognizer = m_immediateActionGestureRecognizer.get())
3452         [m_view addGestureRecognizer:immediateActionRecognizer];
3453 }
3454
3455 NSObject *WebViewImpl::immediateActionAnimationControllerForHitTestResult(API::HitTestResult* hitTestResult, uint32_t type, API::Object* userData)
3456 {
3457     return [m_view _web_immediateActionAnimationControllerForHitTestResultInternal:hitTestResult withType:type userData:userData];
3458 }
3459
3460 void WebViewImpl::didPerformImmediateActionHitTest(const WebHitTestResultData& result, bool contentPreventsDefault, API::Object* userData)
3461 {
3462     [m_immediateActionController didPerformImmediateActionHitTest:result contentPreventsDefault:contentPreventsDefault userData:userData];
3463 }
3464
3465 void WebViewImpl::prepareForImmediateActionAnimation()
3466 {
3467     [m_view _web_prepareForImmediateActionAnimation];
3468 }
3469
3470 void WebViewImpl::cancelImmediateActionAnimation()
3471 {
3472     [m_view _web_cancelImmediateActionAnimation];
3473 }
3474
3475 void WebViewImpl::completeImmediateActionAnimation()
3476 {
3477     [m_view _web_completeImmediateActionAnimation];
3478 }
3479
3480 void WebViewImpl::didChangeContentSize(CGSize newSize)
3481 {
3482     [m_view _web_didChangeContentSize:NSSizeFromCGSize(newSize)];
3483 }
3484
3485 void WebViewImpl::didHandleAcceptedCandidate()
3486 {
3487     m_isHandlingAcceptedCandidate = false;
3488
3489     [m_view _didHandleAcceptedCandidate];
3490 }
3491
3492 void WebViewImpl::videoControlsManagerDidChange()
3493 {
3494 #if HAVE(TOUCH_BAR)
3495     updateTouchBar();
3496 #endif
3497
3498 #if ENABLE(FULLSCREEN_API)
3499     if (hasFullScreenWindowController())
3500         [fullScreenWindowController() videoControlsManagerDidChange];
3501 #endif
3502 }
3503
3504 void WebViewImpl::setIgnoresNonWheelEvents(bool ignoresNonWheelEvents)
3505 {
3506     if (m_ignoresNonWheelEvents == ignoresNonWheelEvents)
3507         return;
3508
3509     m_ignoresNonWheelEvents = ignoresNonWheelEvents;
3510     m_page->setShouldDispatchFakeMouseMoveEvents(!ignoresNonWheelEvents);
3511
3512     if (ignoresNonWheelEvents)
3513         [m_view removeGestureRecognizer:m_immediateActionGestureRecognizer.get()];
3514     else if (NSGestureRecognizer *immediateActionRecognizer = m_immediateActionGestureRecognizer.get()) {
3515         if (m_allowsLinkPreview)
3516             [m_view addGestureRecognizer:immediateActionRecognizer];
3517     }
3518 }
3519
3520 void WebViewImpl::setIgnoresAllEvents(bool ignoresAllEvents)
3521 {
3522     m_ignoresAllEvents = ignoresAllEvents;
3523     setIgnoresNonWheelEvents(ignoresAllEvents);
3524 }
3525
3526 void WebViewImpl::setIgnoresMouseDraggedEvents(bool ignoresMouseDraggedEvents)
3527 {
3528     m_ignoresMouseDraggedEvents = ignoresMouseDraggedEvents;
3529 }
3530
3531 void WebViewImpl::setAccessibilityWebProcessToken(NSData *data)
3532 {
3533     m_remoteAccessibilityChild = data.length ? adoptNS([[NSAccessibilityRemoteUIElement alloc] initWithRemoteToken:data]) : nil;
3534     updateRemoteAccessibilityRegistration(true);
3535 }
3536
3537 void WebViewImpl::updateRemoteAccessibilityRegistration(bool registerProcess)
3538 {
3539     // When the tree is connected/disconnected, the remote accessibility registration
3540     // needs to be updated with the pid of the remote process. If the process is going
3541     // away, that information is not present in WebProcess
3542     pid_t pid = 0;
3543     if (registerProcess)
3544         pid = m_page->process().processIdentifier();
3545     else if (!registerProcess) {
3546         pid = [m_remoteAccessibilityChild processIdentifier];
3547         m_remoteAccessibilityChild = nil;
3548     }
3549     if (!pid)
3550         return;
3551
3552     if (registerProcess)
3553         [NSAccessibilityRemoteUIElement registerRemoteUIProcessIdentifier:pid];
3554     else
3555         [NSAccessibilityRemoteUIElement unregisterRemoteUIProcessIdentifier:pid];
3556 }
3557
3558 void WebViewImpl::accessibilityRegisterUIProcessTokens()
3559 {
3560     // Initialize remote accessibility when the window connection has been established.
3561     NSData *remoteElementToken = [NSAccessibilityRemoteUIElement remoteTokenForLocalUIElement:m_view.getAutoreleased()];
3562     NSData *remoteWindowToken = [NSAccessibilityRemoteUIElement remoteTokenForLocalUIElement:[m_view window]];
3563     IPC::DataReference elementToken = IPC::DataReference(reinterpret_cast<const uint8_t*>([remoteElementToken bytes]), [remoteElementToken length]);
3564     IPC::DataReference windowToken = IPC::DataReference(reinterpret_cast<const uint8_t*>([remoteWindowToken bytes]), [remoteWindowToken length]);
3565     m_page->registerUIProcessAccessibilityTokens(elementToken, windowToken);
3566 }
3567
3568 id WebViewImpl::accessibilityFocusedUIElement()
3569 {
3570     enableAccessibilityIfNecessary();
3571     return m_remoteAccessibilityChild.get();
3572 }
3573
3574 id WebViewImpl::accessibilityHitTest(CGPoint)
3575 {
3576     return accessibilityFocusedUIElement();
3577 }
3578
3579 void WebViewImpl::enableAccessibilityIfNecessary()
3580 {
3581     if (WebCore::AXObjectCache::accessibilityEnabled())
3582         return;
3583
3584     // After enabling accessibility update the window frame on the web process so that the
3585     // correct accessibility position is transmitted (when AX is off, that position is not calculated).
3586     WebCore::AXObjectCache::enableAccessibility();
3587     updateWindowAndViewFrames();
3588 }
3589
3590 id WebViewImpl::accessibilityAttributeValue(NSString *attribute, id parameter)
3591 {
3592     enableAccessibilityIfNecessary();
3593
3594     if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
3595
3596         id child = nil;
3597         if (m_remoteAccessibilityChild)
3598             child = m_remoteAccessibilityChild.get();
3599
3600             if (!child)
3601                 return nil;
3602         return [NSArray arrayWithObject:child];
3603     }
3604     if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
3605         return NSAccessibilityGroupRole;
3606     if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute])
3607         return NSAccessibilityRoleDescription(NSAccessibilityGroupRole, nil);
3608         if ([attribute isEqualToString:NSAccessibilityParentAttribute])
3609             return NSAccessibilityUnignoredAncestor([m_view superview]);
3610             if ([attribute isEqualToString:NSAccessibilityEnabledAttribute])
3611                 return @YES;
3612     
3613     if ([attribute isEqualToString:@"AXConvertRelativeFrame"]) {
3614         if ([parameter isKindOfClass:[NSValue class]]) {
3615             NSRect rect = [(NSValue *)parameter rectValue];
3616             return [NSValue valueWithRect:m_pageClient->rootViewToScreen(IntRect(rect))];
3617         }
3618     }
3619     
3620     return [m_view _web_superAccessibilityAttributeValue:attribute];
3621 }
3622
3623 void WebViewImpl::setPrimaryTrackingArea(NSTrackingArea *trackingArea)
3624 {
3625     [m_view removeTrackingArea:m_primaryTrackingArea.get()];
3626     m_primaryTrackingArea = trackingArea;
3627     [m_view addTrackingArea:trackingArea];
3628 }
3629
3630 // Any non-zero value will do, but using something recognizable might help us debug some day.
3631 #define TRACKING_RECT_TAG 0xBADFACE
3632
3633 NSTrackingRectTag WebViewImpl::addTrackingRect(CGRect, id owner, void* userData, bool assumeInside)
3634 {
3635     ASSERT(m_trackingRectOwner == nil);
3636     m_trackingRectOwner = owner;
3637     m_trackingRectUserData = userData;
3638     return TRACKING_RECT_TAG;
3639 }
3640
3641 NSTrackingRectTag WebViewImpl::addTrackingRectWithTrackingNum(CGRect, id owner, void* userData, bool assumeInside, int tag)
3642 {
3643     ASSERT(tag == 0 || tag == TRACKING_RECT_TAG);
3644     ASSERT(m_trackingRectOwner == nil);
3645     m_trackingRectOwner = owner;
3646     m_trackingRectUserData = userData;
3647     return TRACKING_RECT_TAG;
3648 }
3649
3650 void WebViewImpl::addTrackingRectsWithTrackingNums(CGRect*, id owner, void** userDataList, bool assumeInside, NSTrackingRectTag *trackingNums, int count)
3651 {
3652     ASSERT(count == 1);
3653     ASSERT(trackingNums[0] == 0 || trackingNums[0] == TRACKING_RECT_TAG);
3654     ASSERT(m_trackingRectOwner == nil);
3655     m_trackingRectOwner = owner;
3656     m_trackingRectUserData = userDataList[0];
3657     trackingNums[0] = TRACKING_RECT_TAG;
3658 }
3659
3660 void WebViewImpl::removeTrackingRect(NSTrackingRectTag tag)
3661 {
3662     if (tag == 0)
3663         return;
3664
3665     if (tag == TRACKING_RECT_TAG) {
3666         m_trackingRectOwner = nil;
3667         return;
3668     }
3669
3670     if (tag == m_lastToolTipTag) {
3671         [m_view _web_superRemoveTrackingRect:tag];
3672         m_lastToolTipTag = 0;
3673         return;
3674     }
3675
3676     // If any other tracking rect is being removed, we don't know how it was created
3677     // and it's possible there's a leak involved (see 3500217)
3678     ASSERT_NOT_REACHED();
3679 }
3680
3681 void WebViewImpl::removeTrackingRects(NSTrackingRectTag *tags, int count)
3682 {
3683     for (int i = 0; i < count; ++i) {
3684         int tag = tags[i];
3685         if (tag == 0)
3686             continue;
3687         ASSERT(tag == TRACKING_RECT_TAG);
3688         m_trackingRectOwner = nil;
3689     }
3690 }
3691
3692 void WebViewImpl::sendToolTipMouseExited()
3693 {
3694     // Nothing matters except window, trackingNumber, and userData.
3695     NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSEventTypeMouseExited
3696                                                 location:NSMakePoint(0, 0)
3697                                            modifierFlags:0
3698                                                timestamp:0
3699                                             windowNumber:[m_view window].windowNumber
3700                                                  context:NULL
3701                                              eventNumber:0
3702                                           trackingNumber:TRACKING_RECT_TAG
3703                                                 userData:m_trackingRectUserData];
3704     [m_trackingRectOwner mouseExited:fakeEvent];
3705 }
3706
3707 void WebViewImpl::sendToolTipMouseEntered()
3708 {
3709     // Nothing matters except window, trackingNumber, and userData.
3710     NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSEventTypeMouseEntered
3711                                                 location:NSMakePoint(0, 0)
3712                                            modifierFlags:0
3713                                                timestamp:0
3714                                             windowNumber:[m_view window].windowNumber
3715                                                  context:NULL
3716                                              eventNumber:0
3717                                           trackingNumber:TRACKING_RECT_TAG
3718                                                 userData:m_trackingRectUserData];
3719     [m_trackingRectOwner mouseEntered:fakeEvent];
3720 }
3721
3722 NSString *WebViewImpl::stringForToolTip(NSToolTipTag tag)
3723 {
3724     return nsStringFromWebCoreString(m_page->toolTip());
3725 }
3726
3727 void WebViewImpl::toolTipChanged(const String& oldToolTip, const String& newToolTip)
3728 {
3729     if (!oldToolTip.isNull())
3730         sendToolTipMouseExited();
3731     
3732     if (!newToolTip.isEmpty()) {
3733         // See radar 3500217 for why we remove all tooltips rather than just the single one we created.
3734         [m_view removeAllToolTips];
3735         NSRect wideOpenRect = NSMakeRect(-100000, -100000, 200000, 200000);
3736         m_lastToolTipTag = [m_view addToolTipRect:wideOpenRect owner:m_view.getAutoreleased() userData:NULL];
3737         sendToolTipMouseEntered();
3738     }
3739 }
3740
3741 void WebViewImpl::setAcceleratedCompositingRootLayer(CALayer *rootLayer)
3742 {
3743     [rootLayer web_disableAllActions];
3744
3745     m_rootLayer = rootLayer;
3746
3747 #if WK_API_ENABLED
3748     if (m_thumbnailView) {
3749         updateThumbnailViewLayer();
3750         return;
3751     }
3752 #endif
3753
3754     [CATransaction begin];
3755     [CATransaction setDisableActions:YES];
3756
3757     if (rootLayer) {
3758         if (!m_layerHostingView) {
3759             // Create an NSView that will host our layer tree.
3760             m_layerHostingView = adoptNS([[WKFlippedView alloc] initWithFrame:[m_view bounds]]);
3761             [m_layerHostingView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
3762
3763             [m_view addSubview:m_layerHostingView.get() positioned:NSWindowBelow relativeTo:nil];
3764
3765             // Create a root layer that will back the NSView.
3766             RetainPtr<CALayer> layer = adoptNS([[CALayer alloc] init]);
3767             [layer setDelegate:[WebActionDisablingCALayerDelegate shared]];
3768 #ifndef NDEBUG
3769             [layer setName:@"Hosting root layer"];
3770 #endif
3771
3772             [m_layerHostingView setLayer:layer.get()];
3773             [m_layerHostingView setWantsLayer:YES];
3774         }
3775
3776         [m_layerHostingView layer].sublayers = [NSArray arrayWithObject:rootLayer];
3777     } else if (m_layerHostingView) {
3778         [m_layerHostingView removeFromSuperview];
3779         [m_layerHostingView setLayer:nil];
3780         [m_layerHostingView setWantsLayer:NO];
3781
3782         m_layerHostingView = nullptr;
3783     }
3784
3785     [CATransaction commit];
3786 }
3787
3788 #if WK_API_ENABLED
3789 void WebViewImpl::setThumbnailView(_WKThumbnailView *thumbnailView)
3790 {
3791     ASSERT(!m_thumbnailView || !thumbnailView);
3792
3793     m_thumbnailView = thumbnailView;
3794
3795     if (thumbnailView)
3796         updateThumbnailViewLayer();
3797     else
3798         setAcceleratedCompositingRootLayer(m_rootLayer.get());
3799 }
3800
3801 void WebViewImpl::reparentLayerTreeInThumbnailView()
3802 {
3803     m_thumbnailView._thumbnailLayer = m_rootLayer.get();
3804 }
3805
3806 void WebViewImpl::updateThumbnailViewLayer()
3807 {
3808     _WKThumbnailView *thumbnailView = m_thumbnailView;
3809     ASSERT(thumbnailView);
3810
3811     if (thumbnailView._waitingForSnapshot && [m_view window])
3812         reparentLayerTreeInThumbnailView();
3813 }
3814
3815 void WebViewImpl::setInspectorAttachmentView(NSView *newView)
3816 {
3817     NSView *oldView = m_inspectorAttachmentView.get();
3818     if (oldView == newView)
3819         return;
3820
3821     m_inspectorAttachmentView = newView;
3822     m_page->inspector()->attachmentViewDidChange(oldView ? oldView : m_view.getAutoreleased(), newView ? newView : m_view.getAutoreleased());
3823 }
3824
3825 NSView *WebViewImpl::inspectorAttachmentView()
3826 {
3827     NSView *attachmentView = m_inspectorAttachmentView.get();
3828     return attachmentView ? attachmentView : m_view.getAutoreleased();
3829 }
3830
3831 _WKRemoteObjectRegistry *WebViewImpl::remoteObjectRegistry()
3832 {
3833     if (!m_remoteObjectRegistry) {
3834         m_remoteObjectRegistry = adoptNS([[_WKRemoteObjectRegistry alloc] _initWithWebPageProxy:m_page]);
3835         m_page->process().processPool().addMessageReceiver(Messages::RemoteObjectRegistry::messageReceiverName(), m_page->pageID(), [m_remoteObjectRegistry remoteObjectRegistry]);
3836     }
3837
3838     return m_remoteObjectRegistry.get();
3839 }
3840
3841 ALLOW_DEPRECATED_DECLARATIONS_BEGIN
3842 WKBrowsingContextController *WebViewImpl::browsingContextController()
3843 {
3844     if (!m_browsingContextController)
3845         m_browsingContextController = adoptNS([[WKBrowsingContextController alloc] _initWithPageRef:toAPI(m_page.ptr())]);
3846
3847     return m_browsingContextController.get();
3848 }
3849 ALLOW_DEPRECATED_DECLARATIONS_END
3850 #endif // WK_API_ENABLED
3851
3852 #if ENABLE(DRAG_SUPPORT)
3853 void WebViewImpl::draggedImage(NSImage *, CGPoint endPoint, NSDragOperation operation)
3854 {
3855     sendDragEndToPage(endPoint, operation);
3856 }
3857
3858 void WebViewImpl::sendDragEndToPage(CGPoint endPoint, NSDragOperation operation)
3859 {
3860     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
3861     NSPoint windowImageLoc = [[m_view window] convertScreenToBase:NSPointFromCGPoint(endPoint)];
3862     ALLOW_DEPRECATED_DECLARATIONS_END
3863     NSPoint windowMouseLoc = windowImageLoc;
3864
3865     // Prevent queued mouseDragged events from coming after the drag and fake mouseUp event.
3866     m_ignoresMouseDraggedEvents = true;
3867
3868     m_page->dragEnded(WebCore::IntPoint(windowMouseLoc), WebCore::IntPoint(WebCore::globalPoint(windowMouseLoc, [m_view window])), operation);
3869 }
3870
3871 static WebCore::DragApplicationFlags applicationFlagsForDrag(NSView *view, id <NSDraggingInfo> draggingInfo)
3872 {
3873     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer));
3874     uint32_t flags = 0;
3875     if ([NSApp modalWindow])
3876         flags = WebCore::DragApplicationIsModal;
3877     if (view.window.attachedSheet)
3878         flags |= WebCore::DragApplicationHasAttachedSheet;
3879     if (draggingInfo.draggingSource == view)
3880         flags |= WebCore::DragApplicationIsSource;
3881     if ([NSApp currentEvent].modifierFlags & NSEventModifierFlagOption)
3882         flags |= WebCore::DragApplicationIsCopyKeyDown;
3883     return static_cast<WebCore::DragApplicationFlags>(flags);
3884
3885 }
3886
3887 NSDragOperation WebViewImpl::draggingEntered(id <NSDraggingInfo> draggingInfo)
3888 {
3889     WebCore::IntPoint client([m_view convertPoint:draggingInfo.draggingLocation fromView:nil]);
3890     WebCore::IntPoint global(WebCore::globalPoint(draggingInfo.draggingLocation, [m_view window]));
3891 #if WK_API_ENABLED
3892     auto dragDestinationAction = static_cast<WebCore::DragDestinationAction>([m_view _web_dragDestinationActionForDraggingInfo:draggingInfo]);
3893 #else
3894     auto dragDestinationAction = WebCore::DragDestinationActionAny;
3895 #endif
3896     WebCore::DragData dragData(draggingInfo, client, global, static_cast<WebCore::DragOperation>(draggingInfo.draggingSourceOperationMask), applicationFlagsForDrag(m_view.getAutoreleased(), draggingInfo), dragDestinationAction);
3897
3898     m_page->resetCurrentDragInformation();
3899     m_page->dragEntered(dragData, draggingInfo.draggingPasteboard.name);
3900     m_initialNumberOfValidItemsForDrop = draggingInfo.numberOfValidItemsForDrop;
3901     return NSDragOperationCopy;
3902 }
3903
3904 NSDragOperation WebViewImpl::draggingUpdated(id <NSDraggingInfo> draggingInfo)
3905 {
3906     WebCore::IntPoint client([m_view convertPoint:draggingInfo.draggingLocation fromView:nil]);
3907     WebCore::IntPoint global(WebCore::globalPoint(draggingInfo.draggingLocation, [m_view window]));
3908 #if WK_API_ENABLED
3909     auto dragDestinationAction = static_cast<WebCore::DragDestinationAction>([m_view _web_dragDestinationActionForDraggingInfo:draggingInfo]);
3910 #else
3911     auto dragDestinationAction = WebCore::DragDestinationActionAny;
3912 #endif
3913     WebCore::DragData dragData(draggingInfo, client, global, static_cast<WebCore::DragOperation>(draggingInfo.draggingSourceOperationMask), applicationFlagsForDrag(m_view.getAutoreleased(), draggingInfo), dragDestinationAction);
3914     m_page->dragUpdated(dragData, draggingInfo.draggingPasteboard.name);
3915
3916     NSInteger numberOfValidItemsForDrop = m_page->currentDragNumberOfFilesToBeAccepted();
3917
3918     if (m_page->currentDragOperation() == WebCore::DragOperationNone)
3919         numberOfValidItemsForDrop = m_initialNumberOfValidItemsForDrop;
3920
3921     NSDraggingFormation draggingFormation = NSDraggingFormationNone;
3922     if (m_page->currentDragIsOverFileInput() && numberOfValidItemsForDrop > 0)
3923         draggingFormation = NSDraggingFormationList;
3924
3925     if (draggingInfo.numberOfValidItemsForDrop != numberOfValidItemsForDrop)
3926         [draggingInfo setNumberOfValidItemsForDrop:numberOfValidItemsForDrop];
3927     if (draggingInfo.draggingFormation != draggingFormation)
3928         [draggingInfo setDraggingFormation:draggingFormation];
3929
3930     return m_page->currentDragOperation();
3931 }
3932
3933 void WebViewImpl::draggingExited(id <NSDraggingInfo> draggingInfo)
3934 {
3935     WebCore::IntPoint client([m_view convertPoint:draggingInfo.draggingLocation fromView:nil]);
3936     WebCore::IntPoint global(WebCore::globalPoint(draggingInfo.draggingLocation, [m_view window]));
3937     WebCore::DragData dragData(draggingInfo, client, global, static_cast<WebCore::DragOperation>(draggingInfo.draggingSourceOperationMask), applicationFlagsForDrag(m_view.getAutoreleased(), draggingInfo));
3938     m_page->dragExited(dragData, draggingInfo.draggingPasteboard.name);
3939     m_page->resetCurrentDragInformation();
3940     draggingInfo.numberOfValidItemsForDrop = m_initialNumberOfValidItemsForDrop;
3941     m_initialNumberOfValidItemsForDrop = 0;
3942 }
3943
3944 bool WebViewImpl::prepareForDragOperation(id <NSDraggingInfo>)
3945 {
3946     return true;
3947 }
3948
3949 bool WebViewImpl::performDragOperation(id <NSDraggingInfo> draggingInfo)
3950 {
3951     WebCore::IntPoint client([m_view convertPoint:draggingInfo.draggingLocation fromView:nil]);
3952     WebCore::IntPoint global(WebCore::globalPoint(draggingInfo.draggingLocation, [m_view window]));
3953     WebCore::DragData *dragData = new WebCore::DragData(draggingInfo, client, global, static_cast<WebCore::DragOperation>(draggingInfo.draggingSourceOperationMask), applicationFlagsForDrag(m_view.getAutoreleased(), draggingInfo));
3954
3955     NSArray *types = draggingInfo.draggingPasteboard.types;
3956     SandboxExtension::Handle sandboxExtensionHandle;
3957     SandboxExtension::HandleArray sandboxExtensionForUpload;
3958
3959     if (![types containsObject:PasteboardTypes::WebArchivePboardType] && [types containsObject:WebCore::legacyFilesPromisePasteboardType()]) {
3960         
3961         // FIXME: legacyFilesPromisePasteboardType() contains UTIs, not path names. Also, it's not
3962         // guaranteed that the count of UTIs equals the count of files, since some clients only write
3963         // unique UTIs.
3964         NSArray *files = [draggingInfo.draggingPasteboard propertyListForType:WebCore::legacyFilesPromisePasteboardType()];
3965         if (![files isKindOfClass:[NSArray class]]) {
3966             delete dragData;
3967             return false;
3968         }
3969
3970         NSString *dropDestinationPath = FileSystem::createTemporaryDirectory(@"WebKitDropDestination");
3971         if (!dropDestinationPath) {
3972             delete dragData;
3973             return false;
3974         }
3975
3976         size_t fileCount = files.count;
3977         Vector<String> *fileNames = new Vector<String>;
3978         NSURL *dropDestination = [NSURL fileURLWithPath:dropDestinationPath isDirectory:YES];
3979         String pasteboardName = draggingInfo.draggingPasteboard.name;
3980         [draggingInfo enumerateDraggingItemsWithOptions:0 forView:m_view.getAutoreleased() classes:@[[NSFilePromiseReceiver class]] searchOptions:@{ } usingBlock:^(NSDraggingItem *draggingItem, NSInteger idx, BOOL *stop) {
3981             NSFilePromiseReceiver *item = draggingItem.item;
3982             NSDictionary *options = @{ };
3983
3984             RetainPtr<NSOperationQueue> queue = adoptNS([NSOperationQueue new]);
3985             [item receivePromisedFilesAtDestination:dropDestination options:options operationQueue:queue.get() reader:^(NSURL *fileURL, NSError *errorOrNil) {
3986                 if (errorOrNil)
3987                     return;
3988
3989                 dispatch_async(dispatch_get_main_queue(), [this, path = RetainPtr<NSString>(fileURL.path), fileNames, fileCount, dragData, pasteboardName] {
3990                     fileNames->append(path.get());
3991                     if (fileNames->size() == fileCount) {
3992                         SandboxExtension::Handle sandboxExtensionHandle;
3993                         SandboxExtension::HandleArray sandboxExtensionForUpload;
3994
3995                         m_page->createSandboxExtensionsIfNeeded(*fileNames, sandboxExtensionHandle, sandboxExtensionForUpload);
3996                         dragData->setFileNames(*fileNames);
3997                         m_page->performDragOperation(*dragData, pasteboardName, WTFMove(sandboxExtensionHandle), WTFMove(sandboxExtensionForUpload));
3998                         delete dragData;
3999                         delete fileNames;
4000                     }
4001                 });
4002             }];
4003         }];
4004
4005         return true;
4006     }
4007
4008     if ([types containsObject:WebCore::legacyFilenamesPasteboardType()]) {
4009         NSArray *files = [draggingInfo.draggingPasteboard propertyListForType:WebCore::legacyFilenamesPasteboardType()];
4010         if (![files isKindOfClass:[NSArray class]]) {
4011             delete dragData;
4012             return false;
4013         }
4014         
4015         Vector<String> fileNames;
4016         
4017         for (NSString *file in files)
4018             fileNames.append(file);
4019         m_page->createSandboxExtensionsIfNeeded(fileNames, sandboxExtensionHandle, sandboxExtensionForUpload);
4020     }
4021
4022     m_page->performDragOperation(*dragData, draggingInfo.draggingPasteboard.name, WTFMove(sandboxExtensionHandle), WTFMove(sandboxExtensionForUpload));
4023     delete dragData;
4024
4025     return true;
4026 }
4027
4028 NSView *WebViewImpl::hitTestForDragTypes(CGPoint point, NSSet *types)
4029 {
4030     // This code is needed to support drag and drop when the drag types cannot be matched.
4031     // This is the case for elements that do not place content
4032     // in the drag pasteboard automatically when the drag start (i.e. dragging a DIV element).
4033     if ([[m_view superview] mouse:NSPointFromCGPoint(point) inRect:[m_view frame]])
4034         return m_view.getAutoreleased();
4035     return nil;
4036 }
4037
4038 void WebViewImpl::registerDraggedTypes()
4039 {
4040     auto types = adoptNS([[NSMutableSet alloc] initWithArray:PasteboardTypes::forEditing()]);
4041     [types addObjectsFromArray:PasteboardTypes::forURL()];
4042     [types addObject:PasteboardTypes::WebDummyPboardType];
4043     [m_view registerForDraggedTypes:[types allObjects]];
4044 }
4045
4046 NSString *WebViewImpl::fileNameForFilePromiseProvider(NSFilePromiseProvider *provider, NSString *)
4047 {
4048     id userInfo = provider.userInfo;
4049     if (![userInfo isKindOfClass:[WKPromisedAttachmentContext class]])
4050         return nil;
4051
4052     return [(WKPromisedAttachmentContext *)userInfo fileName];
4053 }
4054
4055 static NSError *webKitUnknownError()
4056 {
4057 #if WK_API_ENABLED
4058     return [NSError errorWithDomain:WKErrorDomain code:WKErrorUnknown userInfo:nil];
4059 #else
4060     return [NSError errorWithDomain:@"WKErrorDomain" code:1 userInfo:nil];
4061 #endif
4062 }
4063
4064 void WebViewImpl::didPerformDragOperation(bool handled)
4065 {
4066 #if WK_API_ENABLED
4067     [m_view _web_didPerformDragOperation:handled];
4068 #else
4069     UNUSED_PARAM(handled);
4070 #endif
4071 }
4072
4073 void WebViewImpl::writeToURLForFilePromiseProvider(NSFilePromiseProvider *provider, NSURL *fileURL, void(^completionHandler)(NSError *))
4074 {
4075     id userInfo = provider.userInfo;
4076     if (![userInfo isKindOfClass:[WKPromisedAttachmentContext class]]) {
4077         completionHandler(webKitUnknownError());
4078         return;
4079     }
4080
4081     WKPromisedAttachmentContext *info = (WKPromisedAttachmentContext *)userInfo;
4082     auto attachment = m_page->attachmentForIdentifier(info.attachmentIdentifier);
4083     if (NSFileWrapper *fileWrapper = attachment ? attachment->fileWrapper() : nil) {
4084         NSError *attachmentWritingError = nil;
4085         if ([fileWrapper writeToURL:fileURL options:0 originalContentsURL:nil error:&attachmentWritingError])
4086             completionHandler(nil);
4087         else
4088             completionHandler(attachmentWritingError);
4089         return;
4090     }
4091
4092     URL blobURL { info.blobURL };
4093     if (blobURL.isEmpty()) {
4094         completionHandler(webKitUnknownError());
4095         return;
4096     }
4097
4098     completionHandler(webKitUnknownError());
4099 }
4100
4101 NSDragOperation WebViewImpl::dragSourceOperationMask(NSDraggingSession *, NSDraggingContext context)
4102 {
4103     if (context == NSDraggingContextOutsideApplication || m_page->currentDragIsOverFileInput())
4104         return NSDragOperationCopy;
4105     return NSDragOperationGeneric | NSDragOperationMove | NSDragOperationCopy;
4106 }
4107
4108 void WebViewImpl::draggingSessionEnded(NSDraggingSession *, NSPoint endPoint, NSDragOperation operation)
4109 {
4110     sendDragEndToPage(NSPointToCGPoint(endPoint), operation);
4111 }
4112
4113 #endif // ENABLE(DRAG_SUPPORT)
4114
4115 void WebViewImpl::startWindowDrag()
4116 {
4117     [[m_view window] performWindowDragWithEvent:m_lastMouseDownEvent.get()];
4118 }
4119
4120 void WebViewImpl::startDrag(const WebCore::DragItem& item, const ShareableBitmap::Handle& dragImageHandle)
4121 {
4122     auto dragImageAsBitmap = ShareableBitmap::create(dragImageHandle);
4123     if (!dragImageAsBitmap) {
4124         m_page->dragCancelled();
4125         return;
4126     }
4127
4128     auto dragCGImage = dragImageAsBitmap->makeCGImage();
4129     auto dragNSImage = adoptNS([[NSImage alloc] initWithCGImage:dragCGImage.get() size:dragImageAsBitmap->size()]);
4130
4131     WebCore::IntSize size([dragNSImage size]);
4132     size.scale(1.0 / m_page->deviceScaleFactor());
4133     [dragNSImage setSize:size];
4134
4135     // The call below could release the view.
4136     auto protector = m_view.get();
4137     auto clientDragLocation = item.dragLocationInWindowCoordinates;
4138     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
4139     NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
4140     ALLOW_DEPRECATED_DECLARATIONS_END
4141
4142     if (auto& info = item.promisedAttachmentInfo) {
4143         N