[webkit-changes] [WebKit/WebKit] d33796: Move off of UIKit SPI: -_dragInteraction:item:shou...

Wenson Hsieh noreply at github.com
Tue Aug 22 17:32:43 PDT 2023


  Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: d3379615c46a7fbd6bdf60a47a101c44c9aa93d5
      https://github.com/WebKit/WebKit/commit/d3379615c46a7fbd6bdf60a47a101c44c9aa93d5
  Author: Wenson Hsieh <wenson_hsieh at apple.com>
  Date:   2023-08-22 (Tue, 22 Aug 2023)

  Changed paths:
    M Source/WebKit/UIProcess/ios/DragDropInteractionState.h
    M Source/WebKit/UIProcess/ios/DragDropInteractionState.mm
    M Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm

  Log Message:
  -----------
  Move off of UIKit SPI: -_dragInteraction:item:shouldDelaySetDownAnimationWithCompletion:
https://bugs.webkit.org/show_bug.cgi?id=260502
rdar://114259800

Reviewed by Aditya Keerthi.

While dragging a selected text range, we paint any text within the selected range at 0.25 opacity
during the drag. Once the drag completes or is cancelled, we'll remove this effect and repaint the
dragged content like normal. In the case of the latter (i.e. cancelling a drag), the drag preview
animates back to its original location on the page and UIKit performs a set-down animation where the
drag preview fades to reveal the content underneath it; as such, we need to coordinate the repaint
at full opacity with this set-down animation, such that the text is still shows with 25%-opacity
while the drag preview is animating back into place, but once the drag preview begins the set-down
animation, it cross-fades to reveal the original, full-opacity content underneath.

We currently achieve this via `-_dragInteraction:item:shouldDelaySetDownAnimationWithCompletion:`
by returning `YES` and calling the completion handler after the next presentation update *after* the
cancel animation completes. This tells UIKit to halt the cancel animation after the drag preview
"flies" back into place but before the set-down animation begins, such that the original drag
preview covers the webpage. We then use this opportunity to issue a repaint of the page without
dragged content ranges, and finally tell UIKit to commence the set-down animation once we're
finished painting. The drag preview naturally cross-fades to reveal the original web content
underneath it.

To move off of this SPI, we can instead leverage the fact that UIKit will *only* automatically
remove the targeted preview's view after the set-down animation, if the preview view was not
*already* in the targeted preview container's view hierarchy upon creating the targeted preview.
This means that if we add the preview view as a subview of the `_interactionViewsContainerView`
ourselves prior to creating the preview in `-dragInteraction:previewForCancellingItem:withDefault:`,
the targeted preview will run the set-down animation, but then cross-fade to reveal the preview view
underneath (rather than the web page). Importantly, this allows us to ensure that the preview view
still covers the webpage while we repaint, and then only remove the preview view from the view
hierarchy once the repaint finishes, to reveal the actual webpage.

I manually tested this by adding a 100 ms sleep in `WebPage::dragCancelled()`, and verifying that
we're still able to (gracefully) coordinate the set-down animation during a drag cancel.

* Source/WebKit/UIProcess/ios/DragDropInteractionState.h:

Remove `m_dragCancelSetDownBlock`, and replace it with `m_previewViewForDragCancel`, which the
content view will use during set-down to coordinate fading out and in the preview view.

(WebKit::DragDropInteractionState::takePreviewViewForDragCancel const):
* Source/WebKit/UIProcess/ios/DragDropInteractionState.mm:
(WebKit::createTargetedDragPreview):

Make this take a new enum to indicate whether the preview view should be added to the view hierarchy
upon creating the targeted preview. See below for more details.

(WebKit::DragDropInteractionState::deliverDelayedDropPreview):
(WebKit::DragDropInteractionState::previewForLifting const):
(WebKit::DragDropInteractionState::previewForCancelling):

Split `previewForDragItem` into two methods: a helper method for the lift preview, and another
helper for the cancel preview. Both are effectively wrappers around the same logic, which is now
moved into a private helper method below; `previewForLifting` behaves exactly the same way as it
does currently, while `previewForCancelling` will automatically add the preview view to the view
hierarchy before returning the preview, and will also save a reference to the preview view.

(WebKit::DragDropInteractionState::createDragPreviewInternal const):
(WebKit::DragDropInteractionState::dragAndDropSessionsDidEnd):
(WebKit::DragDropInteractionState::previewForDragItem const): Deleted.
(WebKit::DragDropInteractionState::dragSessionWillDelaySetDownAnimation): Deleted.
* Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView dragInteraction:previewForLiftingItem:session:]):

Use `previewForLiftingItem` to construct the targeted preview when cancelling a drag. There is a
caveat here, which is that any targeted preview returned by the UI delegate SPI won't go through the
new codepath for managing the drag cancel preview view. In practice, the only internal client that
uses this SPI is Mail, which only uses it for certain types of attachments that (currently) don't
fade as they're dragged, so the mechanism for delaying the set-down animation didn't affect this
scenario anyways.

(-[WKContentView dragInteraction:previewForCancellingItem:withDefault:]):
(-[WKContentView dragInteraction:item:willAnimateCancelWithAnimator:]):

Implement the main fix here — when the cancel animation begins, we start the preview at `alpha=0`,
since we don't want it to obscure the webpage yet. Once the completion block is invoked (i.e. the
set-down animation begins), we then set `alpha=1` to make the preview cover the page as it's being
painted. Finally, upon finishing the next presentation update, we remove the preview view
altogether, revealing the original (non-dragged) appearance of the web page underneath.

(-[WKContentView _dragInteraction:item:shouldDelaySetDownAnimationWithCompletion:]): Deleted.

Canonical link: https://commits.webkit.org/267165@main




More information about the webkit-changes mailing list