⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 281054 in webkit


Ignore:
Timestamp:
Aug 13, 2021, 5:47:03 PM (5 years ago)
Author:
Wenson Hsieh
Message:

[iOS 15] fast/events/touch/ios/long-press-on-link.html is a constant crash
https://bugs.webkit.org/show_bug.cgi?id=229095
rdar://80386326

Reviewed by Tim Horton.

Source/WebKit:

This test crashes when run immediately after another test that attempts to present the context menu and ends
with the context menu still showing (in this case, fast/events/touch/ios/long-press-on-image.html). Running
these tests back to back causes us to immediately dismiss the context menu interaction while transitioning to
the second test, which triggers the context menu interaction's dismissal animation.

This animation ends in the middle of the next test (long-press-on-link.html), after the long press has begun and
the context menu interaction has already requested a targeted hint preview, but (importantly) before the context
menu peek animation actually begins (i.e. -contextMenuInteraction:willDisplayMenuForConfiguration:animator:).
As a result, we tear down the hint container too early (with the hint view still in the view hierarchy), and
subsequently crash with an exception when UIKit tries to perform coordinate space conversions with the now-
unparented view.

To fix this, we make two small adjustments:

  1. Avoid unparenting the context menu hint container if it still has subviews.
  2. Add plumbing to ensure that the context menu hint container is unparented once all of its subviews have

been removed (and the container isn't being used for anything else).

  • Platform/spi/ios/UIKitSPI.h:

Add an SPI declaration for the -_didRemoveSubview: subclassing hook.

  • UIProcess/ios/WKContentViewInteraction.h:
  • UIProcess/ios/WKContentViewInteraction.mm:

(-[WKTargetedPreviewContainer initWithContentView:]):
(-[WKTargetedPreviewContainer _didRemoveSubview:]):

Add a new subclass for WKTargetedPreviewContainer that notifies WKContentView when its last subview has been
removed, such that WKContentView can tear down the container view if needed.

(-[WKContentView cleanUpInteraction]):
(-[WKContentView removeContextMenuViewIfPossibleForActionSheetAssistant:]):
(-[WKContentView _targetedPreviewContainerDidRemoveLastSubview:]):
(-[WKContentView _createPreviewContainerWithLayerName:]):
(-[WKContentView _removeContextMenuHintContainerIfPossible]):
(-[WKContentView contextMenuInteraction:willEndForConfiguration:animator:]):
(-[WKContentView _removeContextMenuViewIfPossible]): Deleted.

Additionally rename -_removeContextMenuViewIfPossible to -_removeContextMenuHintContainerIfPossible, to make
it clear that this method is about removing the container view for context menu hints (and not the hints
themselves).

  • UIProcess/ios/WebDataListSuggestionsDropdownIOS.mm:

(-[WKDataListSuggestionsDropdown _removeContextMenuInteraction]):

  • UIProcess/ios/forms/WKDateTimeInputControl.mm:

(-[WKDateTimePicker removeContextMenuInteraction]):

  • UIProcess/ios/forms/WKFileUploadPanel.mm:

(-[WKFileUploadPanel removeContextMenuInteraction]):

  • UIProcess/ios/forms/WKFormSelectPicker.mm:

(-[WKSelectPicker removeContextMenuInteraction]):

LayoutTests:

Remove the failing test expectation (and remove a passing expectation for iOS 14 which is no longer necessary
after this fix).

  • platform/ios-14/TestExpectations:
  • platform/ios/TestExpectations:
Location:
trunk
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r281038 r281054  
     12021-08-13  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [iOS 15] fast/events/touch/ios/long-press-on-link.html is a constant crash
     4        https://bugs.webkit.org/show_bug.cgi?id=229095
     5        rdar://80386326
     6
     7        Reviewed by Tim Horton.
     8
     9        Remove the failing test expectation (and remove a passing expectation for iOS 14 which is no longer necessary
     10        after this fix).
     11
     12        * platform/ios-14/TestExpectations:
     13        * platform/ios/TestExpectations:
     14
    1152021-08-13  Ayumi Kojima  <ayumi_kojima@apple.com>
    216
  • trunk/LayoutTests/platform/ios-14/TestExpectations

    r280427 r281054  
    7373http/tests/websocket/tests/hybi/too-long-payload.html [ Pass ]
    7474
    75 #rdar://80386326 ([ iOS15 Release ] fast/events/touch/ios/long-press-on-link.html is a constant crash)
    76 fast/events/touch/ios/long-press-on-link.html [ Pass ]
    77 
    7875# rdar://80392337 ([ iOS15 ] fast/text/international/system-language/navigator-language/navigator-language-ru.html is a constant failure)
    7976fast/text/international/system-language/navigator-language/navigator-language-ru.html [ Pass ]
  • trunk/LayoutTests/platform/ios/TestExpectations

    r281010 r281054  
    34113411http/tests/websocket/tests/hybi/too-long-payload.html [ Timeout ]
    34123412
    3413 #rdar://80386326 ([ iOS15 Release ] fast/events/touch/ios/long-press-on-link.html is a constant crash)
    3414 fast/events/touch/ios/long-press-on-link.html [ Crash ]
    3415 
    34163413# rdar://80392337 ([ iOS15 ] fast/text/international/system-language/navigator-language/navigator-language-ru.html is a constant failure)
    34173414fast/text/international/system-language/navigator-language/navigator-language-ru.html [ Failure ]
  • trunk/Source/WebKit/ChangeLog

    r281044 r281054  
     12021-08-13  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        [iOS 15] fast/events/touch/ios/long-press-on-link.html is a constant crash
     4        https://bugs.webkit.org/show_bug.cgi?id=229095
     5        rdar://80386326
     6
     7        Reviewed by Tim Horton.
     8
     9        This test crashes when run immediately after another test that attempts to present the context menu and ends
     10        with the context menu still showing (in this case, fast/events/touch/ios/long-press-on-image.html). Running
     11        these tests back to back causes us to immediately dismiss the context menu interaction while transitioning to
     12        the second test, which triggers the context menu interaction's dismissal animation.
     13
     14        This animation ends in the middle of the next test (long-press-on-link.html), after the long press has begun and
     15        the context menu interaction has already requested a targeted hint preview, but (importantly) before the context
     16        menu peek animation actually begins (i.e. `-contextMenuInteraction:willDisplayMenuForConfiguration:animator:`).
     17        As a result, we tear down the hint container too early (with the hint view still in the view hierarchy), and
     18        subsequently crash with an exception when UIKit tries to perform coordinate space conversions with the now-
     19        unparented view.
     20
     21        To fix this, we make two small adjustments:
     22        1.      Avoid unparenting the context menu hint container if it still has subviews.
     23        2.      Add plumbing to ensure that the context menu hint container is unparented once all of its subviews have
     24                been removed (and the container isn't being used for anything else).
     25
     26        * Platform/spi/ios/UIKitSPI.h:
     27
     28        Add an SPI declaration for the `-_didRemoveSubview:` subclassing hook.
     29
     30        * UIProcess/ios/WKContentViewInteraction.h:
     31        * UIProcess/ios/WKContentViewInteraction.mm:
     32        (-[WKTargetedPreviewContainer initWithContentView:]):
     33        (-[WKTargetedPreviewContainer _didRemoveSubview:]):
     34
     35        Add a new subclass for WKTargetedPreviewContainer that notifies WKContentView when its last subview has been
     36        removed, such that WKContentView can tear down the container view if needed.
     37
     38        (-[WKContentView cleanUpInteraction]):
     39        (-[WKContentView removeContextMenuViewIfPossibleForActionSheetAssistant:]):
     40        (-[WKContentView _targetedPreviewContainerDidRemoveLastSubview:]):
     41        (-[WKContentView _createPreviewContainerWithLayerName:]):
     42        (-[WKContentView _removeContextMenuHintContainerIfPossible]):
     43        (-[WKContentView contextMenuInteraction:willEndForConfiguration:animator:]):
     44        (-[WKContentView _removeContextMenuViewIfPossible]): Deleted.
     45
     46        Additionally rename `-_removeContextMenuViewIfPossible` to `-_removeContextMenuHintContainerIfPossible`, to make
     47        it clear that this method is about removing the container view for context menu hints (and not the hints
     48        themselves).
     49
     50        * UIProcess/ios/WebDataListSuggestionsDropdownIOS.mm:
     51        (-[WKDataListSuggestionsDropdown _removeContextMenuInteraction]):
     52        * UIProcess/ios/forms/WKDateTimeInputControl.mm:
     53        (-[WKDateTimePicker removeContextMenuInteraction]):
     54        * UIProcess/ios/forms/WKFileUploadPanel.mm:
     55        (-[WKFileUploadPanel removeContextMenuInteraction]):
     56        * UIProcess/ios/forms/WKFormSelectPicker.mm:
     57        (-[WKSelectPicker removeContextMenuInteraction]):
     58
    1592021-08-13  Jer Noble  <jer.noble@apple.com>
    260
  • trunk/Source/WebKit/Platform/spi/ios/UIKitSPI.h

    r280986 r281054  
    638638- (void)insertSubview:(UIView *)view above:(UIView *)sibling;
    639639- (void)viewWillMoveToSuperview:(UIView *)newSuperview;
     640- (void)_didRemoveSubview:(UIView *)subview;
    640641- (CGSize)convertSize:(CGSize)size toView:(UIView *)view;
    641642- (void)_removeAllAnimations:(BOOL)includeSubviews;
  • trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h

    r280767 r281054  
    123123@class WKMouseGestureRecognizer;
    124124@class WKInspectorNodeSearchGestureRecognizer;
     125@class WKTargetedPreviewContainer;
    125126@class WKTextRange;
    126127@class _WKTextInputContext;
     
    319320    RetainPtr<_UIHighlightView> _highlightView;
    320321    RetainPtr<UIView> _interactionViewsContainerView;
    321     RetainPtr<UIView> _contextMenuHintContainerView;
     322    RetainPtr<WKTargetedPreviewContainer> _contextMenuHintContainerView;
    322323    WeakObjCPtr<UIScrollView> _scrollViewForTargetedPreview;
    323324    CGPoint _scrollViewForTargetedPreviewInitialOffset;
    324     RetainPtr<UIView> _dragPreviewContainerView;
    325     RetainPtr<UIView> _dropPreviewContainerView;
     325    RetainPtr<WKTargetedPreviewContainer> _dragPreviewContainerView;
     326    RetainPtr<WKTargetedPreviewContainer> _dropPreviewContainerView;
    326327    RetainPtr<NSString> _markedText;
    327328    RetainPtr<WKActionSheetAssistant> _actionSheetAssistant;
     
    732733- (UITargetedPreview *)_createTargetedContextMenuHintPreviewForFocusedElement;
    733734- (UITargetedPreview *)_createTargetedContextMenuHintPreviewIfPossible;
    734 - (void)_removeContextMenuViewIfPossible;
     735- (void)_removeContextMenuHintContainerIfPossible;
     736- (void)_targetedPreviewContainerDidRemoveLastSubview:(WKTargetedPreviewContainer *)containerView;
    735737#endif
    736738
  • trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm

    r280767 r281054  
    769769@end
    770770
     771@interface WKTargetedPreviewContainer : UIView
     772- (instancetype)initWithContentView:(WKContentView *)contentView NS_DESIGNATED_INITIALIZER;
     773- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
     774- (instancetype)initWithCoder:(NSCoder *)coder NS_UNAVAILABLE;
     775@end
     776
     777@implementation WKTargetedPreviewContainer {
     778    __weak WKContentView *_contentView;
     779}
     780
     781- (instancetype)initWithContentView:(WKContentView *)contentView
     782{
     783    if (!(self = [super initWithFrame:CGRectZero]))
     784        return nil;
     785
     786    _contentView = contentView;
     787    return self;
     788}
     789
     790- (void)_didRemoveSubview:(UIView *)subview
     791{
     792    [super _didRemoveSubview:subview];
     793
     794    if (self.subviews.count)
     795        return;
     796
     797#if USE(UICONTEXTMENU)
     798    [_contentView _targetedPreviewContainerDidRemoveLastSubview:self];
     799#endif
     800}
     801
     802@end
     803
    771804@interface WKContentView (WKInteractionPrivate)
    772805- (void)accessibilitySpeakSelectionSetContent:(NSString *)string;
     
    11411174
    11421175#if USE(UICONTEXTMENU)
    1143     [self _removeContextMenuViewIfPossible];
     1176    [self _removeContextMenuHintContainerIfPossible];
    11441177#endif // USE(UICONTEXTMENU)
    11451178
     
    77577790- (void)removeContextMenuViewIfPossibleForActionSheetAssistant:(WKActionSheetAssistant *)assistant
    77587791{
    7759     [self _removeContextMenuViewIfPossible];
     7792    [self _removeContextMenuHintContainerIfPossible];
    77607793}
    77617794
     
    77687801{
    77697802    [_webView _didDismissContextMenu];
     7803}
     7804
     7805- (void)_targetedPreviewContainerDidRemoveLastSubview:(WKTargetedPreviewContainer *)containerView
     7806{
     7807    if (_contextMenuHintContainerView == containerView)
     7808        [self _removeContextMenuHintContainerIfPossible];
    77707809}
    77717810
     
    78587897#endif // HAVE(PASTEBOARD_DATA_OWNER)
    78597898
    7860 - (RetainPtr<UIView>)_createPreviewContainerWithLayerName:(NSString *)layerName
    7861 {
    7862     auto container = adoptNS([[UIView alloc] init]);
     7899- (RetainPtr<WKTargetedPreviewContainer>)_createPreviewContainerWithLayerName:(NSString *)layerName
     7900{
     7901    auto container = adoptNS([[WKTargetedPreviewContainer alloc] initWithContentView:self]);
    78637902    [container layer].anchorPoint = CGPointZero;
    78647903    [container layer].name = layerName;
     
    86978736}
    86988737
    8699 - (void)_removeContextMenuViewIfPossible
     8738- (void)_removeContextMenuHintContainerIfPossible
    87008739{
    87018740#if HAVE(LINK_PREVIEW)
     
    87138752    if (_fileUploadPanel)
    87148753        return;
    8715    
     8754
    87168755    // and for the date/time picker.
    87178756    if ([self dateTimeInputControl])
     
    87208759    if ([self selectControl])
    87218760        return;
    8722    
     8761
     8762    if ([_contextMenuHintContainerView subviews].count)
     8763        return;
     8764
    87238765    [self _removeContainerForContextMenuHintPreviews];
    87248766}
     
    1138311425        if (!strongSelf)
    1138411426            return;
    11385         [strongSelf _removeContextMenuViewIfPossible];
     11427        [strongSelf _removeContextMenuHintContainerIfPossible];
    1138611428        [strongSelf->_webView _didDismissContextMenu];
    1138711429    }];
  • trunk/Source/WebKit/UIProcess/ios/WebDataListSuggestionsDropdownIOS.mm

    r279863 r281054  
    517517    [self.view removeInteraction:_suggestionsContextMenuInteraction.get()];
    518518    _suggestionsContextMenuInteraction = nil;
    519     [self.view _removeContextMenuViewIfPossible];
     519    [self.view _removeContextMenuHintContainerIfPossible];
    520520    [self.view.webView _didDismissContextMenu];
    521521}
  • trunk/Source/WebKit/UIProcess/ios/forms/WKDateTimeInputControl.mm

    r280398 r281054  
    470470        [_view removeInteraction:_dateTimeContextMenuInteraction.get()];
    471471        _dateTimeContextMenuInteraction = nil;
    472         [_view _removeContextMenuViewIfPossible];
     472        [_view _removeContextMenuHintContainerIfPossible];
    473473        [_view.webView _didDismissContextMenu];
    474474    }
  • trunk/Source/WebKit/UIProcess/ios/forms/WKFileUploadPanel.mm

    r280883 r281054  
    497497        [_view removeInteraction:_documentContextMenuInteraction.get()];
    498498        _documentContextMenuInteraction = nil;
    499         [_view _removeContextMenuViewIfPossible];
     499        [_view _removeContextMenuHintContainerIfPossible];
    500500    }
    501501}
  • trunk/Source/WebKit/UIProcess/ios/forms/WKFormSelectPicker.mm

    r280398 r281054  
    702702    [_view removeInteraction:_selectContextMenuInteraction.get()];
    703703    _selectContextMenuInteraction = nil;
    704     [_view _removeContextMenuViewIfPossible];
     704    [_view _removeContextMenuHintContainerIfPossible];
    705705    [_view.webView _didDismissContextMenu];
    706706}
Note: See TracChangeset for help on using the changeset viewer.