[Mac WK2] WebViewImpl should hold a weak pointer to its WKWebView or WKView
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 8 Aug 2017 20:45:21 +0000 (20:45 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 8 Aug 2017 20:45:21 +0000 (20:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=175302
<rdar://problem/33762116>

Reviewed by Tim Horton.

Source/WebKit:

Refactor WebViewImpl's m_view from a raw pointer to a WeakObjCPtr to ensure that it is automatically cleared out
when the WKWebView or WKView are destroyed, and also changes several places where we implicitly block capture
the WebViewImpl to only capture a WeakPtr to the WebViewImpl. Most of the changes here are boilerplate
adjustments for how m_view is now a weak pointer.

Test: WKWebViewMacEditingTests.DoNotCrashWhenInterpretingKeyEventWhileDeallocatingView.

* Shared/mac/WeakObjCPtr.h:
(WebKit::WeakObjCPtr::operator ValueType * const):
* UIProcess/Cocoa/WebViewImpl.h:
* UIProcess/Cocoa/WebViewImpl.mm:
(WebKit::WebViewImpl::updateTouchBar):
(WebKit::WebViewImpl::updateMediaTouchBar):
(WebKit::WebViewImpl::WebViewImpl):
(WebKit::WebViewImpl::~WebViewImpl):
(WebKit::WebViewImpl::window):
(WebKit::WebViewImpl::resignFirstResponder):
(WebKit::WebViewImpl::isFocused const):
(WebKit::WebViewImpl::renewGState):
(WebKit::WebViewImpl::setFrameAndScrollBy):
(WebKit::WebViewImpl::updateWindowAndViewFrames):
(WebKit::WebViewImpl::updateLayer):
(WebKit::WebViewImpl::printOperationWithPrintInfo):
(WebKit::WebViewImpl::updateContentInsetsIfAutomatic):
(WebKit::WebViewImpl::setLayoutMode):
(WebKit::WebViewImpl::intrinsicDeviceScaleFactor const):
(WebKit::WebViewImpl::windowDidBecomeKey):
(WebKit::WebViewImpl::windowDidResignKey):
(WebKit::WebViewImpl::windowDidChangeScreen):
(WebKit::WebViewImpl::mightBeginDragWhileInactive):
(WebKit::WebViewImpl::acceptsFirstMouse):
(WebKit::WebViewImpl::shouldDelayWindowOrderingForEvent):
(WebKit::WebViewImpl::windowResizeMouseLocationIsInVisibleScrollerThumb):
(WebKit::WebViewImpl::viewWillMoveToWindow):
(WebKit::WebViewImpl::viewDidMoveToWindow):
(WebKit::WebViewImpl::viewDidChangeBackingProperties):
(WebKit::WebViewImpl::hitTest):
(WebKit::WebViewImpl::postFakeMouseMovedEventForFlagsChangedEvent):
(WebKit::WebViewImpl::colorSpace):
(WebKit::WebViewImpl::prepareForMoveToWindow):
(WebKit::WebViewImpl::notifyInputContextAboutDiscardedComposition):
(WebKit::WebViewImpl::pressureChangeWithEvent):
(WebKit::WebViewImpl::fullScreenWindowController):
(WebKit::WebViewImpl::executeSavedCommandBySelector):
(WebKit::WebViewImpl::validRequestorForSendAndReturnTypes):
(WebKit::WebViewImpl::handleRequestedCandidates):
(WebKit::WebViewImpl::preferencesDidChange):
(WebKit::WebViewImpl::setTextIndicator):
(WebKit::WebViewImpl::dismissContentRelativeChildWindowsFromViewOnly):
(WebKit::WebViewImpl::accessibilityRegisterUIProcessTokens):
(WebKit::WebViewImpl::sendToolTipMouseExited):
(WebKit::WebViewImpl::sendToolTipMouseEntered):
(WebKit::WebViewImpl::toolTipChanged):
(WebKit::WebViewImpl::setAcceleratedCompositingRootLayer):
(WebKit::WebViewImpl::updateThumbnailViewLayer):
(WebKit::WebViewImpl::setInspectorAttachmentView):
(WebKit::WebViewImpl::inspectorAttachmentView):
(WebKit::WebViewImpl::draggedImage):
(WebKit::WebViewImpl::draggingEntered):
(WebKit::WebViewImpl::draggingUpdated):
(WebKit::WebViewImpl::draggingExited):
(WebKit::WebViewImpl::performDragOperation):
(WebKit::WebViewImpl::hitTestForDragTypes):
(WebKit::WebViewImpl::startWindowDrag):
(WebKit::WebViewImpl::dragImageForView):
(WebKit::WebViewImpl::setPromisedDataForImage):
(WebKit::WebViewImpl::setPromisedDataForAttachment):
(WebKit::WebViewImpl::takeViewSnapshot):
(WebKit::WebViewImpl::scrollWheel):
(WebKit::WebViewImpl::magnifyWithEvent):
(WebKit::WebViewImpl::rotateWithEvent):
(WebKit::WebViewImpl::doneWithKeyEvent):
(WebKit::WebViewImpl::interpretKeyEvent):
(WebKit::WebViewImpl::firstRectForCharacterRange):
(WebKit::WebViewImpl::characterIndexForPoint):
(WebKit::WebViewImpl::performKeyEquivalent):
(WebKit::WebViewImpl::keyUp):
(WebKit::WebViewImpl::keyDown):
(WebKit::WebViewImpl::mouseMoved):
(WebKit::WebViewImpl::windowIsFrontWindowUnderMouse):
(WebKit::WebViewImpl::userInterfaceLayoutDirection):

Tools:

Adds a new unit test checking that delayed event processing in text input context does not cause unwanted behaviors.
See WebKit ChangeLog for more details.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/TestWebKitAPI/mac/AppKitSPI.h: Renamed from Tools/TestWebKitAPI/Tests/TestWebKitAPI/mac/NSTextInputClientSPI.h.
* TestWebKitAPI/Tests/mac/WKWebViewMacEditingTests.mm: Renamed from Tools/TestWebKitAPI/Tests/mac/WKWebViewSelectionTests.mm.
(-[SlowTextInputContext handleEventByInputMethod:completionHandler:]):
(-[SlowTextInputContext handleEvent:completionHandler:]):
(-[SlowInputWebView inputContext]):
(-[SlowInputWebView _web_superInputContext]):
(TEST):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@220418 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit/ChangeLog
Source/WebKit/Shared/mac/WeakObjCPtr.h
Source/WebKit/UIProcess/Cocoa/WebViewImpl.h
Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/TestWebKitAPI/mac/AppKitSPI.h [moved from Tools/TestWebKitAPI/Tests/TestWebKitAPI/mac/NSTextInputClientSPI.h with 85% similarity]
Tools/TestWebKitAPI/Tests/mac/WKWebViewMacEditingTests.mm [moved from Tools/TestWebKitAPI/Tests/mac/WKWebViewSelectionTests.mm with 56% similarity]

index c2cd79d..7d8b4bf 100644 (file)
@@ -1,3 +1,93 @@
+2017-08-08  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [Mac WK2] WebViewImpl should hold a weak pointer to its WKWebView or WKView
+        https://bugs.webkit.org/show_bug.cgi?id=175302
+        <rdar://problem/33762116>
+
+        Reviewed by Tim Horton.
+
+        Refactor WebViewImpl's m_view from a raw pointer to a WeakObjCPtr to ensure that it is automatically cleared out
+        when the WKWebView or WKView are destroyed, and also changes several places where we implicitly block capture
+        the WebViewImpl to only capture a WeakPtr to the WebViewImpl. Most of the changes here are boilerplate
+        adjustments for how m_view is now a weak pointer.
+
+        Test: WKWebViewMacEditingTests.DoNotCrashWhenInterpretingKeyEventWhileDeallocatingView.
+
+        * Shared/mac/WeakObjCPtr.h:
+        (WebKit::WeakObjCPtr::operator ValueType * const):
+        * UIProcess/Cocoa/WebViewImpl.h:
+        * UIProcess/Cocoa/WebViewImpl.mm:
+        (WebKit::WebViewImpl::updateTouchBar):
+        (WebKit::WebViewImpl::updateMediaTouchBar):
+        (WebKit::WebViewImpl::WebViewImpl):
+        (WebKit::WebViewImpl::~WebViewImpl):
+        (WebKit::WebViewImpl::window):
+        (WebKit::WebViewImpl::resignFirstResponder):
+        (WebKit::WebViewImpl::isFocused const):
+        (WebKit::WebViewImpl::renewGState):
+        (WebKit::WebViewImpl::setFrameAndScrollBy):
+        (WebKit::WebViewImpl::updateWindowAndViewFrames):
+        (WebKit::WebViewImpl::updateLayer):
+        (WebKit::WebViewImpl::printOperationWithPrintInfo):
+        (WebKit::WebViewImpl::updateContentInsetsIfAutomatic):
+        (WebKit::WebViewImpl::setLayoutMode):
+        (WebKit::WebViewImpl::intrinsicDeviceScaleFactor const):
+        (WebKit::WebViewImpl::windowDidBecomeKey):
+        (WebKit::WebViewImpl::windowDidResignKey):
+        (WebKit::WebViewImpl::windowDidChangeScreen):
+        (WebKit::WebViewImpl::mightBeginDragWhileInactive):
+        (WebKit::WebViewImpl::acceptsFirstMouse):
+        (WebKit::WebViewImpl::shouldDelayWindowOrderingForEvent):
+        (WebKit::WebViewImpl::windowResizeMouseLocationIsInVisibleScrollerThumb):
+        (WebKit::WebViewImpl::viewWillMoveToWindow):
+        (WebKit::WebViewImpl::viewDidMoveToWindow):
+        (WebKit::WebViewImpl::viewDidChangeBackingProperties):
+        (WebKit::WebViewImpl::hitTest):
+        (WebKit::WebViewImpl::postFakeMouseMovedEventForFlagsChangedEvent):
+        (WebKit::WebViewImpl::colorSpace):
+        (WebKit::WebViewImpl::prepareForMoveToWindow):
+        (WebKit::WebViewImpl::notifyInputContextAboutDiscardedComposition):
+        (WebKit::WebViewImpl::pressureChangeWithEvent):
+        (WebKit::WebViewImpl::fullScreenWindowController):
+        (WebKit::WebViewImpl::executeSavedCommandBySelector):
+        (WebKit::WebViewImpl::validRequestorForSendAndReturnTypes):
+        (WebKit::WebViewImpl::handleRequestedCandidates):
+        (WebKit::WebViewImpl::preferencesDidChange):
+        (WebKit::WebViewImpl::setTextIndicator):
+        (WebKit::WebViewImpl::dismissContentRelativeChildWindowsFromViewOnly):
+        (WebKit::WebViewImpl::accessibilityRegisterUIProcessTokens):
+        (WebKit::WebViewImpl::sendToolTipMouseExited):
+        (WebKit::WebViewImpl::sendToolTipMouseEntered):
+        (WebKit::WebViewImpl::toolTipChanged):
+        (WebKit::WebViewImpl::setAcceleratedCompositingRootLayer):
+        (WebKit::WebViewImpl::updateThumbnailViewLayer):
+        (WebKit::WebViewImpl::setInspectorAttachmentView):
+        (WebKit::WebViewImpl::inspectorAttachmentView):
+        (WebKit::WebViewImpl::draggedImage):
+        (WebKit::WebViewImpl::draggingEntered):
+        (WebKit::WebViewImpl::draggingUpdated):
+        (WebKit::WebViewImpl::draggingExited):
+        (WebKit::WebViewImpl::performDragOperation):
+        (WebKit::WebViewImpl::hitTestForDragTypes):
+        (WebKit::WebViewImpl::startWindowDrag):
+        (WebKit::WebViewImpl::dragImageForView):
+        (WebKit::WebViewImpl::setPromisedDataForImage):
+        (WebKit::WebViewImpl::setPromisedDataForAttachment):
+        (WebKit::WebViewImpl::takeViewSnapshot):
+        (WebKit::WebViewImpl::scrollWheel):
+        (WebKit::WebViewImpl::magnifyWithEvent):
+        (WebKit::WebViewImpl::rotateWithEvent):
+        (WebKit::WebViewImpl::doneWithKeyEvent):
+        (WebKit::WebViewImpl::interpretKeyEvent):
+        (WebKit::WebViewImpl::firstRectForCharacterRange):
+        (WebKit::WebViewImpl::characterIndexForPoint):
+        (WebKit::WebViewImpl::performKeyEquivalent):
+        (WebKit::WebViewImpl::keyUp):
+        (WebKit::WebViewImpl::keyDown):
+        (WebKit::WebViewImpl::mouseMoved):
+        (WebKit::WebViewImpl::windowIsFrontWindowUnderMouse):
+        (WebKit::WebViewImpl::userInterfaceLayoutDirection):
+
 2017-08-08  Filip Pizlo  <fpizlo@apple.com>
 
         Baseline JIT should do caging
index 31fbab0..7cf000c 100644 (file)
@@ -95,6 +95,8 @@ public:
         return static_cast<ValueType *>(objc_loadWeak(const_cast<id*>(&m_weakReference)));
     }
 
+    explicit operator ValueType *() const { return getAutoreleased(); }
+
 private:
     id m_weakReference;
 };
index d4133b4..5776853 100644 (file)
@@ -31,6 +31,7 @@
 #include "PluginComplexTextInputState.h"
 #include "WKDragDestinationAction.h"
 #include "WKLayoutMode.h"
+#include "WeakObjCPtr.h"
 #include "WebPageProxy.h"
 #include "_WKOverlayScrollbarStyle.h"
 #include <WebCore/AVKitSPI.h>
@@ -600,7 +601,7 @@ private:
     void handleRequestedCandidates(NSInteger sequenceNumber, NSArray<NSTextCheckingResult *> *candidates);
 #endif
 
-    NSView <WebViewImplDelegate> *m_view;
+    WeakObjCPtr<NSView<WebViewImplDelegate>> m_view;
     std::unique_ptr<PageClient> m_pageClient;
     Ref<WebPageProxy> m_page;
 
index cacb856..530f47f 100644 (file)
@@ -889,7 +889,7 @@ void WebViewImpl::updateTouchBar()
             touchBar = [m_mediaTouchBarProvider respondsToSelector:@selector(touchBar)] ? [(id)m_mediaTouchBarProvider.get() touchBar] : [(id)m_mediaTouchBarProvider.get() touchBar];
     } else if ([m_mediaTouchBarProvider playbackControlsController]) {
         if (m_clientWantsMediaPlaybackControlsView) {
-            if ([m_view respondsToSelector:@selector(_web_didRemoveMediaControlsManager)] && m_view == m_view.window.firstResponder)
+            if ([m_view respondsToSelector:@selector(_web_didRemoveMediaControlsManager)] && m_view.getAutoreleased() == [m_view window].firstResponder)
                 [m_view _web_didRemoveMediaControlsManager];
         }
         [m_mediaTouchBarProvider setPlaybackControlsController:nil];
@@ -1202,7 +1202,7 @@ void WebViewImpl::updateMediaTouchBar()
         return;
     }
 
-    if (m_playbackControlsManager && m_view == m_view.window.firstResponder && [m_view respondsToSelector:@selector(_web_didAddMediaControlsManager:)])
+    if (m_playbackControlsManager && m_view.getAutoreleased() == [m_view window].firstResponder && [m_view respondsToSelector:@selector(_web_didAddMediaControlsManager:)])
         [m_view _web_didAddMediaControlsManager:m_mediaPlaybackControlsView.get()];
 #endif
 }
@@ -1272,23 +1272,23 @@ WebViewImpl::WebViewImpl(NSView <WebViewImplDelegate> *view, WKWebView *outerWeb
     , m_weakPtrFactory(this)
     , m_needsViewFrameInWindowCoordinates(m_page->preferences().pluginsEnabled())
     , m_intrinsicContentSize(CGSizeMake(NSViewNoInstrinsicMetric, NSViewNoInstrinsicMetric))
-    , m_layoutStrategy([WKViewLayoutStrategy layoutStrategyWithPage:m_page view:m_view viewImpl:*this mode:kWKLayoutModeViewSize])
+    , m_layoutStrategy([WKViewLayoutStrategy layoutStrategyWithPage:m_page view:view viewImpl:*this mode:kWKLayoutModeViewSize])
     , m_undoTarget(adoptNS([[WKEditorUndoTargetObjC alloc] init]))
     , m_windowVisibilityObserver(adoptNS([[WKWindowVisibilityObserver alloc] initWithView:view impl:*this]))
     , m_accessibilitySettingsObserver(adoptNS([[WKAccessibilitySettingsObserver alloc] initWithImpl:*this]))
-    , m_primaryTrackingArea(adoptNS([[NSTrackingArea alloc] initWithRect:m_view.frame options:trackingAreaOptions() owner:m_view userInfo:nil]))
+    , m_primaryTrackingArea(adoptNS([[NSTrackingArea alloc] initWithRect:view.frame options:trackingAreaOptions() owner:view userInfo:nil]))
 {
     static_cast<PageClientImpl&>(*m_pageClient).setImpl(*this);
 
     [NSApp registerServicesMenuSendTypes:PasteboardTypes::forSelection() returnTypes:PasteboardTypes::forEditing()];
 
-    [m_view addTrackingArea:m_primaryTrackingArea.get()];
+    [view addTrackingArea:m_primaryTrackingArea.get()];
 
     m_page->setIntrinsicDeviceScaleFactor(intrinsicDeviceScaleFactor());
 
     if (Class gestureClass = NSClassFromString(@"NSImmediateActionGestureRecognizer")) {
         m_immediateActionGestureRecognizer = adoptNS([(NSImmediateActionGestureRecognizer *)[gestureClass alloc] init]);
-        m_immediateActionController = adoptNS([[WKImmediateActionController alloc] initWithPage:m_page view:m_view viewImpl:*this recognizer:m_immediateActionGestureRecognizer.get()]);
+        m_immediateActionController = adoptNS([[WKImmediateActionController alloc] initWithPage:m_page view:view viewImpl:*this recognizer:m_immediateActionGestureRecognizer.get()]);
         [m_immediateActionGestureRecognizer setDelegate:m_immediateActionController.get()];
         [m_immediateActionGestureRecognizer setDelaysPrimaryMouseButtonEvents:NO];
     }
@@ -1299,13 +1299,13 @@ WebViewImpl::WebViewImpl(NSView <WebViewImplDelegate> *view, WKWebView *outerWeb
 
     registerDraggedTypes();
 
-    m_view.wantsLayer = YES;
+    view.wantsLayer = YES;
 
     // Explicitly set the layer contents placement so AppKit will make sure that our layer has masksToBounds set to YES.
-    m_view.layerContentsPlacement = NSViewLayerContentsPlacementTopLeft;
+    view.layerContentsPlacement = NSViewLayerContentsPlacementTopLeft;
 
 #if ENABLE(FULLSCREEN_API) && WK_API_ENABLED
-    m_page->setFullscreenClient(std::make_unique<WebKit::FullscreenClient>((WKWebView *)m_view));
+    m_page->setFullscreenClient(std::make_unique<WebKit::FullscreenClient>(view));
 #endif
 
     WebProcessPool::statistics().wkViewCount++;
@@ -1329,7 +1329,7 @@ WebViewImpl::~WebViewImpl()
 
     [m_layoutStrategy invalidate];
 
-    [m_immediateActionController willDestroyView:m_view];
+    [m_immediateActionController willDestroyView:m_view.getAutoreleased()];
 
 #if HAVE(TOUCH_BAR)
     [m_textTouchBarItemController didDestroyView];
@@ -1347,7 +1347,7 @@ WebViewImpl::~WebViewImpl()
 
 NSWindow *WebViewImpl::window()
 {
-    return m_view.window;
+    return [m_view window];
 }
 
 void WebViewImpl::processDidExit()
@@ -1441,7 +1441,7 @@ bool WebViewImpl::resignFirstResponder()
     id nextResponder = [[m_view window] _newFirstResponderAfterResigning];
 
     // FIXME: This will probably need to change once WKWebView doesn't contain a WKView.
-    if ([nextResponder isKindOfClass:[WKWebView class]] && m_view.superview == nextResponder) {
+    if ([nextResponder isKindOfClass:[WKWebView class]] && [m_view superview] == nextResponder) {
         m_willBecomeFirstResponderAgain = true;
         return true;
     }
@@ -1472,7 +1472,7 @@ bool WebViewImpl::isFocused() const
         return true;
     if (m_inResignFirstResponder)
         return false;
-    return m_view.window.firstResponder == m_view;
+    return [m_view window].firstResponder == m_view.getAutoreleased();
 }
 
 void WebViewImpl::viewWillStartLiveResize()
@@ -1495,7 +1495,7 @@ void WebViewImpl::renewGState()
         dismissContentRelativeChildWindowsWithAnimation(false);
 
     // Update the view frame.
-    if (m_view.window)
+    if ([m_view window])
         updateWindowAndViewFrames();
 
     updateContentInsetsIfAutomatic();
@@ -1526,7 +1526,7 @@ void WebViewImpl::setFrameAndScrollBy(CGRect frame, CGSize offset)
     ASSERT(CGSizeEqualToSize(m_resizeScrollOffset, CGSizeZero));
 
     m_resizeScrollOffset = offset;
-    m_view.frame = NSRectFromCGRect(frame);
+    [m_view frame] = NSRectFromCGRect(frame);
 }
 
 void WebViewImpl::updateWindowAndViewFrames()
@@ -1550,7 +1550,7 @@ void WebViewImpl::updateWindowAndViewFrames()
         NSPoint accessibilityPosition = NSZeroPoint;
 
         if (weakThis->m_needsViewFrameInWindowCoordinates)
-            viewFrameInWindowCoordinates = [weakThis->m_view convertRect:weakThis->m_view.frame toView:nil];
+            viewFrameInWindowCoordinates = [weakThis->m_view convertRect:[weakThis->m_view frame] toView:nil];
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
@@ -1600,7 +1600,7 @@ void WebViewImpl::setDrawingAreaSize(CGSize size)
 
 void WebViewImpl::updateLayer()
 {
-    m_view.layer.backgroundColor = CGColorGetConstantColor(drawsBackground() ? kCGColorWhite : kCGColorClear);
+    [m_view layer].backgroundColor = CGColorGetConstantColor(drawsBackground() ? kCGColorWhite : kCGColorClear);
 
     // If asynchronous geometry updates have been sent by forceAsyncDrawingAreaSizeUpdate,
     // then subsequent calls to setFrameSize should not result in us waiting for the did
@@ -1627,7 +1627,7 @@ NSPrintOperation *WebViewImpl::printOperationWithPrintInfo(NSPrintInfo *printInf
 
     // FIXME: If the frame cannot be printed (e.g. if it contains an encrypted PDF that disallows
     // printing), this function should return nil.
-    RetainPtr<WKPrintingView> printingView = adoptNS([[WKPrintingView alloc] initWithFrameProxy:&frame view:m_view]);
+    RetainPtr<WKPrintingView> printingView = adoptNS([[WKPrintingView alloc] initWithFrameProxy:&frame view:m_view.getAutoreleased()]);
     // NSPrintOperation takes ownership of the view.
     NSPrintOperation *printOperation = [NSPrintOperation printOperationWithView:printingView.get() printInfo:printInfo];
     [printOperation setCanSpawnSeparateThread:YES];
@@ -1647,7 +1647,7 @@ void WebViewImpl::updateContentInsetsIfAutomatic()
     if (!m_automaticallyAdjustsContentInsets)
         return;
 
-    NSWindow *window = m_view.window;
+    NSWindow *window = [m_view window];
     if ((window.styleMask & NSWindowStyleMaskFullSizeContentView) && !window.titlebarAppearsTransparent && ![m_view enclosingScrollView]) {
         NSRect contentLayoutRect = [m_view convertRect:window.contentLayoutRect fromView:nil];
         CGFloat newTopContentInset = NSMaxY(contentLayoutRect) - NSHeight(contentLayoutRect);
@@ -1794,7 +1794,7 @@ void WebViewImpl::setLayoutMode(WKLayoutMode layoutMode)
         return;
 
     [m_layoutStrategy willChangeLayoutStrategy];
-    m_layoutStrategy = [WKViewLayoutStrategy layoutStrategyWithPage:m_page view:m_view viewImpl:*this mode:layoutMode];
+    m_layoutStrategy = [WKViewLayoutStrategy layoutStrategyWithPage:m_page view:m_view.getAutoreleased() viewImpl:*this mode:layoutMode];
 }
 
 bool WebViewImpl::supportsArbitraryLayoutModes() const
@@ -1848,7 +1848,7 @@ float WebViewImpl::intrinsicDeviceScaleFactor() const
         return m_overrideDeviceScaleFactor;
     if (m_targetWindowForMovePreparation)
         return m_targetWindowForMovePreparation.backingScaleFactor;
-    if (NSWindow *window = m_view.window)
+    if (NSWindow *window = [m_view window])
         return window.backingScaleFactor;
     return [NSScreen mainScreen].backingScaleFactor;
 }
@@ -1865,7 +1865,7 @@ void WebViewImpl::windowDidOrderOnScreen()
 
 void WebViewImpl::windowDidBecomeKey(NSWindow *keyWindow)
 {
-    if (keyWindow == m_view.window || keyWindow == m_view.window.attachedSheet) {
+    if (keyWindow == [m_view window] || keyWindow == [m_view window].attachedSheet) {
 #if ENABLE(GAMEPAD)
         UIGamepadProvider::singleton().viewBecameActive(m_page.get());
 #endif
@@ -1876,7 +1876,7 @@ void WebViewImpl::windowDidBecomeKey(NSWindow *keyWindow)
 
 void WebViewImpl::windowDidResignKey(NSWindow *formerKeyWindow)
 {
-    if (formerKeyWindow == m_view.window || formerKeyWindow == m_view.window.attachedSheet) {
+    if (formerKeyWindow == [m_view window] || formerKeyWindow == [m_view window].attachedSheet) {
 #if ENABLE(GAMEPAD)
         UIGamepadProvider::singleton().viewBecameInactive(m_page.get());
 #endif
@@ -1916,7 +1916,7 @@ void WebViewImpl::windowDidChangeBackingProperties(CGFloat oldBackingScaleFactor
 
 void WebViewImpl::windowDidChangeScreen()
 {
-    NSWindow *window = m_targetWindowForMovePreparation ? m_targetWindowForMovePreparation : m_view.window;
+    NSWindow *window = m_targetWindowForMovePreparation ? m_targetWindowForMovePreparation : [m_view window];
     m_page->windowScreenDidChange([[[[window screen] deviceDescription] objectForKey:@"NSScreenNumber"] intValue]);
 }
 
@@ -1932,7 +1932,7 @@ void WebViewImpl::windowDidChangeOcclusionState()
 
 bool WebViewImpl::mightBeginDragWhileInactive()
 {
-    if (m_view.window.isKeyWindow)
+    if ([m_view window].isKeyWindow)
         return false;
 
     if (m_page->editorState().selectionIsNone || !m_page->editorState().selectionIsRange)
@@ -1969,7 +1969,7 @@ bool WebViewImpl::acceptsFirstMouse(NSEvent *event)
         return false;
 
     setLastMouseDownEvent(event);
-    bool result = m_page->acceptsFirstMouse(event.eventNumber, WebEventFactory::createWebMouseEvent(event, m_lastPressureEvent.get(), m_view));
+    bool result = m_page->acceptsFirstMouse(event.eventNumber, WebEventFactory::createWebMouseEvent(event, m_lastPressureEvent.get(), m_view.getAutoreleased()));
     setLastMouseDownEvent(nil);
     return result;
 }
@@ -1988,7 +1988,7 @@ bool WebViewImpl::shouldDelayWindowOrderingForEvent(NSEvent *event)
         return false;
 
     setLastMouseDownEvent(event);
-    bool result = m_page->shouldDelayWindowOrderingForEvent(WebEventFactory::createWebMouseEvent(event, m_lastPressureEvent.get(), m_view));
+    bool result = m_page->shouldDelayWindowOrderingForEvent(WebEventFactory::createWebMouseEvent(event, m_lastPressureEvent.get(), m_view.getAutoreleased()));
     setLastMouseDownEvent(nil);
     return result;
 }
@@ -1997,7 +1997,7 @@ bool WebViewImpl::windowResizeMouseLocationIsInVisibleScrollerThumb(CGPoint poin
 {
     NSPoint localPoint = [m_view convertPoint:NSPointFromCGPoint(point) fromView:nil];
     NSRect visibleThumbRect = NSRect(m_page->visibleScrollerThumbRect());
-    return NSMouseInRect(localPoint, visibleThumbRect, m_view.isFlipped);
+    return NSMouseInRect(localPoint, visibleThumbRect, [m_view isFlipped]);
 }
 
 void WebViewImpl::viewWillMoveToWindow(NSWindow *window)
@@ -2005,20 +2005,20 @@ void WebViewImpl::viewWillMoveToWindow(NSWindow *window)
     // If we're in the middle of preparing to move to a window, we should only be moved to that window.
     ASSERT(!m_targetWindowForMovePreparation || (m_targetWindowForMovePreparation == window));
 
-    NSWindow *currentWindow = m_view.window;
+    NSWindow *currentWindow = [m_view window];
     if (window == currentWindow)
         return;
 
     clearAllEditCommands();
 
-    NSWindow *stopObservingWindow = m_targetWindowForMovePreparation ? m_targetWindowForMovePreparation : m_view.window;
+    NSWindow *stopObservingWindow = m_targetWindowForMovePreparation ? m_targetWindowForMovePreparation : [m_view window];
     [m_windowVisibilityObserver stopObserving:stopObservingWindow];
     [m_windowVisibilityObserver startObserving:window];
 }
 
 void WebViewImpl::viewDidMoveToWindow()
 {
-    NSWindow *window = m_targetWindowForMovePreparation ? m_targetWindowForMovePreparation : m_view.window;
+    NSWindow *window = m_targetWindowForMovePreparation ? m_targetWindowForMovePreparation : [m_view window];
 
     if (window) {
         windowDidChangeScreen();
@@ -2073,7 +2073,7 @@ void WebViewImpl::viewDidMoveToWindow()
 
 void WebViewImpl::viewDidChangeBackingProperties()
 {
-    NSColorSpace *colorSpace = m_view.window.colorSpace;
+    NSColorSpace *colorSpace = [m_view window].colorSpace;
     if ([colorSpace isEqualTo:m_colorSpace.get()])
         return;
 
@@ -2101,7 +2101,7 @@ NSView *WebViewImpl::hitTest(CGPoint point)
 {
     NSView *hitView = [m_view _web_superHitTest:NSPointFromCGPoint(point)];
     if (hitView && hitView == m_layerHostingView)
-        hitView = m_view;
+        hitView = m_view.getAutoreleased();
 
     return hitView;
 }
@@ -2111,7 +2111,7 @@ void WebViewImpl::postFakeMouseMovedEventForFlagsChangedEvent(NSEvent *flagsChan
     NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSEventTypeMouseMoved location:flagsChangedEvent.window.mouseLocationOutsideOfEventStream
         modifierFlags:flagsChangedEvent.modifierFlags timestamp:flagsChangedEvent.timestamp windowNumber:flagsChangedEvent.windowNumber
         context:nullptr eventNumber:0 clickCount:0 pressure:0];
-    NativeWebMouseEvent webEvent(fakeEvent, m_lastPressureEvent.get(), m_view);
+    NativeWebMouseEvent webEvent(fakeEvent, m_lastPressureEvent.get(), m_view.getAutoreleased());
     m_page->handleMouseEvent(webEvent);
 }
 
@@ -2120,7 +2120,7 @@ ColorSpaceData WebViewImpl::colorSpace()
     if (!m_colorSpace) {
         if (m_targetWindowForMovePreparation)
             m_colorSpace = m_targetWindowForMovePreparation.colorSpace;
-        else if (NSWindow *window = m_view.window)
+        else if (NSWindow *window = [m_view window])
             m_colorSpace = window.colorSpace;
         else
             m_colorSpace = [NSScreen mainScreen].colorSpace;
@@ -2223,7 +2223,7 @@ void WebViewImpl::prepareForMoveToWindow(NSWindow *targetWindow, WTF::Function<v
         if (!weakThis)
             return;
 
-        ASSERT(weakThis->m_view.window == weakThis->m_targetWindowForMovePreparation);
+        ASSERT(weakThis->[m_view window] == weakThis->m_targetWindowForMovePreparation);
         weakThis->m_targetWindowForMovePreparation = nil;
     });
 
@@ -2273,7 +2273,7 @@ void WebViewImpl::notifyInputContextAboutDiscardedComposition()
     // <rdar://problem/9359055>: -discardMarkedText can only be called for active contexts.
     // FIXME: We fail to ever notify the input context if something (e.g. a navigation) happens while the window is not key.
     // This is not a problem when the window is key, because we discard marked text on resigning first responder.
-    if (![[m_view window] isKeyWindow] || m_view != [[m_view window] firstResponder])
+    if (![[m_view window] isKeyWindow] || m_view.getAutoreleased() != [[m_view window] firstResponder])
         return;
 
     LOG(TextInput, "-> discardMarkedText");
@@ -2416,7 +2416,7 @@ void WebViewImpl::pressureChangeWithEvent(NSEvent *event)
     if (event.phase != NSEventPhaseChanged && event.phase != NSEventPhaseBegan && event.phase != NSEventPhaseEnded)
         return;
 
-    NativeWebMouseEvent webEvent(event, m_lastPressureEvent.get(), m_view);
+    NativeWebMouseEvent webEvent(event, m_lastPressureEvent.get(), m_view.getAutoreleased());
     m_page->handleMouseEvent(webEvent);
 
     m_lastPressureEvent = event;
@@ -2432,7 +2432,7 @@ bool WebViewImpl::hasFullScreenWindowController() const
 WKFullScreenWindowController *WebViewImpl::fullScreenWindowController()
 {
     if (!m_fullScreenWindowController)
-        m_fullScreenWindowController = adoptNS([[WKFullScreenWindowController alloc] initWithWindow:createFullScreenWindow() webView:m_view page:m_page]);
+        m_fullScreenWindowController = adoptNS([[WKFullScreenWindowController alloc] initWithWindow:createFullScreenWindow() webView:m_view.getAutoreleased() page:m_page]);
 
     return m_fullScreenWindowController.get();
 }
@@ -2524,7 +2524,7 @@ bool WebViewImpl::executeSavedCommandBySelector(SEL selector)
     LOG(TextInput, "Executing previously saved command %s", sel_getName(selector));
     // The sink does two things: 1) Tells us if the responder went unhandled, and
     // 2) prevents any NSBeep; we don't ever want to beep here.
-    RetainPtr<WKResponderChainSink> sink = adoptNS([[WKResponderChainSink alloc] initWithResponderChain:m_view]);
+    RetainPtr<WKResponderChainSink> sink = adoptNS([[WKResponderChainSink alloc] initWithResponderChain:m_view.getAutoreleased()]);
     [m_view _web_superDoCommandBySelector:selector];
     [sink detach];
     return ![sink didReceiveUnhandledCommand];
@@ -2591,7 +2591,7 @@ id WebViewImpl::validRequestorForSendAndReturnTypes(NSString *sendType, NSString
         isValidReturnType = editorState.isContentRichlyEditable || [returnType isEqualToString:NSStringPboardType];
     }
     if (isValidSendType && isValidReturnType)
-        return m_view;
+        return m_view.getAutoreleased();
     return [[m_view nextResponder] validRequestorForSendType:sendType returnType:returnType];
 }
 
@@ -3037,7 +3037,7 @@ void WebViewImpl::handleRequestedCandidates(NSInteger sequenceNumber, NSArray<NS
     WebCore::IntRect offsetSelectionRect = postLayoutData.selectionClipRect;
     offsetSelectionRect.move(0, offsetSelectionRect.height());
 
-    [candidateListTouchBarItem() setCandidates:candidates forSelectedRange:selectedRange inString:postLayoutData.paragraphContextForCandidateRequest rect:offsetSelectionRect view:m_view completionHandler:nil];
+    [candidateListTouchBarItem() setCandidates:candidates forSelectedRange:selectedRange inString:postLayoutData.paragraphContextForCandidateRequest rect:offsetSelectionRect view:m_view.getAutoreleased() completionHandler:nil];
 #else
     UNUSED_PARAM(candidates);
 #endif
@@ -3107,16 +3107,16 @@ void WebViewImpl::preferencesDidChange()
         return;
 
     m_needsViewFrameInWindowCoordinates = needsViewFrameInWindowCoordinates;
-    if (m_view.window)
+    if ([m_view window])
         updateWindowAndViewFrames();
 }
 
 void WebViewImpl::setTextIndicator(WebCore::TextIndicator& textIndicator, WebCore::TextIndicatorWindowLifetime lifetime)
 {
     if (!m_textIndicatorWindow)
-        m_textIndicatorWindow = std::make_unique<WebCore::TextIndicatorWindow>(m_view);
+        m_textIndicatorWindow = std::make_unique<WebCore::TextIndicatorWindow>(m_view.getAutoreleased());
 
-    NSRect textBoundingRectInScreenCoordinates = [m_view.window convertRectToScreen:[m_view convertRect:textIndicator.textBoundingRectInRootViewCoordinates() toView:nil]];
+    NSRect textBoundingRectInScreenCoordinates = [[m_view window] convertRectToScreen:[m_view convertRect:textIndicator.textBoundingRectInRootViewCoordinates() toView:nil]];
     m_textIndicatorWindow->setTextIndicator(textIndicator, NSRectToCGRect(textBoundingRectInScreenCoordinates), lifetime);
 }
 
@@ -3153,7 +3153,7 @@ void WebViewImpl::dismissContentRelativeChildWindowsFromViewOnly()
     hasActiveImmediateAction = [m_immediateActionController hasActiveImmediateAction];
 
     // FIXME: We don't know which panel we are dismissing, it may not even be in the current page (see <rdar://problem/13875766>).
-    if (m_view.window.isKeyWindow || hasActiveImmediateAction) {
+    if ([m_view window].isKeyWindow || hasActiveImmediateAction) {
         WebCore::DictionaryLookup::hidePopup();
 
         if (DataDetectorsLibrary())
@@ -3305,8 +3305,8 @@ void WebViewImpl::updateRemoteAccessibilityRegistration(bool registerProcess)
 void WebViewImpl::accessibilityRegisterUIProcessTokens()
 {
     // Initialize remote accessibility when the window connection has been established.
-    NSData *remoteElementToken = WKAXRemoteTokenForElement(m_view);
-    NSData *remoteWindowToken = WKAXRemoteTokenForElement(m_view.window);
+    NSData *remoteElementToken = WKAXRemoteTokenForElement(m_view.getAutoreleased());
+    NSData *remoteWindowToken = WKAXRemoteTokenForElement([m_view window]);
     IPC::DataReference elementToken = IPC::DataReference(reinterpret_cast<const uint8_t*>([remoteElementToken bytes]), [remoteElementToken length]);
     IPC::DataReference windowToken = IPC::DataReference(reinterpret_cast<const uint8_t*>([remoteWindowToken bytes]), [remoteWindowToken length]);
     m_page->registerUIProcessAccessibilityTokens(elementToken, windowToken);
@@ -3436,7 +3436,7 @@ void WebViewImpl::sendToolTipMouseExited()
                                                 location:NSMakePoint(0, 0)
                                            modifierFlags:0
                                                timestamp:0
-                                            windowNumber:m_view.window.windowNumber
+                                            windowNumber:[m_view window].windowNumber
                                                  context:NULL
                                              eventNumber:0
                                           trackingNumber:TRACKING_RECT_TAG
@@ -3451,7 +3451,7 @@ void WebViewImpl::sendToolTipMouseEntered()
                                                 location:NSMakePoint(0, 0)
                                            modifierFlags:0
                                                timestamp:0
-                                            windowNumber:m_view.window.windowNumber
+                                            windowNumber:[m_view window].windowNumber
                                                  context:NULL
                                              eventNumber:0
                                           trackingNumber:TRACKING_RECT_TAG
@@ -3473,7 +3473,7 @@ void WebViewImpl::toolTipChanged(const String& oldToolTip, const String& newTool
         // See radar 3500217 for why we remove all tooltips rather than just the single one we created.
         [m_view removeAllToolTips];
         NSRect wideOpenRect = NSMakeRect(-100000, -100000, 200000, 200000);
-        m_lastToolTipTag = [m_view addToolTipRect:wideOpenRect owner:m_view userData:NULL];
+        m_lastToolTipTag = [m_view addToolTipRect:wideOpenRect owner:m_view.getAutoreleased() userData:NULL];
         sendToolTipMouseEntered();
     }
 }
@@ -3497,7 +3497,7 @@ void WebViewImpl::setAcceleratedCompositingRootLayer(CALayer *rootLayer)
     if (rootLayer) {
         if (!m_layerHostingView) {
             // Create an NSView that will host our layer tree.
-            m_layerHostingView = adoptNS([[WKFlippedView alloc] initWithFrame:m_view.bounds]);
+            m_layerHostingView = adoptNS([[WKFlippedView alloc] initWithFrame:[m_view bounds]]);
             [m_layerHostingView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
 
             [m_view addSubview:m_layerHostingView.get() positioned:NSWindowBelow relativeTo:nil];
@@ -3548,7 +3548,7 @@ void WebViewImpl::updateThumbnailViewLayer()
     _WKThumbnailView *thumbnailView = m_thumbnailView;
     ASSERT(thumbnailView);
 
-    if (thumbnailView._waitingForSnapshot && m_view.window)
+    if (thumbnailView._waitingForSnapshot && [m_view window])
         reparentLayerTreeInThumbnailView();
 }
 
@@ -3559,13 +3559,13 @@ void WebViewImpl::setInspectorAttachmentView(NSView *newView)
         return;
 
     m_inspectorAttachmentView = newView;
-    m_page->inspector()->attachmentViewDidChange(oldView ? oldView : m_view, newView ? newView : m_view);
+    m_page->inspector()->attachmentViewDidChange(oldView ? oldView : m_view.getAutoreleased(), newView ? newView : m_view.getAutoreleased());
 }
 
 NSView *WebViewImpl::inspectorAttachmentView()
 {
     NSView *attachmentView = m_inspectorAttachmentView.get();
-    return attachmentView ? attachmentView : m_view;
+    return attachmentView ? attachmentView : m_view.getAutoreleased();
 }
 
 _WKRemoteObjectRegistry *WebViewImpl::remoteObjectRegistry()
@@ -3592,14 +3592,14 @@ void WebViewImpl::draggedImage(NSImage *image, CGPoint endPoint, NSDragOperation
 {
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
-    NSPoint windowImageLoc = [m_view.window convertScreenToBase:NSPointFromCGPoint(endPoint)];
+    NSPoint windowImageLoc = [[m_view window] convertScreenToBase:NSPointFromCGPoint(endPoint)];
 #pragma clang diagnostic pop
     NSPoint windowMouseLoc = windowImageLoc;
 
     // Prevent queued mouseDragged events from coming after the drag and fake mouseUp event.
     m_ignoresMouseDraggedEvents = true;
 
-    m_page->dragEnded(WebCore::IntPoint(windowMouseLoc), WebCore::IntPoint(WebCore::globalPoint(windowMouseLoc, m_view.window)), operation);
+    m_page->dragEnded(WebCore::IntPoint(windowMouseLoc), WebCore::IntPoint(WebCore::globalPoint(windowMouseLoc, [m_view window])), operation);
 }
 
 static WebCore::DragApplicationFlags applicationFlagsForDrag(NSView *view, id <NSDraggingInfo> draggingInfo)
@@ -3620,13 +3620,13 @@ static WebCore::DragApplicationFlags applicationFlagsForDrag(NSView *view, id <N
 NSDragOperation WebViewImpl::draggingEntered(id <NSDraggingInfo> draggingInfo)
 {
     WebCore::IntPoint client([m_view convertPoint:draggingInfo.draggingLocation fromView:nil]);
-    WebCore::IntPoint global(WebCore::globalPoint(draggingInfo.draggingLocation, m_view.window));
+    WebCore::IntPoint global(WebCore::globalPoint(draggingInfo.draggingLocation, [m_view window]));
 #if WK_API_ENABLED
     auto dragDestinationAction = static_cast<WebCore::DragDestinationAction>([m_view _web_dragDestinationActionForDraggingInfo:draggingInfo]);
 #else
     auto dragDestinationAction = WebCore::DragDestinationActionAny;
 #endif
-    WebCore::DragData dragData(draggingInfo, client, global, static_cast<WebCore::DragOperation>(draggingInfo.draggingSourceOperationMask), applicationFlagsForDrag(m_view, draggingInfo), dragDestinationAction);
+    WebCore::DragData dragData(draggingInfo, client, global, static_cast<WebCore::DragOperation>(draggingInfo.draggingSourceOperationMask), applicationFlagsForDrag(m_view.getAutoreleased(), draggingInfo), dragDestinationAction);
 
     m_page->resetCurrentDragInformation();
     m_page->dragEntered(dragData, draggingInfo.draggingPasteboard.name);
@@ -3637,13 +3637,13 @@ NSDragOperation WebViewImpl::draggingEntered(id <NSDraggingInfo> draggingInfo)
 NSDragOperation WebViewImpl::draggingUpdated(id <NSDraggingInfo> draggingInfo)
 {
     WebCore::IntPoint client([m_view convertPoint:draggingInfo.draggingLocation fromView:nil]);
-    WebCore::IntPoint global(WebCore::globalPoint(draggingInfo.draggingLocation, m_view.window));
+    WebCore::IntPoint global(WebCore::globalPoint(draggingInfo.draggingLocation, [m_view window]));
 #if WK_API_ENABLED
     auto dragDestinationAction = static_cast<WebCore::DragDestinationAction>([m_view _web_dragDestinationActionForDraggingInfo:draggingInfo]);
 #else
     auto dragDestinationAction = WebCore::DragDestinationActionAny;
 #endif
-    WebCore::DragData dragData(draggingInfo, client, global, static_cast<WebCore::DragOperation>(draggingInfo.draggingSourceOperationMask), applicationFlagsForDrag(m_view, draggingInfo), dragDestinationAction);
+    WebCore::DragData dragData(draggingInfo, client, global, static_cast<WebCore::DragOperation>(draggingInfo.draggingSourceOperationMask), applicationFlagsForDrag(m_view.getAutoreleased(), draggingInfo), dragDestinationAction);
     m_page->dragUpdated(dragData, draggingInfo.draggingPasteboard.name);
 
     NSInteger numberOfValidItemsForDrop = m_page->currentDragNumberOfFilesToBeAccepted();
@@ -3666,8 +3666,8 @@ NSDragOperation WebViewImpl::draggingUpdated(id <NSDraggingInfo> draggingInfo)
 void WebViewImpl::draggingExited(id <NSDraggingInfo> draggingInfo)
 {
     WebCore::IntPoint client([m_view convertPoint:draggingInfo.draggingLocation fromView:nil]);
-    WebCore::IntPoint global(WebCore::globalPoint(draggingInfo.draggingLocation, m_view.window));
-    WebCore::DragData dragData(draggingInfo, client, global, static_cast<WebCore::DragOperation>(draggingInfo.draggingSourceOperationMask), applicationFlagsForDrag(m_view, draggingInfo));
+    WebCore::IntPoint global(WebCore::globalPoint(draggingInfo.draggingLocation, [m_view window]));
+    WebCore::DragData dragData(draggingInfo, client, global, static_cast<WebCore::DragOperation>(draggingInfo.draggingSourceOperationMask), applicationFlagsForDrag(m_view.getAutoreleased(), draggingInfo));
     m_page->dragExited(dragData, draggingInfo.draggingPasteboard.name);
     m_page->resetCurrentDragInformation();
     draggingInfo.numberOfValidItemsForDrop = m_initialNumberOfValidItemsForDrop;
@@ -3682,8 +3682,8 @@ bool WebViewImpl::prepareForDragOperation(id <NSDraggingInfo>)
 bool WebViewImpl::performDragOperation(id <NSDraggingInfo> draggingInfo)
 {
     WebCore::IntPoint client([m_view convertPoint:draggingInfo.draggingLocation fromView:nil]);
-    WebCore::IntPoint global(WebCore::globalPoint(draggingInfo.draggingLocation, m_view.window));
-    WebCore::DragData *dragData = new WebCore::DragData(draggingInfo, client, global, static_cast<WebCore::DragOperation>(draggingInfo.draggingSourceOperationMask), applicationFlagsForDrag(m_view, draggingInfo));
+    WebCore::IntPoint global(WebCore::globalPoint(draggingInfo.draggingLocation, [m_view window]));
+    WebCore::DragData *dragData = new WebCore::DragData(draggingInfo, client, global, static_cast<WebCore::DragOperation>(draggingInfo.draggingSourceOperationMask), applicationFlagsForDrag(m_view.getAutoreleased(), draggingInfo));
 
     NSArray *types = draggingInfo.draggingPasteboard.types;
     SandboxExtension::Handle sandboxExtensionHandle;
@@ -3713,7 +3713,7 @@ bool WebViewImpl::performDragOperation(id <NSDraggingInfo> draggingInfo)
         Vector<String> *fileNames = new Vector<String>;
         NSURL *dropLocation = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES];
         String pasteboardName = draggingInfo.draggingPasteboard.name;
-        [draggingInfo enumerateDraggingItemsWithOptions:0 forView:m_view classes:@[[NSFilePromiseReceiver class]] searchOptions:@{ } usingBlock:^(NSDraggingItem * __nonnull draggingItem, NSInteger idx, BOOL * __nonnull stop) {
+        [draggingInfo enumerateDraggingItemsWithOptions:0 forView:m_view.getAutoreleased() classes:@[[NSFilePromiseReceiver class]] searchOptions:@{ } usingBlock:^(NSDraggingItem * __nonnull draggingItem, NSInteger idx, BOOL * __nonnull stop) {
             NSFilePromiseReceiver *item = draggingItem.item;
             NSDictionary *options = @{ };
 
@@ -3753,7 +3753,7 @@ NSView *WebViewImpl::hitTestForDragTypes(CGPoint point, NSSet *types)
     // This is the case for elements that do not place content
     // in the drag pasteboard automatically when the drag start (i.e. dragging a DIV element).
     if ([[m_view superview] mouse:NSPointFromCGPoint(point) inRect:[m_view frame]])
-        return m_view;
+        return m_view.getAutoreleased();
     return nil;
 }
 
@@ -3768,13 +3768,13 @@ void WebViewImpl::registerDraggedTypes()
 
 void WebViewImpl::startWindowDrag()
 {
-    [m_view.window performWindowDragWithEvent:m_lastMouseDownEvent.get()];
+    [[m_view window] performWindowDragWithEvent:m_lastMouseDownEvent.get()];
 }
 
 void WebViewImpl::dragImageForView(NSView *view, NSImage *image, CGPoint clientPoint, bool)
 {
     // The call below could release the view.
-    RetainPtr<NSView> protector(m_view);
+    auto protector = m_view.get();
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
     NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
@@ -3787,7 +3787,7 @@ void WebViewImpl::dragImageForView(NSView *view, NSImage *image, CGPoint clientP
              offset:NSZeroSize
               event:m_lastMouseDownEvent.get()
          pasteboard:pasteboard
-             source:m_view
+             source:m_view.getAutoreleased()
           slideBack:YES];
 #pragma clang diagnostic pop
 }
@@ -3819,7 +3819,7 @@ void WebViewImpl::setPromisedDataForImage(WebCore::Image* image, NSString *filen
     RetainPtr<NSMutableArray> types = adoptNS([[NSMutableArray alloc] initWithObjects:NSFilesPromisePboardType, nil]);
 
     [types addObjectsFromArray:archiveBuffer ? PasteboardTypes::forImagesWithArchive() : PasteboardTypes::forImages()];
-    [pasteboard declareTypes:types.get() owner:m_view];
+    [pasteboard declareTypes:types.get() owner:m_view.getAutoreleased()];
     setFileAndURLTypes(filename, extension, title, url, visibleURL, pasteboard);
 
     if (archiveBuffer)
@@ -3834,7 +3834,7 @@ void WebViewImpl::setPromisedDataForAttachment(NSString *filename, NSString *ext
     NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:pasteboardName];
     RetainPtr<NSMutableArray> types = adoptNS([[NSMutableArray alloc] initWithObjects:NSFilesPromisePboardType, nil]);
     [types addObjectsFromArray:PasteboardTypes::forURL()];
-    [pasteboard declareTypes:types.get() owner:m_view];
+    [pasteboard declareTypes:types.get() owner:m_view.getAutoreleased()];
     setFileAndURLTypes(filename, extension, title, url, visibleURL, pasteboard);
     [pasteboard setPropertyList:@[title] forType:NSFilenamesPboardType];
 
@@ -3947,7 +3947,7 @@ static RetainPtr<CGImageRef> takeWindowSnapshot(CGSWindowID windowID, bool captu
 
 RefPtr<ViewSnapshot> WebViewImpl::takeViewSnapshot()
 {
-    NSWindow *window = m_view.window;
+    NSWindow *window = [m_view window];
 
     CGSWindowID windowID = (CGSWindowID)window.windowNumber;
     if (!windowID || !window.isVisible)
@@ -3972,7 +3972,7 @@ RefPtr<ViewSnapshot> WebViewImpl::takeViewSnapshot()
     if (!boundsForCustomSwipeViews.isEmpty())
         windowCaptureRect = boundsForCustomSwipeViews;
     else {
-        NSRect unobscuredBounds = m_view.bounds;
+        NSRect unobscuredBounds = [m_view bounds];
         float topContentInset = m_page->topContentInset();
         unobscuredBounds.origin.y += topContentInset;
         unobscuredBounds.size.height -= topContentInset;
@@ -4110,7 +4110,7 @@ void WebViewImpl::scrollWheel(NSEvent *event)
     if (m_allowsBackForwardNavigationGestures && ensureGestureController().handleScrollWheelEvent(event))
         return;
 
-    NativeWebWheelEvent webEvent = NativeWebWheelEvent(event, m_view);
+    NativeWebWheelEvent webEvent = NativeWebWheelEvent(event, m_view.getAutoreleased());
     m_page->handleWheelEvent(webEvent);
 }
 
@@ -4136,7 +4136,7 @@ void WebViewImpl::magnifyWithEvent(NSEvent *event)
 {
     if (!m_allowsMagnification) {
 #if ENABLE(MAC_GESTURE_EVENTS)
-        NativeWebGestureEvent webEvent = NativeWebGestureEvent(event, m_view);
+        NativeWebGestureEvent webEvent = NativeWebGestureEvent(event, m_view.getAutoreleased());
         m_page->handleGestureEvent(webEvent);
 #endif
         [m_view _web_superMagnifyWithEvent:event];
@@ -4153,7 +4153,7 @@ void WebViewImpl::magnifyWithEvent(NSEvent *event)
         return;
     }
 
-    NativeWebGestureEvent webEvent = NativeWebGestureEvent(event, m_view);
+    NativeWebGestureEvent webEvent = NativeWebGestureEvent(event, m_view.getAutoreleased());
     m_page->handleGestureEvent(webEvent);
 #else
     gestureController.handleMagnificationGestureEvent(event, [m_view convertPoint:event.locationInWindow fromView:nil]);
@@ -4185,7 +4185,7 @@ void WebViewImpl::setLastMouseDownEvent(NSEvent *event)
 #if ENABLE(MAC_GESTURE_EVENTS)
 void WebViewImpl::rotateWithEvent(NSEvent *event)
 {
-    NativeWebGestureEvent webEvent = NativeWebGestureEvent(event, m_view);
+    NativeWebGestureEvent webEvent = NativeWebGestureEvent(event, m_view.getAutoreleased());
     m_page->handleGestureEvent(webEvent);
 }
 #endif
@@ -4223,7 +4223,7 @@ void WebViewImpl::doneWithKeyEvent(NSEvent *event, bool eventWasHandled)
     }
 
     // resending the event may destroy this WKView
-    RetainPtr<NSView> protector(m_view);
+    auto protector = m_view.get();
 
     ASSERT(!m_keyDownEventBeingResent);
     m_keyDownEventBeingResent = event;
@@ -4320,16 +4320,20 @@ void WebViewImpl::interpretKeyEvent(NSEvent *event, void(^completionHandler)(BOO
     }
 
     LOG(TextInput, "-> handleEventByInputMethod:%p %@", event, event);
-    [inputContext() handleEventByInputMethod:event completionHandler:^(BOOL handled) {
-        
+    [inputContext() handleEventByInputMethod:event completionHandler:[weakThis = createWeakPtr(), capturedEvent = retainPtr(event), capturedBlock = makeBlockPtr(completionHandler)](BOOL handled) {
+        if (!weakThis) {
+            capturedBlock(NO, { });
+            return;
+        }
+
         LOG(TextInput, "... handleEventByInputMethod%s handled", handled ? "" : " not");
         if (handled) {
-            completionHandler(YES, { });
+            capturedBlock(YES, { });
             return;
         }
 
-        auto commands = collectKeyboardLayoutCommandsForEvent(event);
-        completionHandler(NO, commands);
+        auto commands = weakThis->collectKeyboardLayoutCommandsForEvent(capturedEvent.get());
+        capturedBlock(NO, commands);
     }];
 }
 
@@ -4512,10 +4516,13 @@ void WebViewImpl::firstRectForCharacterRange(NSRange range, void(^completionHand
 
     auto weakThis = createWeakPtr();
     m_page->firstRectForCharacterRangeAsync(range, [weakThis, completionHandler](const WebCore::IntRect& rect, const EditingRange& actualRange, WebKit::CallbackBase::Error error) {
-        if (!weakThis)
+        auto completionHandlerBlock = (void (^)(NSRect, NSRange))completionHandler.get();
+        if (!weakThis) {
+            LOG(TextInput, "    ...firstRectForCharacterRange failed (WebViewImpl was destroyed).");
+            completionHandlerBlock(NSZeroRect, NSMakeRange(NSNotFound, 0));
             return;
+        }
 
-        void (^completionHandlerBlock)(NSRect, NSRange) = (void (^)(NSRect, NSRange))completionHandler.get();
         if (error != WebKit::CallbackBase::Error::None) {
             LOG(TextInput, "    ...firstRectForCharacterRange failed.");
             completionHandlerBlock(NSZeroRect, NSMakeRange(NSNotFound, 0));
@@ -4523,7 +4530,7 @@ void WebViewImpl::firstRectForCharacterRange(NSRange range, void(^completionHand
         }
 
         NSRect resultRect = [weakThis->m_view convertRect:rect toView:nil];
-        resultRect = [weakThis->m_view.window convertRectToScreen:resultRect];
+        resultRect = [[weakThis->m_view window] convertRectToScreen:resultRect];
 
         LOG(TextInput, "    -> firstRectForCharacterRange returned (%f, %f, %f, %f)", resultRect.origin.x, resultRect.origin.y, resultRect.size.width, resultRect.size.height);
         completionHandlerBlock(resultRect, actualRange);
@@ -4536,7 +4543,7 @@ void WebViewImpl::characterIndexForPoint(NSPoint point, void(^completionHandlerP
 
     LOG(TextInput, "characterIndexForPoint:(%f, %f)", point.x, point.y);
 
-    NSWindow *window = m_view.window;
+    NSWindow *window = [m_view window];
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
@@ -4679,9 +4686,10 @@ bool WebViewImpl::performKeyEquivalent(NSEvent *event)
     // Pass key combos through WebCore if there is a key binding available for
     // this event. This lets webpages have a crack at intercepting key-modified keypresses.
     // FIXME: Why is the firstResponder check needed?
-    if (m_view == m_view.window.firstResponder) {
-        interpretKeyEvent(event, ^(BOOL handledByInputMethod, const Vector<WebCore::KeypressCommand>& commands) {
-            m_page->handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, false, commands));
+    if (m_view.getAutoreleased() == [m_view window].firstResponder) {
+        interpretKeyEvent(event, [weakThis = createWeakPtr(), capturedEvent = retainPtr(event)](BOOL handledByInputMethod, const Vector<WebCore::KeypressCommand>& commands) {
+            if (weakThis)
+                weakThis->m_page->handleKeyboardEvent(NativeWebKeyboardEvent(capturedEvent.get(), handledByInputMethod, false, commands));
         });
         return YES;
     }
@@ -4697,9 +4705,10 @@ void WebViewImpl::keyUp(NSEvent *event)
     LOG(TextInput, "keyUp:%p %@", event, event);
 
     m_isTextInsertionReplacingSoftSpace = false;
-    interpretKeyEvent(event, ^(BOOL handledByInputMethod, const Vector<WebCore::KeypressCommand>& commands) {
+    interpretKeyEvent(event, [weakThis = createWeakPtr(), capturedEvent = retainPtr(event)](BOOL handledByInputMethod, const Vector<WebCore::KeypressCommand>& commands) {
         ASSERT(!handledByInputMethod || commands.isEmpty());
-        m_page->handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, m_isTextInsertionReplacingSoftSpace, commands));
+        if (weakThis)
+            weakThis->m_page->handleKeyboardEvent(NativeWebKeyboardEvent(capturedEvent.get(), handledByInputMethod, weakThis->m_isTextInsertionReplacingSoftSpace, commands));
     });
 }
 
@@ -4725,9 +4734,10 @@ void WebViewImpl::keyDown(NSEvent *event)
     }
 
     m_isTextInsertionReplacingSoftSpace = false;
-    interpretKeyEvent(event, ^(BOOL handledByInputMethod, const Vector<WebCore::KeypressCommand>& commands) {
+    interpretKeyEvent(event, [weakThis = createWeakPtr(), capturedEvent = retainPtr(event)](BOOL handledByInputMethod, const Vector<WebCore::KeypressCommand>& commands) {
         ASSERT(!handledByInputMethod || commands.isEmpty());
-        m_page->handleKeyboardEvent(NativeWebKeyboardEvent(event, handledByInputMethod, m_isTextInsertionReplacingSoftSpace, commands));
+        if (weakThis)
+            weakThis->m_page->handleKeyboardEvent(NativeWebKeyboardEvent(capturedEvent.get(), handledByInputMethod, weakThis->m_isTextInsertionReplacingSoftSpace, commands));
     });
 }
 
@@ -4752,7 +4762,7 @@ void WebViewImpl::flagsChanged(NSEvent *event)
     { \
         if (m_ignoresNonWheelEvents) \
             return; \
-        if (NSTextInputContext *context = m_view.inputContext) { \
+        if (NSTextInputContext *context = [m_view inputContext]) { \
             auto weakThis = createWeakPtr(); \
             RetainPtr<NSEvent> retainedEvent = event; \
             [context handleEvent:event completionHandler:[weakThis, retainedEvent] (BOOL handled) { \
@@ -4761,13 +4771,13 @@ void WebViewImpl::flagsChanged(NSEvent *event)
                 if (handled) \
                     LOG(TextInput, "%s was handled by text input context", String(#EventName).substring(0, String(#EventName).find("Internal")).ascii().data()); \
                 else { \
-                    NativeWebMouseEvent webEvent(retainedEvent.get(), weakThis->m_lastPressureEvent.get(), weakThis->m_view); \
+                    NativeWebMouseEvent webEvent(retainedEvent.get(), weakThis->m_lastPressureEvent.get(), weakThis->m_view.getAutoreleased()); \
                     weakThis->m_page->handleMouseEvent(webEvent); \
                 } \
             }]; \
             return; \
         } \
-        NativeWebMouseEvent webEvent(event, m_lastPressureEvent.get(), m_view); \
+        NativeWebMouseEvent webEvent(event, m_lastPressureEvent.get(), m_view.getAutoreleased()); \
         m_page->handleMouseEvent(webEvent); \
     }
 #define NATIVE_MOUSE_EVENT_HANDLER_INTERNAL(EventName) \
@@ -4775,7 +4785,7 @@ void WebViewImpl::flagsChanged(NSEvent *event)
     { \
         if (m_ignoresNonWheelEvents) \
             return; \
-        if (NSTextInputContext *context = m_view.inputContext) { \
+        if (NSTextInputContext *context = [m_view inputContext]) { \
             auto weakThis = createWeakPtr(); \
             RetainPtr<NSEvent> retainedEvent = event; \
             [context handleEvent:event completionHandler:[weakThis, retainedEvent] (BOOL handled) { \
@@ -4784,13 +4794,13 @@ void WebViewImpl::flagsChanged(NSEvent *event)
                 if (handled) \
                     LOG(TextInput, "%s was handled by text input context", String(#EventName).substring(0, String(#EventName).find("Internal")).ascii().data()); \
                 else { \
-                    NativeWebMouseEvent webEvent(retainedEvent.get(), weakThis->m_lastPressureEvent.get(), weakThis->m_view); \
+                    NativeWebMouseEvent webEvent(retainedEvent.get(), weakThis->m_lastPressureEvent.get(), weakThis->m_view.getAutoreleased()); \
                     weakThis->m_page->handleMouseEvent(webEvent); \
                 } \
             }]; \
             return; \
         } \
-        NativeWebMouseEvent webEvent(event, m_lastPressureEvent.get(), m_view); \
+        NativeWebMouseEvent webEvent(event, m_lastPressureEvent.get(), m_view.getAutoreleased()); \
         m_page->handleMouseEvent(webEvent); \
     }
 
@@ -4817,7 +4827,7 @@ void WebViewImpl::mouseMoved(NSEvent *event)
         return;
 
     // When a view is first responder, it gets mouse moved events even when the mouse is outside its visible rect.
-    if (m_view == m_view.window.firstResponder && !NSPointInRect([m_view convertPoint:[event locationInWindow] fromView:nil], m_view.visibleRect))
+    if (m_view.getAutoreleased() == [m_view window].firstResponder && !NSPointInRect([m_view convertPoint:[event locationInWindow] fromView:nil], [m_view visibleRect]))
         return;
 
     mouseMovedInternal(event);
@@ -4855,10 +4865,10 @@ void WebViewImpl::mouseDragged(NSEvent *event)
 
 bool WebViewImpl::windowIsFrontWindowUnderMouse(NSEvent *event)
 {
-    NSRect eventScreenPosition = [m_view.window convertRectToScreen:NSMakeRect(event.locationInWindow.x, event.locationInWindow.y, 0, 0)];
+    NSRect eventScreenPosition = [[m_view window] convertRectToScreen:NSMakeRect(event.locationInWindow.x, event.locationInWindow.y, 0, 0)];
     NSInteger eventWindowNumber = [NSWindow windowNumberAtPoint:eventScreenPosition.origin belowWindowWithWindowNumber:0];
         
-    return m_view.window.windowNumber != eventWindowNumber;
+    return [m_view window].windowNumber != eventWindowNumber;
 }
 
 static WebCore::UserInterfaceLayoutDirection toUserInterfaceLayoutDirection(NSUserInterfaceLayoutDirection direction)
@@ -4876,7 +4886,7 @@ static WebCore::UserInterfaceLayoutDirection toUserInterfaceLayoutDirection(NSUs
 
 WebCore::UserInterfaceLayoutDirection WebViewImpl::userInterfaceLayoutDirection()
 {
-    return toUserInterfaceLayoutDirection(m_view.userInterfaceLayoutDirection);
+    return toUserInterfaceLayoutDirection([m_view userInterfaceLayoutDirection]);
 }
 
 void WebViewImpl::setUserInterfaceLayoutDirection(NSUserInterfaceLayoutDirection direction)
index a1cf12a..7497f39 100644 (file)
@@ -1,3 +1,23 @@
+2017-08-08  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [Mac WK2] WebViewImpl should hold a weak pointer to its WKWebView or WKView
+        https://bugs.webkit.org/show_bug.cgi?id=175302
+        <rdar://problem/33762116>
+
+        Reviewed by Tim Horton.
+
+        Adds a new unit test checking that delayed event processing in text input context does not cause unwanted behaviors.
+        See WebKit ChangeLog for more details.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/TestWebKitAPI/mac/AppKitSPI.h: Renamed from Tools/TestWebKitAPI/Tests/TestWebKitAPI/mac/NSTextInputClientSPI.h.
+        * TestWebKitAPI/Tests/mac/WKWebViewMacEditingTests.mm: Renamed from Tools/TestWebKitAPI/Tests/mac/WKWebViewSelectionTests.mm.
+        (-[SlowTextInputContext handleEventByInputMethod:completionHandler:]):
+        (-[SlowTextInputContext handleEvent:completionHandler:]):
+        (-[SlowInputWebView inputContext]):
+        (-[SlowInputWebView _web_superInputContext]):
+        (TEST):
+
 2017-08-08  John Wilander  <wilander@apple.com>
 
         Resource Load Statistics: Clear web processes' state on history removal
index 9cde636..79225fb 100644 (file)
                F4F137921D9B683E002BEC57 /* large-video-test-now-playing.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4F137911D9B6832002BEC57 /* large-video-test-now-playing.html */; };
                F4F405BC1D4C0D1C007A9707 /* full-size-autoplaying-video-with-audio.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4F405BA1D4C0CF8007A9707 /* full-size-autoplaying-video-with-audio.html */; };
                F4F405BD1D4C0D1C007A9707 /* skinny-autoplaying-video-with-audio.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4F405BB1D4C0CF8007A9707 /* skinny-autoplaying-video-with-audio.html */; };
-               F4FA91811E61849B007B8C1D /* WKWebViewSelectionTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4FA917F1E61849B007B8C1D /* WKWebViewSelectionTests.mm */; };
+               F4FA91811E61849B007B8C1D /* WKWebViewMacEditingTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4FA917F1E61849B007B8C1D /* WKWebViewMacEditingTests.mm */; };
                F4FA91831E61857B007B8C1D /* double-click-does-not-select-trailing-space.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4FA91821E618566007B8C1D /* double-click-does-not-select-trailing-space.html */; };
                F660AA1115A5F631003A1243 /* GetInjectedBundleInitializationUserDataCallback_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F660AA0F15A5F624003A1243 /* GetInjectedBundleInitializationUserDataCallback_Bundle.cpp */; };
                F660AA1515A61ABF003A1243 /* InjectedBundleInitializationUserDataCallbackWins_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F660AA1415A61ABF003A1243 /* InjectedBundleInitializationUserDataCallbackWins_Bundle.cpp */; };
                2E691AF21D79E75400129407 /* large-video-playing-scroll-away.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "large-video-playing-scroll-away.html"; sourceTree = "<group>"; };
                2E7765CC16C4D80A00BA2BB1 /* mainIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = mainIOS.mm; sourceTree = "<group>"; };
                2E7765CE16C4D81100BA2BB1 /* mainMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = mainMac.mm; sourceTree = "<group>"; };
-               2E7EF7AC1F266A8100DFB67C /* NSTextInputClientSPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSTextInputClientSPI.h; sourceTree = "<group>"; };
+               2E7EF7AC1F266A8100DFB67C /* AppKitSPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppKitSPI.h; sourceTree = "<group>"; };
                2E9896141D8F092B00739892 /* text-and-password-inputs.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "text-and-password-inputs.html"; sourceTree = "<group>"; };
                2ECFF5541D9B12F800B55394 /* NowPlayingControlsTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = NowPlayingControlsTests.mm; sourceTree = "<group>"; };
                2EFF06C21D8862120004BB30 /* large-video-offscreen.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "large-video-offscreen.html"; sourceTree = "<group>"; };
                F4F137911D9B6832002BEC57 /* large-video-test-now-playing.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "large-video-test-now-playing.html"; sourceTree = "<group>"; };
                F4F405BA1D4C0CF8007A9707 /* full-size-autoplaying-video-with-audio.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "full-size-autoplaying-video-with-audio.html"; sourceTree = "<group>"; };
                F4F405BB1D4C0CF8007A9707 /* skinny-autoplaying-video-with-audio.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "skinny-autoplaying-video-with-audio.html"; sourceTree = "<group>"; };
-               F4FA917F1E61849B007B8C1D /* WKWebViewSelectionTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKWebViewSelectionTests.mm; sourceTree = "<group>"; };
+               F4FA917F1E61849B007B8C1D /* WKWebViewMacEditingTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKWebViewMacEditingTests.mm; sourceTree = "<group>"; };
                F4FA91821E618566007B8C1D /* double-click-does-not-select-trailing-space.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = "double-click-does-not-select-trailing-space.html"; path = "Tests/WebKit2Cocoa/double-click-does-not-select-trailing-space.html"; sourceTree = SOURCE_ROOT; };
                F660AA0C15A5F061003A1243 /* GetInjectedBundleInitializationUserDataCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetInjectedBundleInitializationUserDataCallback.cpp; sourceTree = "<group>"; };
                F660AA0F15A5F624003A1243 /* GetInjectedBundleInitializationUserDataCallback_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetInjectedBundleInitializationUserDataCallback_Bundle.cpp; sourceTree = "<group>"; };
                                CE32C7C718184C4900CD8C28 /* WillPerformClientRedirectToURLCrash.mm */,
                                1A7BFC0A171A0BDB00BC5F64 /* WillSendSubmitEvent.mm */,
                                A5E2027215B2181900C13E14 /* WindowlessWebViewWithMedia.mm */,
-                               F4FA917F1E61849B007B8C1D /* WKWebViewSelectionTests.mm */,
+                               F4FA917F1E61849B007B8C1D /* WKWebViewMacEditingTests.mm */,
                                764322D51B61CCA40024F801 /* WordBoundaryTypingAttributes.mm */,
                        );
                        path = mac;
                C08587FA13FEC39B001EF4E5 /* mac */ = {
                        isa = PBXGroup;
                        children = (
+                               2E7EF7AC1F266A8100DFB67C /* AppKitSPI.h */,
                                C08587FB13FEC39B001EF4E5 /* InstanceMethodSwizzler.mm */,
-                               2E7EF7AC1F266A8100DFB67C /* NSTextInputClientSPI.h */,
                        );
                        path = mac;
                        sourceTree = "<group>";
                                46E66A901F0D75590026D83C /* WKWebViewDiagnosticLogging.mm in Sources */,
                                0F3B94A71A77267400DE3272 /* WKWebViewEvaluateJavaScript.mm in Sources */,
                                D34E08761E4E42E1005FF14A /* WKWebViewGetContents.mm in Sources */,
-                               F4FA91811E61849B007B8C1D /* WKWebViewSelectionTests.mm in Sources */,
+                               F4FA91811E61849B007B8C1D /* WKWebViewMacEditingTests.mm in Sources */,
                                93F56DA91E5F919D003EDE84 /* WKWebViewSnapshot.mm in Sources */,
                                9984FACC1CFFAF60008D198C /* WKWebViewTextInput.mm in Sources */,
                                764322D71B61CCC30024F801 /* WordBoundaryTypingAttributes.mm in Sources */,
@@ -28,6 +28,7 @@
 #if USE(APPLE_INTERNAL_SDK)
 
 #import <AppKit/NSTextInputClient_Private.h>
+#import <AppKit/NSTextInputContext_Private.h>
 
 #else
 
 - (void)hasMarkedTextWithCompletionHandler:(void(^)(BOOL hasMarkedText))completionHandler;
 @end
 
+@interface NSTextInputContext (WebKitSupport)
+- (void)handleEvent:(NSEvent *)event completionHandler:(void(^)(BOOL handled))completionHandler;
+- (void)handleEventByInputMethod:(NSEvent *)event completionHandler:(void(^)(BOOL handled))completionHandler;
+@end
+
 #endif
 
 #endif // PLATFORM(MAC)
 
 #if WK_API_ENABLED && PLATFORM(MAC)
 
-#import "NSTextInputClientSPI.h"
+#import "AppKitSPI.h"
 #import "PlatformUtilities.h"
 #import "TestWKWebView.h"
+#import <wtf/BlockPtr.h>
+#import <wtf/RetainPtr.h>
 
-TEST(WKWebViewSelectionTests, DoubleClickDoesNotSelectTrailingSpace)
+@interface SlowTextInputContext : NSTextInputContext
+@property (nonatomic) BlockPtr<void()> handledInputMethodEventBlock;
+@end
+
+@implementation SlowTextInputContext
+
+- (void)handleEventByInputMethod:(NSEvent *)event completionHandler:(void(^)(BOOL handled))completionHandler
+{
+    [super handleEventByInputMethod:event completionHandler:^(BOOL handled) {
+        dispatch_async(dispatch_get_main_queue(), ^() {
+            completionHandler(handled);
+            if (_handledInputMethodEventBlock)
+                _handledInputMethodEventBlock();
+        });
+    }];
+}
+
+- (void)handleEvent:(NSEvent *)event completionHandler:(void(^)(BOOL handled))completionHandler
+{
+    [super handleEvent:event completionHandler:^(BOOL handled) {
+        dispatch_async(dispatch_get_main_queue(), ^() {
+            completionHandler(handled);
+        });
+    }];
+}
+
+@end
+
+@interface SlowInputWebView : TestWKWebView {
+    RetainPtr<SlowTextInputContext> _slowInputContext;
+}
+@end
+
+@implementation SlowInputWebView
+
+- (NSTextInputContext *)inputContext
+{
+    return self._web_superInputContext;
+}
+
+- (SlowTextInputContext *)_web_superInputContext
+{
+    if (!_slowInputContext)
+        _slowInputContext = adoptNS([[SlowTextInputContext alloc] initWithClient:(id<NSTextInputClient>)self]);
+    return _slowInputContext.get();
+}
+
+@end
+
+TEST(WKWebViewMacEditingTests, DoubleClickDoesNotSelectTrailingSpace)
 {
     RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)]);
     [webView synchronouslyLoadTestPageNamed:@"double-click-does-not-select-trailing-space"];
@@ -47,7 +98,7 @@ TEST(WKWebViewSelectionTests, DoubleClickDoesNotSelectTrailingSpace)
     EXPECT_STREQ("Hello", selectedText.UTF8String);
 }
 
-TEST(WKWebViewSelectionTests, DoNotCrashWhenCallingTextInputClientMethodsWhileDeallocatingView)
+TEST(WKWebViewMacEditingTests, DoNotCrashWhenCallingTextInputClientMethodsWhileDeallocatingView)
 {
     NSString *textContent = @"This test should not cause us to dereference null.";
 
@@ -65,4 +116,23 @@ TEST(WKWebViewSelectionTests, DoNotCrashWhenCallingTextInputClientMethodsWhileDe
     EXPECT_WK_STREQ(textContent, [webView stringByEvaluatingJavaScript:@"document.body.textContent"]);
 }
 
+TEST(WKWebViewMacEditingTests, DoNotCrashWhenInterpretingKeyEventWhileDeallocatingView)
+{
+    __block bool isDone = false;
+
+    @autoreleasepool {
+        SlowInputWebView *webView = [[[SlowInputWebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400)] autorelease];
+        [webView synchronouslyLoadHTMLString:[NSString stringWithFormat:@"<body contenteditable>Hello world</body>"]];
+        [webView stringByEvaluatingJavaScript:@"document.body.focus()"];
+        [webView removeFromSuperview];
+        [webView typeCharacter:'a'];
+
+        webView._web_superInputContext.handledInputMethodEventBlock = ^() {
+            isDone = true;
+        };
+    }
+
+    TestWebKitAPI::Util::run(&isDone);
+}
+
 #endif // WK_API_ENABLED && PLATFORM(MAC)