Bug Summary

File:Source/WebKit/WebProcess/WebPage/Cocoa/PositionInformationForWebPage.mm
Warning:line 245, column 96
Call argument for 'this' parameter is uncounted and unsafe

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple arm64-apple-ios26.2.0-simulator -Os -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -Werror=implicit-function-declaration -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name PositionInformationForWebPage.mm -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=osx -analyzer-checker=security.insecureAPI.decodeValueOfObjCType -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=non-leaf -ffp-contract=on -fno-rounding-math -target-sdk-version=26.2 -fdepfile-entry=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/SDKSettings.json -fcompatibility-qualified-id-block-type-checking -fvisibility-inlines-hidden-static-local-var -fno-modulemap-allow-subdirectory-search -fdefine-target-os-macros -enable-tlsdesc -target-cpu apple-m1 -target-feature +v8.4a -target-feature +aes -target-feature +altnzcv -target-feature +ccdp -target-feature +ccpp -target-feature +complxnum -target-feature +crc -target-feature +dotprod -target-feature +flagm -target-feature +fp-armv8 -target-feature +fp16fml -target-feature +fptoint -target-feature +fullfp16 -target-feature +jsconv -target-feature +lse -target-feature +neon -target-feature +pauth -target-feature +perfmon -target-feature +predres -target-feature +ras -target-feature +rcpc -target-feature +rdm -target-feature +sb -target-feature +sha2 -target-feature +sha3 -target-feature +specrestrict -target-feature +ssbs -target-abi darwinpcs -dwarf-ext-refs -fmodule-format=obj -debug-info-kind=standalone -dwarf-version=5 -debugger-tuning=lldb -fdebug-compilation-dir=/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit -target-linker-version 1230.1 -fcoverage-compilation-dir=/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit -resource-dir /Users/buildbot/Library/Developer/Toolchains/swift-webkit.xctoolchain/usr/lib/clang/21 -dependency-file /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebKit/WebKit/normal/arm64/PositionInformationForWebPage.d -skip-unused-modulemap-deps -MT dependencies -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk -iquote /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release-iphonesimulator/WebKit.build/WebKit-generated-files.hmap -iquote /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release-iphonesimulator/WebKit.build/WebKit-project-headers.hmap -isystem /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/iphonesimulator26.0-additions.sdk/usr/local/include -isystem /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/SDKAdditions/usr/include -iframework /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/SDKAdditions/System/Library/Frameworks -iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/PrivateFrameworks -isystem /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/iphonesimulator26.0-additions.sdk/usr/local/include -include-pch /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/PrecompiledHeaders/SharedPrecompiledHeaders/3938699508861868627/WebKit2Prefix.h.gch -D _LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE -D NDEBUG -D HAVE_CORE_PREDICTION -D ENABLE_LOWER_FORMATREADERBUNDLE_CODESIGNING_REQUIREMENTS -D WEBKIT_BUNDLE_VERSION="625.1.10+" -D FRAMEWORK_NAME=WebKit -D OBJC_OLD_DISPATCH_PROTOTYPES=0 -D __clang_analyzer__ -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release-iphonesimulator/WebKit.build/WebKit-own-target-headers.hmap -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release-iphonesimulator/WebKit.build/WebKit-all-target-headers.hmap -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/WebCore.framework/PrivateHeaders/ForwardingHeaders -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/DerivedSources/WebKit -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/DerivedSources/WebKit/IPC -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/pal/graphics/WebGPU -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/pal/graphics/WebGPU -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/WebKitAdditions -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/WebKitAdditions -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/webrtc -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/webrtc -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator/usr/local/include/webm -I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include/webm -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release-iphonesimulator/WebKit.build/DerivedSources-normal/arm64 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release-iphonesimulator/WebKit.build/DerivedSources/arm64 -I /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/WebKit.build/Release-iphonesimulator/WebKit.build/DerivedSources -F/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitBuild/Release-iphonesimulator -F/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/iphonesimulator26.0-additions.sdk/System/Library/PrivateFrameworks -F/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/PrivateFrameworks -D __STDC_WANT_LIB_EXT1__=1 -I/usr/local/include -stdlib=libc++ -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include/c++/v1 -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/local/include -internal-isystem /Users/buildbot/Library/Developer/Toolchains/swift-webkit.xctoolchain/usr/lib/clang/21/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/usr/include -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/Frameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/System/Library/SubFrameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator26.2.sdk/Library/Frameworks -Wno-trigraphs -Werror -Wno-missing-field-initializers -Wmissing-prototypes -Wunreachable-code -Wno-implicit-atomic-properties -Wno-objc-interface-ivars -Wno-arc-repeated-use-of-weak -Wimplicit-retain-self -Wnon-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wduplicate-method-match -Wno-missing-braces -Wparentheses -Wswitch -Wunused-function -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion -Wint-conversion -Wbool-conversion -Wenum-conversion -Wno-float-conversion -Wnon-literal-null-conversion -Wobjc-literal-conversion -Wsign-compare -Wno-shorten-64-to-32 -Wnewline-eof -Wno-selector -Wno-strict-selector-match -Wundeclared-selector -Wdeprecated-implementations -Wno-c++11-extensions -Wno-implicit-fallthrough -Wprotocol -Wdeprecated-declarations -Winvalid-offsetof -Wno-sign-conversion -Winfinite-recursion -Wmove -Wcomma -Wblock-capture-autoreleasing -Wstrict-prototypes -Wrange-loop-analysis -Wno-semicolon-before-method-body -Wall -Wc99-designator -Wconditional-uninitialized -Wextra -Wdeprecated-enum-enum-conversion -Wdeprecated-enum-float-conversion -Wenum-float-conversion -Wfinal-dtor-non-final-class -Wformat=2 -Wmisleading-indentation -Wpointer-to-int-cast -Wreorder-init-list -Wundef -Wunused-but-set-variable -Wvla -Werror=unguarded-availability -Wno-elaborated-enum-base -Wno-unused-parameter -Wcast-qual -Wchar-subscripts -Wextra-tokens -Winit-self -Wmissing-noreturn -Wpacked -Wpointer-arith -Wredundant-decls -Wwrite-strings -Wexit-time-destructors -Wglobal-constructors -Wtautological-compare -Wimplicit-fallthrough -Wvla -Wliteral-conversion -Wthread-safety -Wno-profile-instr-out-of-date -Wno-profile-instr-unprofiled -Wno-backend-plugin -Wunsafe-buffer-usage -Wno-unknown-warning-option -Wno-missing-field-initializers -Wno-nullability-completeness -std=c++2b -fdeprecated-macro -ferror-limit 19 -fmacro-backtrace-limit=0 -fvisibility=hidden -fvisibility-inlines-hidden -stack-protector 1 -fblocks -fencode-extended-block-signature -fno-rtti -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fno-cxx-modules -fno-implicit-modules -fskip-odr-check-in-gmf -fobjc-runtime=ios-26.2.0 -fobjc-weak -fobjc-exceptions -fexceptions -fpascal-strings -fmax-type-align=16 -fdiagnostics-show-note-include-stack -vectorize-loops -vectorize-slp -fsafe-buffer-usage-suggestions -analyzer-output=html -analyzer-config report-in-main-source-file=true -analyzer-config nullability:NoDiagnoseCallsToSystemHeaders=true -analyzer-checker optin.osx.cocoa.localizability.NonLocalizedStringChecker -analyzer-checker security.insecureAPI.UncheckedReturn -analyzer-checker security.insecureAPI.getpw -analyzer-checker security.insecureAPI.gets -analyzer-checker security.insecureAPI.mkstemp -analyzer-checker security.insecureAPI.mktemp -analyzer-disable-checker security.insecureAPI.rand -analyzer-disable-checker security.insecureAPI.strcpy -analyzer-checker security.insecureAPI.vfork -analyzer-disable-checker alpha,apiModeling,core,cplusplus,deadcode,debug,fuchsia,nullability,optin,osx,security,unix,webkit -analyzer-checker alpha.webkit.ForwardDeclChecker,alpha.webkit.MemoryUnsafeCastChecker,alpha.webkit.NoDeleteChecker,alpha.webkit.NoUncheckedPtrMemberChecker,alpha.webkit.NoUnretainedMemberChecker,alpha.webkit.RetainPtrCtorAdoptChecker,alpha.webkit.UncheckedCallArgsChecker,alpha.webkit.UncheckedLocalVarsChecker,alpha.webkit.UncountedCallArgsChecker,alpha.webkit.UncountedLocalVarsChecker,alpha.webkit.UnretainedCallArgsChecker,alpha.webkit.UnretainedLambdaCapturesChecker,alpha.webkit.UnretainedLocalVarsChecker,webkit.NoUncountedMemberChecker,webkit.RefCntblBaseVirtualDtor,webkit.UncountedLambdaCapturesChecker -analyzer-config max-nodes=10000000 -analyzer-config verbose-report-filename=true -fdwarf2-cfi-asm -o /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebKit/WebKit/normal/arm64/PositionInformationForWebPage.plist -x objective-c++ /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/WebProcess/WebPage/Cocoa/PositionInformationForWebPage.mm
1/*
2 * Copyright (C) 2026 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#import "config.h"
27#import "PositionInformationForWebPage.h"
28
29#if PLATFORM(COCOA)(defined 1 && 1)
30
31#import "InteractionInformationAtPosition.h"
32#import "InteractionInformationRequest.h"
33#import "PluginView.h"
34#import "ShareableBitmapUtilities.h"
35#import "WebPage.h"
36#import <WebCore/ContainerNodeInlines.h>
37#import <WebCore/DataDetection.h>
38#import <WebCore/DataDetectionResultsStorage.h>
39#import <WebCore/Document.h>
40#import <WebCore/DocumentQuirks.h>
41#import <WebCore/Editor.h>
42#import <WebCore/Element.h>
43#import <WebCore/ElementInlines.h>
44#import <WebCore/EventHandler.h>
45#import <WebCore/EventNames.h>
46#import <WebCore/EventTargetInlines.h>
47#import <WebCore/FocusController.h>
48#import <WebCore/FrameDestructionObserverInlines.h>
49#import <WebCore/HTMLAnchorElement.h>
50#import <WebCore/HTMLAttachmentElement.h>
51#import <WebCore/HTMLElement.h>
52#import <WebCore/HTMLImageElement.h>
53#import <WebCore/HTMLInputElement.h>
54#import <WebCore/HTMLModelElement.h>
55#import <WebCore/HTMLSelectElement.h>
56#import <WebCore/HTMLTextAreaElement.h>
57#import <WebCore/HTMLVideoElement.h>
58#import <WebCore/HitTestRequest.h>
59#import <WebCore/HitTestResult.h>
60#import <WebCore/ImageOverlay.h>
61#import <WebCore/LocalDOMWindow.h>
62#import <WebCore/LocalFrameInlines.h>
63#import <WebCore/Model.h>
64#import <WebCore/NodeDocument.h>
65#import <WebCore/Page.h>
66#import <WebCore/Quirks.h>
67#import <WebCore/RenderBlockFlow.h>
68#import <WebCore/RenderBoxInlines.h>
69#import <WebCore/RenderImage.h>
70#import <WebCore/RenderObjectDocument.h>
71#import <WebCore/RenderObjectStyle.h>
72#import <WebCore/RenderVideo.h>
73#import <WebCore/RenderVideoInlines.h>
74#import <WebCore/ScrollingCoordinator.h>
75#import <WebCore/VisibleUnits.h>
76#import <wtf/text/StringToIntegerConversion.h>
77
78namespace WebKit {
79
80static void focusedElementPositionInformation(WebPage& page, WebCore::Element& focusedElement, const InteractionInformationRequest& request, InteractionInformationAtPosition& info)
81{
82 RefPtr frame = page.corePage()->focusController().focusedOrMainFrame();
83 if (!frame || !frame->editor().hasComposition())
84 return;
85
86 const uint32_t kHitAreaWidth = 66;
87 const uint32_t kHitAreaHeight = 66;
88 Ref view = *frame->view();
89 WebCore::IntPoint adjustedPoint(view->rootViewToContents(request.point));
90 WebCore::IntPoint constrainedPoint = WebPage::constrainPoint(adjustedPoint, *frame, focusedElement);
91 WebCore::VisiblePosition position = frame->visiblePositionForPoint(constrainedPoint);
92
93 auto compositionRange = protect(frame->editor())->compositionRange();
94 if (!compositionRange)
95 return;
96
97 auto startPosition = makeDeprecatedLegacyPosition(compositionRange->start);
98 auto endPosition = makeDeprecatedLegacyPosition(compositionRange->end);
99 if (position < startPosition)
100 position = startPosition;
101 else if (position > endPosition)
102 position = endPosition;
103 WebCore::IntRect caretRect = view->contentsToRootView(position.absoluteCaretBounds());
104 float deltaX = std::abs(caretRect.x() + (caretRect.width() / 2) - request.point.x());
105 float deltaYFromTheTop = std::abs(caretRect.y() - request.point.y());
106 float deltaYFromTheBottom = std::abs(caretRect.y() + caretRect.height() - request.point.y());
107
108 info.isNearMarkedText = !(deltaX > kHitAreaWidth || deltaYFromTheTop > kHitAreaHeight || deltaYFromTheBottom > kHitAreaHeight);
109}
110
111static void linkIndicatorPositionInformation(WebPage& page, WebCore::Element& linkElement, const InteractionInformationRequest& request, InteractionInformationAtPosition& info)
112{
113 if (!request.includeLinkIndicator)
114 return;
115
116 auto linkRange = makeRangeSelectingNodeContents(linkElement);
117 float deviceScaleFactor = page.corePage()->deviceScaleFactor();
118 const float marginInPoints = request.linkIndicatorShouldHaveLegacyMargins ? 4 : 0;
119
120 constexpr OptionSet<WebCore::TextIndicatorOption> textIndicatorOptions {
121 WebCore::TextIndicatorOption::TightlyFitContent,
122 WebCore::TextIndicatorOption::RespectTextColor,
123 WebCore::TextIndicatorOption::PaintBackgrounds,
124 WebCore::TextIndicatorOption::UseBoundingRectAndPaintAllContentForComplexRanges,
125 WebCore::TextIndicatorOption::IncludeMarginIfRangeMatchesSelection,
126 WebCore::TextIndicatorOption::ComputeEstimatedBackgroundColor
127 };
128 auto textIndicator = WebCore::TextIndicator::createWithRange(linkRange, textIndicatorOptions, WebCore::TextIndicatorPresentationTransition::None, WebCore::FloatSize(marginInPoints * deviceScaleFactor, marginInPoints * deviceScaleFactor));
129
130 info.textIndicator = WTF::move(textIndicator);
131}
132
133#if ENABLE(DATA_DETECTION)(defined 1 && 1) && PLATFORM(IOS_FAMILY)(defined 1 && 1)
134
135static void dataDetectorLinkPositionInformation(WebCore::Element& element, InteractionInformationAtPosition& info)
136{
137 if (!WebCore::DataDetection::isDataDetectorLink(element))
138 return;
139
140 info.isDataDetectorLink = true;
141 info.dataDetectorBounds = info.bounds;
142 const int dataDetectionExtendedContextLength = 350;
143 info.dataDetectorIdentifier = WebCore::DataDetection::dataDetectorIdentifier(element);
144 if (auto* results = element.document().frame()->dataDetectionResultsIfExists())
145 info.dataDetectorResults = results->documentLevelResults();
146
147 if (!WebCore::DataDetection::requiresExtendedContext(element))
148 return;
149
150 auto range = WebCore::makeRangeSelectingNodeContents(element);
151 info.textBefore = plainTextForDisplay(WebCore::rangeExpandedByCharactersInDirectionAtWordBoundary(makeDeprecatedLegacyPosition(range.start),
152 dataDetectionExtendedContextLength, WebCore::SelectionDirection::Backward));
153 info.textAfter = plainTextForDisplay(WebCore::rangeExpandedByCharactersInDirectionAtWordBoundary(makeDeprecatedLegacyPosition(range.end),
154 dataDetectionExtendedContextLength, WebCore::SelectionDirection::Forward));
155}
156
157static void dataDetectorImageOverlayPositionInformation(const WebCore::HTMLElement& overlayHost, const InteractionInformationRequest& request, InteractionInformationAtPosition& info)
158{
159 RefPtr frame = overlayHost.document().frame();
160 if (!frame)
161 return;
162
163 auto elementAndBounds = WebCore::DataDetection::findDataDetectionResultElementInImageOverlay(request.point, overlayHost);
164 if (!elementAndBounds)
165 return;
166
167 auto [foundElement, elementBounds] = *elementAndBounds;
168 auto identifierValue = parseInteger<uint64_t>(foundElement->attributeWithoutSynchronization(WebCore::HTMLNames::x_apple_data_detectors_resultAttr));
169 if (!identifierValue || !*identifierValue)
170 return;
171
172 auto identifier = ObjectIdentifier<WebCore::ImageOverlayDataDetectionResultIdentifierType>(*identifierValue);
173
174 auto* dataDetectionResults = frame->dataDetectionResultsIfExists();
175 if (!dataDetectionResults)
176 return;
177
178 auto dataDetectionResult = retainPtr(dataDetectionResults->imageOverlayDataDetectionResult(identifier));
179 if (!dataDetectionResult)
180 return;
181
182 info.dataDetectorBounds = WTF::move(elementBounds);
183 info.dataDetectorResults = @[ dataDetectionResult.get() ];
184}
185
186#endif // ENABLE(DATA_DETECTION) && PLATFORM(IOS_FAMILY)
187
188static std::optional<std::pair<WebCore::RenderImage&, WebCore::Image&>> imageRendererAndImage(WebCore::Element& element)
189{
190 CheckedPtr renderImage = dynamicDowncast<WebCore::RenderImage>(element.renderer());
191 if (!renderImage)
192 return std::nullopt;
193
194 if (!renderImage->cachedImage() || renderImage->cachedImage()->errorOccurred())
195 return std::nullopt;
196
197 RefPtr image = renderImage->cachedImage()->imageForRenderer(renderImage);
198 if (!image || image->width() <= 1 || image->height() <= 1)
199 return std::nullopt;
200
201 return { { *renderImage, *image } };
202}
203
204#if PLATFORM(IOS_FAMILY)(defined 1 && 1)
205static void videoPositionInformation(WebPage& page, WebCore::HTMLVideoElement& element, const InteractionInformationRequest& request, InteractionInformationAtPosition& info)
206{
207 info.elementContainsImageOverlay = WebCore::ImageOverlay::hasOverlay(element);
208
209 if (!element.paused())
210 return;
211
212 CheckedPtr renderVideo = element.renderer();
213 if (!renderVideo)
214 return;
215
216 info.isPausedVideo = true;
217
218 if (request.includeImageData)
219 info.image = createShareableBitmap(*renderVideo);
220
221 info.hostImageOrVideoElementContext = page.contextForElement(element);
222}
223#endif // PLATFORM(IOS_FAMILY)
224
225static RefPtr<WebCore::HTMLVideoElement> hostVideoElementIgnoringImageOverlay(WebCore::Node& node)
226{
227 if (WebCore::ImageOverlay::isInsideOverlay(node))
228 return { };
229
230 if (RefPtr video = dynamicDowncast<WebCore::HTMLVideoElement>(node))
231 return video;
232
233 return dynamicDowncast<WebCore::HTMLVideoElement>(node.shadowHost());
234}
235
236#if PLATFORM(IOS_FAMILY)(defined 1 && 1)
237static void imagePositionInformation(WebPage& page, WebCore::Element& element, const InteractionInformationRequest& request, InteractionInformationAtPosition& info)
238{
239 auto rendererAndImage = imageRendererAndImage(element);
240 if (!rendererAndImage)
241 return;
242
243 auto& [renderImage, image] = *rendererAndImage;
244 info.isImage = true;
245 info.imageURL = page.applyLinkDecorationFiltering(protect(element.document())->completeURL(renderImage.cachedImage()->url().string()), WebCore::LinkDecorationFilteringTrigger::Unspecified);
Call argument for 'this' parameter is uncounted and unsafe
246 info.imageMIMEType = image.mimeType();
247 info.isAnimatedImage = image.isAnimated();
248 info.isAnimating = image.isAnimating();
249 RefPtr htmlElement = dynamicDowncast<WebCore::HTMLElement>(element);
250 info.elementContainsImageOverlay = htmlElement && WebCore::ImageOverlay::hasOverlay(*htmlElement);
251#if ENABLE(SPATIAL_IMAGE_DETECTION)(defined ENABLE_SPATIAL_IMAGE_DETECTION && ENABLE_SPATIAL_IMAGE_DETECTION
)
252 info.isSpatialImage = image.isSpatial();
253#endif
254
255 if (request.includeSnapshot || request.includeImageData)
256 info.image = createShareableBitmap(renderImage, { WebCore::screenSize() * page.corePage()->deviceScaleFactor(), AllowAnimatedImages::Yes, UseSnapshotForTransparentImages::Yes });
257
258 info.hostImageOrVideoElementContext = page.contextForElement(element);
259}
260#endif // PLATFORM(IOS_FAMILY)
261
262static void boundsPositionInformation(WebCore::RenderObject& renderer, InteractionInformationAtPosition& info)
263{
264 if (CheckedPtr renderImage = dynamicDowncast<WebCore::RenderImage>(renderer))
265 info.bounds = renderImage->absoluteContentQuad().enclosingBoundingBox();
266 else
267 info.bounds = renderer.absoluteBoundingBoxRect();
268
269 if (!renderer.document().frame()->isMainFrame()) {
270 RefPtr view = renderer.document().frame()->view();
271 info.bounds = view->contentsToRootView(info.bounds);
272 }
273}
274
275static void elementPositionInformation(WebPage& page, WebCore::Element& element, const InteractionInformationRequest& request, const WebCore::Node* innerNonSharedNode, InteractionInformationAtPosition& info)
276{
277 Ref document = element.document();
278 RefPtr<WebCore::Element> linkElement;
279 if (element.renderer() && element.renderer()->isRenderImage())
280 linkElement = WebPage::containingLinkAnchorElement(element);
281 else if (element.isLink())
282 linkElement = &element;
283
284 info.isElement = true;
285 info.idAttribute = element.getIdAttribute();
286 info.isImageOverlayText = WebCore::ImageOverlay::isOverlayText(innerNonSharedNode);
287
288 info.title = element.attributeWithoutSynchronization(WebCore::HTMLNames::titleAttr).string();
289 if (linkElement && info.title.isEmpty())
290 info.title = element.innerText();
291#if PLATFORM(IOS_FAMILY)(defined 1 && 1)
292 if (element.renderer())
293 info.touchCalloutEnabled = element.renderer()->style().touchCallout() == WebCore::Style::WebkitTouchCallout::Default;
294#endif
295
296 if (linkElement && !info.isImageOverlayText) {
297 info.isLink = true;
298 info.url = page.applyLinkDecorationFiltering(document->completeURL(linkElement->getAttribute(WebCore::HTMLNames::hrefAttr)), WebCore::LinkDecorationFilteringTrigger::Unspecified);
299
300 linkIndicatorPositionInformation(page, *linkElement, request, info);
301#if ENABLE(DATA_DETECTION)(defined 1 && 1) && PLATFORM(IOS_FAMILY)(defined 1 && 1)
302 dataDetectorLinkPositionInformation(element, info);
303#endif
304 }
305
306 RefPtr elementForScrollTesting = linkElement ? linkElement.get() : &element;
307 if (CheckedPtr renderer = elementForScrollTesting->renderer()) {
308 if (RefPtr scrollingCoordinator = page.scrollingCoordinator())
309 info.containerScrollingNodeID = scrollingCoordinator->scrollableContainerNodeID(*renderer);
310 }
311
312#if PLATFORM(IOS_FAMILY)(defined 1 && 1)
313 info.needsPointerTouchCompatibilityQuirk = document->quirks().needsPointerTouchCompatibility(element);
314#endif
315
316 if (CheckedPtr renderer = element.renderer()) {
317#if PLATFORM(IOS_FAMILY)(defined 1 && 1)
318 bool shouldCollectImagePositionInformation = renderer->isRenderImage();
319 if (shouldCollectImagePositionInformation && info.isImageOverlayText) {
320 shouldCollectImagePositionInformation = false;
321 if (request.includeImageData) {
322 if (auto rendererAndImage = imageRendererAndImage(element)) {
323 auto& [renderImage, image] = *rendererAndImage;
324 info.imageURL = page.applyLinkDecorationFiltering(document->completeURL(renderImage.cachedImage()->url().string()), WebCore::LinkDecorationFilteringTrigger::Unspecified);
325 info.imageMIMEType = image.mimeType();
326 info.image = createShareableBitmap(renderImage, { WebCore::screenSize() * page.corePage()->deviceScaleFactor(), AllowAnimatedImages::Yes, UseSnapshotForTransparentImages::Yes });
327 }
328 }
329 }
330 if (shouldCollectImagePositionInformation) {
331 if (auto video = hostVideoElementIgnoringImageOverlay(element))
332 videoPositionInformation(page, *video, request, info);
333 else
334 imagePositionInformation(page, element, request, info);
335 }
336#endif // PLATFORM(IOS_FAMILY)
337 boundsPositionInformation(*renderer, info);
338 }
339
340 info.elementContext = page.contextForElement(element);
341}
342
343static void selectionPositionInformation(WebPage& page, const InteractionInformationRequest& request, InteractionInformationAtPosition& info)
344{
345 RefPtr localMainFrame = dynamicDowncast<WebCore::LocalFrame>(page.corePage()->mainFrame());
346 if (!localMainFrame)
347 return;
348
349 constexpr OptionSet<WebCore::HitTestRequest::Type> hitType {
350 WebCore::HitTestRequest::Type::ReadOnly,
351 WebCore::HitTestRequest::Type::Active,
352 WebCore::HitTestRequest::Type::AllowVisibleChildFrameContentOnly
353 };
354 WebCore::HitTestResult result = localMainFrame->eventHandler().hitTestResultAtPoint(request.point, hitType);
355 RefPtr hitNode = result.innerNode();
356
357 // Hit test could return HTMLHtmlElement that has no renderer, if the body is smaller than the document.
358 if (!hitNode || !hitNode->renderer())
359 return;
360
361 CheckedPtr renderer = hitNode->renderer();
362
363 info.selectability = ([&] {
364 if (protect(renderer->style())->usedUserSelect() == WebCore::UserSelect::None)
365 return InteractionInformationAtPosition::Selectability::UnselectableDueToUserSelectNoneOrQuirk;
366
367 if (RefPtr element = dynamicDowncast<WebCore::Element>(*hitNode)) {
368 if (WebPage::isAssistableElement(*element))
369 return InteractionInformationAtPosition::Selectability::UnselectableDueToFocusableElement;
370
371 if (hostVideoElementIgnoringImageOverlay(*hitNode))
372 return InteractionInformationAtPosition::Selectability::UnselectableDueToMediaControls;
373 }
374
375 if (protect(hitNode->document())->quirks().shouldAvoidStartingSelectionOnMouseDownOverPointerCursor(*hitNode))
376 return InteractionInformationAtPosition::Selectability::UnselectableDueToUserSelectNoneOrQuirk;
377
378 return InteractionInformationAtPosition::Selectability::Selectable;
379 })();
380 info.isSelected = result.isSelected();
381
382 if (info.isLink || info.isImage)
383 return;
384
385 boundsPositionInformation(*renderer, info);
386
387 if (RefPtr element = dynamicDowncast<WebCore::Element>(*hitNode))
388 info.idAttribute = element->getIdAttribute();
389
390 if (RefPtr attachment = dynamicDowncast<WebCore::HTMLAttachmentElement>(*hitNode)) {
391 info.isAttachment = true;
392 info.title = attachment->attachmentTitle();
393 linkIndicatorPositionInformation(page, *attachment, request, info);
394 if (attachment->file())
395 info.url = URL::fileURLWithFileSystemPath(attachment->file()->path());
396 }
397
398 for (RefPtr currentNode = hitNode; currentNode; currentNode = currentNode->parentOrShadowHostNode()) {
399 CheckedPtr renderer = currentNode->renderer();
400 if (!renderer)
401 continue;
402
403 CheckedRef style = renderer->style();
404 if (style->usedUserSelect() == WebCore::UserSelect::None && style->userDrag() == WebCore::UserDrag::Element) {
405 info.prefersDraggingOverTextSelection = true;
406 break;
407 }
408 }
409#if PLATFORM(MACCATALYST)(defined WTF_PLATFORM_MACCATALYST && WTF_PLATFORM_MACCATALYST
)
410 bool isInsideFixedPosition;
411 WebCore::VisiblePosition caretPosition(renderer->visiblePositionForPoint(request.point, WebCore::HitTestSource::User));
412 info.caretRect = caretPosition.absoluteCaretBounds(&isInsideFixedPosition);
413#endif
414
415#if ENABLE(MODEL_PROCESS)(defined 0 && 0)
416 if (is<WebCore::HTMLModelElement>(*hitNode))
417 info.prefersDraggingOverTextSelection = true;
418#endif
419}
420
421static void textInteractionPositionInformation(WebPage& page, const WebCore::HTMLInputElement& input, const InteractionInformationRequest& request, InteractionInformationAtPosition& info)
422{
423 if (!input.list())
424 return;
425
426 constexpr OptionSet<WebCore::HitTestRequest::Type> hitType { WebCore::HitTestRequest::Type::ReadOnly, WebCore::HitTestRequest::Type::Active, WebCore::HitTestRequest::Type::AllowVisibleChildFrameContentOnly };
427 RefPtr localMainFrame = dynamicDowncast<WebCore::LocalFrame>(page.corePage()->mainFrame());
428 if (!localMainFrame)
429 return;
430 WebCore::HitTestResult result = localMainFrame->eventHandler().hitTestResultAtPoint(request.point, hitType);
431 if (result.innerNode() == input.dataListButtonElement())
432 info.preventTextInteraction = true;
433}
434
435static bool canForceCaretForPosition(const WebCore::VisiblePosition& position)
436{
437 RefPtr node = position.deepEquivalent().anchorNode();
438 if (!node)
439 return false;
440
441 CheckedPtr renderer = node->renderer();
442 CheckedPtr style = renderer ? &renderer->style() : nullptr;
443 auto cursorType = style ? style->cursorType() : WebCore::CursorType::Auto;
444
445 if (cursorType == WebCore::CursorType::Text)
446 return true;
447
448 if (cursorType != WebCore::CursorType::Auto)
449 return false;
450
451 if (node->hasEditableStyle())
452 return true;
453
454 if (!renderer)
455 return false;
456
457 return renderer->isRenderText() && node->canStartSelection();
458}
459
460static CursorContext cursorContext(const WebCore::HitTestResult& hitTestResult, const InteractionInformationRequest& request)
461{
462 CursorContext context;
463 RefPtr frame = hitTestResult.innerNodeFrame();
464 if (!frame)
465 return context;
466
467 // FIXME: Do we really need to set the cursor here if `includeCursorContext` is not set?
468 context.cursor = frame->eventHandler().selectCursor(hitTestResult, false);
469
470 if (!request.includeCursorContext)
471 return context;
472
473 RefPtr view = frame->view();
474 if (!view)
475 return context;
476
477 RefPtr node = hitTestResult.innerNode();
478 if (!node)
479 return context;
480
481 CheckedPtr renderer = node->renderer();
482 if (!renderer)
483 return context;
484
485 while (renderer && !is<WebCore::RenderBlockFlow>(*renderer))
486 renderer = renderer->parent();
487
488 if (!renderer)
489 return context;
490
491 // FIXME: We should be able to retrieve this geometry information without
492 // forcing the text to fall out of Simple Line Layout.
493 CheckedRef blockFlow = downcast<WebCore::RenderBlockFlow>(*renderer);
494 auto position = frame->visiblePositionForPoint(view->rootViewToContents(request.point));
495 auto lineRect = position.absoluteSelectionBoundsForLine();
496 bool isEditable = node->hasEditableStyle();
497
498 if (isEditable)
499 lineRect.setWidth(blockFlow->contentBoxWidth());
500
501 context.isVerticalWritingMode = !renderer->isHorizontalWritingMode();
502 context.lineCaretExtent = view->contentsToRootView(lineRect);
503
504 auto cursorTypeIs = [](const auto& maybeCursor, auto type) {
505 return maybeCursor.transform([type](const auto& cursor) {
506 return cursor.type() == type;
507 }).value_or(false);
508 };
509
510 bool lineContainsRequestPoint = context.lineCaretExtent.contains(request.point);
511 // Force an I-beam cursor if the page didn't request a hand, and we're inside the bounds of the line.
512 if (lineContainsRequestPoint && !cursorTypeIs(context.cursor, WebCore::Cursor::Type::Hand) && canForceCaretForPosition(position))
513 context.cursor = WebCore::Cursor::fromType(WebCore::Cursor::Type::IBeam);
514
515 if (!lineContainsRequestPoint && cursorTypeIs(context.cursor, WebCore::Cursor::Type::IBeam)) {
516 auto approximateLineRectInContentCoordinates = renderer->absoluteBoundingBoxRect();
517 approximateLineRectInContentCoordinates.setHeight(protect(renderer->style())->computedLineHeight());
518 context.lineCaretExtent = view->contentsToRootView(approximateLineRectInContentCoordinates);
519 if (!context.lineCaretExtent.contains(request.point) || !isEditable)
520 context.lineCaretExtent.setY(request.point.y() - context.lineCaretExtent.height() / 2);
521 }
522
523 auto nodeShouldNotUseIBeam = ^(WebCore::Node* node) {
524 if (!node)
525 return false;
526 WebCore::RenderObject *renderer = node->renderer();
527 if (!renderer)
528 return false;
529 return is<WebCore::RenderReplaced>(*renderer);
530 };
531
532 const auto& deepPosition = position.deepEquivalent();
533 context.shouldNotUseIBeamInEditableContent = nodeShouldNotUseIBeam(node) || nodeShouldNotUseIBeam(deepPosition.computeNodeBeforePosition()) || nodeShouldNotUseIBeam(deepPosition.computeNodeAfterPosition());
534 return context;
535}
536
537static void animationPositionInformation(WebPage& page, const InteractionInformationRequest& request, const WebCore::HitTestResult& hitTestResult, InteractionInformationAtPosition& info)
538{
539#if ENABLE(ACCESSIBILITY_ANIMATION_CONTROL)(defined 1 && 1)
540 if (!request.gatherAnimations)
541 return;
542
543 for (const auto& node : hitTestResult.listBasedTestResult()) {
544 RefPtr element = dynamicDowncast<WebCore::Element>(node.ptr());
545 if (!element)
546 continue;
547
548 auto rendererAndImage = imageRendererAndImage(*element);
549 if (!rendererAndImage)
550 continue;
551
552 Ref image = rendererAndImage->second;
553 if (!image->isAnimated())
554 continue;
555
556 if (auto elementContext = page.contextForElement(*element))
557 info.animationsAtPoint.append({ WTF::move(*elementContext), image->isAnimating() });
558 }
559#else
560 UNUSED_PARAM(page)(void)page;
561 UNUSED_PARAM(request)(void)request;
562 UNUSED_PARAM(info)(void)info;
563#endif // ENABLE(ACCESSIBILITY_ANIMATION_CONTROL)
564}
565
566static RefPtr<WebCore::LocalDOMWindow> windowWithDoubleClickEventListener(RefPtr<WebCore::LocalFrame> frame)
567{
568 if (!frame)
569 return nullptr;
570
571 RefPtr window = frame->window();
572 if (!window || !window->hasEventListeners(WebCore::eventNames().dblclickEvent))
573 return nullptr;
574
575 return window;
576}
577
578InteractionInformationAtPosition positionInformationForWebPage(WebPage& page, const InteractionInformationRequest& request)
579{
580 InteractionInformationAtPosition info;
581 info.request = request;
582
583 WebCore::FloatPoint adjustedPoint;
584 RefPtr localMainFrame = WTF::protect(page.corePage())->localMainFrame();
585 if (!localMainFrame)
586 return info;
587
588 RefPtr nodeRespondingToClickEvents = localMainFrame->nodeRespondingToClickEvents(request.point, adjustedPoint);
589
590 info.isContentEditable = nodeRespondingToClickEvents && nodeRespondingToClickEvents->isContentEditable();
591 info.adjustedPointForNodeRespondingToClickEvents = adjustedPoint;
592
593 if (request.includeHasDoubleClickHandler)
594 info.hitNodeOrWindowHasDoubleClickListener = localMainFrame->nodeRespondingToDoubleClickEvent(request.point, adjustedPoint) || windowWithDoubleClickEventListener(localMainFrame);
595
596 auto hitTestRequestTypes = OptionSet<WebCore::HitTestRequest::Type> {
597 WebCore::HitTestRequest::Type::ReadOnly,
598 WebCore::HitTestRequest::Type::AllowFrameScrollbars,
599 WebCore::HitTestRequest::Type::AllowVisibleChildFrameContentOnly,
600 };
601
602#if ENABLE(ACCESSIBILITY_ANIMATION_CONTROL)(defined 1 && 1)
603 if (request.gatherAnimations) {
604 hitTestRequestTypes.add(WebCore::HitTestRequest::Type::IncludeAllElementsUnderPoint);
605 hitTestRequestTypes.add(WebCore::HitTestRequest::Type::CollectMultipleElements);
606 }
607#endif // ENABLE(ACCESSIBILITY_ANIMATION_CONTROL)
608
609 auto& eventHandler = localMainFrame->eventHandler();
610 auto hitTestResult = eventHandler.hitTestResultAtPoint(request.point, hitTestRequestTypes);
611
612#if ENABLE(PDF_PLUGIN)(defined 1 && 1)
613 RefPtr pluginView = hitTestResult.isOverWidget() ? WebPage::pluginViewForFrame(WTF::protect(hitTestResult.innerNodeFrame())) : nullptr;
614#endif
615
616 info.cursorContext = [&] {
617 if (request.includeCursorContext) {
618#if ENABLE(PDF_PLUGIN)(defined 1 && 1) && PLATFORM(IOS_FAMILY)(defined 1 && 1)
619 if (pluginView)
620 return pluginView->cursorContext(request.point);
621#endif
622 }
623 return cursorContext(hitTestResult, request);
624 }();
625
626 if (page.focusedElement())
627 focusedElementPositionInformation(page, *page.focusedElement(), request, info);
628
629 RefPtr hitTestNode = hitTestResult.innerNonSharedNode();
630 if (RefPtr element = dynamicDowncast<WebCore::Element>(nodeRespondingToClickEvents)) {
631 elementPositionInformation(page, *element, request, hitTestNode.get(), info);
632
633 if (info.isLink && !info.isImage && request.includeSnapshot)
634 info.image = page.shareableBitmapSnapshotForNode(*element);
635 }
636
637#if ENABLE(DATA_DETECTION)(defined 1 && 1) && PLATFORM(IOS_FAMILY)(defined 1 && 1)
638 auto hitTestedImageOverlayHost = ([&]() -> RefPtr<WebCore::HTMLElement> {
639 if (!hitTestNode || !info.isImageOverlayText)
640 return nullptr;
641
642 RefPtr htmlElement = dynamicDowncast<WebCore::HTMLElement>(hitTestNode->shadowHost());
643 if (!htmlElement || !WebCore::ImageOverlay::hasOverlay(*htmlElement))
644 return nullptr;
645
646 return htmlElement;
647 })();
648
649 if (hitTestedImageOverlayHost)
650 dataDetectorImageOverlayPositionInformation(*hitTestedImageOverlayHost, request, info);
651#endif // ENABLE(DATA_DETECTION) && PLATFORM(IOS_FAMILY)
652
653#if PLATFORM(IOS_FAMILY)(defined 1 && 1)
654 if (!info.isImage && request.includeImageData && hitTestNode) {
655 if (auto video = hostVideoElementIgnoringImageOverlay(*hitTestNode))
656 videoPositionInformation(page, *video, request, info);
657 else if (RefPtr img = dynamicDowncast<WebCore::HTMLImageElement>(hitTestNode))
658 imagePositionInformation(page, *img, request, info);
659 }
660#endif // PLATFORM(IOS_FAMILY)
661
662 animationPositionInformation(page, request, hitTestResult, info);
663 selectionPositionInformation(page, request, info);
664
665 // Prevent the callout bar from showing when tapping on the datalist button.
666 if (RefPtr input = dynamicDowncast<WebCore::HTMLInputElement>(nodeRespondingToClickEvents))
667 textInteractionPositionInformation(page, *input, request, info);
668
669#if ENABLE(MODEL_PROCESS)(defined 0 && 0)
670 if (RefPtr modelElement = dynamicDowncast<WebCore::HTMLModelElement>(hitTestNode))
671 info.isInteractiveModel = modelElement->model() && modelElement->supportsStageModeInteraction();
672#endif
673
674#if ENABLE(PDF_PLUGIN)(defined 1 && 1) && PLATFORM(IOS_FAMILY)(defined 1 && 1)
675 if (pluginView) {
676 if (auto&& [url, bounds, textIndicator] = pluginView->linkDataAtPoint(request.point); !url.isEmpty()) {
677 info.isLink = true;
678 info.url = WTF::move(url);
679 info.bounds = enclosingIntRect(bounds);
680 info.textIndicator = WTF::move(textIndicator);
681 }
682 info.isInPlugin = true;
683 }
684#endif // ENABLE(PDF_PLUGIN) && PLATFORM(IOS_FAMILY)
685
686 return info;
687}
688
689};
690
691#endif // PLATFORM(COCOA)