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