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

Changeset 284766 in webkit


Ignore:
Timestamp:
Oct 24, 2021, 1:39:35 PM (5 years ago)
Author:
Wenson Hsieh
Message:

REGRESSION (iOS 15): Safari shows zoom callout even if -webkit-user-select is none
https://bugs.webkit.org/show_bug.cgi?id=231161
rdar://83863266

Reviewed by Darin Adler.

Source/WebKit:

Make several minor tweaks to prevent the text interaction assistant's loupe gesture from beginning when long
pressing inside content with -webkit-user-select: none;. Importantly, this prevents both the text
interaction's haptic feedback and the text selection magnifier UI (introduced in iOS 15) from showing up. See
comments below for more details.

Test: editing/selection/ios/do-not-allow-text-selection-in-user-select-none.html

  • Shared/ios/InteractionInformationAtPosition.h:

(WebKit::InteractionInformationAtPosition::isSelectable const):

Add a helper method to return whether the selectability flag is equal to Selectable, and use this in places
where we current check the isSelectable flag.

  • Shared/ios/InteractionInformationAtPosition.mm:

(WebKit::InteractionInformationAtPosition::encode const):
(WebKit::InteractionInformationAtPosition::decode):

Break the current isSelectable flag out into different enum types, which enumerate the reasons why we might
need to treat hit-tested content as non-user-selectable. Importantly, this allows us to only early return inside
-textInteractionGesture:shouldBeginAtPoint: below if the element has an explicit -webkit-user-select: none;,
and not because of the other reasons (i.e. large element bounds or the fact that we're long pressing editable
text while not editing).

This nuance is important in order to continue allowing the loupe gesture (which manifests as a floating caret)
to begin when long pressing inside a focused a text field.

  • UIProcess/ios/WKContentViewInteraction.mm:

(-[WKContentView hasSelectablePositionAtPoint:]):
(-[WKContentView textInteractionGesture:shouldBeginAtPoint:]):

Return NO here in the case where we're recognizing a loupe gesture (i.e. long press) inside content with
-webkit-user-select: none; (by consulting the new selectability enumeration). This allows us to prevent both
haptic feedback as well as the new magnifier UI from triggering when long pressing inside content that has
explicitly disabled text selection.

(-[WKContentView closestPositionToPoint:]):

  • WebProcess/WebPage/ios/WebPageIOS.mm:

(WebKit::selectionPositionInformation):
(WebKit::WebPage::positionInformation):

Additionally populate the selectability flag even when long pressing inside images and links. Instead of
putting the call to selectionPositionInformation behind the isLink/isImage check, move that condition into
selectionPositionInformation in the form of an early return, and always populate selectability in either
case.

LayoutTests:

See Source/WebKit/ChangeLog for more details.

  • editing/selection/ios/do-not-allow-text-selection-in-user-select-none-expected.txt: Added.
  • editing/selection/ios/do-not-allow-text-selection-in-user-select-none.html: Added.
Location:
trunk
Files:
2 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r284758 r284766  
     12021-10-24  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        REGRESSION (iOS 15): Safari shows zoom callout even if -webkit-user-select is none
     4        https://bugs.webkit.org/show_bug.cgi?id=231161
     5        rdar://83863266
     6
     7        Reviewed by Darin Adler.
     8
     9        See Source/WebKit/ChangeLog for more details.
     10
     11        * editing/selection/ios/do-not-allow-text-selection-in-user-select-none-expected.txt: Added.
     12        * editing/selection/ios/do-not-allow-text-selection-in-user-select-none.html: Added.
     13
    1142021-10-24  Alexey Shvayka  <shvaikalesh@gmail.com>
    215
  • trunk/Source/WebKit/ChangeLog

    r284763 r284766  
     12021-10-24  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        REGRESSION (iOS 15): Safari shows zoom callout even if -webkit-user-select is none
     4        https://bugs.webkit.org/show_bug.cgi?id=231161
     5        rdar://83863266
     6
     7        Reviewed by Darin Adler.
     8
     9        Make several minor tweaks to prevent the text interaction assistant's loupe gesture from beginning when long
     10        pressing inside content with `-webkit-user-select: none;`. Importantly, this prevents both the text
     11        interaction's haptic feedback and the text selection magnifier UI (introduced in iOS 15) from showing up. See
     12        comments below for more details.
     13
     14        Test: editing/selection/ios/do-not-allow-text-selection-in-user-select-none.html
     15
     16        * Shared/ios/InteractionInformationAtPosition.h:
     17        (WebKit::InteractionInformationAtPosition::isSelectable const):
     18
     19        Add a helper method to return whether the `selectability` flag is equal to `Selectable`, and use this in places
     20        where we current check the `isSelectable` flag.
     21
     22        * Shared/ios/InteractionInformationAtPosition.mm:
     23        (WebKit::InteractionInformationAtPosition::encode const):
     24        (WebKit::InteractionInformationAtPosition::decode):
     25
     26        Break the current `isSelectable` flag out into different enum types, which enumerate the reasons why we might
     27        need to treat hit-tested content as non-user-selectable. Importantly, this allows us to only early return inside
     28        `-textInteractionGesture:shouldBeginAtPoint:` below if the element has an explicit `-webkit-user-select: none;`,
     29        and not because of the other reasons (i.e. large element bounds or the fact that we're long pressing editable
     30        text while not editing).
     31
     32        This nuance is important in order to continue allowing the loupe gesture (which manifests as a floating caret)
     33        to begin when long pressing inside a focused a text field.
     34
     35        * UIProcess/ios/WKContentViewInteraction.mm:
     36        (-[WKContentView hasSelectablePositionAtPoint:]):
     37        (-[WKContentView textInteractionGesture:shouldBeginAtPoint:]):
     38
     39        Return NO here in the case where we're recognizing a loupe gesture (i.e. long press) inside content with
     40        `-webkit-user-select: none;` (by consulting the new `selectability` enumeration). This allows us to prevent both
     41        haptic feedback as well as the new magnifier UI from triggering when long pressing inside content that has
     42        explicitly disabled text selection.
     43
     44        (-[WKContentView closestPositionToPoint:]):
     45        * WebProcess/WebPage/ios/WebPageIOS.mm:
     46        (WebKit::selectionPositionInformation):
     47        (WebKit::WebPage::positionInformation):
     48
     49        Additionally populate the `selectability` flag even when long pressing inside images and links. Instead of
     50        putting the call to `selectionPositionInformation` behind the `isLink`/`isImage` check, move that condition into
     51        `selectionPositionInformation` in the form of an early return, and always populate `selectability` in either
     52        case.
     53
    1542021-10-24  Darin Adler  <darin@apple.com>
    255
  • trunk/Source/WebKit/Shared/ios/InteractionInformationAtPosition.h

    r280098 r284766  
    5454    bool canBeValid { true };
    5555    std::optional<bool> nodeAtPositionHasDoubleClickHandler;
    56     bool isSelectable { false };
     56
     57    enum class Selectability : uint8_t {
     58        Selectable,
     59        UnselectableDueToFocusableElement,
     60        UnselectableDueToLargeElementBounds,
     61        UnselectableDueToUserSelectNone,
     62    };
     63    Selectability selectability { Selectability::Selectable };
     64
    5765    bool isSelected { false };
    5866    bool prefersDraggingOverTextSelection { false };
     
    108116    void mergeCompatibleOptionalInformation(const InteractionInformationAtPosition& oldInformation);
    109117
     118    bool isSelectable() const { return selectability == Selectability::Selectable; }
     119
    110120    void encode(IPC::Encoder&) const;
    111121    static WARN_UNUSED_RETURN bool decode(IPC::Decoder&, InteractionInformationAtPosition&);
    112122};
    113123
    114 }
     124} // namespace WebKit
     125
     126namespace WTF {
     127
     128template<> struct EnumTraits<WebKit::InteractionInformationAtPosition::Selectability> {
     129    using values = EnumValues<
     130        WebKit::InteractionInformationAtPosition::Selectability,
     131        WebKit::InteractionInformationAtPosition::Selectability::Selectable,
     132        WebKit::InteractionInformationAtPosition::Selectability::UnselectableDueToFocusableElement,
     133        WebKit::InteractionInformationAtPosition::Selectability::UnselectableDueToLargeElementBounds,
     134        WebKit::InteractionInformationAtPosition::Selectability::UnselectableDueToUserSelectNone
     135    >;
     136};
     137
     138} // namespace WTF
    115139
    116140#endif // PLATFORM(IOS_FAMILY)
  • trunk/Source/WebKit/Shared/ios/InteractionInformationAtPosition.mm

    r280098 r284766  
    4141    encoder << canBeValid;
    4242    encoder << nodeAtPositionHasDoubleClickHandler;
    43     encoder << isSelectable;
     43    encoder << selectability;
    4444    encoder << isSelected;
    4545    encoder << prefersDraggingOverTextSelection;
     
    100100        return false;
    101101
    102     if (!decoder.decode(result.isSelectable))
     102    if (!decoder.decode(result.selectability))
    103103        return false;
    104104
  • trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm

    r284630 r284766  
    28872887#endif
    28882888
    2889     return _positionInformation.isSelectable;
     2889    return _positionInformation.isSelectable();
    28902890}
    28912891
     
    29532953    WebKit::InteractionInformationRequest request(WebCore::roundedIntPoint(point));
    29542954    if (![self ensurePositionInformationIsUpToDate:request])
     2955        return NO;
     2956
     2957    if (gesture == UIWKGestureLoupe && _positionInformation.selectability == WebKit::InteractionInformationAtPosition::Selectability::UnselectableDueToUserSelectNone)
    29552958        return NO;
    29562959
     
    52555258    WebKit::InteractionInformationRequest request(WebCore::roundedIntPoint(point));
    52565259    [self requestAsynchronousPositionInformationUpdate:request];
    5257     if ([self _currentPositionInformationIsApproximatelyValidForRequest:request radiusForApproximation:2] && _positionInformation.isSelectable)
     5260    if ([self _currentPositionInformationIsApproximatelyValidForRequest:request radiusForApproximation:2] && _positionInformation.isSelectable())
    52585261        return [WKTextPosition textPositionWithRect:_positionInformation.caretRect];
    52595262#endif
  • trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm

    r284628 r284766  
    28892889        return;
    28902890
    2891     RenderObject* renderer = hitNode->renderer();
     2891    auto* renderer = hitNode->renderer();
     2892
     2893    info.selectability = ([&] {
     2894        if (renderer->style().userSelectIncludingInert() == UserSelect::None)
     2895            return InteractionInformationAtPosition::Selectability::UnselectableDueToUserSelectNone;
     2896
     2897        if (is<Element>(*hitNode)) {
     2898            if (isAssistableElement(downcast<Element>(*hitNode)))
     2899                return InteractionInformationAtPosition::Selectability::UnselectableDueToFocusableElement;
     2900
     2901            if (rectIsTooBigForSelection(info.bounds, *result.innerNodeFrame())) {
     2902                // We don't want to select blocks that are larger than 97% of the visible area of the document.
     2903                // FIXME: Is this heuristic still needed, now that block selection has been removed?
     2904                return InteractionInformationAtPosition::Selectability::UnselectableDueToLargeElementBounds;
     2905            }
     2906        }
     2907
     2908        return InteractionInformationAtPosition::Selectability::Selectable;
     2909    })();
     2910    info.isSelected = result.isSelected();
     2911
     2912    if (info.isLink || info.isImage)
     2913        return;
     2914
    28922915    boundsPositionInformation(*renderer, info);
    2893 
    2894     info.isSelected = result.isSelected();
    28952916   
    28962917    if (is<Element>(*hitNode)) {
     
    29062927        if (attachment.file())
    29072928            info.url = URL::fileURLWithFileSystemPath(downcast<HTMLAttachmentElement>(*hitNode).file()->path());
    2908     } else {
    2909         info.isSelectable = renderer->style().userSelectIncludingInert() != UserSelect::None;
    2910         // We don't want to select blocks that are larger than 97% of the visible area of the document.
    2911         // FIXME: Is this heuristic still needed, now that block selection has been removed?
    2912         if (info.isSelectable && !hitNode->isTextNode())
    2913             info.isSelectable = !isAssistableElement(*downcast<Element>(hitNode)) && !rectIsTooBigForSelection(info.bounds, *result.innerNodeFrame());
    2914     }
     2929    }
     2930
    29152931    for (RefPtr currentNode = hitNode; currentNode; currentNode = currentNode->parentOrShadowHostNode()) {
    29162932        auto* renderer = currentNode->renderer();
     
    30883104        imagePositionInformation(*this, downcast<HTMLImageElement>(*hitTestNode), request, info);
    30893105
    3090     if (!(info.isLink || info.isImage))
    3091         selectionPositionInformation(*this, request, info);
     3106    selectionPositionInformation(*this, request, info);
    30923107
    30933108    // Prevent the callout bar from showing when tapping on the datalist button.
Note: See TracChangeset for help on using the changeset viewer.