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