<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[246800] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/246800">246800</a></dd>
<dt>Author</dt> <dd>wenson_hsieh@apple.com</dd>
<dt>Date</dt> <dd>2019-06-25 11:48:25 -0700 (Tue, 25 Jun 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>[iOS] Occasional crash under -[UIPreviewTarget initWithContainer:center:transform:] when generating a drag preview
https://bugs.webkit.org/show_bug.cgi?id=199192
<rdar://problem/51554509>

Reviewed by Tim Horton.

Source/WebKit:

Tweak our preview generation code (for both the context menu and dragging) to be robust in the case where the
content view's unscaled view is nil; this may happen in the case after the web content process is terminated
and -cleanupInteraction is called, but before -setupInteraction is subsequently called.

Additionally, make our logic for creating targeted previews robust in the case where the view is removed from
the view hierarchy right before the platform asks for a targeted preview.

Test:   DragAndDropTests.WebProcessTerminationDuringDrag
        DragAndDropTests.WebViewRemovedFromViewHierarchyDuringDrag

* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView containerViewForTargetedPreviews]):
(-[WKContentView _deliverDelayedDropPreviewIfPossible:]):
(-[WKContentView dragInteraction:previewForLiftingItem:session:]):
(-[WKContentView _ensureTargetedPreview]):

Tools:

Tweak the drag and drop simulator to ask for drag cancellation previews, and use this to write a couple tests to
verify that we gracefully handle web process termination and web view unparenting mid-drag.

* TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm:
(TestWebKitAPI::TEST):
* TestWebKitAPI/cocoa/DragAndDropSimulator.h:
* TestWebKitAPI/ios/DragAndDropSimulatorIOS.mm:
(-[DragAndDropSimulator _resetSimulatedState]):
(-[DragAndDropSimulator _concludeDropAndPerformOperationIfNecessary]):
(-[DragAndDropSimulator _advanceProgress]):
(-[DragAndDropSimulator liftPreviews]):
(-[DragAndDropSimulator cancellationPreviews]):
(-[DragAndDropSimulator setSessionWillBeginBlock:]):
(-[DragAndDropSimulator sessionWillBeginBlock]):
(-[DragAndDropSimulator _webView:dataInteraction:sessionWillBegin:]):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKitChangeLog">trunk/Source/WebKit/ChangeLog</a></li>
<li><a href="#trunkSourceWebKitUIProcessiosDragDropInteractionStatemm">trunk/Source/WebKit/UIProcess/ios/DragDropInteractionState.mm</a></li>
<li><a href="#trunkSourceWebKitUIProcessiosWKContentViewInteractionmm">trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsiosDragAndDropTestsIOSmm">trunk/Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm</a></li>
<li><a href="#trunkToolsTestWebKitAPIcocoaDragAndDropSimulatorh">trunk/Tools/TestWebKitAPI/cocoa/DragAndDropSimulator.h</a></li>
<li><a href="#trunkToolsTestWebKitAPIiosDragAndDropSimulatorIOSmm">trunk/Tools/TestWebKitAPI/ios/DragAndDropSimulatorIOS.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKitChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/ChangeLog (246799 => 246800)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/ChangeLog    2019-06-25 18:47:01 UTC (rev 246799)
+++ trunk/Source/WebKit/ChangeLog       2019-06-25 18:48:25 UTC (rev 246800)
</span><span class="lines">@@ -1,3 +1,27 @@
</span><ins>+2019-06-25  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Occasional crash under -[UIPreviewTarget initWithContainer:center:transform:] when generating a drag preview
+        https://bugs.webkit.org/show_bug.cgi?id=199192
+        <rdar://problem/51554509>
+
+        Reviewed by Tim Horton.
+
+        Tweak our preview generation code (for both the context menu and dragging) to be robust in the case where the
+        content view's unscaled view is nil; this may happen in the case after the web content process is terminated
+        and -cleanupInteraction is called, but before -setupInteraction is subsequently called.
+
+        Additionally, make our logic for creating targeted previews robust in the case where the view is removed from
+        the view hierarchy right before the platform asks for a targeted preview.
+
+        Test:   DragAndDropTests.WebProcessTerminationDuringDrag
+                DragAndDropTests.WebViewRemovedFromViewHierarchyDuringDrag
+
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView containerViewForTargetedPreviews]):
+        (-[WKContentView _deliverDelayedDropPreviewIfPossible:]):
+        (-[WKContentView dragInteraction:previewForLiftingItem:session:]):
+        (-[WKContentView _ensureTargetedPreview]):
+
</ins><span class="cx"> 2019-06-25  Youenn Fablet  <youenn@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Close sockets with too high file descriptor
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessiosDragDropInteractionStatemm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/ios/DragDropInteractionState.mm (246799 => 246800)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/ios/DragDropInteractionState.mm    2019-06-25 18:47:01 UTC (rev 246799)
+++ trunk/Source/WebKit/UIProcess/ios/DragDropInteractionState.mm       2019-06-25 18:48:25 UTC (rev 246800)
</span><span class="lines">@@ -46,7 +46,7 @@
</span><span class="cx"> 
</span><span class="cx"> static RetainPtr<UITargetedDragPreview> createTargetedDragPreview(UIImage *image, UIView *rootView, UIView *previewContainer, const FloatRect& frameInRootViewCoordinates, const Vector<FloatRect>& clippingRectsInFrameCoordinates, UIColor *backgroundColor, UIBezierPath *visiblePath)
</span><span class="cx"> {
</span><del>-    if (frameInRootViewCoordinates.isEmpty() || !image)
</del><ins>+    if (frameInRootViewCoordinates.isEmpty() || !image || !previewContainer.window)
</ins><span class="cx">         return nullptr;
</span><span class="cx"> 
</span><span class="cx">     NSMutableArray *clippingRectValuesInFrameCoordinates = [NSMutableArray arrayWithCapacity:clippingRectsInFrameCoordinates.size()];
</span></span></pre></div>
<a id="trunkSourceWebKitUIProcessiosWKContentViewInteractionmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (246799 => 246800)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm    2019-06-25 18:47:01 UTC (rev 246799)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm       2019-06-25 18:48:25 UTC (rev 246800)
</span><span class="lines">@@ -6214,6 +6214,11 @@
</span><span class="cx">     return NO;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (UIView *)containerViewForTargetedPreviews
+{
+    return self.unscaledView ?: self;
+}
+
</ins><span class="cx"> #if ENABLE(DRAG_SUPPORT)
</span><span class="cx"> 
</span><span class="cx"> static BOOL shouldEnableDragInteractionForPolicy(_WKDragInteractionPolicy policy)
</span><span class="lines">@@ -6446,7 +6451,7 @@
</span><span class="cx">     [_unselectedContentSnapshot setFrame:data->contentImageWithoutSelectionRectInRootViewCoordinates];
</span><span class="cx"> 
</span><span class="cx">     [self insertSubview:_unselectedContentSnapshot.get() belowSubview:_visibleContentViewSnapshot.get()];
</span><del>-    _dragDropInteractionState.deliverDelayedDropPreview(self, self.unscaledView, data.value());
</del><ins>+    _dragDropInteractionState.deliverDelayedDropPreview(self, self.containerViewForTargetedPreviews, data.value());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (void)_didPerformDragOperation:(BOOL)handled
</span><span class="lines">@@ -6792,7 +6797,7 @@
</span><span class="cx">         if (overriddenPreview)
</span><span class="cx">             return overriddenPreview;
</span><span class="cx">     }
</span><del>-    return _dragDropInteractionState.previewForDragItem(item, self, self.unscaledView);
</del><ins>+    return _dragDropInteractionState.previewForDragItem(item, self, self.containerViewForTargetedPreviews);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (void)dragInteraction:(UIDragInteraction *)interaction willAnimateLiftWithAnimator:(id <UIDragAnimating>)animator session:(id <UIDragSession>)session
</span><span class="lines">@@ -7880,7 +7885,7 @@
</span><span class="cx"> // FIXME: This should be merged with createTargetedDragPreview in DragDropInteractionState.
</span><span class="cx"> static RetainPtr<UITargetedPreview> createTargetedPreview(UIImage *image, UIView *rootView, UIView *previewContainer, const WebCore::FloatRect& frameInRootViewCoordinates, const Vector<WebCore::FloatRect>& clippingRectsInFrameCoordinates, UIColor *backgroundColor)
</span><span class="cx"> {
</span><del>-    if (frameInRootViewCoordinates.isEmpty() || !image)
</del><ins>+    if (frameInRootViewCoordinates.isEmpty() || !image || !previewContainer.window)
</ins><span class="cx">         return nil;
</span><span class="cx"> 
</span><span class="cx">     WebCore::FloatRect frameInContainerCoordinates = [rootView convertRect:frameInRootViewCoordinates toView:previewContainer];
</span><span class="lines">@@ -7936,15 +7941,15 @@
</span><span class="cx">     if (_positionInformation.isLink && _positionInformation.linkIndicator.contentImage) {
</span><span class="cx">         auto indicator = _positionInformation.linkIndicator;
</span><span class="cx">         auto textIndicatorImage = uiImageForImage(indicator.contentImage.get());
</span><del>-        targetedPreview = createTargetedPreview(textIndicatorImage.get(), self, self.unscaledView, indicator.textBoundingRectInRootViewCoordinates, indicator.textRectsInBoundingRectCoordinates, [UIColor colorWithCGColor:cachedCGColor(indicator.estimatedBackgroundColor)]);
</del><ins>+        targetedPreview = createTargetedPreview(textIndicatorImage.get(), self, self.containerViewForTargetedPreviews, indicator.textBoundingRectInRootViewCoordinates, indicator.textRectsInBoundingRectCoordinates, [UIColor colorWithCGColor:cachedCGColor(indicator.estimatedBackgroundColor)]);
</ins><span class="cx">     } else if ((_positionInformation.isAttachment || _positionInformation.isImage) && _positionInformation.image) {
</span><span class="cx">         auto cgImage = _positionInformation.image->makeCGImageCopy();
</span><span class="cx">         auto image = adoptNS([[UIImage alloc] initWithCGImage:cgImage.get()]);
</span><del>-        targetedPreview = createTargetedPreview(image.get(), self, self.unscaledView, _positionInformation.bounds, { }, nil);
</del><ins>+        targetedPreview = createTargetedPreview(image.get(), self, self.containerViewForTargetedPreviews, _positionInformation.bounds, { }, nil);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (!targetedPreview)
</span><del>-        targetedPreview = createFallbackTargetedPreview(self, self.unscaledView, _positionInformation.bounds);
</del><ins>+        targetedPreview = createFallbackTargetedPreview(self, self.containerViewForTargetedPreviews, _positionInformation.bounds);
</ins><span class="cx"> 
</span><span class="cx">     _contextMenuInteractionTargetedPreview = WTFMove(targetedPreview);
</span><span class="cx">     return _contextMenuInteractionTargetedPreview.get();
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (246799 => 246800)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog    2019-06-25 18:47:01 UTC (rev 246799)
+++ trunk/Tools/ChangeLog       2019-06-25 18:48:25 UTC (rev 246800)
</span><span class="lines">@@ -1,3 +1,27 @@
</span><ins>+2019-06-25  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [iOS] Occasional crash under -[UIPreviewTarget initWithContainer:center:transform:] when generating a drag preview
+        https://bugs.webkit.org/show_bug.cgi?id=199192
+        <rdar://problem/51554509>
+
+        Reviewed by Tim Horton.
+
+        Tweak the drag and drop simulator to ask for drag cancellation previews, and use this to write a couple tests to
+        verify that we gracefully handle web process termination and web view unparenting mid-drag.
+
+        * TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm:
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/cocoa/DragAndDropSimulator.h:
+        * TestWebKitAPI/ios/DragAndDropSimulatorIOS.mm:
+        (-[DragAndDropSimulator _resetSimulatedState]):
+        (-[DragAndDropSimulator _concludeDropAndPerformOperationIfNecessary]):
+        (-[DragAndDropSimulator _advanceProgress]):
+        (-[DragAndDropSimulator liftPreviews]):
+        (-[DragAndDropSimulator cancellationPreviews]):
+        (-[DragAndDropSimulator setSessionWillBeginBlock:]):
+        (-[DragAndDropSimulator sessionWillBeginBlock]):
+        (-[DragAndDropSimulator _webView:dataInteraction:sessionWillBegin:]):
+
</ins><span class="cx"> 2019-06-25  Aakash Jain  <aakash_jain@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [ews-build] UploadTestResults and ExtractTestResults clobber results in case of multiple layout test runs in a build
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsiosDragAndDropTestsIOSmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm (246799 => 246800)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm       2019-06-25 18:47:01 UTC (rev 246799)
+++ trunk/Tools/TestWebKitAPI/Tests/ios/DragAndDropTestsIOS.mm  2019-06-25 18:48:25 UTC (rev 246800)
</span><span class="lines">@@ -1445,6 +1445,30 @@
</span><span class="cx">     checkStringArraysAreEqual(@[@"dragstart", @"dragend"], [outputText componentsSeparatedByString:@" "]);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+TEST(DragAndDropTests, WebProcessTerminationDuringDrag)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"link-and-target-div"];
+    auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebView:webView.get()]);
+    [simulator setSessionWillBeginBlock:^{
+        [webView _killWebContentProcessAndResetState];
+    }];
+    [simulator runFrom:CGPointMake(100, 50) to:CGPointMake(300, 50)];
+}
+
+TEST(DragAndDropTests, WebViewRemovedFromViewHierarchyDuringDrag)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"link-and-target-div"];
+    auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebView:webView.get()]);
+    [simulator setConvertItemProvidersBlock:[webView] (NSItemProvider *item, NSArray *, NSDictionary *) -> NSArray * {
+        [webView removeFromSuperview];
+        return @[ item ];
+    }];
+    [simulator runFrom:CGPointMake(100, 50) to:CGPointMake(300, 50)];
+    EXPECT_EQ([simulator cancellationPreviews].firstObject, nil);
+}
+
</ins><span class="cx"> static void testDragAndDropOntoTargetElements(TestWKWebView *webView)
</span><span class="cx"> {
</span><span class="cx">     auto simulator = adoptNS([[DragAndDropSimulator alloc] initWithWebView:webView]);
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPIcocoaDragAndDropSimulatorh"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/cocoa/DragAndDropSimulator.h (246799 => 246800)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/cocoa/DragAndDropSimulator.h   2019-06-25 18:47:01 UTC (rev 246799)
+++ trunk/Tools/TestWebKitAPI/cocoa/DragAndDropSimulator.h      2019-06-25 18:48:25 UTC (rev 246800)
</span><span class="lines">@@ -104,6 +104,7 @@
</span><span class="cx"> @property (nonatomic, copy) NSArray *(^convertItemProvidersBlock)(NSItemProvider *, NSArray *, NSDictionary *);
</span><span class="cx"> @property (nonatomic, copy) NSArray *(^overridePerformDropBlock)(id <UIDropSession>);
</span><span class="cx"> @property (nonatomic, copy) void(^dropCompletionBlock)(BOOL, NSArray *);
</span><ins>+@property (nonatomic, copy) dispatch_block_t sessionWillBeginBlock;
</ins><span class="cx"> @property (nonatomic, copy) UIDropOperation(^overrideDragUpdateBlock)(UIDropOperation, id <UIDropSession>);
</span><span class="cx"> 
</span><span class="cx"> @property (nonatomic, readonly) NSArray *sourceItemProviders;
</span><span class="lines">@@ -111,6 +112,7 @@
</span><span class="cx"> @property (nonatomic, readonly) CGRect finalSelectionStartRect;
</span><span class="cx"> @property (nonatomic, readonly) CGRect lastKnownDragCaretRect;
</span><span class="cx"> @property (nonatomic, readonly) NSArray<UITargetedDragPreview *> *liftPreviews;
</span><ins>+@property (nonatomic, readonly) NSArray<UITargetedDragPreview *> *cancellationPreviews;
</ins><span class="cx"> @property (nonatomic, readonly) NSArray *dropPreviews;
</span><span class="cx"> @property (nonatomic, readonly) NSArray *delayedDropPreviews;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPIiosDragAndDropSimulatorIOSmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/ios/DragAndDropSimulatorIOS.mm (246799 => 246800)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/ios/DragAndDropSimulatorIOS.mm 2019-06-25 18:47:01 UTC (rev 246799)
+++ trunk/Tools/TestWebKitAPI/ios/DragAndDropSimulatorIOS.mm    2019-06-25 18:48:25 UTC (rev 246800)
</span><span class="lines">@@ -310,7 +310,8 @@
</span><span class="cx"> 
</span><span class="cx">     RetainPtr<NSMutableDictionary<NSNumber *, NSValue *>>_remainingAdditionalItemRequestLocationsByProgress;
</span><span class="cx">     RetainPtr<NSMutableArray<NSValue *>>_queuedAdditionalItemRequestLocations;
</span><del>-    RetainPtr<NSMutableArray<UITargetedDragPreview *>> _liftPreviews;
</del><ins>+    RetainPtr<NSMutableArray> _liftPreviews;
+    RetainPtr<NSMutableArray<UITargetedDragPreview *>> _cancellationPreviews;
</ins><span class="cx">     RetainPtr<NSMutableArray> _dropPreviews;
</span><span class="cx">     RetainPtr<NSMutableArray> _delayedDropPreviews;
</span><span class="cx"> 
</span><span class="lines">@@ -330,6 +331,7 @@
</span><span class="cx">     BlockPtr<NSArray *(id <UIDropSession>)> _overridePerformDropBlock;
</span><span class="cx">     BlockPtr<UIDropOperation(UIDropOperation, id)> _overrideDragUpdateBlock;
</span><span class="cx">     BlockPtr<void(BOOL, NSArray *)> _dropCompletionBlock;
</span><ins>+    BlockPtr<void()> _sessionWillBeginBlock;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (instancetype)initWithWebViewFrame:(CGRect)frame
</span><span class="lines">@@ -388,6 +390,7 @@
</span><span class="cx">     _queuedAdditionalItemRequestLocations = adoptNS([[NSMutableArray alloc] init]);
</span><span class="cx">     _liftPreviews = adoptNS([[NSMutableArray alloc] init]);
</span><span class="cx">     _dropPreviews = adoptNS([[NSMutableArray alloc] init]);
</span><ins>+    _cancellationPreviews = adoptNS([[NSMutableArray alloc] init]);
</ins><span class="cx">     _delayedDropPreviews = adoptNS([[NSMutableArray alloc] init]);
</span><span class="cx">     _hasStartedInputSession = false;
</span><span class="cx"> }
</span><span class="lines">@@ -497,6 +500,15 @@
</span><span class="cx">     } else {
</span><span class="cx">         _isDoneWithCurrentRun = true;
</span><span class="cx">         _phase = DragAndDropPhaseCancelled;
</span><ins>+        [[_dropSession items] enumerateObjectsUsingBlock:^(UIDragItem *item, NSUInteger index, BOOL *) {
+            UITargetedDragPreview *defaultPreview = nil;
+            if ([_liftPreviews count] && [[_liftPreviews objectAtIndex:index] isEqual:NSNull.null])
+                defaultPreview = [_liftPreviews objectAtIndex:index];
+
+            UITargetedDragPreview *preview = [[_webView dragInteractionDelegate] dragInteraction:[_webView dragInteraction] previewForCancellingItem:item withDefault:defaultPreview];
+            if (preview)
+                [_cancellationPreviews addObject:preview];
+        }];
</ins><span class="cx">         [[_webView dropInteractionDelegate] dropInteraction:[_webView dropInteraction] concludeDrop:_dropSession.get()];
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -576,9 +588,8 @@
</span><span class="cx">         for (UIDragItem *item in items) {
</span><span class="cx">             [itemProviders addObject:item.itemProvider];
</span><span class="cx">             UITargetedDragPreview *liftPreview = [[_webView dragInteractionDelegate] dragInteraction:[_webView dragInteraction] previewForLiftingItem:item session:_dragSession.get()];
</span><del>-            EXPECT_TRUE(!!liftPreview);
-            if (liftPreview)
-                [_liftPreviews addObject:liftPreview];
</del><ins>+            EXPECT_TRUE(liftPreview || ![_webView window]);
+            [_liftPreviews addObject:liftPreview ?: NSNull.null];
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         _dropSession = adoptNS([[MockDropSession alloc] initWithProviders:itemProviders location:self._currentLocation window:[_webView window] allowMove:self.shouldAllowMoveOperation]);
</span><span class="lines">@@ -662,11 +673,16 @@
</span><span class="cx">     return _phase;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (NSArray<UITargetedDragPreview *> *)liftPreviews
</del><ins>+- (NSArray *)liftPreviews
</ins><span class="cx"> {
</span><span class="cx">     return _liftPreviews.get();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (NSArray<UITargetedDragPreview *> *)cancellationPreviews
+{
+    return _cancellationPreviews.get();
+}
+
</ins><span class="cx"> - (NSArray<UITargetedDragPreview *> *)dropPreviews
</span><span class="cx"> {
</span><span class="cx">     return _dropPreviews.get();
</span><span class="lines">@@ -757,8 +773,24 @@
</span><span class="cx">     return _dropCompletionBlock.get();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (void)setSessionWillBeginBlock:(dispatch_block_t)block
+{
+    _sessionWillBeginBlock = block;
+}
+
+- (dispatch_block_t)sessionWillBeginBlock
+{
+    return _sessionWillBeginBlock.get();
+}
+
</ins><span class="cx"> #pragma mark - WKUIDelegatePrivate
</span><span class="cx"> 
</span><ins>+- (void)_webView:(WKWebView *)webView dataInteraction:(UIDragInteraction *)interaction sessionWillBegin:(id <UIDragSession>)session
+{
+    if (_sessionWillBeginBlock)
+        _sessionWillBeginBlock();
+}
+
</ins><span class="cx"> - (void)_webView:(WKWebView *)webView dataInteractionOperationWasHandled:(BOOL)handled forSession:(id)session itemProviders:(NSArray<NSItemProvider *> *)itemProviders
</span><span class="cx"> {
</span><span class="cx">     if (self.dropCompletionBlock)
</span></span></pre>
</div>
</div>

</body>
</html>