Changeset 257214 in webkit


Ignore:
Timestamp:
Feb 24, 2020 10:05:20 AM (4 years ago)
Author:
Wenson Hsieh
Message:

REGRESSION (r248481): drag animation of a link starts from the incorrect location
https://bugs.webkit.org/show_bug.cgi?id=208113
<rdar://problem/59448696>

Reviewed by Tim Horton.

For both dragging and context menu interactions, UIKit asks us for targeted previews, which are hosted under
container views provided by WebKit. These container views must be in the hierarchy (i.e. they must have a
UIWindow); otherwise, UIKit incorrectly computes some geometry when animating the previews. Prior to the fix for
<rdar://problem/57172514>, this caused targeted drag previews to animate in from a seemingly random location;
however, UIKit worked around this by falling back to the same codepath used for remotely hosted views, which
uses the last known touch location as an approximation of where to start the drag preview animation. This mostly
makes the bug go away, but the delta between the touch location and the actual location of the dragged element
in the page still causes some very minor visual differences.

Due to r248481, a separate UIView (_contextMenuHintContainerView) under the content view is used when generating
targeted previews for both drag and drop and context menu hints. This view is removed when the context menu
interaction ends; however, when starting a drag, the context menu interaction ends right before the drag session
actually begins, which means that when UIKit actually starts to animate the drag preview, the container view has
already been unparented.

To address this, introduce a separate _dragPreviewContainerView alongside _contextMenuHintContainerView, and use
this new view when generating targeted previews for dragging. This view is generated lazily and cleaned up
(unparented and cleared out) when the drag interaction has ended, in -cleanUpDragSourceSessionState.

  • UIProcess/ios/WKContentViewInteraction.h:

Add _dragPreviewContainerView.

  • UIProcess/ios/WKContentViewInteraction.mm:

(-[WKContentView _didCommitLoadForMainFrame]):
(-[WKContentView dataDetectionContextForPositionInformation:]):
(-[WKContentView containerForDragPreviews]):
(-[WKContentView containerForContextMenuHintPreviews]):

Split -containerViewForTargetedPreviews into -containerForDragPreviews and -containerForContextMenuHintPreviews,
and use them as appropriate.

(-[WKContentView _hideTargetedPreviewContainerViews]):

Renamed from _hideContextMenuHintContainer, since it hides both types of targeted preview containers now.

(-[WKContentView cleanUpDragSourceSessionState]):

Clear out and remove _dragPreviewContainerView here.

(-[WKContentView _deliverDelayedDropPreviewIfPossible:]):
(-[WKContentView dragInteraction:previewForLiftingItem:session:]):

Use -containerForDragPreviews when creating previews for dragging.

(-[WKContentView _createTargetedContextMenuHintPreviewIfPossible]):
(-[WKContentView contextMenuInteraction:previewForHighlightingMenuWithConfiguration:]):

Use -containerForContextMenuHintPreviews when creating previews for the context menu hint.

(-[WKContentView containerViewForTargetedPreviews]): Deleted.
(-[WKContentView _hideContextMenuHintContainer]): Deleted.
(-[WKContentView _createTargetedPreviewIfPossible]): Deleted.

Location:
trunk/Source/WebKit
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit/ChangeLog

    r257211 r257214  
     12020-02-24  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        REGRESSION (r248481): drag animation of a link starts from the incorrect location
     4        https://bugs.webkit.org/show_bug.cgi?id=208113
     5        <rdar://problem/59448696>
     6
     7        Reviewed by Tim Horton.
     8
     9        For both dragging and context menu interactions, UIKit asks us for targeted previews, which are hosted under
     10        container views provided by WebKit. These container views must be in the hierarchy (i.e. they must have a
     11        UIWindow); otherwise, UIKit incorrectly computes some geometry when animating the previews. Prior to the fix for
     12        <rdar://problem/57172514>, this caused targeted drag previews to animate in from a seemingly random location;
     13        however, UIKit worked around this by falling back to the same codepath used for remotely hosted views, which
     14        uses the last known touch location as an approximation of where to start the drag preview animation. This mostly
     15        makes the bug go away, but the delta between the touch location and the actual location of the dragged element
     16        in the page still causes some very minor visual differences.
     17
     18        Due to r248481, a separate UIView (_contextMenuHintContainerView) under the content view is used when generating
     19        targeted previews for both drag and drop and context menu hints. This view is removed when the context menu
     20        interaction ends; however, when starting a drag, the context menu interaction ends right before the drag session
     21        actually begins, which means that when UIKit actually starts to animate the drag preview, the container view has
     22        already been unparented.
     23
     24        To address this, introduce a separate _dragPreviewContainerView alongside _contextMenuHintContainerView, and use
     25        this new view when generating targeted previews for dragging. This view is generated lazily and cleaned up
     26        (unparented and cleared out) when the drag interaction has ended, in -cleanUpDragSourceSessionState.
     27
     28        * UIProcess/ios/WKContentViewInteraction.h:
     29
     30        Add _dragPreviewContainerView.
     31
     32        * UIProcess/ios/WKContentViewInteraction.mm:
     33        (-[WKContentView _didCommitLoadForMainFrame]):
     34        (-[WKContentView dataDetectionContextForPositionInformation:]):
     35        (-[WKContentView containerForDragPreviews]):
     36        (-[WKContentView containerForContextMenuHintPreviews]):
     37
     38        Split -containerViewForTargetedPreviews into -containerForDragPreviews and -containerForContextMenuHintPreviews,
     39        and use them as appropriate.
     40
     41        (-[WKContentView _hideTargetedPreviewContainerViews]):
     42
     43        Renamed from _hideContextMenuHintContainer, since it hides both types of targeted preview containers now.
     44
     45        (-[WKContentView cleanUpDragSourceSessionState]):
     46
     47        Clear out and remove _dragPreviewContainerView here.
     48
     49        (-[WKContentView _deliverDelayedDropPreviewIfPossible:]):
     50        (-[WKContentView dragInteraction:previewForLiftingItem:session:]):
     51
     52        Use -containerForDragPreviews when creating previews for dragging.
     53
     54        (-[WKContentView _createTargetedContextMenuHintPreviewIfPossible]):
     55        (-[WKContentView contextMenuInteraction:previewForHighlightingMenuWithConfiguration:]):
     56
     57        Use -containerForContextMenuHintPreviews when creating previews for the context menu hint.
     58
     59        (-[WKContentView containerViewForTargetedPreviews]): Deleted.
     60        (-[WKContentView _hideContextMenuHintContainer]): Deleted.
     61        (-[WKContentView _createTargetedPreviewIfPossible]): Deleted.
     62
    1632020-02-24  Rob Buis  <rbuis@igalia.com>
    264
  • trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h

    r256864 r257214  
    253253    RetainPtr<UIView> _interactionViewsContainerView;
    254254    RetainPtr<UIView> _contextMenuHintContainerView;
     255    RetainPtr<UIView> _dragPreviewContainerView;
    255256    RetainPtr<NSString> _markedText;
    256257    RetainPtr<WKActionSheetAssistant> _actionSheetAssistant;
     
    487488- (void)_updateInputContextAfterBlurringAndRefocusingElement;
    488489- (void)_elementDidBlur;
    489 - (void)_hideContextMenuHintContainer;
     490- (void)_hideTargetedPreviewContainerViews;
    490491- (void)_didUpdateInputMode:(WebCore::InputMode)mode;
    491492- (void)_didUpdateEditorState;
  • trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm

    r256921 r257214  
    42584258    [self _elementDidBlur];
    42594259    [self _cancelLongPressGestureRecognizer];
    4260     [self _hideContextMenuHintContainer];
     4260    [self _hideTargetedPreviewContainerViews];
    42614261    [_webView _didCommitLoadForMainFrame];
    42624262
     
    67626762        sourceRect = positionInformation.bounds;
    67636763
    6764     CGRect frameInContainerViewCoordinates = [self convertRect:sourceRect toView:self.containerViewForTargetedPreviews];
     6764    CGRect frameInContainerViewCoordinates = [self convertRect:sourceRect toView:self.containerForContextMenuHintPreviews];
    67656765    context.get()[getkDataDetectorsSourceRectKey()] = [NSValue valueWithCGRect:frameInContainerViewCoordinates];
    67666766#endif
     
    68226822}
    68236823
    6824 // FIXME: This is used for drag previews and context menu hints; it needs a better name.
    6825 - (UIView *)containerViewForTargetedPreviews
     6824- (UIView *)containerForDragPreviews
     6825{
     6826    if (_dragPreviewContainerView) {
     6827        ASSERT([_dragPreviewContainerView superview]);
     6828        [_dragPreviewContainerView setHidden:NO];
     6829        return _dragPreviewContainerView.get();
     6830    }
     6831
     6832    _dragPreviewContainerView = adoptNS([[UIView alloc] init]);
     6833    [_dragPreviewContainerView layer].anchorPoint = CGPointZero;
     6834    [_dragPreviewContainerView layer].name = @"Drag Preview Container";
     6835    [_interactionViewsContainerView addSubview:_dragPreviewContainerView.get()];
     6836
     6837    return _dragPreviewContainerView.get();
     6838}
     6839
     6840- (UIView *)containerForContextMenuHintPreviews
    68266841{
    68276842    if (_contextMenuHintContainerView) {
     
    68336848    _contextMenuHintContainerView = adoptNS([[UIView alloc] init]);
    68346849    [_contextMenuHintContainerView layer].anchorPoint = CGPointZero;
    6835     [_contextMenuHintContainerView layer].name = @"Context Menu Container";
     6850    [_contextMenuHintContainerView layer].name = @"Context Menu Hint Container";
    68366851    [_interactionViewsContainerView addSubview:_contextMenuHintContainerView.get()];
    68376852
     
    68396854}
    68406855
    6841 - (void)_hideContextMenuHintContainer
    6842 {
     6856- (void)_hideTargetedPreviewContainerViews
     6857{
     6858    [_dragPreviewContainerView setHidden:YES];
    68436859    [_contextMenuHintContainerView setHidden:YES];
    68446860}
     
    70687084    [self _restoreCalloutBarIfNeeded];
    70697085
     7086    [std::exchange(_dragPreviewContainerView, nil) removeFromSuperview];
    70707087    [std::exchange(_visibleContentViewSnapshot, nil) removeFromSuperview];
    70717088    [_editDropCaretView remove];
     
    71357152
    71367153    [self insertSubview:_unselectedContentSnapshot.get() belowSubview:_visibleContentViewSnapshot.get()];
    7137     _dragDropInteractionState.deliverDelayedDropPreview(self, self.containerViewForTargetedPreviews, data.value());
     7154    _dragDropInteractionState.deliverDelayedDropPreview(self, self.containerForDragPreviews, data.value());
    71387155}
    71397156
     
    75727589            return overriddenPreview;
    75737590    }
    7574     return _dragDropInteractionState.previewForDragItem(item, self, self.containerViewForTargetedPreviews);
     7591    return _dragDropInteractionState.previewForDragItem(item, self, self.containerForDragPreviews);
    75757592}
    75767593
     
    87558772}
    87568773
    8757 - (UITargetedPreview *)_createTargetedPreviewIfPossible
     8774- (UITargetedPreview *)_createTargetedContextMenuHintPreviewIfPossible
    87588775{
    87598776    RetainPtr<UITargetedPreview> targetedPreview;
     
    87628779        auto indicator = _positionInformation.linkIndicator;
    87638780        auto textIndicatorImage = uiImageForImage(indicator.contentImage.get());
    8764         targetedPreview = createTargetedPreview(textIndicatorImage.get(), self, self.containerViewForTargetedPreviews, indicator.textBoundingRectInRootViewCoordinates, indicator.textRectsInBoundingRectCoordinates, [UIColor colorWithCGColor:cachedCGColor(indicator.estimatedBackgroundColor)]);
     8781        targetedPreview = createTargetedPreview(textIndicatorImage.get(), self, self.containerForContextMenuHintPreviews, indicator.textBoundingRectInRootViewCoordinates, indicator.textRectsInBoundingRectCoordinates, [UIColor colorWithCGColor:cachedCGColor(indicator.estimatedBackgroundColor)]);
    87658782    } else if ((_positionInformation.isAttachment || _positionInformation.isImage) && _positionInformation.image) {
    87668783        auto cgImage = _positionInformation.image->makeCGImageCopy();
    87678784        auto image = adoptNS([[UIImage alloc] initWithCGImage:cgImage.get()]);
    8768         targetedPreview = createTargetedPreview(image.get(), self, self.containerViewForTargetedPreviews, _positionInformation.bounds, { }, nil);
     8785        targetedPreview = createTargetedPreview(image.get(), self, self.containerForContextMenuHintPreviews, _positionInformation.bounds, { }, nil);
    87698786    }
    87708787
    87718788    if (!targetedPreview)
    8772         targetedPreview = createFallbackTargetedPreview(self, self.containerViewForTargetedPreviews, _positionInformation.bounds);
     8789        targetedPreview = createFallbackTargetedPreview(self, self.containerForContextMenuHintPreviews, _positionInformation.bounds);
    87738790
    87748791    if (_positionInformation.containerScrollingNodeID) {
     
    87888805{
    87898806    [self _startSuppressingSelectionAssistantForReason:WebKit::InteractionIsHappening];
    8790     return [self _createTargetedPreviewIfPossible];
     8807    return [self _createTargetedContextMenuHintPreviewIfPossible];
    87918808}
    87928809
Note: See TracChangeset for help on using the changeset viewer.