Skip to content

Commit

Permalink
Move off of UIKit SPI: `-_pointerInteraction:regionForRequest:default…
Browse files Browse the repository at this point in the history
…Region:completion:`

https://bugs.webkit.org/show_bug.cgi?id=260662
rdar://114331132

Reviewed by Tim Horton.

Refactor some iOS-specific logic for computing pointer regions when using `UIPointerInteraction`,
such that we no longer require this UIKit SPI delegate method for asynchronously retrieving regions:
`-_pointerInteraction:regionForRequest:defaultRegion:completion:`. Rather than performing the hit-
test and then invoking the completion handler when the results arrive from the web process, we
instead cache the last computed `UIPointerRegion` on the content view and continuously perform
position information updates to update this cached `UIPointerRegion`, until we reach a state where
the most recent `UIPointerRegionRequest` is satisfied by the cached `_positionInformation`. This
actually allows us to simplify a bit of the logic here for updating pointer regions, since we'll now
simply return `_lastPointerRegion` from the delegate method, and continuously schedule position
information updates via `-doAfterPositionInformationUpdate:` until we catch up to the current
pointer location.

Test: iOSMouseSupport.BasicPointerInteractionRegions

* Source/WebKit/Platform/spi/ios/UIKitSPI.h:

Remove SPI declarations that are now unused.

* Source/WebKit/UIProcess/ios/WKContentViewInteraction.h:
* Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView cleanUpInteraction]):
(-[WKContentView pointerInteraction:regionForRequest:defaultRegion:]):
(-[WKContentView _updateLastPointerRegionIfNeeded:]):

Drive-by fix: use `[_lastPointerRegion rect]` instead of `self.bounds` when returning a region in
the case where the entire web view is `_editable`, but the position information is not yet up to
date. This shouldn't actually make any difference since the use of `"WKEditablePointerRegion"` means
that we'll always use `UIAxisNeither` to avoid nudging the cursor in any direction for this region,
but it makes visually debugging these pointer regions in Mail compose a bit easier, since we no
longer flicker rapidly between a pointer region the size of the web view that constraints neither
axis, and a pointer region the size of the expanded line rect that constrains to block direction,
when UIKit asks for `-pointerInteraction:styleForRegion:`.

(-[WKContentView pointerRegionForPositionInformation:point:]):
(-[WKContentView pointerInteraction:styleForRegion:]):

Another drive-by fix: it's actually possible in shipping iPadOS to end up in a situation where we
return an IBeam cursor that tries to align to the Y-axis, but the region is the entire bounds of the
view (which causes the cursor to disappear altogether until the user hovers over a different pointer
region). This is observable by hovering over the left edge of a `blockquote` on daringfireball.net.
After the changes in this patch (but without the tweak in this method), we no longer cause the
cursor to disappear, but we do get a visual flicker as the cursor attempts to animate to the center
of the view bounds. It's unclear whether this is better or worse, so it's probably better to just
fix this existing bug as a part of this refactoring:

The root cause is the fact that `-pointerRegionForPositionInformation:point:` can return a region
the size of `self.bounds` despite the position information containing an IBeam cursor type, if
`expandedLineRect.contains(location)` returns `false`, which is possible if the request location is
_just_ left or right of the `expandedLineRect`. To mitigate this, I'm making it so that we don't
attempt to constrain to the region, if the region is taller (or wider, in vertical writing mode)
than an arbitrary length.

(-[WKContentView _pointerInteraction:regionForRequest:defaultRegion:completion:]): Deleted.
* Source/WebKit/UIProcess/ios/WKScrollView.mm:
* Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* Tools/TestWebKitAPI/Tests/WebKitCocoa/cursor-styles.html: Added.
* Tools/TestWebKitAPI/Tests/WebKitCocoa/iOSMouseSupport.mm:
(-[TestPointerRegionRequest initWithLocation:]):
(-[TestPointerRegionRequest location]):
(-[TestWKWebView pointerInteraction]):
(-[TestWKWebView pointerInfoAtLocation:]):

Additionally, write some test infrastructure and a basic API test to exercise this functionality by
calling directly into the `UIPointerInteractionDelegate` methods to grab the cursor styles and
regions for several common scenarios (e.g. CSS `cursor` property, editable regions, non-editable
text, links).

* Tools/TestWebKitAPI/cocoa/TestWKWebView.h:
* Tools/TestWebKitAPI/cocoa/TestWKWebView.mm:
(-[WKWebView elementRectFromSelector:]):
(-[WKWebView elementMidpointFromSelector:]):

Canonical link: https://commits.webkit.org/267361@main
  • Loading branch information
whsieh committed Aug 28, 2023
1 parent d417f61 commit 5063252
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 51 deletions.
14 changes: 0 additions & 14 deletions Source/WebKit/Platform/spi/ios/UIKitSPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@

#if HAVE(UI_POINTER_INTERACTION)
#import <UIKit/UIPointerInteraction_ForWebKitOnly.h>
#import <UIKit/UIPointerStyle_Private.h>
#endif

#if HAVE(UIKIT_RESIZABLE_WINDOWS)
Expand Down Expand Up @@ -779,10 +778,6 @@ typedef NS_ENUM(NSInteger, UIWKGestureType) {
@property (nonatomic, readonly, assign) UITapGestureRecognizer *singleTapGesture;
@end

@interface UITextInteraction ()
@property (class, nonatomic, readonly) CGFloat _maximumBeamSnappingLength;
@end

@class UIWKDocumentRequest;
@class UIWKDocumentContext;

Expand Down Expand Up @@ -1171,19 +1166,10 @@ typedef NS_ENUM(NSUInteger, UIMenuOptionsPrivate) {
@property (readonly) BOOL isLowConfidence;
@end

@interface UIPointerStyle ()
+ (instancetype)_systemPointerStyle;
@end

@interface UIPointerInteraction ()
@property (nonatomic, assign, getter=_pausesPointerUpdatesWhilePanning, setter=_setPausesPointerUpdatesWhilePanning:) BOOL pausesPointerUpdatesWhilePanning;
@end

@protocol UIPointerInteractionDelegate_ForWebKitOnly <UIPointerInteractionDelegate>
@optional
- (void)_pointerInteraction:(UIPointerInteraction *)interaction regionForRequest:(UIPointerRegionRequest *)request defaultRegion:(UIPointerRegion *)defaultRegion completion:(void(^)(UIPointerRegion *region))completion;
@end

#if PLATFORM(WATCHOS)
@interface UIStatusBar : UIView
@end
Expand Down
5 changes: 3 additions & 2 deletions Source/WebKit/UIProcess/ios/WKContentViewInteraction.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ class WebPageProxy;
#endif

@class UIPointerInteraction;
@class UIPointerRegion;
@class UITargetedPreview;
@class _UILookupGestureRecognizer;
@class _UIHighlightView;
Expand Down Expand Up @@ -335,8 +336,8 @@ struct ImageAnalysisContextMenuActionData {

#if HAVE(UI_POINTER_INTERACTION)
RetainPtr<UIPointerInteraction> _pointerInteraction;
BOOL _hasOutstandingPointerInteractionRequest;
std::optional<std::pair<WebKit::InteractionInformationRequest, BlockPtr<void(UIPointerRegion *)>>> _deferredPointerInteractionRequest;
RetainPtr<UIPointerRegion> _lastPointerRegion;
BOOL _pointerInteractionRegionNeedsUpdate;
#endif

RetainPtr<UIWKTextInteractionAssistant> _textInteractionAssistant;
Expand Down
71 changes: 36 additions & 35 deletions Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@
static NSString * const pointerRegionIdentifier = @"WKPointerRegion";
static NSString * const editablePointerRegionIdentifier = @"WKEditablePointerRegion";

@interface WKContentView (WKUIPointerInteractionDelegate) <UIPointerInteractionDelegate_ForWebKitOnly>
@interface WKContentView (WKUIPointerInteractionDelegate) <UIPointerInteractionDelegate>
@end
#endif

Expand Down Expand Up @@ -1233,6 +1233,7 @@ - (void)cleanUpInteraction
#if HAVE(UI_POINTER_INTERACTION)
[self removeInteraction:_pointerInteraction.get()];
_pointerInteraction = nil;
_pointerInteractionRegionNeedsUpdate = NO;
#endif

_revealFocusedElementDeferrer = nullptr;
Expand Down Expand Up @@ -10459,60 +10460,58 @@ - (void)setUpPointerInteraction
[self addInteraction:_pointerInteraction.get()];
}

- (void)_pointerInteraction:(UIPointerInteraction *)interaction regionForRequest:(UIPointerRegionRequest *)request defaultRegion:(UIPointerRegion *)defaultRegion completion:(void(^)(UIPointerRegion *region))completion
- (UIPointerRegion *)pointerInteraction:(UIPointerInteraction *)interaction regionForRequest:(UIPointerRegionRequest *)request defaultRegion:(UIPointerRegion *)defaultRegion
{
[self _updateLastPointerRegionIfNeeded:request];
return _lastPointerRegion.get();
}

- (void)_updateLastPointerRegionIfNeeded:(UIPointerRegionRequest *)request
{
WebKit::InteractionInformationRequest interactionInformationRequest;
interactionInformationRequest.point = WebCore::roundedIntPoint(request.location);
interactionInformationRequest.includeCaretContext = true;
interactionInformationRequest.includeHasDoubleClickHandler = false;

__block BOOL didSynchronouslyReplyWithApproximation = false;
if (![self _currentPositionInformationIsValidForRequest:interactionInformationRequest] && self.webView._editable && !_positionInformation.shouldNotUseIBeamInEditableContent) {
didSynchronouslyReplyWithApproximation = true;
completion([UIPointerRegion regionWithRect:self.bounds identifier:editablePointerRegionIdentifier]);
}

// If we already have an outstanding interaction information request, defer this one until
// we hear back, so that requests don't pile up if the Web Content process is slow.
if (_hasOutstandingPointerInteractionRequest) {
_deferredPointerInteractionRequest = std::make_pair(interactionInformationRequest, makeBlockPtr(completion));
if ([self _currentPositionInformationIsValidForRequest:interactionInformationRequest]) {
_lastPointerRegion = [self pointerRegionForPositionInformation:_positionInformation point:request.location];
_pointerInteractionRegionNeedsUpdate = NO;
return;
}

_hasOutstandingPointerInteractionRequest = YES;

__block BlockPtr<void(WebKit::InteractionInformationAtPosition, void(^)(UIPointerRegion *))> replyHandler;
replyHandler = ^(WebKit::InteractionInformationAtPosition interactionInformation, void(^completion)(UIPointerRegion *region)) {
if (!_deferredPointerInteractionRequest)
_hasOutstandingPointerInteractionRequest = NO;
// Note: In this case where position information is not up-to-date, checking the last cached
// position information may not yield expected results, since the client (or any other code in
// WebKit) may have queried position information at a totally different location, for unrelated
// reasons. However, this seems to work well in practice, since pointer updates are very frequent,
// so any invalid state would only persist for a single frame.
if (self.webView._editable && !_positionInformation.shouldNotUseIBeamInEditableContent) {
auto lastRegionRect = _lastPointerRegion ? [_lastPointerRegion rect] : self.bounds;
_lastPointerRegion = [UIPointerRegion regionWithRect:lastRegionRect identifier:editablePointerRegionIdentifier];
}

if (didSynchronouslyReplyWithApproximation)
[interaction invalidate];
else
completion([self pointerRegionForPositionInformation:interactionInformation point:request.location]);
if (_pointerInteractionRegionNeedsUpdate)
return;

if (_deferredPointerInteractionRequest) {
didSynchronouslyReplyWithApproximation = false;
_pointerInteractionRegionNeedsUpdate = YES;

auto deferredRequest = std::exchange(_deferredPointerInteractionRequest, std::nullopt);
[self doAfterPositionInformationUpdate:^(WebKit::InteractionInformationAtPosition interactionInformation) {
replyHandler(interactionInformation, deferredRequest->second.get());
} forRequest:deferredRequest->first];
[self doAfterPositionInformationUpdate:[weakSelf = WeakObjCPtr<WKContentView>(self), location = request.location](WebKit::InteractionInformationAtPosition information) {
auto strongSelf = weakSelf.get();
if (!strongSelf)
return;
}
};

[self doAfterPositionInformationUpdate:^(WebKit::InteractionInformationAtPosition interactionInformation) {
replyHandler(interactionInformation, completion);
strongSelf->_pointerInteractionRegionNeedsUpdate = NO;
strongSelf->_lastPointerRegion = [strongSelf pointerRegionForPositionInformation:information point:location];
[strongSelf->_pointerInteraction invalidate];
} forRequest:interactionInformationRequest];
}

- (UIPointerRegion *)pointerRegionForPositionInformation:(WebKit::InteractionInformationAtPosition&)interactionInformation point:(CGPoint)location
- (UIPointerRegion *)pointerRegionForPositionInformation:(const WebKit::InteractionInformationAtPosition&)interactionInformation point:(CGPoint)location
{
WebCore::FloatRect expandedLineRect = enclosingIntRect(interactionInformation.lineCaretExtent);

// Pad lines of text in order to avoid switching back to the dot cursor between lines.
// This matches the value that UIKit uses.
// FIXME: Should this account for vertical writing mode?
expandedLineRect.inflateY(10);

if (interactionInformation.cursor) {
Expand Down Expand Up @@ -10540,10 +10539,12 @@ - (UIPointerStyle *)pointerInteraction:(UIPointerInteraction *)interaction style
UIPointerStyle *(^iBeamCursor)(void) = ^{
float beamLength = _positionInformation.caretLength * scaleFactor;
auto axisOrientation = _positionInformation.isVerticalWritingMode ? UIAxisHorizontal : UIAxisVertical;
UIAxis iBeamConstraintAxes = _positionInformation.isVerticalWritingMode ? UIAxisHorizontal : UIAxisVertical;
auto iBeamConstraintAxes = _positionInformation.isVerticalWritingMode ? UIAxisHorizontal : UIAxisVertical;
auto regionLengthInBlockAxis = _positionInformation.isVerticalWritingMode ? CGRectGetWidth(region.rect) : CGRectGetHeight(region.rect);

// If the I-beam is so large that the magnetism is hard to fight, we should not apply any magnetism.
if (beamLength > [UITextInteraction _maximumBeamSnappingLength])
static constexpr auto maximumBeamSnappingLength = 100;
if (beamLength > maximumBeamSnappingLength || regionLengthInBlockAxis > maximumBeamSnappingLength)
iBeamConstraintAxes = UIAxisNeither;

// If the region is the size of the view, we should not apply any magnetism.
Expand Down
4 changes: 4 additions & 0 deletions Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1194,6 +1194,7 @@
F46D43AB26D7092800969E5E /* test.jpg in Copy Resources */ = {isa = PBXBuildFile; fileRef = F46D43AA26D7090300969E5E /* test.jpg */; };
F472874727816BCE003EBE7F /* NSResponderTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F43C3823278133190099ABCE /* NSResponderTests.mm */; };
F472E00327D966F200F3A172 /* TextAlternatives.mm in Sources */ = {isa = PBXBuildFile; fileRef = F472E00227D966F200F3A172 /* TextAlternatives.mm */; };
F4740A342A97C99900B657B6 /* cursor-styles.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4740A2C2A97C97E00B657B6 /* cursor-styles.html */; };
F47728991E4AE3C1007ABF6A /* full-page-contenteditable.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F47728981E4AE3AD007ABF6A /* full-page-contenteditable.html */; };
F47DFB2621A878DF00021FB6 /* data-detectors.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F47DFB2421A8704A00021FB6 /* data-detectors.html */; };
F4856CA31E649EA8009D7EE7 /* attachment-element.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4856CA21E6498A8009D7EE7 /* attachment-element.html */; };
Expand Down Expand Up @@ -1549,6 +1550,7 @@
952F7167270BD9CB00D00DCC /* CSSViewportUnits.html in Copy Resources */,
952F7167270BD9CB00D00DCD /* CSSViewportUnits.svg in Copy Resources */,
2DDD4DA4270B8B3500659A61 /* cube.usdz in Copy Resources */,
F4740A342A97C99900B657B6 /* cursor-styles.html in Copy Resources */,
F4AB578A1F65165400DB0DA1 /* custom-draggable-div.html in Copy Resources */,
290F4275172A221C00939FF0 /* custom-protocol-sync-xhr.html in Copy Resources */,
1CF59AE521E6977D006E37EC /* dark-mode.html in Copy Resources */,
Expand Down Expand Up @@ -3504,6 +3506,7 @@
F46C45C327D42A2F00ECED2C /* ApplicationStateTracking.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ApplicationStateTracking.mm; sourceTree = "<group>"; };
F46D43AA26D7090300969E5E /* test.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = test.jpg; sourceTree = "<group>"; };
F472E00227D966F200F3A172 /* TextAlternatives.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TextAlternatives.mm; sourceTree = "<group>"; };
F4740A2C2A97C97E00B657B6 /* cursor-styles.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "cursor-styles.html"; sourceTree = "<group>"; };
F47728981E4AE3AD007ABF6A /* full-page-contenteditable.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "full-page-contenteditable.html"; sourceTree = "<group>"; };
F47D30EB1ED28619000482E1 /* apple.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = apple.gif; sourceTree = "<group>"; };
F47D30ED1ED28A6C000482E1 /* gif-and-file-input.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "gif-and-file-input.html"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4668,6 +4671,7 @@
4995A6EF25E876A300E5F0A9 /* csp-document-uri-report.html */,
952F7166270BD99700D00DCC /* CSSViewportUnits.html */,
952F7166270BD99700D00DCD /* CSSViewportUnits.svg */,
F4740A2C2A97C97E00B657B6 /* cursor-styles.html */,
F4AB57891F65164B00DB0DA1 /* custom-draggable-div.html */,
F47DFB2421A8704A00021FB6 /* data-detectors.html */,
F486B1CF1F6794FF00F34BDD /* DataTransfer-setDragImage.html */,
Expand Down
39 changes: 39 additions & 0 deletions Tools/TestWebKitAPI/Tests/WebKitCocoa/cursor-styles.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body, html {
margin: 0;
font-size: 20px;
}

div {
width: 100px;
height: 100px;
border: 1px solid tomato;
margin: 0;
overflow: hidden;
text-align: center;
box-sizing: border-box;
padding-top: 38px;
}

div#container-with-cursor-pointer {
cursor: pointer;
}

div#container-with-cursor-text {
cursor: text;
}
</style>
</head>
<body>
<div id="container"></div>
<div id="editable-container" contenteditable></div>
<div id="container-with-cursor-pointer"></div>
<div id="container-with-text">Hello</div>
<div id="container-with-link"><a href="https://webkit.org">Hello</div>
<div id="container-with-cursor-text"></div>
</body>
</html>
115 changes: 115 additions & 0 deletions Tools/TestWebKitAPI/Tests/WebKitCocoa/iOSMouseSupport.mm
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,75 @@ - (void)_updateMouseTouches:(NSSet<UITouch *> *)touches;
- (void)_hoverGestureRecognized:(UIHoverGestureRecognizer *)gestureRecognizer;
@end

#if HAVE(UI_POINTER_INTERACTION)

@interface TestPointerRegionRequest : UIPointerRegionRequest
- (instancetype)initWithLocation:(CGPoint)location;
@end

@implementation TestPointerRegionRequest {
CGPoint _requestLocation;
}

- (instancetype)initWithLocation:(CGPoint)location
{
if (!(self = [super init]))
return nil;

_requestLocation = location;
return self;
}

- (CGPoint)location
{
return _requestLocation;
}

@end

namespace TestWebKitAPI {

struct PointerInfo {
BOOL isDefault { NO };
CGRect regionRect { CGRectNull };
};

} // namespace TestWebKitAPI

@interface TestWKWebView (PointerInteractionTests)
- (TestWebKitAPI::PointerInfo)pointerInfoAtLocation:(CGPoint)location;
@end

@implementation TestWKWebView (PointerInteractionTests)

- (UIPointerInteraction *)pointerInteraction
{
for (id<UIInteraction> interaction in self.textInputContentView.interactions) {
if (auto result = dynamic_objc_cast<UIPointerInteraction>(interaction))
return result;
}
return nil;
}

- (TestWebKitAPI::PointerInfo)pointerInfoAtLocation:(CGPoint)location
{
auto contentView = (UIView<UIPointerInteractionDelegate> *)[self textInputContentView];
auto interaction = [self pointerInteraction];
auto request = adoptNS([[TestPointerRegionRequest alloc] initWithLocation:location]);

RetainPtr defaultRegion = [UIPointerRegion regionWithRect:contentView.bounds identifier:nil];
[contentView pointerInteraction:interaction regionForRequest:request.get() defaultRegion:defaultRegion.get()];
[self waitForNextPresentationUpdate];

auto region = [contentView pointerInteraction:interaction regionForRequest:request.get() defaultRegion:defaultRegion.get()];
auto style = [contentView pointerInteraction:interaction styleForRegion:region];
return { [style isEqual:UIPointerStyle.systemPointerStyle], region.rect };
}

@end

#endif // HAVE(UI_POINTER_INTERACTION)

namespace TestWebKitAPI {

class MouseEventTestHarness {
Expand Down Expand Up @@ -776,6 +845,52 @@ static void simulateEditContextMenuAppearance(TestWKWebView *webView, CGPoint lo

#endif // PLATFORM(MACCATALYST)

#if HAVE(UI_POINTER_INTERACTION)

TEST(iOSMouseSupport, BasicPointerInteractionRegions)
{
auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600)]);
[webView synchronouslyLoadTestPageNamed:@"cursor-styles"];

{
auto info = [webView pointerInfoAtLocation:[webView elementMidpointFromSelector:@"#container"]];
EXPECT_TRUE(info.isDefault);
EXPECT_TRUE(CGRectEqualToRect(info.regionRect, [webView bounds]));
}
{
auto elementRect = [webView elementRectFromSelector:@"#editable-container"];
auto info = [webView pointerInfoAtLocation:[webView elementMidpointFromSelector:@"#editable-container"]];
EXPECT_FALSE(info.isDefault);
EXPECT_TRUE(CGRectContainsRect(elementRect, info.regionRect));
}
{
auto elementRect = [webView elementRectFromSelector:@"#container-with-cursor-pointer"];
auto info = [webView pointerInfoAtLocation:[webView elementMidpointFromSelector:@"#container-with-cursor-pointer"]];
EXPECT_TRUE(info.isDefault);
EXPECT_TRUE(CGRectContainsRect(elementRect, info.regionRect));
}
{
auto elementRect = [webView elementRectFromSelector:@"#container-with-text"];
auto info = [webView pointerInfoAtLocation:[webView elementMidpointFromSelector:@"#container-with-text"]];
EXPECT_FALSE(info.isDefault);
EXPECT_TRUE(CGRectContainsRect(elementRect, info.regionRect));
}
{
auto elementRect = [webView elementRectFromSelector:@"#container-with-link"];
auto info = [webView pointerInfoAtLocation:[webView elementMidpointFromSelector:@"#container-with-link"]];
EXPECT_TRUE(info.isDefault);
EXPECT_TRUE(CGRectContainsRect(elementRect, info.regionRect));
}
{
auto elementRect = [webView elementRectFromSelector:@"#container-with-cursor-text"];
auto info = [webView pointerInfoAtLocation:[webView elementMidpointFromSelector:@"#container-with-cursor-text"]];
EXPECT_FALSE(info.isDefault);
EXPECT_TRUE(CGRectContainsRect(elementRect, info.regionRect));
}
}

#endif // HAVE(UI_POINTER_INTERACTION)

} // namespace TestWebKitAPI

#endif // PLATFORM(IOS) || PLATFORM(MACCATALYST) || PLATFORM(VISION)
2 changes: 2 additions & 0 deletions Tools/TestWebKitAPI/cocoa/TestWKWebView.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@
- (id)objectByEvaluatingJavaScript:(NSString *)script;
- (id)objectByCallingAsyncFunction:(NSString *)script withArguments:(NSDictionary *)arguments error:(NSError **)errorOut;
- (unsigned)waitUntilClientWidthIs:(unsigned)expectedClientWidth;
- (CGRect)elementRectFromSelector:(NSString *)selector;
- (CGPoint)elementMidpointFromSelector:(NSString *)selector;
@end

@interface TestMessageHandler : NSObject <WKScriptMessageHandler>
Expand Down
Loading

0 comments on commit 5063252

Please sign in to comment.