Bug Summary

File:Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Warning:line 4285, column 1
The return value is +1 and results in a memory leak

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 WKContentViewInteraction.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/WKContentViewInteraction.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.8+" -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 -Wunsafe-buffer-usage -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/WKContentViewInteraction.plist -x objective-c++ /Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
1/*
2 * Copyright (C) 2012-2024 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 "WKContentViewInteraction.h"
28
29#if PLATFORM(IOS_FAMILY)(defined 1 && 1)
30
31#import "APIUIClient.h"
32#import "CocoaImage.h"
33#import "CompletionHandlerCallChecker.h"
34#import "DefaultWebBrowserChecks.h"
35#import "DocumentEditingContext.h"
36#import "ImageAnalysisUtilities.h"
37#import "InsertTextOptions.h"
38#import "KeyEventInterpretationContext.h"
39#import "Logging.h"
40#import "NativeWebKeyboardEvent.h"
41#import "NativeWebTouchEvent.h"
42#import "NetworkProcessMessages.h"
43#import "PDFDisplayMode.h"
44#import "PageClient.h"
45#import "PickerDismissalReason.h"
46#import "PlatformWritingToolsUtilities.h"
47#import "RemoteLayerTreeDrawingAreaProxy.h"
48#import "RemoteLayerTreeViews.h"
49#import "RemoteScrollingCoordinatorProxyIOS.h"
50#import "RevealItem.h"
51#import "SmartMagnificationController.h"
52#import "TextChecker.h"
53#import "TextCheckerState.h"
54#import "TextInputSPI.h"
55#import "TextRecognitionUpdateResult.h"
56#import "UIGamepadProvider.h"
57#import "UIKitSPI.h"
58#import "UIKitUtilities.h"
59#import "WKActionSheetAssistant.h"
60#import "WKContextMenuElementInfoInternal.h"
61#import "WKContextMenuElementInfoPrivate.h"
62#import "WKDatePickerViewController.h"
63#import "WKDateTimeInputControl.h"
64#import "WKError.h"
65#import "WKExtendedTextInputTraits.h"
66#import "WKFocusedFormControlView.h"
67#import "WKFormColorControl.h"
68#import "WKFormSelectControl.h"
69#import "WKFrameInfoInternal.h"
70#import "WKHighlightLongPressGestureRecognizer.h"
71#import "WKImageAnalysisGestureRecognizer.h"
72#import "WKImagePreviewViewController.h"
73#import "WKInspectorNodeSearchGestureRecognizer.h"
74#import "WKNSURLExtras.h"
75#import "WKPreviewActionItemIdentifiers.h"
76#import "WKPreviewActionItemInternal.h"
77#import "WKPreviewElementInfoInternal.h"
78#import "WKQuickboardViewControllerDelegate.h"
79#import "WKScrollView.h"
80#import "WKSelectMenuListViewController.h"
81#import "WKSyntheticFlagsChangedWebEvent.h"
82#import "WKTapHighlightView.h"
83#import "WKTextInputListViewController.h"
84#import "WKTextInteractionWrapper.h"
85#import "WKTextPlaceholder.h"
86#import "WKTextSelectionRect.h"
87#import "WKTimePickerViewController.h"
88#import "WKTouchEventsGestureRecognizer.h"
89#import "WKUIDelegatePrivate.h"
90#import "WKWebViewConfiguration.h"
91#import "WKWebViewConfigurationPrivate.h"
92#import "WKWebViewIOS.h"
93#import "WKWebViewInternal.h"
94#import "WKWebViewPrivate.h"
95#import "WKWebViewPrivateForTesting.h"
96#import "WebAutocorrectionContext.h"
97#import "WebAutocorrectionData.h"
98#import "WebDataListSuggestionsDropdownIOS.h"
99#import "WebEvent.h"
100#import "WebFoundTextRange.h"
101#import "WebIOSEventFactory.h"
102#import "WebMouseEvent.h"
103#import "WebPageMessages.h"
104#import "WebPageProxy.h"
105#import "WebPageProxyMessages.h"
106#import "WebProcessProxy.h"
107#import "_WKActivatedElementInfoInternal.h"
108#import "_WKDragActionsInternal.h"
109#import "_WKElementAction.h"
110#import "_WKElementActionInternal.h"
111#import "_WKFocusedElementInfo.h"
112#import "_WKInputDelegate.h"
113#import "_WKTextInputContextInternal.h"
114#import <CoreText/CTFont.h>
115#import <CoreText/CTFontDescriptor.h>
116#import <MobileCoreServices/UTCoreTypes.h>
117#import <UniformTypeIdentifiers/UTCoreTypes.h>
118#import <WebCore/AppHighlight.h>
119#import <WebCore/ColorCocoa.h>
120#import <WebCore/ColorSerialization.h>
121#import <WebCore/CompositionHighlight.h>
122#import <WebCore/DOMPasteAccess.h>
123#import <WebCore/DataDetection.h>
124#import <WebCore/FloatQuad.h>
125#import <WebCore/FloatRect.h>
126#import <WebCore/FontAttributeChanges.h>
127#import <WebCore/InputMode.h>
128#import <WebCore/KeyEventCodesIOS.h>
129#import <WebCore/KeyboardScroll.h>
130#import <WebCore/LocalizedStrings.h>
131#import <WebCore/MIMETypeRegistry.h>
132#import <WebCore/NodeIdentifier.h>
133#import <WebCore/NotImplemented.h>
134#import <WebCore/Pasteboard.h>
135#import <WebCore/Path.h>
136#import <WebCore/PathUtilities.h>
137#import <WebCore/PlatformLayerIdentifier.h>
138#import <WebCore/PlatformTextAlternativesBETextAlternatives.h>
139#import <WebCore/PromisedAttachmentInfo.h>
140#import <WebCore/ScrollTypes.h>
141#import <WebCore/Scrollbar.h>
142#import <WebCore/ShareData.h>
143#import <WebCore/TextAlternativeWithRange.h>
144#import <WebCore/TextAnimationTypes.h>
145#import <WebCore/TextIndicator.h>
146#import <WebCore/TextRecognitionResult.h>
147#import <WebCore/TouchAction.h>
148#import <WebCore/UTIRegistry.h>
149#import <WebCore/UTIUtilities.h>
150#import <WebCore/VisibleSelection.h>
151#import <WebCore/WebCoreCALayerExtras.h>
152#import <WebCore/WebEventPrivate.h>
153#import <WebCore/WebTextIndicatorLayer.h>
154#import <WebCore/WindowsKeyboardCodes.h>
155#import <WebCore/WritingDirection.h>
156#import <WebKit/WebSelectionRect.h> // FIXME: WebKit should not include WebKitLegacy headers!
157#import <pal/spi/cg/CoreGraphicsSPI.h>
158#import <pal/spi/cocoa/DataDetectorsCoreSPI.h>
159#import <pal/spi/cocoa/LaunchServicesSPI.h>
160#import <pal/spi/cocoa/NSAttributedStringSPI.h>
161#import <pal/spi/cocoa/QuartzCoreSPI.h>
162#import <pal/spi/ios/BarcodeSupportSPI.h>
163#import <pal/spi/ios/GraphicsServicesSPI.h>
164#import <pal/spi/ios/ManagedConfigurationSPI.h>
165#import <pal/system/ios/UserInterfaceIdiom.h>
166#import <ranges>
167#import <wtf/BlockObjCExceptions.h>
168#import <wtf/BlockPtr.h>
169#import <wtf/CallbackAggregator.h>
170#import <wtf/RuntimeApplicationChecks.h>
171#import <wtf/Scope.h>
172#import <wtf/SetForScope.h>
173#import <wtf/StdLibExtras.h>
174#import <wtf/SystemFree.h>
175#import <wtf/WeakObjCPtr.h>
176#import <wtf/cocoa/NSURLExtras.h>
177#import <wtf/cocoa/RuntimeApplicationChecksCocoa.h>
178#import <wtf/cocoa/TypeCastsCocoa.h>
179#import <wtf/cocoa/VectorCocoa.h>
180#import <wtf/text/MakeString.h>
181#import <wtf/text/TextStream.h>
182
183#if ENABLE(DRAG_SUPPORT)(defined 1 && 1)
184#import <WebCore/DragData.h>
185#import <WebCore/DragItem.h>
186#import <WebCore/PlatformPasteboard.h>
187#import <WebCore/WebItemProviderPasteboard.h>
188#if ENABLE(MODEL_PROCESS)(defined 0 && 0)
189#import "ModelPresentationManagerProxy.h"
190#endif
191#endif
192
193#if HAVE(LOOKUP_GESTURE_RECOGNIZER)(defined HAVE_LOOKUP_GESTURE_RECOGNIZER && HAVE_LOOKUP_GESTURE_RECOGNIZER
)
194#import <UIKit/_UILookupGestureRecognizer.h>
195#endif
196
197#if ENABLE(ATTACHMENT_ELEMENT)(defined 1 && 1)
198#import "APIAttachment.h"
199#endif
200
201#if HAVE(PEPPER_UI_CORE)(defined HAVE_PEPPER_UI_CORE && HAVE_PEPPER_UI_CORE)
202#import "PepperUICoreSPI.h"
203#endif
204
205#if HAVE(AVKIT)(defined 1 && 1)
206#import <pal/spi/cocoa/AVKitSPI.h>
207#endif
208
209#if ENABLE(WEB_AUTHN)(defined 1 && 1)
210#import "WKDigitalCredentialsPicker.h"
211#endif
212
213#if ENABLE(WRITING_TOOLS)(defined 1 && 1)
214#import "WKTextAnimationManagerIOS.h"
215#endif
216
217#if ENABLE(MODEL_PROCESS)(defined 0 && 0) || ENABLE(WRITING_TOOLS)(defined 1 && 1)
218#import "WebKitSwiftSoftLink.h"
219#endif
220
221#import <pal/cocoa/VisionKitCoreSoftLink.h>
222#import <pal/cocoa/TranslationUIServicesSoftLink.h>
223#import <pal/ios/ManagedConfigurationSoftLink.h>
224#import <pal/ios/QuickLookSoftLink.h>
225#import <pal/spi/ios/DataDetectorsUISoftLink.h>
226
227#if HAVE(AUTOCORRECTION_ENHANCEMENTS)(defined 1 && 1)
228#define UIWKDocumentRequestAutocorrectedRanges(1 << 7) (1 << 7)
229#endif
230
231#if USE(BROWSERENGINEKIT)(defined 1 && 1)
232
233@interface WKUITextSelectionRect : UITextSelectionRect
234+ (instancetype)selectionRectWithCGRect:(CGRect)rect;
235@end
236
237@implementation WKUITextSelectionRect {
238 CGRect _selectionRect;
239}
240
241+ (instancetype)selectionRectWithCGRect:(CGRect)rect
242{
243 return adoptNS([[WKUITextSelectionRect alloc] initWithCGRect:rect]).autorelease();
244}
245
246- (instancetype)initWithCGRect:(CGRect)rect
247{
248 if (self = [super init])
249 _selectionRect = rect;
250 return self;
251}
252
253- (CGRect)rect
254{
255 return _selectionRect;
256}
257
258@end
259
260#endif // USE(BROWSERENGINEKIT)
261
262#if HAVE(LINK_PREVIEW)(defined 1 && 1) && USE(UICONTEXTMENU)(defined 1 && 1)
263static NSString * const webkitShowLinkPreviewsPreferenceKey = @"WebKitShowLinkPreviews";
264#endif
265
266#if HAVE(UI_POINTER_INTERACTION)(defined 1 && 1)
267static NSString * const pointerRegionIdentifier = @"WKPointerRegion";
268static NSString * const editablePointerRegionIdentifier = @"WKEditablePointerRegion";
269
270@interface WKContentView (WKUIPointerInteractionDelegate) <UIPointerInteractionDelegate>
271@end
272#endif
273
274#if HAVE(PENCILKIT_TEXT_INPUT)(defined 1 && 1)
275@interface WKContentView (WKUIIndirectScribbleInteractionDelegate) <UIIndirectScribbleInteractionDelegate>
276@end
277#endif
278
279#if HAVE(PEPPER_UI_CORE)(defined HAVE_PEPPER_UI_CORE && HAVE_PEPPER_UI_CORE)
280#if HAVE(QUICKBOARD_CONTROLLER)(defined HAVE_QUICKBOARD_CONTROLLER && HAVE_QUICKBOARD_CONTROLLER
)
281@interface WKContentView (QuickboardControllerSupport) <PUICQuickboardControllerDelegate>
282@end
283#endif // HAVE(QUICKBOARD_CONTROLLER)
284
285@interface WKContentView (WatchSupport) <WKFocusedFormControlViewDelegate, WKSelectMenuListViewControllerDelegate, WKTextInputListViewControllerDelegate>
286@end
287#endif // HAVE(PEPPER_UI_CORE)
288
289static void *WKContentViewKVOTransformContext = &WKContentViewKVOTransformContext;
290
291#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
292
293@interface WKContentView (ImageAnalysis) <WKImageAnalysisGestureRecognizerDelegate>
294@end
295
296#if USE(QUICK_LOOK)(defined 1 && 1)
297
298@interface WKContentView (ImageAnalysisPreview) <QLPreviewControllerDelegate, QLPreviewControllerDataSource, QLPreviewItemDataProvider>
299@end
300
301#endif // USE(QUICK_LOOK)
302
303#endif // ENABLE(IMAGE_ANALYSIS)
304
305#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
306
307@interface WKContentView (ImageAnalysisInteraction) <VKCImageAnalysisInteractionDelegate>
308@end
309
310#endif
311
312#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
313
314static bool canAttemptTextRecognitionForNonImageElements(const WebKit::InteractionInformationAtPosition& information, const WebKit::WebPreferences& preferences)
315{
316 return preferences.textRecognitionInVideosEnabled() && information.isPausedVideo;
317}
318
319#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
320
321@interface AVPlayerViewController (Staging_86237428)
322- (void)setImageAnalysis:(CocoaImageAnalysis *)analysis;
323@end
324
325#endif // ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)
326
327#endif // ENABLE(IMAGE_ANALYSIS)
328
329#if HAVE(UI_TEXT_SELECTION_DISPLAY_INTERACTION)(defined 1 && 1)
330
331@interface WKContentView (UITextSelectionDisplayInteraction) <UITextSelectionDisplayInteractionDelegate>
332@end
333
334#endif
335
336namespace WebKit {
337using namespace WebCore;
338
339enum class IgnoreTapGestureReason : uint8_t {
340 None,
341 ToggleEditMenu,
342 DeferToScrollView,
343};
344
345static NSArray<NSString *> *supportedPlainTextPasteboardTypes()
346{
347 static NeverDestroyed supportedTypes = [] {
348 auto types = adoptNS([[NSMutableArray alloc] init]);
349 [types addObject:@(WebCore::PasteboardCustomData::cocoaType().characters())];
350 [types addObject:UTTypeURL.identifier];
351 [types addObjectsFromArray:UIPasteboardTypeListString];
352 return types;
353 }();
354 return supportedTypes.get().get();
355}
356
357static NSArray<NSString *> *supportedRichTextPasteboardTypesForPasteConfiguration()
358{
359 static NeverDestroyed supportedTypes = [] {
360 auto types = adoptNS([[NSMutableArray alloc] init]);
361 [types addObject:UTTypeWebArchive.identifier];
362 [types addObjectsFromArray:UIPasteboardTypeListImage];
363 [types addObjectsFromArray:protect(supportedPlainTextPasteboardTypes()).get()];
364 return types;
365 }();
366 return supportedTypes.get().get();
367}
368
369static NSArray<NSString *> *supportedRichTextPasteboardTypes()
370{
371 static NeverDestroyed supportedTypes = [] {
372 auto types = adoptNS([[NSMutableArray alloc] init]);
373 [types addObject:protect(WebCore::WebArchivePboardType).get()];
374 [types addObjectsFromArray:protect(supportedRichTextPasteboardTypesForPasteConfiguration()).get()];
375 return types;
376 }();
377 return supportedTypes.get().get();
378}
379
380#if HAVE(UI_PASTE_CONFIGURATION)(defined 1 && 1)
381
382static NSArray<NSString *> *supportedRichTextPasteboardTypesWithAttachmentsForPasteConfiguration()
383{
384 static NeverDestroyed supportedTypes = [] {
385 auto types = adoptNS([[NSMutableArray alloc] init]);
386 [types addObjectsFromArray:protect(supportedRichTextPasteboardTypesForPasteConfiguration()).get()];
387 [types addObjectsFromArray:protect(WebCore::Pasteboard::supportedFileUploadPasteboardTypes()).get()];
388 return types;
389 }();
390 return supportedTypes.get().get();
391}
392
393#endif // HAVE(UI_PASTE_CONFIGURATION)
394
395WKSelectionDrawingInfo::WKSelectionDrawingInfo()
396 : type(WebCore::SelectionType::None)
397{
398}
399
400WKSelectionDrawingInfo::WKSelectionDrawingInfo(const EditorState& editorState)
401{
402 if (editorState.selectionType == WebCore::SelectionType::None || (editorState.selectionType == WebCore::SelectionType::Caret && !editorState.isContentEditable)) {
403 type = WebCore::SelectionType::None;
404 return;
405 }
406
407 type = WebCore::SelectionType::Range;
408 if (!editorState.postLayoutData)
409 return;
410
411 auto& postLayoutData = *editorState.postLayoutData;
412 auto& visualData = *editorState.visualData;
413 caretRect = visualData.caretRectAtEnd;
414 caretColor = postLayoutData.caretColor;
415 selectionGeometries = visualData.selectionGeometries;
416 selectionClipRect = visualData.selectionClipRect;
417 enclosingLayerID = visualData.enclosingLayerID;
418}
419
420auto WKSelectionDrawingInfo::compare(const WKSelectionDrawingInfo& other) const -> ComparisonResult
421{
422 using enum ComparisonResult;
423
424 if (type != other.type)
425 return VisuallyDistinct;
426
427 if (type == WebCore::SelectionType::Range) {
428 if (caretRect != other.caretRect)
429 return VisuallyDistinct;
430
431 if (caretColor != other.caretColor)
432 return VisuallyDistinct;
433
434 if (selectionGeometries.size() != other.selectionGeometries.size())
435 return VisuallyDistinct;
436
437 for (unsigned i = 0; i < selectionGeometries.size(); ++i) {
438 auto& aGeometry = selectionGeometries[i];
439 auto& bGeometry = other.selectionGeometries[i];
440 auto behavior = aGeometry.behavior();
441 if (behavior != bGeometry.behavior())
442 return VisuallyDistinct;
443
444 if (behavior == WebCore::SelectionRenderingBehavior::CoalesceBoundingRects && aGeometry.rect() != bGeometry.rect())
445 return VisuallyDistinct;
446
447 if (behavior == WebCore::SelectionRenderingBehavior::UseIndividualQuads && aGeometry.quad() != bGeometry.quad())
448 return VisuallyDistinct;
449 }
450 }
451
452 if (type != WebCore::SelectionType::None && selectionClipRect != other.selectionClipRect)
453 return VisuallyDistinct;
454
455 if (enclosingLayerID != other.enclosingLayerID)
456 return EquivalentExceptForEnclosingLayer;
457
458 return EquivalentIncludingEnclosingLayer;
459}
460
461TextStream& operator<<(TextStream& stream, const WKSelectionDrawingInfo& info)
462{
463 TextStream::GroupScope group(stream);
464 stream.dumpProperty("type"_s, std::to_underlying(info.type));
465 stream.dumpProperty("caret rect"_s, info.caretRect);
466 stream.dumpProperty("caret color"_s, info.caretColor);
467 stream.dumpProperty("selection geometries"_s, info.selectionGeometries);
468 stream.dumpProperty("selection clip rect"_s, info.selectionClipRect);
469 stream.dumpProperty("layer"_s, info.enclosingLayerID);
470 return stream;
471}
472
473#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
474
475class ImageAnalysisGestureDeferralToken final : public RefCounted<ImageAnalysisGestureDeferralToken> {
476public:
477 static RefPtr<ImageAnalysisGestureDeferralToken> create(WKContentView *view)
478 {
479 return adoptRef(*new ImageAnalysisGestureDeferralToken(view));
480 }
481
482 ~ImageAnalysisGestureDeferralToken()
483 {
484 if (auto view = m_view.get())
485 [view _endImageAnalysisGestureDeferral:m_shouldPreventTextSelection ? WebKit::ShouldPreventGestures::Yes : WebKit::ShouldPreventGestures::No];
486 }
487
488 void setShouldPreventTextSelection()
489 {
490 m_shouldPreventTextSelection = true;
491 }
492
493private:
494 ImageAnalysisGestureDeferralToken(WKContentView *view)
495 : m_view(view)
496 {
497 }
498
499 WeakObjCPtr<WKContentView> m_view;
500 bool m_shouldPreventTextSelection { false };
501};
502
503#endif // ENABLE(IMAGE_ANALYSIS)
504
505enum class TextPositionAnchor : uint8_t {
506 Start = 1 << 0,
507 End = 1 << 1
508};
509
510enum class NotifyInputDelegate : bool { No, Yes };
511
512} // namespace WebKit
513
514@interface WKRelativeTextPosition : UITextPosition
515- (instancetype)initWithAnchors:(OptionSet<WebKit::TextPositionAnchor>)start offset:(NSInteger)offset;
516@property (nonatomic, readonly) OptionSet<WebKit::TextPositionAnchor> anchors;
517@property (nonatomic, readonly, getter=isRelativeToStart) BOOL relativeToStart;
518@property (nonatomic, readonly) NSInteger offset;
519@end
520
521@interface WKRelativeTextRange : UITextRange
522- (instancetype)initWithStart:(UITextPosition *)start end:(UITextPosition *)end;
523@property (nonatomic, readonly) WKRelativeTextPosition *start;
524@property (nonatomic, readonly) WKRelativeTextPosition *end;
525@end
526
527constexpr float highlightDelay = 0.12;
528constexpr float tapAndHoldDelay = 0.75;
529constexpr CGFloat minimumTapHighlightRadius = 2.0;
530constexpr double fasterTapSignificantZoomThreshold = 0.8;
531
532@interface WKTextRange : UITextRange {
533 CGRect _startRect;
534 CGRect _endRect;
535 BOOL _isNone;
536 BOOL _isRange;
537 BOOL _isEditable;
538 RetainPtr<NSArray<WKTextSelectionRect *>> _selectionRects;
539 NSUInteger _selectedTextLength;
540}
541@property (nonatomic) CGRect startRect;
542@property (nonatomic) CGRect endRect;
543@property (nonatomic) BOOL isNone;
544@property (nonatomic) BOOL isRange;
545@property (nonatomic) BOOL isEditable;
546@property (nonatomic) NSUInteger selectedTextLength;
547@property (copy, nonatomic) NSArray<WKTextSelectionRect *> *selectionRects;
548
549+ (WKTextRange *)textRangeWithState:(BOOL)isNone isRange:(BOOL)isRange isEditable:(BOOL)isEditable startRect:(CGRect)startRect endRect:(CGRect)endRect selectionRects:(NSArray *)selectionRects selectedTextLength:(NSUInteger)selectedTextLength;
550
551@end
552
553@interface WKTextPosition : UITextPosition
554
555@property (nonatomic) CGRect positionRect;
556@property (nonatomic) OptionSet<WebKit::TextPositionAnchor> anchors;
557
558+ (WKTextPosition *)textPositionWithRect:(CGRect)positionRect;
559
560@end
561
562#if HAVE(UIFINDINTERACTION)(defined 1 && 1)
563
564@interface WKFoundTextRange : UITextRange
565
566@property (nonatomic) NSUInteger order;
567@property (nonatomic, copy) NSArray *pathToFrame;
568
569+ (WKFoundTextRange *)foundTextRangeWithWebFoundTextRange:(WebKit::WebFoundTextRange)range;
570
571- (WebKit::WebFoundTextRange)webFoundTextRange;
572
573@end
574
575@interface WKFoundTextPosition : UITextPosition
576
577@property (nonatomic) NSUInteger order;
578
579@end
580
581@interface WKFoundDOMTextRange : WKFoundTextRange
582
583@property (nonatomic) NSUInteger location;
584@property (nonatomic) NSUInteger length;
585
586@end
587
588@interface WKFoundDOMTextPosition : WKFoundTextPosition
589
590@property (nonatomic) NSUInteger offset;
591
592+ (WKFoundDOMTextPosition *)textPositionWithOffset:(NSUInteger)offset order:(NSUInteger)order;
593
594@end
595
596@interface WKFoundPDFTextRange : WKFoundTextRange
597
598@property (nonatomic) NSUInteger startPage;
599@property (nonatomic) NSUInteger startPageOffset;
600@property (nonatomic) NSUInteger endPage;
601@property (nonatomic) NSUInteger endPageOffset;
602
603@end
604
605@interface WKFoundPDFTextPosition : WKFoundTextPosition
606
607@property (nonatomic) NSUInteger page;
608@property (nonatomic) NSUInteger offset;
609
610+ (WKFoundPDFTextPosition *)textPositionWithPage:(NSUInteger)page offset:(NSUInteger)offset;
611
612@end
613
614#endif
615
616inline static UITextPosition *positionWithOffsetFrom(UITextPosition *position, NSInteger offset)
617{
618 if (!offset)
619 return position;
620
621 if (auto concretePosition = dynamic_objc_cast<WKTextPosition>(position); !concretePosition.anchors.isEmpty())
622 return adoptNS([[WKRelativeTextPosition alloc] initWithAnchors:concretePosition.anchors offset:offset]).autorelease();
623
624 if (auto relativePosition = dynamic_objc_cast<WKRelativeTextPosition>(position))
625 return adoptNS([[WKRelativeTextPosition alloc] initWithAnchors:[relativePosition anchors] offset:offset + [relativePosition offset]]).autorelease();
626
627 return nilnullptr;
628}
629
630inline static std::pair<OptionSet<WebKit::TextPositionAnchor>, NSInteger> anchorsAndOffset(UITextPosition *position)
631{
632 if (auto concretePosition = dynamic_objc_cast<WKTextPosition>(position); concretePosition.anchors)
633 return { concretePosition.anchors, 0 };
634
635 if (auto relativePosition = dynamic_objc_cast<WKRelativeTextPosition>(position))
636 return { relativePosition.anchors, relativePosition.offset };
637
638 return { { }, 0 };
639}
640
641inline static RetainPtr<NSString> textRelativeToSelectionStart(WKRelativeTextRange *range, const WebKit::EditorState::PostLayoutData& data, std::optional<char32_t> lastInsertedCharacterOverride)
642{
643 auto start = range.start;
644 auto end = range.end;
645 if (!start || !end)
646 return nilnullptr;
647
648 if (!start.relativeToStart || !end.relativeToStart)
649 return nilnullptr;
650
651 auto startOffset = start.offset;
652 auto endOffset = end.offset;
653 if (startOffset < -2 || endOffset > 1 || startOffset >= endOffset)
654 return nilnullptr;
655
656 StringBuilder string;
657 string.reserveCapacity(endOffset - startOffset);
658 auto appendIfNonZero = [&string](auto character) {
659 if (character)
660 string.append(character);
661 };
662 for (auto offset = startOffset; offset < endOffset; ++offset) {
663 switch (offset) {
664 case -2:
665 appendIfNonZero(data.twoCharacterBeforeSelection);
666 break;
667 case -1: {
668 appendIfNonZero(lastInsertedCharacterOverride.value_or(data.characterBeforeSelection));
669 break;
670 }
671 case 0:
672 appendIfNonZero(data.characterAfterSelection);
673 break;
674 }
675 }
676 return string.createNSString();
677}
678
679@implementation WKRelativeTextPosition
680
681- (instancetype)initWithAnchors:(OptionSet<WebKit::TextPositionAnchor>)anchors offset:(NSInteger)offset
682{
683 if (self = [super init]) {
684 _anchors = anchors;
685 _offset = offset;
686 }
687 return self;
688}
689
690- (BOOL)isRelativeToStart
691{
692 return _anchors.contains(WebKit::TextPositionAnchor::Start);
693}
694
695- (NSString *)description
696{
697 return [NSString stringWithFormat:@"WKRelativeTextPosition(%s, %d)", _anchors.contains(WebKit::TextPositionAnchor::Start) ? "start" : "end", static_cast<int>(_offset)];
698}
699
700@end
701
702@implementation WKRelativeTextRange {
703 RetainPtr<WKRelativeTextPosition> _start;
704 RetainPtr<WKRelativeTextPosition> _end;
705}
706
707- (instancetype)initWithStart:(UITextPosition *)start end:(UITextPosition *)end
708{
709 if (self = [super init]) {
710 auto [startAnchors, startOffset] = anchorsAndOffset(start);
711 auto [endAnchors, endOffset] = anchorsAndOffset(end);
712 if (!startAnchors.isEmpty() && !endAnchors.isEmpty()) {
713 _start = adoptNS([[WKRelativeTextPosition alloc] initWithAnchors:startAnchors offset:startOffset]);
714 _end = adoptNS([[WKRelativeTextPosition alloc] initWithAnchors:endAnchors offset:endOffset]);
715 }
716 }
717 return self;
718}
719
720- (WKRelativeTextPosition *)start
721{
722 return _start.get();
723}
724
725- (WKRelativeTextPosition *)end
726{
727 return _end.get();
728}
729
730- (BOOL)isEmpty
731{
732 return [_start anchors] == [_end anchors] && [_start offset] == [_end offset];
733}
734
735- (NSString *)description
736{
737 return [NSString stringWithFormat:@"WKRelativeTextRange(start=%@, end=%@)", _start.get(), _end.get()];
738}
739
740@end
741
742@interface WKAutocorrectionRects : UIWKAutocorrectionRects
743+ (WKAutocorrectionRects *)autocorrectionRectsWithFirstCGRect:(CGRect)firstRect lastCGRect:(CGRect)lastRect;
744@end
745
746@interface WKAutocorrectionContext : UIWKAutocorrectionContext
747+ (WKAutocorrectionContext *)emptyAutocorrectionContext;
748+ (WKAutocorrectionContext *)autocorrectionContextWithWebContext:(const WebKit::WebAutocorrectionContext&)context;
749@end
750
751@interface UIView (UIViewInternalHack)
752+ (BOOL)_addCompletion:(void(^)(BOOL))completion;
753@end
754
755@interface WKFocusedElementInfo : NSObject <_WKFocusedElementInfo>
756- (instancetype)initWithFocusedElementInformation:(const WebKit::FocusedElementInformation&)information isUserInitiated:(BOOL)isUserInitiated webView:(WKWebView *)webView userObject:(NSObject <NSSecureCoding> *)userObject;
757@end
758
759@implementation WKFormInputSession {
760 WeakObjCPtr<WKContentView> _contentView;
761 RetainPtr<WKFocusedElementInfo> _focusedElementInfo;
762 RetainPtr<UIView> _customInputView;
763 RetainPtr<UIView> _customInputAccessoryView;
764 RetainPtr<NSArray<UITextSuggestion *>> _suggestions;
765 BOOL _accessoryViewShouldNotShow;
766 BOOL _forceSecureTextEntry;
767 BOOL _requiresStrongPasswordAssistance;
768}
769
770- (instancetype)initWithContentView:(WKContentView *)view focusedElementInfo:(WKFocusedElementInfo *)elementInfo requiresStrongPasswordAssistance:(BOOL)requiresStrongPasswordAssistance
771{
772 if (!(self = [super init]))
773 return nilnullptr;
774
775 _contentView = view;
776 _focusedElementInfo = elementInfo;
777 _requiresStrongPasswordAssistance = requiresStrongPasswordAssistance;
778
779 return self;
780}
781
782- (id <_WKFocusedElementInfo>)focusedElementInfo
783{
784 return _focusedElementInfo.get();
785}
786
787- (NSObject <NSSecureCoding> *)userObject
788{
789 return [_focusedElementInfo userObject];
790}
791
792- (BOOL)isValid
793{
794 return !!_contentView;
795}
796
797- (NSString *)accessoryViewCustomButtonTitle
798{
799 return [_contentView.get() formAccessoryView].autoFillButtonItem.title;
800}
801
802- (void)setAccessoryViewCustomButtonTitle:(NSString *)title
803{
804 if (title.length)
805 [[_contentView.get() formAccessoryView] showAutoFillButtonWithTitle:title];
806 else
807 [[_contentView.get() formAccessoryView] hideAutoFillButton];
808 if (!PAL::currentUserInterfaceIdiomIsSmallScreen())
809 [_contentView.get() reloadInputViews];
810}
811
812- (BOOL)accessoryViewShouldNotShow
813{
814 return _accessoryViewShouldNotShow;
815}
816
817- (void)setAccessoryViewShouldNotShow:(BOOL)accessoryViewShouldNotShow
818{
819 if (_accessoryViewShouldNotShow == accessoryViewShouldNotShow)
820 return;
821
822 _accessoryViewShouldNotShow = accessoryViewShouldNotShow;
823 [_contentView.get() reloadInputViews];
824}
825
826- (BOOL)forceSecureTextEntry
827{
828 return _forceSecureTextEntry;
829}
830
831- (void)setForceSecureTextEntry:(BOOL)forceSecureTextEntry
832{
833 if (_forceSecureTextEntry == forceSecureTextEntry)
834 return;
835
836 _forceSecureTextEntry = forceSecureTextEntry;
837 [_contentView.get() reloadInputViews];
838}
839
840- (UIView *)customInputView
841{
842 return _customInputView.get();
843}
844
845- (void)setCustomInputView:(UIView *)customInputView
846{
847 if (customInputView == _customInputView)
848 return;
849
850 _customInputView = customInputView;
851 [_contentView.get() reloadInputViews];
852}
853
854- (UIView *)customInputAccessoryView
855{
856 return _customInputAccessoryView.get();
857}
858
859- (void)setCustomInputAccessoryView:(UIView *)customInputAccessoryView
860{
861 if (_customInputAccessoryView == customInputAccessoryView)
862 return;
863
864 _customInputAccessoryView = customInputAccessoryView;
865 [_contentView.get() reloadInputViews];
866}
867
868- (void)endEditing
869{
870 if ([_customInputView conformsToProtocol:@protocol(WKFormControl)])
871 [(id<WKFormControl>)_customInputView.get() controlEndEditing];
872}
873
874- (NSArray<UITextSuggestion *> *)suggestions
875{
876 return _suggestions.get();
877}
878
879- (void)setSuggestions:(NSArray<UITextSuggestion *> *)suggestions
880{
881 if (suggestions == _suggestions || [suggestions isEqualToArray:_suggestions.get()])
882 return;
883
884 _suggestions = adoptNS([suggestions copy]);
885 [_contentView.get() updateTextSuggestionsForInputDelegate];
886}
887
888- (BOOL)requiresStrongPasswordAssistance
889{
890 return _requiresStrongPasswordAssistance;
891}
892
893- (void)invalidate
894{
895 RetainPtr<WKContentView> contentView = _contentView.get();
896 _contentView = nilnullptr;
897 [contentView _provideSuggestionsToInputDelegate:nilnullptr];
898}
899
900- (void)reloadFocusedElementContextView
901{
902 [_contentView.get() reloadContextViewForPresentedListViewController];
903}
904
905@end
906
907@implementation WKFocusedElementInfo {
908 WKInputType _type;
909 RetainPtr<NSString> _value;
910 BOOL _isUserInitiated;
911 RetainPtr<NSObject <NSSecureCoding>> _userObject;
912 RetainPtr<NSString> _placeholder;
913 RetainPtr<NSString> _label;
914 RetainPtr<WKFrameInfo> _frame;
915}
916
917- (instancetype)initWithFocusedElementInformation:(const WebKit::FocusedElementInformation&)information isUserInitiated:(BOOL)isUserInitiated webView:(WKWebView *)webView userObject:(NSObject <NSSecureCoding> *)userObject
918{
919 if (!(self = [super init]))
920 return nilnullptr;
921
922 switch (information.elementType) {
923 case WebKit::InputType::ContentEditable:
924 _type = WKInputTypeContentEditable;
925 break;
926 case WebKit::InputType::Text:
927 _type = WKInputTypeText;
928 break;
929 case WebKit::InputType::Password:
930 _type = WKInputTypePassword;
931 break;
932 case WebKit::InputType::TextArea:
933 _type = WKInputTypeTextArea;
934 break;
935 case WebKit::InputType::Search:
936 _type = WKInputTypeSearch;
937 break;
938 case WebKit::InputType::Email:
939 _type = WKInputTypeEmail;
940 break;
941 case WebKit::InputType::URL:
942 _type = WKInputTypeURL;
943 break;
944 case WebKit::InputType::Phone:
945 _type = WKInputTypePhone;
946 break;
947 case WebKit::InputType::Number:
948 _type = WKInputTypeNumber;
949 break;
950 case WebKit::InputType::NumberPad:
951 _type = WKInputTypeNumberPad;
952 break;
953 case WebKit::InputType::Date:
954 _type = WKInputTypeDate;
955 break;
956 case WebKit::InputType::DateTimeLocal:
957 _type = WKInputTypeDateTimeLocal;
958 break;
959 case WebKit::InputType::Month:
960 _type = WKInputTypeMonth;
961 break;
962 case WebKit::InputType::Week:
963 _type = WKInputTypeWeek;
964 break;
965 case WebKit::InputType::Time:
966 _type = WKInputTypeTime;
967 break;
968 case WebKit::InputType::Select:
969 _type = WKInputTypeSelect;
970 break;
971 case WebKit::InputType::Drawing:
972 _type = WKInputTypeDrawing;
973 break;
974 case WebKit::InputType::Color:
975 _type = WKInputTypeColor;
976 break;
977 case WebKit::InputType::None:
978 _type = WKInputTypeNone;
979 break;
980 }
981 _value = information.value.createNSString().get();
982 _isUserInitiated = isUserInitiated;
983 _userObject = userObject;
984 _placeholder = information.placeholder.createNSString().get();
985 _label = information.label.createNSString().get();
986 if (information.frame)
987 _frame = wrapper(API::FrameInfo::create(WebKit::FrameInfoData { *information.frame }));
988 return self;
989}
990
991- (WKInputType)type
992{
993 return _type;
994}
995
996- (NSString *)value
997{
998 return _value.get();
999}
1000
1001- (BOOL)isUserInitiated
1002{
1003 return _isUserInitiated;
1004}
1005
1006- (NSObject <NSSecureCoding> *)userObject
1007{
1008 return _userObject.get();
1009}
1010
1011- (NSString *)label
1012{
1013 return _label.get();
1014}
1015
1016- (NSString *)placeholder
1017{
1018 return _placeholder.get();
1019}
1020
1021- (WKFrameInfo *)frame
1022{
1023 return _frame.get();
1024}
1025
1026@end
1027
1028#if ENABLE(DRAG_SUPPORT)(defined 1 && 1)
1029
1030@interface WKDragSessionContext : NSObject
1031- (void)addTemporaryDirectory:(NSString *)temporaryDirectory;
1032- (void)cleanUpTemporaryDirectories;
1033@end
1034
1035@implementation WKDragSessionContext {
1036 RetainPtr<NSMutableArray> _temporaryDirectories;
1037}
1038
1039- (void)addTemporaryDirectory:(NSString *)temporaryDirectory
1040{
1041 if (!_temporaryDirectories)
1042 _temporaryDirectories = adoptNS([NSMutableArray new]);
1043 [_temporaryDirectories addObject:temporaryDirectory];
1044}
1045
1046- (void)cleanUpTemporaryDirectories
1047{
1048 for (NSString *directory in _temporaryDirectories.get()) {
1049 NSError *error = nilnullptr;
1050 [[NSFileManager defaultManager] removeItemAtPath:directory error:&error];
1051 RELEASE_LOG(DragAndDrop, "Removed temporary download directory: %@ with error: %@", directory, error)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Removed temporary download directory: %@ with error: %@"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG147"
) = "Removed temporary download directory: %@ with error: %@"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Removed temporary download directory: %@ with error: %@"
, directory, error)]; _os_log_impl(&__dso_handle, _log_tmp
, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format(
_os_fmt_buf, "Removed temporary download directory: %@ with error: %@"
, directory, error), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop
;
1052 }
1053 _temporaryDirectories = nilnullptr;
1054}
1055
1056@end
1057
1058static WKDragSessionContext *existingLocalDragSessionContext(id <UIDragSession> session)
1059{
1060 return dynamic_objc_cast<WKDragSessionContext>(session.localContext);
1061}
1062
1063static WKDragSessionContext *ensureLocalDragSessionContext(id <UIDragSession> session)
1064{
1065 if (WKDragSessionContext *existingContext = existingLocalDragSessionContext(session))
1066 return existingContext;
1067
1068 if (session.localContext) {
1069 RELEASE_LOG(DragAndDrop, "Overriding existing local context: %@ on session: %@", session.localContext, session)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Overriding existing local context: %@ on session: %@"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG148"
) = "Overriding existing local context: %@ on session: %@"; uint8_t
_Alignas(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Overriding existing local context: %@ on session: %@", session
.localContext, session)]; _os_log_impl(&__dso_handle, _log_tmp
, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format(
_os_fmt_buf, "Overriding existing local context: %@ on session: %@"
, session.localContext, session), (uint32_t)sizeof(_os_fmt_buf
)) clang diagnostic pop ; }); } }) clang diagnostic pop
;
1070 ASSERT_NOT_REACHED()((void)0);
1071 }
1072
1073 session.localContext = adoptNS([[WKDragSessionContext alloc] init]).get();
1074 return existingLocalDragSessionContext(session);
1075}
1076
1077#endif // ENABLE(DRAG_SUPPORT)
1078
1079@implementation UIGestureRecognizer (WKContentViewHelpers)
1080
1081- (void)_wk_cancel
1082{
1083 if (!self.enabled)
1084 return;
1085
1086 [self setEnabled:NO__objc_no];
1087 [self setEnabled:YES__objc_yes];
1088}
1089
1090- (BOOL)_wk_isTapAndAHalf
1091{
1092 return [NSStringFromClass(self.class) containsString:@"TapAndAHalfRecognizer"];
1093}
1094
1095@end
1096
1097@interface WKTargetedPreviewContainer : UIView
1098- (instancetype)initWithContentView:(WKContentView *)contentView NS_DESIGNATED_INITIALIZER__attribute__((objc_designated_initializer));
1099- (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE__attribute__((unavailable));
1100- (instancetype)initWithCoder:(NSCoder *)coder NS_UNAVAILABLE__attribute__((unavailable));
1101@end
1102
1103@implementation WKTargetedPreviewContainer {
1104 __weak__attribute__((objc_ownership(weak))) WKContentView *_contentView;
1105}
1106
1107- (instancetype)initWithContentView:(WKContentView *)contentView
1108{
1109 if (!(self = [super initWithFrame:CGRectZero]))
1110 return nilnullptr;
1111
1112 _contentView = contentView;
1113 return self;
1114}
1115
1116- (void)_didRemoveSubview:(UIView *)subview
1117{
1118 [super _didRemoveSubview:subview];
1119
1120 if (self.subviews.count)
1121 return;
1122
1123#if USE(UICONTEXTMENU)(defined 1 && 1)
1124 [protect(_contentView) _targetedPreviewContainerDidRemoveLastSubview:self];
1125#endif
1126}
1127
1128@end
1129
1130#if USE(UICONTEXTMENU)(defined 1 && 1)
1131
1132@protocol UIContextMenuInteractionDelegate_LegacyAsyncSupport<NSObject>
1133- (void)_contextMenuInteraction:(UIContextMenuInteraction *)interaction configurationForMenuAtLocation:(CGPoint)location completion:(void(^)(UIContextMenuConfiguration *))completion;
1134@end
1135
1136#endif
1137
1138@interface WKContentView (WKInteractionPrivate)
1139- (void)accessibilitySpeakSelectionSetContent:(NSString *)string;
1140- (NSArray *)webSelectionRectsForSelectionGeometries:(const Vector<WebCore::SelectionGeometry>&)selectionRects;
1141- (void)_accessibilityDidGetSelectionRects:(NSArray *)selectionRects withGranularity:(UITextGranularity)granularity atOffset:(NSInteger)offset;
1142#if USE(UICONTEXTMENU)(defined 1 && 1)
1143- (void)_internalContextMenuInteraction:(UIContextMenuInteraction *)interaction configurationForMenuAtLocation:(CGPoint)location completion:(void(^)(UIContextMenuConfiguration *))completion;
1144#endif
1145@end
1146
1147#define ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG149"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(1147, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
do { \
1148 if (self.shouldUseAsyncInteractions) [[unlikely]] { \
1149 RELEASE_LOG_ERROR(TextInteraction, "Received unexpected call to %s", __PRETTY_FUNCTION__)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG150"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop
; \
1150 if (WebKit::isFullWebBrowserOrRunningTest()) \
1151 RELEASE_ASSERT_NOT_REACHED()do { WTF::isIntegralOrPointerType(); compilerFenceForCrash();
WTFCrashWithInfo(1151, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false)
; \
1152 else \
1153 ASSERT_NOT_REACHED()((void)0); \
1154 } \
1155} while (0)
1156
1157@implementation WKContentView (WKInteraction)
1158
1159- (BOOL)preventsPanningInXAxis
1160{
1161 return _preventsPanningInXAxis;
1162}
1163
1164- (BOOL)preventsPanningInYAxis
1165{
1166 return _preventsPanningInYAxis;
1167}
1168
1169- (WKFormInputSession *)_formInputSession
1170{
1171 return _formInputSession.get();
1172}
1173
1174- (void)_createAndConfigureDoubleTapGestureRecognizer
1175{
1176 if (_doubleTapGestureRecognizer) {
1177 [self removeGestureRecognizer:_doubleTapGestureRecognizer.get()];
1178 [_doubleTapGestureRecognizer setDelegate:nilnullptr];
1179 [_doubleTapGestureRecognizer setGestureFailedTarget:nilnullptr action:nilnullptr];
1180 }
1181
1182 _doubleTapGestureRecognizer = adoptNS([[WKSyntheticTapGestureRecognizer alloc] initWithTarget:self action:@selector(_doubleTapRecognized:)]);
1183 [_doubleTapGestureRecognizer setGestureFailedTarget:self action:@selector(_doubleTapDidFail:)];
1184 [_doubleTapGestureRecognizer setNumberOfTapsRequired:2];
1185 [_doubleTapGestureRecognizer setDelegate:self];
1186 [self addGestureRecognizer:_doubleTapGestureRecognizer.get()];
1187 [_singleTapGestureRecognizer requireGestureRecognizerToFail:_doubleTapGestureRecognizer.get()];
1188 [_keyboardDismissalGestureRecognizer requireGestureRecognizerToFail:_doubleTapGestureRecognizer.get()];
1189}
1190
1191- (void)_createAndConfigureHighlightLongPressGestureRecognizer
1192{
1193 _highlightLongPressGestureRecognizer = adoptNS([[WKHighlightLongPressGestureRecognizer alloc] initWithTarget:self action:@selector(_highlightLongPressRecognized:)]);
1194 [_highlightLongPressGestureRecognizer setDelay:highlightDelay];
1195 [_highlightLongPressGestureRecognizer setDelegate:self];
1196 [self addGestureRecognizer:_highlightLongPressGestureRecognizer.get()];
1197}
1198
1199- (void)_createAndConfigureLongPressGestureRecognizer
1200{
1201 _longPressGestureRecognizer = adoptNS([[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(_longPressRecognized:)]);
1202 [_longPressGestureRecognizer setDelay:tapAndHoldDelay];
1203 [_longPressGestureRecognizer setDelegate:self];
1204 [_longPressGestureRecognizer _setRequiresQuietImpulse:YES__objc_yes];
1205 [self addGestureRecognizer:_longPressGestureRecognizer.get()];
1206}
1207
1208- (BOOL)shouldUseAsyncInteractions
1209{
1210 return protect(_page->preferences())->useAsyncUIKitInteractions();
1211}
1212
1213- (BOOL)selectionHonorsOverflowScrolling
1214{
1215 return protect(_page->preferences())->selectionHonorsOverflowScrolling();
1216}
1217
1218- (ScopeExit<Function<void()>>)makeTextSelectionViewsNonInteractiveForScope
1219{
1220 Vector<RetainPtr<UIView>> viewsToRestore;
1221 for (UIView *view in [_textInteractionWrapper managedTextSelectionViews]) {
1222 [view _wk_collectDescendantsIncludingSelf:viewsToRestore matching:^(UIView *view) {
1223 return view.userInteractionEnabled;
1224 }];
1225 }
1226
1227 for (RetainPtr view : viewsToRestore)
1228 [view setUserInteractionEnabled:NO__objc_no];
1229
1230 return makeScopeExit(Function<void()> { [viewsToRestore = WTF::move(viewsToRestore)] {
1231 for (RetainPtr view : viewsToRestore)
1232 [view setUserInteractionEnabled:YES__objc_yes];
1233 } });
1234}
1235
1236- (BOOL)_shouldUseUIContextMenuAsyncConfiguration
1237{
1238#if USE(BROWSERENGINEKIT)(defined 1 && 1)
1239 return self.shouldUseAsyncInteractions;
1240#else
1241 return NO__objc_no;
1242#endif
1243}
1244
1245- (BOOL)_shouldUseTextCursorDragAnimator
1246{
1247#if HAVE(UI_TEXT_CURSOR_DROP_POSITION_ANIMATOR)(defined 1 && 1)
1248 return YES__objc_yes;
1249#else
1250 return NO__objc_no;
1251#endif
1252}
1253
1254- (void)_updateRuntimeProtocolConformanceIfNeeded
1255{
1256 static bool hasUpdatedProtocolConformance = false;
1257 if (std::exchange(hasUpdatedProtocolConformance, true))
1258 return;
1259
1260#if USE(BROWSERENGINEKIT)(defined 1 && 1)
1261 if (self.shouldUseAsyncInteractions) {
1262 RELEASE_LOG(TextInteraction, "Conforming to BrowserEngineKit text input protocol")clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Conforming to BrowserEngineKit text input protocol"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG151"
) = "Conforming to BrowserEngineKit text input protocol"; uint8_t
_Alignas(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Conforming to BrowserEngineKit text input protocol")]; _os_log_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Conforming to BrowserEngineKit text input protocol"
), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); }
}) clang diagnostic pop
;
1263 class_addProtocol(self.class, @protocol(BETextInput));
1264 } else
1265#endif
1266 {
1267 RELEASE_LOG(TextInteraction, "Conforming to legacy UIKit interaction and text input protocols")clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Conforming to legacy UIKit interaction and text input protocols"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG152"
) = "Conforming to legacy UIKit interaction and text input protocols"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Conforming to legacy UIKit interaction and text input protocols"
)]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str
, (uint8_t *)__builtin_os_log_format(_os_fmt_buf, "Conforming to legacy UIKit interaction and text input protocols"
), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); }
}) clang diagnostic pop
;
1268 auto legacyProtocols = std::array {
1269 @protocol(UIWKInteractionViewProtocol),
1270 @protocol(UITextInputPrivate),
1271 @protocol(UITextAutoscrolling),
1272 @protocol(UITextInputMultiDocument),
1273 @protocol(_UITextInputTranslationSupport),
1274 };
1275 for (RetainPtr protocol : legacyProtocols)
1276 class_addProtocol(self.class, protocol);
1277 }
1278
1279#if USE(UICONTEXTMENU)(defined 1 && 1)
1280 if (!self._shouldUseUIContextMenuAsyncConfiguration) {
1281 auto legacyAsyncConfigurationSelector = @selector(_contextMenuInteraction:configurationForMenuAtLocation:completion:);
1282 auto internalAsyncConfigurationSelector = @selector(_internalContextMenuInteraction:configurationForMenuAtLocation:completion:);
1283 auto internalMethod = class_getInstanceMethod(self.class, internalAsyncConfigurationSelector);
1284 auto internalImplementation = method_getImplementation(internalMethod);
1285 class_addMethod(self.class, legacyAsyncConfigurationSelector, internalImplementation, method_getTypeEncoding(internalMethod));
1286 }
1287#endif // USE(UICONTEXTMENU)
1288}
1289
1290- (void)setUpInteraction
1291{
1292 // If the page is not valid yet then delay interaction setup until the process is launched/relaunched.
1293 if (!protect(_page)->hasRunningProcess())
1294 return;
1295
1296 if (_hasSetUpInteractions)
1297 return;
1298
1299 _cachedHasCustomTintColor = std::nullopt;
1300
1301 if (!_interactionViewsContainerView) {
1302 _interactionViewsContainerView = adoptNS([[UIView alloc] init]);
1303 [_interactionViewsContainerView layer].name = @"InteractionViewsContainer";
1304 [_interactionViewsContainerView setOpaque:NO__objc_no];
1305 [_interactionViewsContainerView layer].anchorPoint = CGPointZero;
1306 [self.superview addSubview:_interactionViewsContainerView.get()];
1307 }
1308
1309 _keyboardScrollingAnimator = adoptNS([[WKKeyboardScrollViewAnimator alloc] init]);
1310 [protect(_keyboardScrollingAnimator) setDelegate:self];
1311
1312 [self.layer addObserver:self forKeyPath:@"transform" options:NSKeyValueObservingOptionInitial context:WKContentViewKVOTransformContext];
1313
1314 _touchActionLeftSwipeGestureRecognizer = adoptNS([[UISwipeGestureRecognizer alloc] initWithTarget:nilnullptr action:nilnullptr]);
1315 [_touchActionLeftSwipeGestureRecognizer setDirection:UISwipeGestureRecognizerDirectionLeft];
1316 [_touchActionLeftSwipeGestureRecognizer setDelegate:self];
1317 [_touchActionLeftSwipeGestureRecognizer setName:@"Touch action swipe left"];
1318 [self addGestureRecognizer:_touchActionLeftSwipeGestureRecognizer.get()];
1319
1320 _touchActionRightSwipeGestureRecognizer = adoptNS([[UISwipeGestureRecognizer alloc] initWithTarget:nilnullptr action:nilnullptr]);
1321 [_touchActionRightSwipeGestureRecognizer setDirection:UISwipeGestureRecognizerDirectionRight];
1322 [_touchActionRightSwipeGestureRecognizer setDelegate:self];
1323 [_touchActionRightSwipeGestureRecognizer setName:@"Touch action swipe right"];
1324 [self addGestureRecognizer:_touchActionRightSwipeGestureRecognizer.get()];
1325
1326 _touchActionUpSwipeGestureRecognizer = adoptNS([[UISwipeGestureRecognizer alloc] initWithTarget:nilnullptr action:nilnullptr]);
1327 [_touchActionUpSwipeGestureRecognizer setDirection:UISwipeGestureRecognizerDirectionUp];
1328 [_touchActionUpSwipeGestureRecognizer setDelegate:self];
1329 [_touchActionUpSwipeGestureRecognizer setName:@"Touch action swipe up"];
1330 [self addGestureRecognizer:_touchActionUpSwipeGestureRecognizer.get()];
1331
1332 _touchActionDownSwipeGestureRecognizer = adoptNS([[UISwipeGestureRecognizer alloc] initWithTarget:nilnullptr action:nilnullptr]);
1333 [_touchActionDownSwipeGestureRecognizer setDirection:UISwipeGestureRecognizerDirectionDown];
1334 [_touchActionDownSwipeGestureRecognizer setDelegate:self];
1335 [_touchActionDownSwipeGestureRecognizer setName:@"Touch action swipe down"];
1336 [self addGestureRecognizer:_touchActionDownSwipeGestureRecognizer.get()];
1337
1338 _touchStartDeferringGestureRecognizerForImmediatelyResettableGestures = adoptNS([[WKDeferringGestureRecognizer alloc] initWithDeferringGestureDelegate:self]);
1339 [_touchStartDeferringGestureRecognizerForImmediatelyResettableGestures setName:@"Deferrer for touch start (immediate reset)"];
1340
1341 _touchStartDeferringGestureRecognizerForDelayedResettableGestures = adoptNS([[WKDeferringGestureRecognizer alloc] initWithDeferringGestureDelegate:self]);
1342 [_touchStartDeferringGestureRecognizerForDelayedResettableGestures setName:@"Deferrer for touch start (delayed reset)"];
1343
1344 _touchStartDeferringGestureRecognizerForSyntheticTapGestures = adoptNS([[WKDeferringGestureRecognizer alloc] initWithDeferringGestureDelegate:self]);
1345 [_touchStartDeferringGestureRecognizerForSyntheticTapGestures setName:@"Deferrer for touch start (synthetic tap)"];
1346
1347 _touchEndDeferringGestureRecognizerForImmediatelyResettableGestures = adoptNS([[WKDeferringGestureRecognizer alloc] initWithDeferringGestureDelegate:self]);
1348 [_touchEndDeferringGestureRecognizerForImmediatelyResettableGestures setName:@"Deferrer for touch end (immediate reset)"];
1349
1350 _touchEndDeferringGestureRecognizerForDelayedResettableGestures = adoptNS([[WKDeferringGestureRecognizer alloc] initWithDeferringGestureDelegate:self]);
1351 [_touchEndDeferringGestureRecognizerForDelayedResettableGestures setName:@"Deferrer for touch end (delayed reset)"];
1352
1353 _touchEndDeferringGestureRecognizerForSyntheticTapGestures = adoptNS([[WKDeferringGestureRecognizer alloc] initWithDeferringGestureDelegate:self]);
1354 [_touchEndDeferringGestureRecognizerForSyntheticTapGestures setName:@"Deferrer for touch end (synthetic tap)"];
1355
1356 _touchMoveDeferringGestureRecognizer = adoptNS([[WKDeferringGestureRecognizer alloc] initWithDeferringGestureDelegate:self]);
1357 [_touchMoveDeferringGestureRecognizer setName:@"Deferrer for touch move"];
1358
1359#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
1360 _imageAnalysisDeferringGestureRecognizer = adoptNS([[WKDeferringGestureRecognizer alloc] initWithDeferringGestureDelegate:self]);
1361 [_imageAnalysisDeferringGestureRecognizer setName:@"Deferrer for image analysis"];
1362 [_imageAnalysisDeferringGestureRecognizer setImmediatelyFailsAfterTouchEnd:YES__objc_yes];
1363 [_imageAnalysisDeferringGestureRecognizer setEnabled:WebKit::isLiveTextAvailableAndEnabled()];
1364#endif
1365
1366 for (WKDeferringGestureRecognizer *gesture in self.deferringGestures) {
1367 gesture.delegate = self;
1368 [self addGestureRecognizer:gesture];
1369 }
1370
1371 if (_gestureRecognizerConsistencyEnforcer)
1372 _gestureRecognizerConsistencyEnforcer->reset();
1373
1374 _touchEventGestureRecognizer = adoptNS([[WKTouchEventsGestureRecognizer alloc] initWithContentView:self]);
1375 [_touchEventGestureRecognizer setDelegate:self];
1376 [self addGestureRecognizer:_touchEventGestureRecognizer.get()];
1377
1378#if HAVE(UIKIT_WITH_MOUSE_SUPPORT)(defined 1 && 1)
1379 [self setUpMouseGestureRecognizer];
1380#endif
1381
1382#if HAVE(LOOKUP_GESTURE_RECOGNIZER)(defined HAVE_LOOKUP_GESTURE_RECOGNIZER && HAVE_LOOKUP_GESTURE_RECOGNIZER
)
1383 _lookupGestureRecognizer = adoptNS([[_UILookupGestureRecognizer alloc] initWithTarget:self action:@selector(_lookupGestureRecognized:)]);
1384 [_lookupGestureRecognizer setDelegate:self];
1385 [self addGestureRecognizer:_lookupGestureRecognizer.get()];
1386#endif
1387
1388 _singleTapGestureRecognizer = adoptNS([[WKSyntheticTapGestureRecognizer alloc] initWithTarget:self action:@selector(_singleTapRecognized:)]);
1389 [_singleTapGestureRecognizer setDelegate:self];
1390 [_singleTapGestureRecognizer setGestureIdentifiedTarget:self action:@selector(_singleTapIdentified:)];
1391 [_singleTapGestureRecognizer setResetTarget:self action:@selector(_singleTapDidReset:)];
1392 [_singleTapGestureRecognizer setSupportingTouchEventsGestureRecognizer:_touchEventGestureRecognizer.get()];
1393 [self addGestureRecognizer:_singleTapGestureRecognizer.get()];
1394
1395#if ENABLE(MODEL_PROCESS)(defined 0 && 0)
1396 _modelInteractionPanGestureRecognizer = adoptNS([[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(_modelInteractionPanGestureRecognized:)]);
1397 [_modelInteractionPanGestureRecognizer setMinimumNumberOfTouches:1];
1398 [_modelInteractionPanGestureRecognizer setMaximumNumberOfTouches:1];
1399 [_modelInteractionPanGestureRecognizer setDelegate:self];
1400 [self addGestureRecognizer:_modelInteractionPanGestureRecognizer.get()];
1401#endif
1402
1403 _nonBlockingDoubleTapGestureRecognizer = adoptNS([[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_nonBlockingDoubleTapRecognized:)]);
1404 [_nonBlockingDoubleTapGestureRecognizer setNumberOfTapsRequired:2];
1405 [_nonBlockingDoubleTapGestureRecognizer setDelegate:self];
1406 [_nonBlockingDoubleTapGestureRecognizer setEnabled:NO__objc_no];
1407 [self addGestureRecognizer:_nonBlockingDoubleTapGestureRecognizer.get()];
1408
1409 _doubleTapGestureRecognizerForDoubleClick = adoptNS([[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_doubleTapRecognizedForDoubleClick:)]);
1410 [_doubleTapGestureRecognizerForDoubleClick setNumberOfTapsRequired:2];
1411 [_doubleTapGestureRecognizerForDoubleClick setDelegate:self];
1412 [self addGestureRecognizer:_doubleTapGestureRecognizerForDoubleClick.get()];
1413
1414 [self _createAndConfigureDoubleTapGestureRecognizer];
1415
1416 _twoFingerDoubleTapGestureRecognizer = adoptNS([[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_twoFingerDoubleTapRecognized:)]);
1417 [_twoFingerDoubleTapGestureRecognizer setNumberOfTapsRequired:2];
1418 [_twoFingerDoubleTapGestureRecognizer setNumberOfTouchesRequired:2];
1419 [_twoFingerDoubleTapGestureRecognizer setDelegate:self];
1420 [self addGestureRecognizer:_twoFingerDoubleTapGestureRecognizer.get()];
1421
1422 [self _createAndConfigureHighlightLongPressGestureRecognizer];
1423 [self _createAndConfigureLongPressGestureRecognizer];
1424
1425 [self _updateLongPressAndHighlightLongPressGestures];
1426
1427#if ENABLE(DRAG_SUPPORT)(defined 1 && 1)
1428 [self setUpDragAndDropInteractions];
1429#endif
1430
1431#if HAVE(UI_POINTER_INTERACTION)(defined 1 && 1)
1432 [self setUpPointerInteraction];
1433#endif
1434
1435#if HAVE(PENCILKIT_TEXT_INPUT)(defined 1 && 1)
1436 [self setUpScribbleInteraction];
1437#endif
1438
1439 _twoFingerSingleTapGestureRecognizer = adoptNS([[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_twoFingerSingleTapGestureRecognized:)]);
1440 [_twoFingerSingleTapGestureRecognizer setAllowableMovement:60];
1441 [_twoFingerSingleTapGestureRecognizer _setAllowableSeparation:150];
1442 [_twoFingerSingleTapGestureRecognizer setNumberOfTapsRequired:1];
1443 [_twoFingerSingleTapGestureRecognizer setNumberOfTouchesRequired:2];
1444 [_twoFingerSingleTapGestureRecognizer setDelaysTouchesEnded:NO__objc_no];
1445 [_twoFingerSingleTapGestureRecognizer setDelegate:self];
1446 [_twoFingerSingleTapGestureRecognizer setEnabled:!self.webView._editable];
1447 [self addGestureRecognizer:_twoFingerSingleTapGestureRecognizer.get()];
1448
1449 _touchActionGestureRecognizer = adoptNS([[WKTouchActionGestureRecognizer alloc] initWithTouchActionDelegate:self]);
1450 [self addGestureRecognizer:_touchActionGestureRecognizer.get()];
1451
1452 // FIXME: This should be called when we get notified that loading has completed.
1453 [self setUpTextSelectionAssistant];
1454
1455 _keyboardDismissalGestureRecognizer = adoptNS([[WKScrollViewTrackingTapGestureRecognizer alloc] initWithTarget:self action:@selector(_keyboardDismissalGestureRecognized:)]);
1456 [_keyboardDismissalGestureRecognizer setNumberOfTapsRequired:1];
1457 [_keyboardDismissalGestureRecognizer setDelegate:self];
1458 [_keyboardDismissalGestureRecognizer setName:@"Keyboard dismissal tap gesture"];
1459 [_keyboardDismissalGestureRecognizer setEnabled:protect(_page->preferences())->keyboardDismissalGestureEnabled()];
1460 [self addGestureRecognizer:_keyboardDismissalGestureRecognizer.get()];
1461
1462#if ENABLE(GAMEPAD)(defined 1 && 1)
1463 _gamepadInteractionGestureRecognizer = adoptNS([[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_gamepadInteractionGestureRecognized:)]);
1464 [_gamepadInteractionGestureRecognizer setDelegate:self];
1465 [_gamepadInteractionGestureRecognizer setName:@"Gamepad interaction menu gesture"];
1466 _gamepadInteractionGestureRecognizer.get().allowedTouchTypes = @[];
1467 _gamepadInteractionGestureRecognizer.get().allowedPressTypes = @[@(UIPressTypeMenu)];
1468 [self addGestureRecognizer:_gamepadInteractionGestureRecognizer.get()];
1469#endif
1470
1471#if HAVE(UI_PASTE_CONFIGURATION)(defined 1 && 1)
1472 self.pasteConfiguration = adoptNS([[UIPasteConfiguration alloc] initWithAcceptableTypeIdentifiers:protect([&] {
1473 if (protect(_page->preferences())->attachmentElementEnabled())
1474 return WebKit::supportedRichTextPasteboardTypesWithAttachmentsForPasteConfiguration();
1475 return WebKit::supportedRichTextPasteboardTypesForPasteConfiguration();
1476 }())]);
1477#endif
1478
1479#if HAVE(LINK_PREVIEW)(defined 1 && 1)
1480 [self _registerPreview];
1481#endif
1482
1483 NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
1484
1485ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
1486 [center addObserver:self selector:@selector(_willHideMenu:) name:UIMenuControllerWillHideMenuNotification object:nilnullptr];
1487ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
1488
1489 [center addObserver:self selector:@selector(_keyboardDidRequestDismissal:) name:UIKeyboardPrivateDidRequestDismissalNotification object:nilnullptr];
1490
1491 _actionSheetAssistant = adoptNS([[WKActionSheetAssistant alloc] initWithView:self]);
1492 [protect(_actionSheetAssistant) setDelegate:self];
1493 _smartMagnificationController = WebKit::SmartMagnificationController::create(self);
1494 _touchEventsCanPreventNativeGestures = YES__objc_yes;
1495 _isExpectingFastSingleTapCommit = NO__objc_no;
1496 _potentialTapInProgress = NO__objc_no;
1497 _isDoubleTapPending = NO__objc_no;
1498 _showDebugTapHighlightsForFastClicking = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitShowFastClickDebugTapHighlights"];
1499 _needsDeferredEndScrollingSelectionUpdate = NO__objc_no;
1500 _isChangingFocus = NO__objc_no;
1501 _isBlurringFocusedElement = NO__objc_no;
1502#if USE(UICONTEXTMENU)(defined 1 && 1)
1503 _isDisplayingContextMenuWithAnimation = NO__objc_no;
1504 _isPreparingToDisplayContextMenu = NO__objc_no;
1505#endif
1506 _isUpdatingAccessoryView = NO__objc_no;
1507
1508 _dataListTextSuggestionsInputView = nilnullptr;
1509 _dataListTextSuggestions = nilnullptr;
1510
1511#if ENABLE(PLATFORM_DRIVEN_TEXT_CHECKING)(defined 0 && 0)
1512 _textCheckingController = makeUnique<WebKit::TextCheckingController>(*_page);
1513#endif
1514
1515 _autocorrectionContextNeedsUpdate = YES__objc_yes;
1516
1517 protect(_page->legacyMainFrameProcess())->updateTextCheckerState();
1518 protect(_page)->setScreenIsBeingCaptured([self screenIsBeingCaptured]);
1519
1520#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
1521 [self _setUpImageAnalysis];
1522#endif
1523
1524 _sourceAnimationIDtoDestinationAnimationID = adoptNS([[NSMutableDictionary alloc] init]);
1525
1526 _selectionInteractionType = SelectionInteractionType::None;
1527
1528 _editingEndedByUser = YES__objc_yes;
1529
1530 _hasSetUpInteractions = YES__objc_yes;
1531}
1532
1533- (void)cleanUpInteraction
1534{
1535 if (!_hasSetUpInteractions)
1536 return;
1537
1538 _textInteractionWrapper = nilnullptr;
1539
1540 [protect(_actionSheetAssistant) cleanupSheet];
1541 _actionSheetAssistant = nilnullptr;
1542
1543 _smartMagnificationController = nilnullptr;
1544 _didAccessoryTabInitiateFocus = NO__objc_no;
1545 _isChangingFocusUsingAccessoryTab = NO__objc_no;
1546 _isExpectingFastSingleTapCommit = NO__objc_no;
1547 _needsDeferredEndScrollingSelectionUpdate = NO__objc_no;
1548 [_formInputSession invalidate];
1549 _formInputSession = nilnullptr;
1550 [_tapHighlightView removeFromSuperview];
1551 _lastOutstandingPositionInformationRequest = std::nullopt;
1552 _isWaitingOnPositionInformation = NO__objc_no;
1553
1554 _focusRequiresStrongPasswordAssistance = NO__objc_no;
1555 _additionalContextForStrongPasswordAssistance = nilnullptr;
1556 _waitingForEditDragSnapshot = NO__objc_no;
1557
1558 _autocorrectionContextNeedsUpdate = YES__objc_yes;
1559 _lastAutocorrectionContext = { };
1560
1561 _candidateViewNeedsUpdate = NO__objc_no;
1562 _seenHardwareKeyDownInNonEditableElement = NO__objc_no;
1563
1564 _textInteractionDidChangeFocusedElement = NO__objc_no;
1565 _activeTextInteractionCount = 0;
1566
1567 _treatAsContentEditableUntilNextEditorStateUpdate = NO__objc_no;
1568 _isHandlingActiveKeyEvent = NO__objc_no;
1569 _isHandlingActivePressesEvent = NO__objc_no;
1570 _isDeferringKeyEventsToInputMethod = NO__objc_no;
1571 _usingMouseDragForSelection = NO__objc_no;
1572
1573 if (_interactionViewsContainerView) {
1574 [self.layer removeObserver:self forKeyPath:@"transform" context:WKContentViewKVOTransformContext];
1575 [_interactionViewsContainerView removeFromSuperview];
1576 _interactionViewsContainerView = nilnullptr;
1577 }
1578
1579 _waitingForKeyboardAppearanceAnimationToStart = NO__objc_no;
1580 _lastInsertedCharacterToOverrideCharacterBeforeSelection = std::nullopt;
1581
1582 [_touchEventGestureRecognizer setDelegate:nilnullptr];
1583 [self removeGestureRecognizer:_touchEventGestureRecognizer.get()];
1584
1585 for (WKDeferringGestureRecognizer *gesture in self.deferringGestures) {
1586 gesture.delegate = nilnullptr;
1587 [self removeGestureRecognizer:gesture];
1588 }
1589
1590 if (_gestureRecognizerConsistencyEnforcer)
1591 _gestureRecognizerConsistencyEnforcer->reset();
1592
1593#if HAVE(UIKIT_WITH_MOUSE_SUPPORT)(defined 1 && 1)
1594 [self removeInteraction:_mouseInteraction.get()];
1595#endif
1596
1597#if HAVE(LOOKUP_GESTURE_RECOGNIZER)(defined HAVE_LOOKUP_GESTURE_RECOGNIZER && HAVE_LOOKUP_GESTURE_RECOGNIZER
)
1598 [_lookupGestureRecognizer setDelegate:nilnullptr];
1599 [self removeGestureRecognizer:_lookupGestureRecognizer.get()];
1600#endif
1601
1602 [_keyboardDismissalGestureRecognizer setDelegate:nilnullptr];
1603 [self removeGestureRecognizer:_keyboardDismissalGestureRecognizer.get()];
1604
1605 [_singleTapGestureRecognizer setDelegate:nilnullptr];
1606 [_singleTapGestureRecognizer setGestureIdentifiedTarget:nilnullptr action:nilnullptr];
1607 [_singleTapGestureRecognizer setResetTarget:nilnullptr action:nilnullptr];
1608 [_singleTapGestureRecognizer setSupportingTouchEventsGestureRecognizer:nilnullptr];
1609 [self removeGestureRecognizer:_singleTapGestureRecognizer.get()];
1610
1611#if ENABLE(MODEL_PROCESS)(defined 0 && 0)
1612 [_modelInteractionPanGestureRecognizer setDelegate:nilnullptr];
1613 [self removeGestureRecognizer:_modelInteractionPanGestureRecognizer.get()];
1614#endif
1615
1616 [_highlightLongPressGestureRecognizer setDelegate:nilnullptr];
1617 [self removeGestureRecognizer:_highlightLongPressGestureRecognizer.get()];
1618
1619 [_longPressGestureRecognizer setDelegate:nilnullptr];
1620 [self removeGestureRecognizer:_longPressGestureRecognizer.get()];
1621
1622 [_doubleTapGestureRecognizer setDelegate:nilnullptr];
1623 [self removeGestureRecognizer:_doubleTapGestureRecognizer.get()];
1624
1625 [_nonBlockingDoubleTapGestureRecognizer setDelegate:nilnullptr];
1626 [self removeGestureRecognizer:_nonBlockingDoubleTapGestureRecognizer.get()];
1627
1628 [_doubleTapGestureRecognizerForDoubleClick setDelegate:nilnullptr];
1629 [self removeGestureRecognizer:_doubleTapGestureRecognizerForDoubleClick.get()];
1630
1631 [_twoFingerDoubleTapGestureRecognizer setDelegate:nilnullptr];
1632 [self removeGestureRecognizer:_twoFingerDoubleTapGestureRecognizer.get()];
1633
1634 [_twoFingerSingleTapGestureRecognizer setDelegate:nilnullptr];
1635 [self removeGestureRecognizer:_twoFingerSingleTapGestureRecognizer.get()];
1636
1637 [self removeGestureRecognizer:_touchActionGestureRecognizer.get()];
1638 [self removeGestureRecognizer:_touchActionLeftSwipeGestureRecognizer.get()];
1639 [self removeGestureRecognizer:_touchActionRightSwipeGestureRecognizer.get()];
1640 [self removeGestureRecognizer:_touchActionUpSwipeGestureRecognizer.get()];
1641 [self removeGestureRecognizer:_touchActionDownSwipeGestureRecognizer.get()];
1642
1643 _layerTreeTransactionIdAtLastInteractionStart = { };
1644
1645#if ENABLE(DRAG_SUPPORT)(defined 1 && 1)
1646 [protect(existingLocalDragSessionContext(protect(_dragDropInteractionState.dragSession()))) cleanUpTemporaryDirectories];
1647 [self teardownDragAndDropInteractions];
1648#endif
1649
1650#if HAVE(UI_POINTER_INTERACTION)(defined 1 && 1)
1651 [self removeInteraction:_pointerInteraction.get()];
1652 _pointerInteraction = nilnullptr;
1653 _pointerInteractionRegionNeedsUpdate = NO__objc_no;
1654#endif
1655
1656 _revealFocusedElementDeferrer = nullptr;
1657
1658#if HAVE(PENCILKIT_TEXT_INPUT)(defined 1 && 1)
1659 [self cleanUpScribbleInteraction];
1660#endif
1661
1662 _inspectorNodeSearchEnabled = NO__objc_no;
1663 if (_inspectorNodeSearchGestureRecognizer) {
1664 [_inspectorNodeSearchGestureRecognizer setDelegate:nilnullptr];
1665 [self removeGestureRecognizer:_inspectorNodeSearchGestureRecognizer.get()];
1666 _inspectorNodeSearchGestureRecognizer = nilnullptr;
1667 }
1668
1669#if HAVE(LINK_PREVIEW)(defined 1 && 1)
1670 [self _unregisterPreview];
1671#endif
1672
1673 [self dismissPickersIfNeededWithReason:WebKit::PickerDismissalReason::ProcessExited];
1674
1675 [self stopDeferringInputViewUpdatesForAllSources];
1676 _focusedElementInformation = { };
1677
1678 [protect(_keyboardScrollingAnimator) invalidate];
1679 _keyboardScrollingAnimator = nilnullptr;
1680
1681 _dataListTextSuggestionsInputView = nilnullptr;
1682 _dataListTextSuggestions = nilnullptr;
1683
1684#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
1685 [self _tearDownImageAnalysis];
1686#endif
1687
1688 [_webView.get() _updateFixedContainerEdges:WebCore::FixedContainerEdges { }];
1689
1690#if USE(UICONTEXTMENU)(defined 1 && 1)
1691 [self _removeContextMenuHintContainerIfPossible];
1692#endif
1693 [self _removeContainerForDragPreviews];
1694 [self _removeContainerForDropPreviews];
1695 [self unsuppressSoftwareKeyboardUsingLastAutocorrectionContextIfNeeded];
1696
1697 _hasSetUpInteractions = NO__objc_no;
1698 _suppressSelectionAssistantReasons = { };
1699
1700 [self _resetPanningPreventionFlags];
1701 [self _handleDOMPasteRequestWithResult:WebCore::DOMPasteAccessResponse::DeniedForGesture];
1702 [self _cancelPendingKeyEventHandlers:NO__objc_no];
1703
1704#if HAVE(UI_PASTE_CONFIGURATION)(defined 1 && 1)
1705 self.pasteConfiguration = nilnullptr;
1706#endif
1707
1708 _selectionInteractionType = SelectionInteractionType::None;
1709 _lastSelectionChildScrollViewContentOffset = std::nullopt;
1710 _lastSelectionContainerViewOrigin = std::nullopt;
1711 _lastSiblingBeforeSelectionHighlight = nilnullptr;
1712 _waitingForEditorStateAfterScrollingSelectionContainer = NO__objc_no;
1713
1714 _cachedHasCustomTintColor = std::nullopt;
1715 _cachedSelectedTextRange = nilnullptr;
1716 _cachedSelectionContainerView = nilnullptr;
1717}
1718
1719- (void)cleanUpInteractionPreviewContainers
1720{
1721#if USE(UICONTEXTMENU)(defined 1 && 1)
1722 [self _removeContextMenuHintContainerIfPossible];
1723#endif
1724}
1725
1726- (void)_cancelPendingKeyEventHandlers:(BOOL)handled
1727{
1728 for (auto [event, keyEventHandler] : std::exchange(_keyWebEventHandlers, { }))
1729 keyEventHandler(event.get(), handled);
1730}
1731
1732- (void)_removeDefaultGestureRecognizers
1733{
1734 for (WKDeferringGestureRecognizer *gesture in self.deferringGestures)
1735 [self removeGestureRecognizer:gesture];
1736 [self removeGestureRecognizer:_touchEventGestureRecognizer.get()];
1737 [self removeGestureRecognizer:_singleTapGestureRecognizer.get()];
1738 [self removeGestureRecognizer:_highlightLongPressGestureRecognizer.get()];
1739 [self removeGestureRecognizer:_doubleTapGestureRecognizer.get()];
1740 [self removeGestureRecognizer:_nonBlockingDoubleTapGestureRecognizer.get()];
1741 [self removeGestureRecognizer:_doubleTapGestureRecognizerForDoubleClick.get()];
1742 [self removeGestureRecognizer:_twoFingerDoubleTapGestureRecognizer.get()];
1743 [self removeGestureRecognizer:_twoFingerSingleTapGestureRecognizer.get()];
1744#if ENABLE(MODEL_PROCESS)(defined 0 && 0)
1745 [self removeGestureRecognizer:_modelInteractionPanGestureRecognizer.get()];
1746#endif
1747#if HAVE(UIKIT_WITH_MOUSE_SUPPORT)(defined 1 && 1)
1748 [self removeInteraction:_mouseInteraction.get()];
1749#endif
1750#if HAVE(LOOKUP_GESTURE_RECOGNIZER)(defined HAVE_LOOKUP_GESTURE_RECOGNIZER && HAVE_LOOKUP_GESTURE_RECOGNIZER
)
1751 [self removeGestureRecognizer:_lookupGestureRecognizer.get()];
1752#endif
1753 [self removeGestureRecognizer:_touchActionGestureRecognizer.get()];
1754 [self removeGestureRecognizer:_touchActionLeftSwipeGestureRecognizer.get()];
1755 [self removeGestureRecognizer:_touchActionRightSwipeGestureRecognizer.get()];
1756 [self removeGestureRecognizer:_touchActionUpSwipeGestureRecognizer.get()];
1757 [self removeGestureRecognizer:_touchActionDownSwipeGestureRecognizer.get()];
1758 [self removeGestureRecognizer:_keyboardDismissalGestureRecognizer.get()];
1759}
1760
1761- (void)_addDefaultGestureRecognizers
1762{
1763 for (WKDeferringGestureRecognizer *gesture in self.deferringGestures)
1764 [self addGestureRecognizer:gesture];
1765 [self addGestureRecognizer:_touchEventGestureRecognizer.get()];
1766 [self addGestureRecognizer:_singleTapGestureRecognizer.get()];
1767 [self addGestureRecognizer:_highlightLongPressGestureRecognizer.get()];
1768 [self addGestureRecognizer:_doubleTapGestureRecognizer.get()];
1769 [self addGestureRecognizer:_nonBlockingDoubleTapGestureRecognizer.get()];
1770 [self addGestureRecognizer:_doubleTapGestureRecognizerForDoubleClick.get()];
1771 [self addGestureRecognizer:_twoFingerDoubleTapGestureRecognizer.get()];
1772 [self addGestureRecognizer:_twoFingerSingleTapGestureRecognizer.get()];
1773#if ENABLE(MODEL_PROCESS)(defined 0 && 0)
1774 [self addGestureRecognizer:_modelInteractionPanGestureRecognizer.get()];
1775#endif
1776#if HAVE(UIKIT_WITH_MOUSE_SUPPORT)(defined 1 && 1)
1777 [self addInteraction:_mouseInteraction.get()];
1778#endif
1779#if HAVE(LOOKUP_GESTURE_RECOGNIZER)(defined HAVE_LOOKUP_GESTURE_RECOGNIZER && HAVE_LOOKUP_GESTURE_RECOGNIZER
)
1780 [self addGestureRecognizer:_lookupGestureRecognizer.get()];
1781#endif
1782 [self addGestureRecognizer:_touchActionGestureRecognizer.get()];
1783 [self addGestureRecognizer:_touchActionLeftSwipeGestureRecognizer.get()];
1784 [self addGestureRecognizer:_touchActionRightSwipeGestureRecognizer.get()];
1785 [self addGestureRecognizer:_touchActionUpSwipeGestureRecognizer.get()];
1786 [self addGestureRecognizer:_touchActionDownSwipeGestureRecognizer.get()];
1787 [self addGestureRecognizer:_keyboardDismissalGestureRecognizer.get()];
1788
1789#if ENABLE(GAMEPAD)(defined 1 && 1)
1790 [self addGestureRecognizer:_gamepadInteractionGestureRecognizer.get()];
1791#endif
1792}
1793
1794- (void)_didChangeLinkPreviewAvailability
1795{
1796 [self _updateLongPressAndHighlightLongPressGestures];
1797}
1798
1799- (void)_updateLongPressAndHighlightLongPressGestures
1800{
1801#if HAVE(LINK_PREVIEW)(defined 1 && 1)
1802 // We only disable the highlight long press gesture in the case where UIContextMenu is available and we
1803 // also allow link previews, since the context menu interaction's gestures need to take precedence over
1804 // highlight long press gestures.
1805 [_highlightLongPressGestureRecognizer setEnabled:!self._shouldUseContextMenus || !self.webView.allowsLinkPreview];
1806
1807 // We only enable the long press gesture in the case where the app is linked on iOS 12 or earlier (and
1808 // therefore prefers the legacy action sheet over context menus), and link previews are also enabled.
1809 [_longPressGestureRecognizer setEnabled:!self._shouldUseContextMenus && self.webView.allowsLinkPreview];
1810#else
1811 [_highlightLongPressGestureRecognizer setEnabled:NO__objc_no];
1812 [_longPressGestureRecognizer setEnabled:NO__objc_no];
1813#endif
1814}
1815
1816- (UIView *)unscaledView
1817{
1818 return _interactionViewsContainerView.get();
1819}
1820
1821- (UIScrollView *)_scroller
1822{
1823 return [_webView.get() scrollView];
1824}
1825
1826- (CGRect)unobscuredContentRect
1827{
1828 return protect(_page)->unobscuredContentRect();
1829}
1830
1831#pragma mark - UITextAutoscrolling
1832
1833- (void)startAutoscroll:(CGPoint)pointInDocument
1834{
1835 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG153"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(1835, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
1836
1837 protect(_page)->startAutoscrollAtPosition(pointInDocument);
1838}
1839
1840- (void)cancelAutoscroll
1841{
1842 _selectionInteractionType = SelectionInteractionType::None;
1843 protect(_page)->cancelAutoscroll();
1844}
1845
1846- (void)scrollSelectionToVisible:(BOOL)animated
1847{
1848 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG154"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(1848, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
1849 // Used to scroll selection on keyboard up; we already scroll to visible.
1850}
1851
1852- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
1853{
1854 if (context != WKContentViewKVOTransformContext) {
1855 [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
1856 return;
1857 }
1858
1859 ASSERT([keyPath isEqualToString:@"transform"])((void)0);
1860 ASSERT(object == self.layer)((void)0);
1861
1862 if ([UIView _isInAnimationBlock] && protect(_page)->editorState().selectionType == WebCore::SelectionType::None) {
1863 // If the utility views are not already visible, we don't want them to become visible during the animation since
1864 // they could not start from a reasonable state.
1865 // This is not perfect since views could also get updated during the animation, in practice this is rare and the end state
1866 // remains correct.
1867 [self _cancelInteraction];
1868 [_interactionViewsContainerView setHidden:YES__objc_yes];
1869 [UIView _addCompletion:^(BOOL){ [_interactionViewsContainerView setHidden:NO__objc_no]; }];
1870 }
1871
1872 [self _updateTapHighlight];
1873
1874 if (protect(_page)->editorState().selectionType == WebCore::SelectionType::None && _lastSelectionDrawingInfo.type == WebCore::SelectionType::None)
1875 return;
1876
1877 _selectionNeedsUpdate = YES__objc_yes;
1878 [self _updateChangedSelection:YES__objc_yes];
1879}
1880
1881- (void)_enableInspectorNodeSearch
1882{
1883 _inspectorNodeSearchEnabled = YES__objc_yes;
1884
1885 [self _cancelInteraction];
1886
1887 [self _removeDefaultGestureRecognizers];
1888 _inspectorNodeSearchGestureRecognizer = adoptNS([[WKInspectorNodeSearchGestureRecognizer alloc] initWithTarget:self action:@selector(_inspectorNodeSearchRecognized:)]);
1889 [self addGestureRecognizer:_inspectorNodeSearchGestureRecognizer.get()];
1890}
1891
1892- (void)_disableInspectorNodeSearch
1893{
1894 _inspectorNodeSearchEnabled = NO__objc_no;
1895
1896 [self _addDefaultGestureRecognizers];
1897 [self removeGestureRecognizer:_inspectorNodeSearchGestureRecognizer.get()];
1898 _inspectorNodeSearchGestureRecognizer = nilnullptr;
1899}
1900
1901- (UIView *)hitTest:(CGPoint)point withEvent:(::UIEvent *)event
1902{
1903 for (UIView *subView in [_interactionViewsContainerView.get() subviews]) {
1904 UIView *hitView = [subView hitTest:[subView convertPoint:point fromView:self] withEvent:event];
1905 if (hitView) {
1906 LOG_WITH_STREAM(UIHitTesting, stream << self << "hitTest at " << WebCore::FloatPoint(point) << " found interaction view " << hitView)((void)0);
1907 return hitView;
1908 }
1909 }
1910
1911 LOG_WITH_STREAM(UIHitTesting, stream << "hit-testing WKContentView subviews " << [[self recursiveDescription] UTF8String])((void)0);
1912 UIView* hitView = [super hitTest:point withEvent:event];
1913 LOG_WITH_STREAM(UIHitTesting, stream << " found view " << [hitView class] << " " << (void*)hitView)((void)0);
1914 return hitView;
1915}
1916
1917- (const WebKit::InteractionInformationAtPosition&)positionInformation
1918{
1919 return _positionInformation;
1920}
1921
1922- (void)setInputDelegate:(id <UITextInputDelegate>)inputDelegate
1923{
1924 _inputDelegate = inputDelegate;
1925}
1926
1927- (id <UITextInputDelegate>)inputDelegate
1928{
1929 return _inputDelegate.getAutoreleased();
1930}
1931
1932- (CGPoint)lastInteractionLocation
1933{
1934 return _lastInteractionLocation;
1935}
1936
1937- (BOOL)shouldHideSelectionInFixedPositionWhenScrolling
1938{
1939 if (self.selectionHonorsOverflowScrolling)
1940 return NO__objc_no;
1941
1942 if (_isEditable)
1943 return _focusedElementInformation.insideFixedPosition;
1944
1945 auto& editorState = protect(_page)->editorState();
1946 return editorState.hasPostLayoutData() && editorState.selectionType == WebCore::SelectionType::Range && editorState.postLayoutData->insideFixedPosition;
1947}
1948
1949- (BOOL)isEditable
1950{
1951 return _isEditable;
1952}
1953
1954- (BOOL)setIsEditable:(BOOL)isEditable
1955{
1956 if (isEditable == _isEditable)
1957 return NO__objc_no;
1958
1959 _isEditable = isEditable;
1960 return YES__objc_yes;
1961}
1962
1963- (void)_endEditing
1964{
1965 [_inputPeripheral endEditing];
1966 [_formInputSession endEditing];
1967 [_dataListTextSuggestionsInputView controlEndEditing];
1968}
1969
1970- (void)_cancelPreviousResetInputViewDeferralRequest
1971{
1972 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(stopDeferringInputViewUpdatesForAllSources) object:nilnullptr];
1973}
1974
1975- (void)_scheduleResetInputViewDeferralAfterBecomingFirstResponder
1976{
1977 [self _cancelPreviousResetInputViewDeferralRequest];
1978
1979 const NSTimeInterval inputViewDeferralWatchdogTimerDuration = 0.5;
1980 [self performSelector:@selector(stopDeferringInputViewUpdatesForAllSources) withObject:self afterDelay:inputViewDeferralWatchdogTimerDuration];
1981}
1982
1983- (BOOL)canBecomeFirstResponder
1984{
1985 return _becomingFirstResponder;
1986}
1987
1988- (BOOL)canBecomeFirstResponderForWebView
1989{
1990 if (_resigningFirstResponder)
1991 return NO__objc_no;
1992 // We might want to return something else
1993 // if we decide to enable/disable interaction programmatically.
1994 return YES__objc_yes;
1995}
1996
1997- (BOOL)becomeFirstResponder
1998{
1999 return [_webView.get() becomeFirstResponder];
2000}
2001
2002- (BOOL)becomeFirstResponderForWebView
2003{
2004 if (_resigningFirstResponder)
2005 return NO__objc_no;
2006
2007 [self startDeferringInputViewUpdates:WebKit::InputViewUpdateDeferralSource::BecomeFirstResponder];
2008
2009 BOOL didBecomeFirstResponder;
2010 {
2011 SetForScope becomingFirstResponder { _becomingFirstResponder, YES__objc_yes };
2012 didBecomeFirstResponder = [super becomeFirstResponder];
2013 }
2014
2015 if (didBecomeFirstResponder) {
2016 protect(_page)->installActivityStateChangeCompletionHandler([weakSelf = WeakObjCPtr<WKContentView>(self)] {
2017 if (!weakSelf)
2018 return;
2019
2020 auto strongSelf = weakSelf.get();
2021 [strongSelf stopDeferringInputViewUpdates:WebKit::InputViewUpdateDeferralSource::BecomeFirstResponder];
2022 });
2023
2024#if ENABLE(GAMEPAD)(defined 1 && 1)
2025 WebKit::UIGamepadProvider::singleton().viewBecameActive(*protect(_page));
2026#endif
2027
2028 protect(_page)->activityStateDidChange(WebCore::ActivityState::IsFocused, WebKit::WebPageProxy::ActivityStateChangeDispatchMode::Immediate);
2029
2030 if (self._shouldActivateSelectionAfterBecomingFirstResponder) {
2031 protect(_page)->callAfterNextPresentationUpdate([weakSelf = WeakObjCPtr<WKContentView>(self)] {
2032 RetainPtr strongSelf = weakSelf.get();
2033 if (![strongSelf _shouldActivateSelectionAfterBecomingFirstResponder])
2034 return;
2035
2036 [strongSelf->_textInteractionWrapper setNeedsSelectionUpdate];
2037 [strongSelf->_textInteractionWrapper activateSelection];
2038 });
2039 }
2040
2041 [self _scheduleResetInputViewDeferralAfterBecomingFirstResponder];
2042 } else
2043 [self stopDeferringInputViewUpdates:WebKit::InputViewUpdateDeferralSource::BecomeFirstResponder];
2044
2045 return didBecomeFirstResponder;
2046}
2047
2048- (BOOL)_shouldActivateSelectionAfterBecomingFirstResponder
2049{
2050 return self.canShowNonEmptySelectionView || (!_suppressSelectionAssistantReasons && _activeTextInteractionCount);
2051}
2052
2053- (BOOL)resignFirstResponder
2054{
2055 return [_webView.get() resignFirstResponder];
2056}
2057
2058typedef NS_ENUM(NSInteger, EndEditingReason)enum __attribute__((enum_extensibility(open))) EndEditingReason
: NSInteger EndEditingReason; enum EndEditingReason : NSInteger
{
2059 EndEditingReasonAccessoryDone,
2060 EndEditingReasonResigningFirstResponder,
2061};
2062
2063- (void)endEditingAndUpdateFocusAppearanceWithReason:(EndEditingReason)reason
2064{
2065 _editingEndedByUser = YES__objc_yes;
2066
2067 if (!self.webView._retainingActiveFocusedState) {
2068 // We need to complete the editing operation before we blur the element.
2069 [self _endEditing];
2070
2071 auto shouldBlurFocusedElement = [&] {
2072 if (_keyboardDidRequestDismissal)
2073 return true;
2074
2075 if (self._shouldUseLegacySelectPopoverDismissalBehavior)
2076 return true;
2077
2078 if (reason == EndEditingReasonAccessoryDone) {
2079 if (_focusRequiresStrongPasswordAssistance)
2080 return true;
2081
2082 if (PAL::currentUserInterfaceIdiomIsSmallScreen())
2083 return true;
2084 }
2085
2086 return false;
2087 };
2088
2089 if (shouldBlurFocusedElement()) {
2090 protect(_page)->blurFocusedElement();
2091 // Don't wait for WebPageProxy::blurFocusedElement() to round-trip back to us to hide the keyboard
2092 // because we know that the user explicitly requested us to do so.
2093 [self _elementDidBlur];
2094 }
2095 }
2096
2097 [self _cancelInteraction];
2098
2099 BOOL shouldDeactivateSelection = [&]() -> BOOL {
2100#if PLATFORM(MACCATALYST)(defined WTF_PLATFORM_MACCATALYST && WTF_PLATFORM_MACCATALYST
)
2101 if (reason == EndEditingReasonResigningFirstResponder) {
2102 // This logic is based on a similar check on macOS (in WebViewImpl::resignFirstResponder()) to
2103 // maintain the active selection when resigning first responder, if the new responder is in a
2104 // modal popover or panel.
2105 // FIXME: Ideally, this would additionally check that the new first responder corresponds to
2106 // a view underneath this view controller; however, there doesn't seem to be any way of doing
2107 // so at the moment. In lieu of this, we can at least check that the web view itself isn't
2108 // inside the popover.
2109 auto controller = self._wk_viewControllerForFullScreenPresentation;
2110 return [self isDescendantOfView:controller.viewIfLoaded] || controller.modalPresentationStyle != UIModalPresentationPopover;
2111 }
2112#endif // PLATFORM(MACCATALYST)
2113 return YES__objc_yes;
2114 }();
2115
2116 if (shouldDeactivateSelection)
2117 [_textInteractionWrapper deactivateSelection];
2118
2119 [self stopDeferringInputViewUpdatesForAllSources];
2120}
2121
2122- (BOOL)resignFirstResponderForWebView
2123{
2124 // FIXME: Maybe we should call resignFirstResponder on the superclass
2125 // and do nothing if the return value is NO.
2126
2127 SetForScope resigningFirstResponderScope { _resigningFirstResponder, YES__objc_yes };
2128
2129 [self endEditingAndUpdateFocusAppearanceWithReason:EndEditingReasonResigningFirstResponder];
2130
2131 // If the user explicitly dismissed the keyboard then we will lose first responder
2132 // status only to gain it back again. Just don't resign in that case.
2133 if (_keyboardDidRequestDismissal) {
2134 _keyboardDidRequestDismissal = NO__objc_no;
2135 return NO__objc_no;
2136 }
2137
2138 bool superDidResign = [super resignFirstResponder];
2139
2140 if (superDidResign) {
2141 [self _handleDOMPasteRequestWithResult:WebCore::DOMPasteAccessResponse::DeniedForGesture];
2142 protect(_page)->activityStateDidChange(WebCore::ActivityState::IsFocused, WebKit::WebPageProxy::ActivityStateChangeDispatchMode::Immediate);
2143
2144#if ENABLE(GAMEPAD)(defined 1 && 1)
2145 WebKit::UIGamepadProvider::singleton().viewBecameInactive(*protect(_page));
2146#endif
2147
2148 _isHandlingActiveKeyEvent = NO__objc_no;
2149 _isHandlingActivePressesEvent = NO__objc_no;
2150
2151 if (!_keyWebEventHandlers.isEmpty()) {
2152 RunLoop::mainSingleton().dispatch([weakSelf = WeakObjCPtr<WKContentView>(self)] {
2153 RetainPtr strongSelf = weakSelf.get();
2154 if (!strongSelf || [strongSelf isFirstResponder])
2155 return;
2156 [strongSelf _cancelPendingKeyEventHandlers:YES__objc_yes];
2157 });
2158 }
2159 }
2160
2161 return superDidResign;
2162}
2163
2164- (void)cancelPointersForGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
2165{
2166 NSMapTable<NSNumber *, UITouch *> *activeTouches = [_touchEventGestureRecognizer activeTouchesByIdentifier];
2167 for (NSNumber *touchIdentifier in activeTouches) {
2168 UITouch *touch = [activeTouches objectForKey:touchIdentifier];
2169 if ([touch.gestureRecognizers containsObject:gestureRecognizer])
2170 protect(_page)->cancelPointer([touchIdentifier unsignedIntValue], WebCore::roundedIntPoint([touch locationInView:self]));
2171 }
2172}
2173
2174- (std::optional<unsigned>)activeTouchIdentifierForGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
2175{
2176 NSMapTable<NSNumber *, UITouch *> *activeTouches = [_touchEventGestureRecognizer activeTouchesByIdentifier];
2177 for (NSNumber *touchIdentifier in activeTouches) {
2178 UITouch *touch = [activeTouches objectForKey:touchIdentifier];
2179 if ([touch.gestureRecognizers containsObject:gestureRecognizer])
2180 return [touchIdentifier unsignedIntValue];
2181 }
2182 return std::nullopt;
2183}
2184
2185- (BOOL)_touchEventsMustRequireGestureRecognizerToFail:(UIGestureRecognizer *)gestureRecognizer
2186{
2187 auto webView = self.webView;
2188 if ([webView _isNavigationSwipeGestureRecognizer:gestureRecognizer])
2189 return YES__objc_yes;
2190
2191 id <WKUIDelegatePrivate> uiDelegate = static_cast<id <WKUIDelegatePrivate>>([webView UIDelegate]);
2192 return gestureRecognizer.view == webView && [uiDelegate respondsToSelector:@selector(_webView:touchEventsMustRequireGestureRecognizerToFail:)]
2193 && [uiDelegate _webView:webView touchEventsMustRequireGestureRecognizerToFail:gestureRecognizer];
2194}
2195
2196- (BOOL)_gestureRecognizerCanBePreventedByTouchEvents:(UIGestureRecognizer *)gestureRecognizer
2197{
2198 id<WKUIDelegatePrivate> uiDelegate = static_cast<id<WKUIDelegatePrivate>>([self.webView UIDelegate]);
2199 return [uiDelegate respondsToSelector:@selector(_webView:gestureRecognizerCanBePreventedByTouchEvents:)] && [uiDelegate _webView:self.webView gestureRecognizerCanBePreventedByTouchEvents:gestureRecognizer];
2200}
2201
2202- (void)_touchEventsRecognized
2203{
2204 if (!protect(_page)->hasRunningProcess())
2205 return;
2206
2207 auto& lastTouchEvent = [_touchEventGestureRecognizer lastTouchEvent];
2208 _lastInteractionLocation = lastTouchEvent.locationInRootViewCoordinates;
2209
2210 if (lastTouchEvent.type == WebKit::WKTouchEventType::Begin) {
2211 if (!_failedTouchStartDeferringGestures)
2212 _failedTouchStartDeferringGestures = { { } };
2213
2214 [self _handleDOMPasteRequestWithResult:WebCore::DOMPasteAccessResponse::DeniedForGesture];
2215 _layerTreeTransactionIdAtLastInteractionStart = protect(downcast<WebKit::RemoteLayerTreeDrawingAreaProxy>(*_page->drawingArea()))->lastCommittedMainFrameLayerTreeTransactionID();
2216
2217#if ENABLE(TOUCH_EVENTS)(defined 0 && 0)
2218 _page->didBeginTouchPoint(lastTouchEvent.locationInRootViewCoordinates);
2219#endif
2220
2221 WebKit::InteractionInformationRequest positionInformationRequest { WebCore::IntPoint(_lastInteractionLocation) };
2222 [self doAfterPositionInformationUpdate:[assistant = WeakObjCPtr<WKActionSheetAssistant>(_actionSheetAssistant.get())] (WebKit::InteractionInformationAtPosition information) {
2223 [assistant.get() interactionDidStartWithPositionInformation:information];
2224 } forRequest:positionInformationRequest];
2225 }
2226
2227#if ENABLE(TOUCH_EVENTS)(defined 0 && 0)
2228 WebKit::NativeWebTouchEvent nativeWebTouchEvent { lastTouchEvent, [_touchEventGestureRecognizer modifierFlags] };
2229 nativeWebTouchEvent.setCanPreventNativeGestures(_touchEventsCanPreventNativeGestures || [_touchEventGestureRecognizer isDefaultPrevented]);
2230
2231 [self _handleTouchActionsForTouchEvent:nativeWebTouchEvent];
2232
2233 if (_touchEventsCanPreventNativeGestures)
2234 _page->handlePreventableTouchEvent(nativeWebTouchEvent);
2235 else
2236 _page->handleUnpreventableTouchEvent(nativeWebTouchEvent);
2237
2238 if (nativeWebTouchEvent.allTouchPointsAreReleased()) {
2239 _touchEventsCanPreventNativeGestures = YES__objc_yes;
2240
2241 if (!_page->isScrollingOrZooming())
2242 [self _resetPanningPreventionFlags];
2243
2244 if (nativeWebTouchEvent.isPotentialTap() && self.hasHiddenContentEditable && self._hasFocusedElement && !self.window.keyWindow)
2245 [self.window makeKeyWindow];
2246
2247 auto stopDeferringNativeGesturesIfNeeded = [] (WKDeferringGestureRecognizer *gestureRecognizer) {
2248 if (gestureRecognizer.state == UIGestureRecognizerStatePossible)
2249 gestureRecognizer.state = UIGestureRecognizerStateFailed;
2250 };
2251
2252 if (!_page->isHandlingPreventableTouchStart()) {
2253 for (WKDeferringGestureRecognizer *gestureRecognizer in self._touchStartDeferringGestures)
2254 stopDeferringNativeGesturesIfNeeded(gestureRecognizer);
2255 }
2256
2257 if (!_page->isHandlingPreventableTouchMove())
2258 stopDeferringNativeGesturesIfNeeded(_touchMoveDeferringGestureRecognizer.get());
2259
2260 if (!_page->isHandlingPreventableTouchEnd()) {
2261 for (WKDeferringGestureRecognizer *gestureRecognizer in self._touchEndDeferringGestures)
2262 stopDeferringNativeGesturesIfNeeded(gestureRecognizer);
2263 }
2264
2265 _failedTouchStartDeferringGestures = std::nullopt;
2266 }
2267#endif // ENABLE(TOUCH_EVENTS)
2268}
2269
2270- (void)_touchEventsGestureRecognizerReset
2271{
2272 protect(_page)->resetPointerCapture();
2273}
2274
2275#if ENABLE(TOUCH_EVENTS)(defined 0 && 0)
2276- (void)_handleTouchActionsForTouchEvent:(const WebKit::NativeWebTouchEvent&)touchEvent
2277{
2278 auto* scrollingCoordinator = downcast<WebKit::RemoteScrollingCoordinatorProxyIOS>(_page->scrollingCoordinatorProxy());
2279 if (!scrollingCoordinator)
2280 return;
2281
2282 for (const auto& touchPoint : touchEvent.touchPoints()) {
2283 auto phase = touchPoint.phase();
2284 if (phase == WebKit::WebPlatformTouchPoint::State::Pressed) {
2285 auto touchActions = WebKit::touchActionsForPoint(self, WebCore::roundedIntPoint(touchPoint.locationInRootView()));
2286 LOG_WITH_STREAM(UIHitTesting, stream << "touchActionsForPoint " << touchPoint.locationInRootView() << " found " << touchActions)((void)0);
2287 if (!touchActions || touchActions.contains(WebCore::TouchAction::Auto))
2288 continue;
2289 [_touchActionGestureRecognizer setTouchActions:touchActions forTouchIdentifier:touchPoint.identifier()];
2290 scrollingCoordinator->setTouchActionsForTouchIdentifier(touchActions, touchPoint.identifier());
2291 _preventsPanningInXAxis = !touchActions.containsAny({ WebCore::TouchAction::PanX, WebCore::TouchAction::Manipulation });
2292 _preventsPanningInYAxis = !touchActions.containsAny({ WebCore::TouchAction::PanY, WebCore::TouchAction::Manipulation });
2293 } else if (phase == WebKit::WebPlatformTouchPoint::State::Released || phase == WebKit::WebPlatformTouchPoint::State::Cancelled) {
2294 [_touchActionGestureRecognizer clearTouchActionsForTouchIdentifier:touchPoint.identifier()];
2295 scrollingCoordinator->clearTouchActionsForTouchIdentifier(touchPoint.identifier());
2296 }
2297 }
2298}
2299#endif // ENABLE(TOUCH_EVENTS)
2300
2301- (BOOL)_isTouchActionSwipeGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
2302{
2303 return gestureRecognizer == _touchActionLeftSwipeGestureRecognizer || gestureRecognizer == _touchActionRightSwipeGestureRecognizer || gestureRecognizer == _touchActionUpSwipeGestureRecognizer || gestureRecognizer == _touchActionDownSwipeGestureRecognizer;
2304}
2305
2306- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveEvent:(UIEvent *)event
2307{
2308 if ([self _isTouchActionSwipeGestureRecognizer:gestureRecognizer])
2309 return event.type != UIEventTypeScroll;
2310 return YES__objc_yes;
2311}
2312
2313- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
2314{
2315#if HAVE(LOOKUP_GESTURE_RECOGNIZER)(defined HAVE_LOOKUP_GESTURE_RECOGNIZER && HAVE_LOOKUP_GESTURE_RECOGNIZER
)
2316 if (gestureRecognizer == _lookupGestureRecognizer)
2317 return YES__objc_yes;
2318#endif
2319
2320#if HAVE(UIKIT_WITH_MOUSE_SUPPORT)(defined 1 && 1)
2321 auto isMouseGestureRecognizer = gestureRecognizer == [_mouseInteraction mouseTouchGestureRecognizer];
2322 if (!isMouseGestureRecognizer && [_mouseInteraction mouseTouch] == touch && touch._isPointerTouch)
2323 return NO__objc_no;
2324
2325 if (isMouseGestureRecognizer && !touch._isPointerTouch)
2326 return NO__objc_no;
2327
2328 if (gestureRecognizer == _doubleTapGestureRecognizer || gestureRecognizer == _nonBlockingDoubleTapGestureRecognizer)
2329 return touch.type != UITouchTypeIndirectPointer;
2330#endif
2331
2332 if ([self _isTouchActionSwipeGestureRecognizer:gestureRecognizer]) {
2333 // We update the enabled state of the various swipe gesture recognizers such that if we have a unidirectional touch-action
2334 // specified (only pan-x or only pan-y) we enable the two recognizers in the opposite axis to prevent scrolling from starting
2335 // if the initial gesture is such a swipe. Since the recognizers are specified to use a single finger for recognition, we don't
2336 // need to worry about the case where there may be more than a single touch for a given UIScrollView.
2337 auto touchLocation = [touch locationInView:self];
2338 auto touchActions = WebKit::touchActionsForPoint(self, WebCore::roundedIntPoint(touchLocation));
2339 LOG_WITH_STREAM(UIHitTesting, stream << "gestureRecognizer:shouldReceiveTouch: at " << WebCore::FloatPoint(touchLocation) << " - touch actions " << touchActions)((void)0);
2340 if (gestureRecognizer == _touchActionLeftSwipeGestureRecognizer || gestureRecognizer == _touchActionRightSwipeGestureRecognizer)
2341 return touchActions == WebCore::TouchAction::PanY;
2342 return touchActions == WebCore::TouchAction::PanX;
2343 }
2344
2345 return YES__objc_yes;
2346}
2347
2348- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceivePress:(UIPress *)press
2349{
2350 return YES__objc_yes;
2351}
2352
2353#pragma mark - WKTouchActionGestureRecognizerDelegate implementation
2354
2355- (BOOL)gestureRecognizerMayPanWebView:(UIGestureRecognizer *)gestureRecognizer
2356{
2357 // The gesture recognizer is the main UIScrollView's UIPanGestureRecognizer.
2358 if (gestureRecognizer == [_webView.get() scrollView].panGestureRecognizer)
2359 return YES__objc_yes;
2360
2361 // The gesture recognizer is a child UIScrollView's UIPanGestureRecognizer created by WebKit.
2362 if (gestureRecognizer.view && [gestureRecognizer.view isKindOfClass:[WKChildScrollView class]])
2363 return YES__objc_yes;
2364
2365 return NO__objc_no;
2366}
2367
2368- (BOOL)gestureRecognizerMayPinchToZoomWebView:(UIGestureRecognizer *)gestureRecognizer
2369{
2370 // The gesture recognizer is the main UIScrollView's UIPinchGestureRecognizer.
2371 if (gestureRecognizer == [_webView.get() scrollView].pinchGestureRecognizer)
2372 return YES__objc_yes;
2373
2374 // The gesture recognizer is another UIPinchGestureRecognizer known to lead to pinch-to-zoom.
2375 if ([gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]) {
2376 if (auto uiDelegate = static_cast<id<WKUIDelegatePrivate>>(self.webView.UIDelegate)) {
2377 if ([uiDelegate respondsToSelector:@selector(_webView:gestureRecognizerCouldPinch:)])
2378 return [uiDelegate _webView:self.webView gestureRecognizerCouldPinch:gestureRecognizer];
2379 }
2380 }
2381 return NO__objc_no;
2382}
2383
2384- (BOOL)gestureRecognizerMayDoubleTapToZoomWebView:(UIGestureRecognizer *)gestureRecognizer
2385{
2386 return gestureRecognizer == _doubleTapGestureRecognizer || gestureRecognizer == _twoFingerDoubleTapGestureRecognizer;
2387}
2388
2389- (NSMapTable<NSNumber *, UITouch *> *)touchActionActiveTouches
2390{
2391 return [_touchEventGestureRecognizer activeTouchesByIdentifier];
2392}
2393
2394- (void)_resetPanningPreventionFlags
2395{
2396 _preventsPanningInXAxis = NO__objc_no;
2397 _preventsPanningInYAxis = NO__objc_no;
2398}
2399
2400- (void)_inspectorNodeSearchRecognized:(UIGestureRecognizer *)gestureRecognizer
2401{
2402 ASSERT(_inspectorNodeSearchEnabled)((void)0);
2403 [self _resetIsDoubleTapPending];
2404
2405 CGPoint point = [gestureRecognizer locationInView:self];
2406
2407 switch (gestureRecognizer.state) {
2408 case UIGestureRecognizerStateBegan:
2409 case UIGestureRecognizerStateChanged:
2410 protect(_page)->inspectorNodeSearchMovedToPosition(point);
2411 break;
2412 case UIGestureRecognizerStateEnded:
2413 case UIGestureRecognizerStateCancelled:
2414 default: // To ensure we turn off node search.
2415 protect(_page)->inspectorNodeSearchEndedAtPosition(point);
2416 break;
2417 }
2418}
2419
2420static WebCore::FloatQuad inflateQuad(const WebCore::FloatQuad& quad, float inflateSize)
2421{
2422 // We sort the output points like this (as expected by the highlight view):
2423 // p2------p3
2424 // | |
2425 // p1------p4
2426
2427 // 1) Sort the points horizontally.
2428 std::array points { quad.p1(), quad.p4(), quad.p2(), quad.p3() };
2429 if (points[0].x() > points[1].x())
2430 std::swap(points[0], points[1]);
2431 if (points[2].x() > points[3].x())
2432 std::swap(points[2], points[3]);
2433
2434 if (points[0].x() > points[2].x())
2435 std::swap(points[0], points[2]);
2436 if (points[1].x() > points[3].x())
2437 std::swap(points[1], points[3]);
2438
2439 if (points[1].x() > points[2].x())
2440 std::swap(points[1], points[2]);
2441
2442 // 2) Swap them vertically to have the output points [p2, p1, p3, p4].
2443 if (points[1].y() < points[0].y())
2444 std::swap(points[0], points[1]);
2445 if (points[3].y() < points[2].y())
2446 std::swap(points[2], points[3]);
2447
2448 // 3) Adjust the positions.
2449 points[0].move(-inflateSize, -inflateSize);
2450 points[1].move(-inflateSize, inflateSize);
2451 points[2].move(inflateSize, -inflateSize);
2452 points[3].move(inflateSize, inflateSize);
2453
2454 return WebCore::FloatQuad(points[1], points[0], points[2], points[3]);
2455}
2456
2457#if ENABLE(TOUCH_EVENTS)(defined 0 && 0)
2458- (void)_touchEvent:(const WebKit::WebTouchEvent&)touchEvent preventsNativeGestures:(BOOL)preventsNativeGesture
2459{
2460 if (!preventsNativeGesture || ![_touchEventGestureRecognizer isDispatchingTouchEvents])
2461 return;
2462
2463 _longPressCanClick = NO__objc_no;
2464 _touchEventsCanPreventNativeGestures = NO__objc_no;
2465 [_touchEventGestureRecognizer setDefaultPrevented:YES__objc_yes];
2466}
2467#endif
2468
2469- (WKTouchEventsGestureRecognizer *)touchEventGestureRecognizer
2470{
2471 return _touchEventGestureRecognizer.get();
2472}
2473
2474- (WebKit::GestureRecognizerConsistencyEnforcer&)gestureRecognizerConsistencyEnforcer
2475{
2476 if (!_gestureRecognizerConsistencyEnforcer)
2477 lazyInitialize(_gestureRecognizerConsistencyEnforcer, makeUniqueWithoutRefCountedCheck<WebKit::GestureRecognizerConsistencyEnforcer>(self));
2478
2479 return *_gestureRecognizerConsistencyEnforcer;
2480}
2481
2482- (NSArray<WKDeferringGestureRecognizer *> *)deferringGestures
2483{
2484 auto gestures = [NSMutableArray arrayWithCapacity:7];
2485 [gestures addObjectsFromArray:self._touchStartDeferringGestures];
2486 [gestures addObjectsFromArray:self._touchEndDeferringGestures];
2487 if (_touchMoveDeferringGestureRecognizer)
2488 [gestures addObject:_touchMoveDeferringGestureRecognizer.get()];
2489#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
2490 if (_imageAnalysisDeferringGestureRecognizer)
2491 [gestures addObject:_imageAnalysisDeferringGestureRecognizer.get()];
2492#endif
2493 return gestures;
2494}
2495
2496static void appendRecognizerIfNonNull(RetainPtr<NSMutableArray>& array, const RetainPtr<WKDeferringGestureRecognizer>& recognizer)
2497{
2498 if (recognizer)
2499 [array addObject:recognizer.get()];
2500}
2501
2502- (NSArray<WKDeferringGestureRecognizer *> *)_touchStartDeferringGestures
2503{
2504 RetainPtr recognizers = adoptNS([[NSMutableArray alloc] initWithCapacity:3]);
2505 appendRecognizerIfNonNull(recognizers, _touchStartDeferringGestureRecognizerForImmediatelyResettableGestures);
2506 appendRecognizerIfNonNull(recognizers, _touchStartDeferringGestureRecognizerForDelayedResettableGestures);
2507 appendRecognizerIfNonNull(recognizers, _touchStartDeferringGestureRecognizerForSyntheticTapGestures);
2508 return recognizers.autorelease();
2509}
2510
2511- (NSArray<WKDeferringGestureRecognizer *> *)_touchEndDeferringGestures
2512{
2513 RetainPtr recognizers = adoptNS([[NSMutableArray alloc] initWithCapacity:3]);
2514 appendRecognizerIfNonNull(recognizers, _touchEndDeferringGestureRecognizerForImmediatelyResettableGestures);
2515 appendRecognizerIfNonNull(recognizers, _touchEndDeferringGestureRecognizerForDelayedResettableGestures);
2516 appendRecognizerIfNonNull(recognizers, _touchEndDeferringGestureRecognizerForSyntheticTapGestures);
2517 return recognizers.autorelease();
2518}
2519
2520- (void)_doneDeferringTouchStart:(BOOL)preventNativeGestures
2521{
2522 for (WKDeferringGestureRecognizer *gestureRecognizer in self._touchStartDeferringGestures) {
2523 [gestureRecognizer endDeferral:preventNativeGestures ? WebKit::ShouldPreventGestures::Yes : WebKit::ShouldPreventGestures::No];
2524 if (_failedTouchStartDeferringGestures && !preventNativeGestures)
2525 _failedTouchStartDeferringGestures->add(gestureRecognizer);
2526 }
2527}
2528
2529- (void)_doneDeferringTouchMove:(BOOL)preventNativeGestures
2530{
2531 [_touchMoveDeferringGestureRecognizer endDeferral:preventNativeGestures ? WebKit::ShouldPreventGestures::Yes : WebKit::ShouldPreventGestures::No];
2532}
2533
2534- (void)_doneDeferringTouchEnd:(BOOL)preventNativeGestures
2535{
2536 for (WKDeferringGestureRecognizer *gesture in self._touchEndDeferringGestures)
2537 [gesture endDeferral:preventNativeGestures ? WebKit::ShouldPreventGestures::Yes : WebKit::ShouldPreventGestures::No];
2538}
2539
2540- (BOOL)_isTouchStartDeferringGesture:(WKDeferringGestureRecognizer *)gesture
2541{
2542 return gesture == _touchStartDeferringGestureRecognizerForSyntheticTapGestures || gesture == _touchStartDeferringGestureRecognizerForImmediatelyResettableGestures
2543 || gesture == _touchStartDeferringGestureRecognizerForDelayedResettableGestures;
2544}
2545
2546- (BOOL)_isTouchEndDeferringGesture:(WKDeferringGestureRecognizer *)gesture
2547{
2548 return gesture == _touchEndDeferringGestureRecognizerForSyntheticTapGestures || gesture == _touchEndDeferringGestureRecognizerForImmediatelyResettableGestures
2549 || gesture == _touchEndDeferringGestureRecognizerForDelayedResettableGestures;
2550}
2551
2552static inline WebCore::FloatSize tapHighlightBorderRadius(WebCore::FloatSize borderRadii, CGFloat borderRadiusScale)
2553{
2554 auto inflatedSize = borderRadii * borderRadiusScale;
2555 inflatedSize.expand(minimumTapHighlightRadius, minimumTapHighlightRadius);
2556 return inflatedSize;
2557}
2558
2559- (void)_updateTapHighlight
2560{
2561 if (![_tapHighlightView superview])
2562 return;
2563
2564 [_tapHighlightView setColor:cocoaColor(_tapHighlightInformation.color).get()];
2565
2566 auto& highlightedQuads = _tapHighlightInformation.quads;
2567 bool allRectilinear = true;
2568 for (auto& quad : highlightedQuads) {
2569 if (!quad.isRectilinear()) {
2570 allRectilinear = false;
2571 break;
2572 }
2573 }
2574
2575 auto selfScale = self.layer.transform.m11;
2576 if (allRectilinear) {
2577 float deviceScaleFactor = protect(_page)->deviceScaleFactor();
2578 auto rects = createNSArray(highlightedQuads, [&] (auto& quad) {
2579 auto boundingBox = quad.boundingBox();
2580 boundingBox.scale(selfScale);
2581 boundingBox.inflate(minimumTapHighlightRadius);
2582 return [NSValue valueWithCGRect:encloseRectToDevicePixels(boundingBox, deviceScaleFactor)];
2583 });
2584 [_tapHighlightView setFrames:highlightedQuads.map([&](auto& quad) {
2585 auto boundingBox = quad.boundingBox();
2586 boundingBox.scale(selfScale);
2587 boundingBox.inflate(minimumTapHighlightRadius);
2588 return boundingBox;
2589 })];
2590 } else {
2591 auto quads = adoptNS([[NSMutableArray alloc] initWithCapacity:highlightedQuads.size() * 4]);
2592 for (auto quad : highlightedQuads) {
2593 quad.scale(selfScale);
2594 auto extendedQuad = inflateQuad(quad, minimumTapHighlightRadius);
2595 [quads addObject:[NSValue valueWithCGPoint:extendedQuad.p1()]];
2596 [quads addObject:[NSValue valueWithCGPoint:extendedQuad.p2()]];
2597 [quads addObject:[NSValue valueWithCGPoint:extendedQuad.p3()]];
2598 [quads addObject:[NSValue valueWithCGPoint:extendedQuad.p4()]];
2599 }
2600
2601 auto inflatedHighlightQuads = highlightedQuads.map([&](auto quad) {
2602 quad.scale(selfScale);
2603 return inflateQuad(quad, minimumTapHighlightRadius);
2604 });
2605 [_tapHighlightView setQuads:WTF::move(inflatedHighlightQuads) boundaryRect:protect(_page)->exposedContentRect()];
2606 }
2607
2608 [_tapHighlightView setCornerRadii:WebCore::CornerRadii {
2609 tapHighlightBorderRadius(_tapHighlightInformation.topLeftRadius, selfScale),
2610 tapHighlightBorderRadius(_tapHighlightInformation.topRightRadius, selfScale),
2611 tapHighlightBorderRadius(_tapHighlightInformation.bottomLeftRadius, selfScale),
2612 tapHighlightBorderRadius(_tapHighlightInformation.bottomRightRadius, selfScale)
2613 }];
2614}
2615
2616- (CGRect)tapHighlightViewRect
2617{
2618 return [_tapHighlightView frame];
2619}
2620
2621- (UIGestureRecognizer *)imageAnalysisGestureRecognizer
2622{
2623#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
2624 return _imageAnalysisGestureRecognizer.get();
2625#else
2626 return nilnullptr;
2627#endif
2628}
2629
2630- (void)_showTapHighlight
2631{
2632 auto shouldPaintTapHighlight = [&](const WebCore::FloatRect& rect) {
2633#if PLATFORM(MACCATALYST)(defined WTF_PLATFORM_MACCATALYST && WTF_PLATFORM_MACCATALYST
)
2634 UNUSED_PARAM(rect)(void)rect;
2635 return NO__objc_no;
2636#else
2637 if (_tapHighlightInformation.nodeHasBuiltInClickHandling)
2638 return true;
2639
2640 static const float highlightPaintThreshold = 0.3; // 30%
2641 float highlightArea = 0;
2642 for (auto highlightQuad : _tapHighlightInformation.quads) {
2643 auto boundingBox = highlightQuad.boundingBox();
2644 highlightArea += boundingBox.area();
2645 if (boundingBox.width() > (rect.width() * highlightPaintThreshold) || boundingBox.height() > (rect.height() * highlightPaintThreshold))
2646 return false;
2647 }
2648 return highlightArea < rect.area() * highlightPaintThreshold;
2649#endif
2650 };
2651
2652 if (!shouldPaintTapHighlight(protect(_page)->unobscuredContentRect()) && !_showDebugTapHighlightsForFastClicking)
2653 return;
2654
2655 if (!_tapHighlightView) {
2656 _tapHighlightView = adoptNS([[WKTapHighlightView alloc] initWithFrame:CGRectZero]);
2657 [_tapHighlightView setUserInteractionEnabled:NO__objc_no];
2658 [_tapHighlightView setOpaque:NO__objc_no];
2659 [_tapHighlightView setMinimumCornerRadius:minimumTapHighlightRadius];
2660 }
2661 [_tapHighlightView setAlpha:1];
2662 [_interactionViewsContainerView addSubview:_tapHighlightView.get()];
2663 [self _updateTapHighlight];
2664}
2665
2666- (void)_didGetTapHighlightForRequest:(WebKit::TapIdentifier)requestID color:(const WebCore::Color&)color quads:(const Vector<WebCore::FloatQuad>&)highlightedQuads topLeftRadius:(const WebCore::IntSize&)topLeftRadius topRightRadius:(const WebCore::IntSize&)topRightRadius bottomLeftRadius:(const WebCore::IntSize&)bottomLeftRadius bottomRightRadius:(const WebCore::IntSize&)bottomRightRadius nodeHasBuiltInClickHandling:(BOOL)nodeHasBuiltInClickHandling
2667{
2668 if (!_isTapHighlightIDValid || _latestTapID != requestID)
2669 return;
2670
2671 if (self._hasFocusedElement && _positionInformation.elementContext && _positionInformation.elementContext->isSameElement(_focusedElementInformation.elementContext))
2672 return;
2673
2674 _isTapHighlightIDValid = NO__objc_no;
2675
2676 _tapHighlightInformation.quads = highlightedQuads;
2677 _tapHighlightInformation.topLeftRadius = topLeftRadius;
2678 _tapHighlightInformation.topRightRadius = topRightRadius;
2679 _tapHighlightInformation.bottomLeftRadius = bottomLeftRadius;
2680 _tapHighlightInformation.bottomRightRadius = bottomRightRadius;
2681 _tapHighlightInformation.nodeHasBuiltInClickHandling = nodeHasBuiltInClickHandling;
2682 if (_showDebugTapHighlightsForFastClicking)
2683 _tapHighlightInformation.color = [self _tapHighlightColorForFastClick:![_doubleTapGestureRecognizer isEnabled]];
2684 else
2685 _tapHighlightInformation.color = color;
2686
2687 if (_potentialTapInProgress) {
2688 _hasTapHighlightForPotentialTap = YES__objc_yes;
2689 return;
2690 }
2691
2692 [self _showTapHighlight];
2693 if (_isExpectingFastSingleTapCommit) {
2694 [self _finishInteraction];
2695 if (!_potentialTapInProgress)
2696 _isExpectingFastSingleTapCommit = NO__objc_no;
2697 }
2698}
2699
2700- (BOOL)_mayDisableDoubleTapGesturesDuringSingleTap
2701{
2702 return _potentialTapInProgress;
2703}
2704
2705- (void)_disableDoubleTapGesturesDuringTapIfNecessary:(WebKit::TapIdentifier)requestID
2706{
2707 if (_latestTapID != requestID)
2708 return;
2709
2710 [self _setDoubleTapGesturesEnabled:NO__objc_no];
2711}
2712
2713- (void)_handleSmartMagnificationInformationForPotentialTap:(WebKit::TapIdentifier)requestID renderRect:(const WebCore::FloatRect&)renderRect fitEntireRect:(BOOL)fitEntireRect viewportMinimumScale:(double)viewportMinimumScale viewportMaximumScale:(double)viewportMaximumScale nodeIsRootLevel:(BOOL)nodeIsRootLevel nodeIsPluginElement:(BOOL)nodeIsPluginElement
2714{
2715 Ref preferences = _page->preferences();
2716
2717 ASSERT(preferences->fasterClicksEnabled())((void)0);
2718 if (!_potentialTapInProgress)
2719 return;
2720
2721 // We check both the system preference and the page preference, because we only want this
2722 // to apply in "desktop" mode.
2723 if (preferences->preferFasterClickOverDoubleTap() && _page->preferFasterClickOverDoubleTap()) {
2724 RELEASE_LOG(ViewGestures, "Potential tap found an element and fast taps are preferred. Trigger click. (%p, pageProxyID=%llu)", self, _page->identifier().toUInt64())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogViewGestures
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Potential tap found an element and fast taps are preferred. Trigger click. (%p, pageProxyID=%llu)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG155"
) = "Potential tap found an element and fast taps are preferred. Trigger click. (%p, pageProxyID=%llu)"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Potential tap found an element and fast taps are preferred. Trigger click. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64())]; _os_log_impl(&
__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format
(_os_fmt_buf, "Potential tap found an element and fast taps are preferred. Trigger click. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64()), (uint32_t)sizeof(
_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
2725 if (preferences->zoomOnDoubleTapWhenRoot() && nodeIsRootLevel) {
2726 RELEASE_LOG(ViewGestures, "The click handler was on a root-level element, so don't disable double-tap. (%p, pageProxyID=%llu)", self, _page->identifier().toUInt64())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogViewGestures
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("The click handler was on a root-level element, so don't disable double-tap. (%p, pageProxyID=%llu)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG156"
) = "The click handler was on a root-level element, so don't disable double-tap. (%p, pageProxyID=%llu)"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("The click handler was on a root-level element, so don't disable double-tap. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64())]; _os_log_impl(&
__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format
(_os_fmt_buf, "The click handler was on a root-level element, so don't disable double-tap. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64()), (uint32_t)sizeof(
_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
2727 return;
2728 }
2729
2730 if (preferences->alwaysZoomOnDoubleTap()) {
2731 RELEASE_LOG(ViewGestures, "DTTZ is forced on, so don't disable double-tap. (%p, pageProxyID=%llu)", self, _page->identifier().toUInt64())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogViewGestures
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("DTTZ is forced on, so don't disable double-tap. (%p, pageProxyID=%llu)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG157"
) = "DTTZ is forced on, so don't disable double-tap. (%p, pageProxyID=%llu)"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("DTTZ is forced on, so don't disable double-tap. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64())]; _os_log_impl(&
__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format
(_os_fmt_buf, "DTTZ is forced on, so don't disable double-tap. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64()), (uint32_t)sizeof(
_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
2732 return;
2733 }
2734
2735 if (nodeIsPluginElement) {
2736 RELEASE_LOG(ViewGestures, "The click handler was on a plugin element, so don't disable double-tap. (%p, pageProxyID=%llu)", self, _page->identifier().toUInt64())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogViewGestures
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("The click handler was on a plugin element, so don't disable double-tap. (%p, pageProxyID=%llu)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG158"
) = "The click handler was on a plugin element, so don't disable double-tap. (%p, pageProxyID=%llu)"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("The click handler was on a plugin element, so don't disable double-tap. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64())]; _os_log_impl(&
__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format
(_os_fmt_buf, "The click handler was on a plugin element, so don't disable double-tap. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64()), (uint32_t)sizeof(
_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
2737 return;
2738 }
2739
2740 RELEASE_LOG(ViewGestures, "Give preference to click by disabling double-tap. (%p, pageProxyID=%llu)", self, _page->identifier().toUInt64())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogViewGestures
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Give preference to click by disabling double-tap. (%p, pageProxyID=%llu)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG159"
) = "Give preference to click by disabling double-tap. (%p, pageProxyID=%llu)"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Give preference to click by disabling double-tap. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64())]; _os_log_impl(&
__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format
(_os_fmt_buf, "Give preference to click by disabling double-tap. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64()), (uint32_t)sizeof(
_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
2741 [self _setDoubleTapGesturesEnabled:NO__objc_no];
2742 return;
2743 }
2744
2745 auto currentScale = self._contentZoomScale;
2746 auto targetScale = protect(_smartMagnificationController)->zoomFactorForTargetRect(renderRect, fitEntireRect, viewportMinimumScale, viewportMaximumScale);
2747 if (std::min(targetScale, currentScale) / std::max(targetScale, currentScale) > fasterTapSignificantZoomThreshold) {
2748 RELEASE_LOG(ViewGestures, "Potential tap would not cause a significant zoom. Trigger click. (%p, pageProxyID=%llu)", self, _page->identifier().toUInt64())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogViewGestures
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Potential tap would not cause a significant zoom. Trigger click. (%p, pageProxyID=%llu)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG160"
) = "Potential tap would not cause a significant zoom. Trigger click. (%p, pageProxyID=%llu)"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Potential tap would not cause a significant zoom. Trigger click. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64())]; _os_log_impl(&
__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format
(_os_fmt_buf, "Potential tap would not cause a significant zoom. Trigger click. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64()), (uint32_t)sizeof(
_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
2749 [self _setDoubleTapGesturesEnabled:NO__objc_no];
2750 return;
2751 }
2752 RELEASE_LOG(ViewGestures, "Potential tap may cause significant zoom. Wait. (%p, pageProxyID=%llu)", self, _page->identifier().toUInt64())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogViewGestures
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Potential tap may cause significant zoom. Wait. (%p, pageProxyID=%llu)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG161"
) = "Potential tap may cause significant zoom. Wait. (%p, pageProxyID=%llu)"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Potential tap may cause significant zoom. Wait. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64())]; _os_log_impl(&
__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format
(_os_fmt_buf, "Potential tap may cause significant zoom. Wait. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64()), (uint32_t)sizeof(
_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
2753}
2754
2755- (void)_cancelLongPressGestureRecognizer
2756{
2757 [_highlightLongPressGestureRecognizer cancel];
2758}
2759
2760- (void)_cancelTouchEventGestureRecognizer
2761{
2762 [_touchEventGestureRecognizer cancel];
2763}
2764
2765- (void)_didScroll
2766{
2767 [self _updateFrameOfContainerForContextMenuHintPreviewsIfNeeded];
2768
2769 [self _cancelLongPressGestureRecognizer];
2770 [self _cancelInteraction];
2771}
2772
2773- (void)_scrollingNodeScrollingWillBegin:(std::optional<WebCore::ScrollingNodeID>)scrollingNodeID
2774{
2775 [_textInteractionWrapper willStartScrollingOverflow:[self _scrollViewForScrollingNodeID:scrollingNodeID]];
2776}
2777
2778- (void)_scrollingNodeScrollingDidEnd:(std::optional<WebCore::ScrollingNodeID>)scrollingNodeID
2779{
2780 if (auto& state = protect(_page)->editorState(); state.hasVisualData() && scrollingNodeID && scrollingNodeID == state.visualData->enclosingScrollingNodeID) {
2781 protect(_page)->scheduleFullEditorStateUpdate();
2782 _waitingForEditorStateAfterScrollingSelectionContainer = YES__objc_yes;
2783 protect(_page)->callAfterNextPresentationUpdate([weakSelf = WeakObjCPtr<WKContentView>(self)] {
2784 if (auto strongSelf = weakSelf.get())
2785 strongSelf->_waitingForEditorStateAfterScrollingSelectionContainer = NO__objc_no;
2786 });
2787 }
2788
2789 // If scrolling ends before we've received a selection update,
2790 // we postpone showing the selection until the update is received.
2791 if (!_selectionNeedsUpdate) {
2792 _shouldRestoreSelection = YES__objc_yes;
2793 return;
2794 }
2795 [self _updateChangedSelection];
2796 [_textInteractionWrapper didEndScrollingOverflow];
2797
2798 [_webView.get() _didFinishScrolling:[self _scrollViewForScrollingNodeID:scrollingNodeID]];
2799}
2800
2801- (BOOL)shouldShowAutomaticKeyboardUI
2802{
2803 if (_focusedElementInformation.inputMode == WebCore::InputMode::None)
2804 return NO__objc_no;
2805
2806 if (_focusedElementInformation.isFocusingWithDataListDropdown && !UIKeyboard.isInHardwareKeyboardMode)
2807 return NO__objc_no;
2808
2809 return [self _shouldShowAutomaticKeyboardUIIgnoringInputMode];
2810}
2811
2812- (BOOL)_shouldShowAutomaticKeyboardUIIgnoringInputMode
2813{
2814 if (_focusedElementInformation.isReadOnly)
2815 return NO__objc_no;
2816
2817 switch (_focusedElementInformation.elementType) {
2818 case WebKit::InputType::None:
2819 case WebKit::InputType::Color:
2820 case WebKit::InputType::Drawing:
2821 case WebKit::InputType::Date:
2822 case WebKit::InputType::Month:
2823 case WebKit::InputType::DateTimeLocal:
2824 case WebKit::InputType::Time:
2825#if ENABLE(INPUT_TYPE_WEEK_PICKER)(defined 1 && 1)
2826 case WebKit::InputType::Week:
2827#endif
2828 return NO__objc_no;
2829 case WebKit::InputType::Select: {
2830 if (self._shouldUseContextMenusForFormControls)
2831 return NO__objc_no;
2832 return PAL::currentUserInterfaceIdiomIsSmallScreen();
2833 }
2834 default:
2835 return YES__objc_yes;
2836 }
2837 return NO__objc_no;
2838}
2839
2840- (BOOL)_disableAutomaticKeyboardUI
2841{
2842 // Always enable automatic keyboard UI if we are not the first responder to avoid
2843 // interfering with other focused views (e.g. Find-in-page).
2844 return [self isFirstResponder] && ![self shouldShowAutomaticKeyboardUI];
2845}
2846
2847- (BOOL)_requiresKeyboardWhenFirstResponder
2848{
2849 BOOL webViewIsEditable = [_webView.get() _isEditable];
2850#if USE(BROWSERENGINEKIT)(defined 1 && 1)
2851 if (!webViewIsEditable && self.shouldUseAsyncInteractions)
2852 return [super _requiresKeyboardWhenFirstResponder];
2853#endif
2854
2855 if (webViewIsEditable && !self._disableAutomaticKeyboardUI)
2856 return YES__objc_yes;
2857
2858 // FIXME: We should add the logic to handle keyboard visibility during focus redirects.
2859 return [self _shouldShowAutomaticKeyboardUIIgnoringInputMode] || _seenHardwareKeyDownInNonEditableElement;
2860}
2861
2862- (BOOL)_requiresKeyboardResetOnReload
2863{
2864#if USE(BROWSERENGINEKIT)(defined 1 && 1)
2865 if (self.shouldUseAsyncInteractions)
2866 return [super _requiresKeyboardResetOnReload];
2867#endif
2868
2869 return YES__objc_yes;
2870}
2871
2872- (WebCore::FloatRect)rectToRevealWhenZoomingToFocusedElement
2873{
2874 WebCore::IntRect elementInteractionRect;
2875 if (_focusedElementInformation.interactionRect.contains(_focusedElementInformation.lastInteractionLocation))
2876 elementInteractionRect = { _focusedElementInformation.lastInteractionLocation, { 1, 1 } };
2877
2878 if (!mayContainSelectableText(_focusedElementInformation.elementType))
2879 return elementInteractionRect;
2880
2881 if (!protect(_page)->editorState().hasPostLayoutAndVisualData())
2882 return elementInteractionRect;
2883
2884 auto boundingRect = protect(_page)->selectionBoundingRectInRootViewCoordinates();
2885 boundingRect.intersect(_focusedElementInformation.interactionRect);
2886 return boundingRect;
2887}
2888
2889- (void)_keyboardWillShow
2890{
2891 _waitingForKeyboardAppearanceAnimationToStart = NO__objc_no;
2892
2893 if (_revealFocusedElementDeferrer)
2894 protect(_revealFocusedElementDeferrer)->fulfill(WebKit::RevealFocusedElementDeferralReason::KeyboardWillShow);
2895}
2896
2897- (void)_keyboardDidShow
2898{
2899 // FIXME: This deferred call to -_zoomToRevealFocusedElement works around the fact that Mail compose
2900 // disables automatic content inset adjustment using the keyboard height, and instead has logic to
2901 // explicitly set WKScrollView's contentScrollInset after receiving UIKeyboardDidShowNotification.
2902 // This means that if we -_zoomToRevealFocusedElement immediately after focusing the body field in
2903 // Mail, we won't take the keyboard height into account when scrolling.
2904 // Mitigate this by deferring the call to -_zoomToRevealFocusedElement in this case until after the
2905 // keyboard has finished animating. We can revert this once rdar://87733414 is fixed.
2906 RunLoop::mainSingleton().dispatch([weakSelf = WeakObjCPtr<WKContentView>(self)] {
2907 auto strongSelf = weakSelf.get();
2908 if (!strongSelf || !strongSelf->_revealFocusedElementDeferrer)
2909 return;
2910
2911 protect(strongSelf->_revealFocusedElementDeferrer)->fulfill(WebKit::RevealFocusedElementDeferralReason::KeyboardDidShow);
2912 });
2913
2914#if USE(UICONTEXTMENU)(defined 1 && 1)
2915 [_fileUploadPanel repositionContextMenuIfNeeded:WebKit::KeyboardIsDismissing::No];
2916#endif
2917}
2918
2919- (void)_zoomToRevealFocusedElement
2920{
2921 _revealFocusedElementDeferrer = nullptr;
2922
2923 if (_focusedElementInformation.preventScroll)
2924 return;
2925
2926 if (_suppressSelectionAssistantReasons || _activeTextInteractionCount)
2927 return;
2928
2929 // In case user scaling is force enabled, do not use that scaling when zooming in with an input field.
2930 // Zooming above the page's default scale factor should only happen when the user performs it.
2931 [self _zoomToFocusRect:_focusedElementInformation.interactionRect
2932 selectionRect:_didAccessoryTabInitiateFocus ? WebCore::FloatRect() : self.rectToRevealWhenZoomingToFocusedElement
2933 fontSize:_focusedElementInformation.nodeFontSize
2934 minimumScale:_focusedElementInformation.minimumScaleFactor
2935 maximumScale:_focusedElementInformation.maximumScaleFactorIgnoringAlwaysScalable
2936 allowScaling:_focusedElementInformation.allowsUserScalingIgnoringAlwaysScalable && PAL::currentUserInterfaceIdiomIsSmallScreen()
2937 forceScroll:[self requiresAccessoryView]];
2938}
2939
2940- (UIView *)inputView
2941{
2942 return [_webView.get() inputView];
2943}
2944
2945- (UIView *)inputViewForWebView
2946{
2947 if (!self._hasFocusedElement)
2948 return nilnullptr;
2949
2950 if (_inputPeripheral) {
2951 // FIXME: UIKit may invoke -[WKContentView inputView] at any time when WKContentView is the first responder;
2952 // as such, it doesn't make sense to change the enclosing scroll view's zoom scale and content offset to reveal
2953 // the focused element here. It seems this behavior was added to match logic in legacy WebKit (refer to
2954 // UIWebBrowserView). Instead, we should find the places where we currently assume that UIKit (or other clients)
2955 // invoke -inputView to zoom to the focused element, and either surface SPI for clients to zoom to the focused
2956 // element, or explicitly trigger the zoom from WebKit.
2957 // For instance, one use case that currently relies on this detail is adjusting the zoom scale and viewport upon
2958 // rotation, when a select element is focused. See <https://webkit.org/b/192878> for more information.
2959 [self _zoomToRevealFocusedElement];
2960
2961 [self _updateAccessory];
2962 }
2963
2964 if (UIView *customInputView = [_formInputSession customInputView])
2965 return customInputView;
2966
2967 if (_dataListTextSuggestionsInputView)
2968 return _dataListTextSuggestionsInputView.get();
2969
2970 return [_inputPeripheral assistantView];
2971}
2972
2973- (CGRect)_selectionClipRect
2974{
2975 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG162"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(2975, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
2976
2977 return self.selectionClipRect;
2978}
2979
2980static BOOL isBuiltInScrollViewPanGestureRecognizer(UIGestureRecognizer *recognizer)
2981{
2982 static Class scrollViewPanGestureClass = NSClassFromString(@"UIScrollViewPanGestureRecognizer");
2983 return [recognizer isKindOfClass:scrollViewPanGestureClass];
2984}
2985
2986static BOOL isBuiltInScrollViewGestureRecognizer(UIGestureRecognizer *recognizer)
2987{
2988 static Class scrollViewPinchGestureClass = NSClassFromString(@"UIScrollViewPinchGestureRecognizer");
2989 static Class scrollViewKnobLongPressGestureRecognizerClass = NSClassFromString(@"UIScrollViewKnobLongPressGestureRecognizer");
2990 return isBuiltInScrollViewPanGestureRecognizer(recognizer)
2991 || [recognizer isKindOfClass:scrollViewPinchGestureClass]
2992 || [recognizer isKindOfClass:scrollViewKnobLongPressGestureRecognizerClass];
2993}
2994
2995- (BOOL)_isContextMenuGestureRecognizerForFailureRelationships:(UIGestureRecognizer *)gestureRecognizer
2996{
2997 return [gestureRecognizer.name isEqualToString:@"com.apple.UIKit.clickPresentationFailure"] && gestureRecognizer.view == self;
2998}
2999
3000#if ENABLE(DRAG_SUPPORT)(defined 1 && 1)
3001
3002- (BOOL)_isDragInitiationGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
3003{
3004 if (!_dragInteraction)
3005 return NO__objc_no;
3006
3007 id gestureDelegate = gestureRecognizer.delegate;
3008 if (![gestureDelegate respondsToSelector:@selector(delegate)])
3009 return NO__objc_no;
3010
3011 return _dragInteraction == [gestureDelegate delegate];
3012}
3013
3014#endif // ENABLE(DRAG_SUPPORT)
3015
3016- (BOOL)gestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer
3017{
3018 // A long-press gesture can not be recognized while panning, but a pan can be recognized
3019 // during a long-press gesture.
3020 BOOL shouldNotPreventScrollViewGestures = preventingGestureRecognizer == _highlightLongPressGestureRecognizer || preventingGestureRecognizer == _longPressGestureRecognizer;
3021
3022 return !(shouldNotPreventScrollViewGestures && isBuiltInScrollViewGestureRecognizer(preventedGestureRecognizer));
3023}
3024
3025- (BOOL)gestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer
3026{
3027 if (preventingGestureRecognizer._wk_isTextInteractionLoupeGesture && (preventedGestureRecognizer == _highlightLongPressGestureRecognizer || preventedGestureRecognizer == _longPressGestureRecognizer)) {
3028#if PLATFORM(MACCATALYST)(defined WTF_PLATFORM_MACCATALYST && WTF_PLATFORM_MACCATALYST
)
3029 return YES__objc_yes;
3030#else
3031 return NO__objc_no;
3032#endif
3033 }
3034
3035 return YES__objc_yes;
3036}
3037
3038- (UIGestureRecognizer *)textInteractionLoupeGestureRecognizer
3039{
3040 if (protect(_cachedTextInteractionLoupeGestureRecognizer).get().view != self) {
3041 _cachedTextInteractionLoupeGestureRecognizer = nilnullptr;
3042 for (UIGestureRecognizer *gestureRecognizer in self.gestureRecognizers) {
3043 if (gestureRecognizer._wk_isTextInteractionLoupeGesture) {
3044 _cachedTextInteractionLoupeGestureRecognizer = gestureRecognizer;
3045 break;
3046 }
3047 }
3048 }
3049 return _cachedTextInteractionLoupeGestureRecognizer;
3050}
3051
3052- (UIGestureRecognizer *)textInteractionTapGestureRecognizer
3053{
3054 if (protect(_cachedTextInteractionTapGestureRecognizer).get().view != self) {
3055 _cachedTextInteractionTapGestureRecognizer = nilnullptr;
3056 for (UIGestureRecognizer *gestureRecognizer in self.gestureRecognizers) {
3057 if (gestureRecognizer._wk_isTextInteractionTapGesture) {
3058 _cachedTextInteractionTapGestureRecognizer = gestureRecognizer;
3059 break;
3060 }
3061 }
3062 }
3063 return _cachedTextInteractionTapGestureRecognizer;
3064}
3065
3066static inline bool isSamePair(UIGestureRecognizer *a, UIGestureRecognizer *b, UIGestureRecognizer *x, UIGestureRecognizer *y)
3067{
3068 return (a == x && b == y) || (b == x && a == y);
3069}
3070
3071- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
3072{
3073#if ENABLE(GAMEPAD)(defined 1 && 1)
3074 if (gestureRecognizer == _gamepadInteractionGestureRecognizer || otherGestureRecognizer == _gamepadInteractionGestureRecognizer) {
3075 if (WebKit::UIGamepadProvider::singleton().platformWebPageProxyForGamepadInput() == _page)
3076 return NO__objc_no;
3077 }
3078#endif
3079
3080 if (gestureRecognizer == _keyboardDismissalGestureRecognizer || otherGestureRecognizer == _keyboardDismissalGestureRecognizer)
3081 return YES__objc_yes;
3082
3083 for (WKDeferringGestureRecognizer *gesture in self.deferringGestures) {
3084 if (isSamePair(gestureRecognizer, otherGestureRecognizer, _touchEventGestureRecognizer.get(), gesture))
3085 return YES__objc_yes;
3086 }
3087
3088 if ([gestureRecognizer isKindOfClass:WKDeferringGestureRecognizer.class] && [otherGestureRecognizer isKindOfClass:WKDeferringGestureRecognizer.class])
3089 return YES__objc_yes;
3090
3091#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
3092 if (gestureRecognizer == _imageAnalysisDeferringGestureRecognizer)
3093 return ![self shouldDeferGestureDueToImageAnalysis:otherGestureRecognizer];
3094
3095 if (otherGestureRecognizer == _imageAnalysisDeferringGestureRecognizer)
3096 return ![self shouldDeferGestureDueToImageAnalysis:gestureRecognizer];
3097#endif
3098
3099 if (gestureRecognizer == _singleTapGestureRecognizer
3100 && isBuiltInScrollViewPanGestureRecognizer(otherGestureRecognizer)
3101 && [otherGestureRecognizer.view isKindOfClass:UIScrollView.class]
3102 && ![self _isInterruptingDecelerationForScrollViewOrAncestor:[_singleTapGestureRecognizer lastTouchedScrollView]])
3103 return YES__objc_yes;
3104
3105 if (isSamePair(gestureRecognizer, otherGestureRecognizer, _highlightLongPressGestureRecognizer.get(), _longPressGestureRecognizer.get()))
3106 return YES__objc_yes;
3107
3108#if HAVE(UIKIT_WITH_MOUSE_SUPPORT)(defined 1 && 1)
3109 if ([_mouseInteraction hasGesture:otherGestureRecognizer])
3110 return YES__objc_yes;
3111#endif
3112
3113#if PLATFORM(MACCATALYST)(defined WTF_PLATFORM_MACCATALYST && WTF_PLATFORM_MACCATALYST
)
3114 if ((gestureRecognizer == _singleTapGestureRecognizer && otherGestureRecognizer._wk_isTextInteractionLoupeGesture)
3115 || (otherGestureRecognizer == _singleTapGestureRecognizer && gestureRecognizer._wk_isTextInteractionLoupeGesture))
3116 return YES__objc_yes;
3117
3118 if (([gestureRecognizer isKindOfClass:[_UILookupGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) || ([otherGestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]] && [gestureRecognizer isKindOfClass:[_UILookupGestureRecognizer class]]))
3119 return YES__objc_yes;
3120#endif // PLATFORM(MACCATALYST)
3121
3122 if (gestureRecognizer == _highlightLongPressGestureRecognizer.get() || otherGestureRecognizer == _highlightLongPressGestureRecognizer.get()) {
3123 if (gestureRecognizer._wk_isTextInteractionLoupeGesture || otherGestureRecognizer._wk_isTextInteractionLoupeGesture)
3124 return YES__objc_yes;
3125
3126 if (gestureRecognizer._wk_isTapAndAHalf || otherGestureRecognizer._wk_isTapAndAHalf)
3127 return YES__objc_yes;
3128 }
3129
3130 if ((gestureRecognizer == _singleTapGestureRecognizer && otherGestureRecognizer._wk_isTextInteractionTapGesture)
3131 || (otherGestureRecognizer == _singleTapGestureRecognizer && gestureRecognizer._wk_isTextInteractionTapGesture))
3132 return YES__objc_yes;
3133
3134#if ENABLE(MODEL_PROCESS)(defined 0 && 0)
3135 if (isSamePair(gestureRecognizer, otherGestureRecognizer, _modelInteractionPanGestureRecognizer.get(), _longPressGestureRecognizer.get()))
3136 return YES__objc_yes;
3137
3138 if (isSamePair(gestureRecognizer, otherGestureRecognizer, _modelInteractionPanGestureRecognizer.get(), _nonBlockingDoubleTapGestureRecognizer.get()))
3139 return YES__objc_yes;
3140
3141 if (isSamePair(gestureRecognizer, otherGestureRecognizer, _modelInteractionPanGestureRecognizer.get(), _singleTapGestureRecognizer.get()))
3142 return YES__objc_yes;
3143
3144 if (isSamePair(gestureRecognizer, otherGestureRecognizer, _modelInteractionPanGestureRecognizer.get(), _previewGestureRecognizer.get()))
3145 return YES__objc_yes;
3146#endif
3147
3148 if (isSamePair(gestureRecognizer, otherGestureRecognizer, _singleTapGestureRecognizer.get(), _nonBlockingDoubleTapGestureRecognizer.get()))
3149 return YES__objc_yes;
3150
3151 if (isSamePair(gestureRecognizer, otherGestureRecognizer, _highlightLongPressGestureRecognizer.get(), _nonBlockingDoubleTapGestureRecognizer.get()))
3152 return YES__objc_yes;
3153
3154 if (isSamePair(gestureRecognizer, otherGestureRecognizer, _highlightLongPressGestureRecognizer.get(), _previewSecondaryGestureRecognizer.get()))
3155 return YES__objc_yes;
3156
3157 if (isSamePair(gestureRecognizer, otherGestureRecognizer, _highlightLongPressGestureRecognizer.get(), _previewGestureRecognizer.get()))
3158 return YES__objc_yes;
3159
3160 if (isSamePair(gestureRecognizer, otherGestureRecognizer, _nonBlockingDoubleTapGestureRecognizer.get(), _doubleTapGestureRecognizerForDoubleClick.get()))
3161 return YES__objc_yes;
3162
3163 if (isSamePair(gestureRecognizer, otherGestureRecognizer, _doubleTapGestureRecognizer.get(), _doubleTapGestureRecognizerForDoubleClick.get()))
3164 return YES__objc_yes;
3165
3166#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
3167 if (gestureRecognizer == _imageAnalysisGestureRecognizer)
3168 return YES__objc_yes;
3169#endif
3170
3171#if PLATFORM(VISION)(defined WTF_PLATFORM_VISION && WTF_PLATFORM_VISION)
3172 Class graspGesture = NSClassFromString(@"MRUIGraspGestureRecognizer");
3173 if (([gestureRecognizer isKindOfClass:graspGesture] && otherGestureRecognizer == _singleTapGestureRecognizer.get()) || (gestureRecognizer == _singleTapGestureRecognizer.get() && [otherGestureRecognizer isKindOfClass:graspGesture]))
3174 return YES__objc_yes;
3175#endif
3176
3177 return NO__objc_no;
3178}
3179
3180- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
3181{
3182 if (gestureRecognizer == _touchEventGestureRecognizer && [self _touchEventsMustRequireGestureRecognizerToFail:otherGestureRecognizer])
3183 return YES__objc_yes;
3184
3185 if ([otherGestureRecognizer isKindOfClass:WKDeferringGestureRecognizer.class])
3186 return [(WKDeferringGestureRecognizer *)otherGestureRecognizer shouldDeferGestureRecognizer:gestureRecognizer];
3187
3188 return NO__objc_no;
3189}
3190
3191- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
3192{
3193#if ENABLE(GAMEPAD)(defined 1 && 1)
3194 if (gestureRecognizer == _gamepadInteractionGestureRecognizer || otherGestureRecognizer == _gamepadInteractionGestureRecognizer) {
3195 if (WebKit::UIGamepadProvider::singleton().platformWebPageProxyForGamepadInput() == _page)
3196 return NO__objc_no;
3197 }
3198#endif
3199
3200 if ([gestureRecognizer isKindOfClass:WKDeferringGestureRecognizer.class])
3201 return [(WKDeferringGestureRecognizer *)gestureRecognizer shouldDeferGestureRecognizer:otherGestureRecognizer];
3202
3203 return NO__objc_no;
3204}
3205
3206- (void)_showImageSheet
3207{
3208 [protect(_actionSheetAssistant) showImageSheet];
3209}
3210
3211- (void)_showAttachmentSheet
3212{
3213 RetainPtr uiDelegate = static_cast<id <WKUIDelegatePrivate>>([_webView.get() UIDelegate]);
3214 if (![uiDelegate respondsToSelector:@selector(_webView:showCustomSheetForElement:)])
3215 return;
3216
3217 auto element = adoptNS([[_WKActivatedElementInfo alloc] _initWithType:_WKActivatedElementTypeAttachment image:nilnullptr information:_positionInformation]);
3218ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
3219 [uiDelegate _webView:self.webView showCustomSheetForElement:element.get()];
3220ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
3221}
3222
3223- (void)_showLinkSheet
3224{
3225 [protect(_actionSheetAssistant) showLinkSheet];
3226}
3227
3228- (void)_showDataDetectorsUI
3229{
3230 [self _showDataDetectorsUIForPositionInformation:_positionInformation];
3231}
3232
3233- (void)_showDataDetectorsUIForPositionInformation:(const WebKit::InteractionInformationAtPosition&)positionInformation
3234{
3235 [protect(_actionSheetAssistant) showDataDetectorsUIForPositionInformation:positionInformation];
3236}
3237
3238- (SEL)_actionForLongPressFromPositionInformation:(const WebKit::InteractionInformationAtPosition&)positionInformation
3239{
3240 if (!self.webView.configuration._longPressActionsEnabled)
3241 return nilnullptr;
3242
3243 if (!positionInformation.touchCalloutEnabled)
3244 return nilnullptr;
3245
3246 if (positionInformation.isImage)
3247 return @selector(_showImageSheet);
3248
3249 if (positionInformation.isLink) {
3250#if ENABLE(DATA_DETECTION)(defined 1 && 1)
3251 if (WebCore::DataDetection::canBePresentedByDataDetectors(positionInformation.url))
3252 return @selector(_showDataDetectorsUI);
3253#endif
3254 return @selector(_showLinkSheet);
3255 }
3256 if (positionInformation.isAttachment)
3257 return @selector(_showAttachmentSheet);
3258
3259 return nilnullptr;
3260}
3261
3262- (SEL)_actionForLongPress
3263{
3264 return [self _actionForLongPressFromPositionInformation:_positionInformation];
3265}
3266
3267- (void)doAfterPositionInformationUpdate:(void (^)(WebKit::InteractionInformationAtPosition))action forRequest:(WebKit::InteractionInformationRequest)request
3268{
3269 if ([self _currentPositionInformationIsValidForRequest:request]) {
3270 // If the most recent position information is already valid, invoke the given action block immediately.
3271 action(_positionInformation);
3272 return;
3273 }
3274
3275 _pendingPositionInformationHandlers.append(InteractionInformationRequestAndCallback(request, action));
3276
3277 if (![self _hasValidOutstandingPositionInformationRequest:request])
3278 [self requestAsynchronousPositionInformationUpdate:request];
3279}
3280
3281- (BOOL)ensurePositionInformationIsUpToDate:(WebKit::InteractionInformationRequest)request
3282{
3283 [_webView.get() didEnsurePositionInformationIsUpToDate];
3284 if ([self _currentPositionInformationIsValidForRequest:request])
3285 return YES__objc_yes;
3286
3287 if (!protect(_page)->hasRunningProcess())
3288 return NO__objc_no;
3289
3290 Ref process = _page->legacyMainFrameProcess();
3291 if (!process->hasConnection())
3292 return NO__objc_no;
3293
3294 if (_isWaitingOnPositionInformation)
3295 return NO__objc_no;
3296
3297 _isWaitingOnPositionInformation = YES__objc_yes;
3298
3299 if (![self _hasValidOutstandingPositionInformationRequest:request])
3300 [self requestAsynchronousPositionInformationUpdate:request];
3301
3302 bool receivedResponse = protect(process->connection())->waitForAndDispatchImmediately<Messages::WebPageProxy::DidReceivePositionInformation>(_page->webPageIDInMainFrameProcess(), 1_s, IPC::WaitForOption::InterruptWaitingIfSyncMessageArrives) == IPC::Error::NoError;
3303 _hasValidPositionInformation = receivedResponse && _positionInformation.canBeValid;
3304 return _hasValidPositionInformation;
3305}
3306
3307- (void)requestAsynchronousPositionInformationUpdate:(WebKit::InteractionInformationRequest)request
3308{
3309 if ([self _currentPositionInformationIsValidForRequest:request])
3310 return;
3311
3312 _lastOutstandingPositionInformationRequest = request;
3313
3314 protect(_page)->requestPositionInformation(request);
3315}
3316
3317- (BOOL)_currentPositionInformationIsValidForRequest:(const WebKit::InteractionInformationRequest&)request
3318{
3319 return _hasValidPositionInformation && _positionInformation.request.isValidForRequest(request);
3320}
3321
3322- (BOOL)_hasValidOutstandingPositionInformationRequest:(const WebKit::InteractionInformationRequest&)request
3323{
3324 return _lastOutstandingPositionInformationRequest && _lastOutstandingPositionInformationRequest->isValidForRequest(request);
3325}
3326
3327- (BOOL)_currentPositionInformationIsApproximatelyValidForRequest:(const WebKit::InteractionInformationRequest&)request radiusForApproximation:(int)radius
3328{
3329 return _hasValidPositionInformation && _positionInformation.request.isApproximatelyValidForRequest(request, radius);
3330}
3331
3332- (void)_invokeAndRemovePendingHandlersValidForCurrentPositionInformation
3333{
3334 ASSERT(_hasValidPositionInformation)((void)0);
3335
3336 // FIXME: We need to clean up these handlers in the event that we are not able to collect data, or if the WebProcess crashes.
3337 ++_positionInformationCallbackDepth;
3338 auto updatedPositionInformation = _positionInformation;
3339
3340 for (size_t index = 0; index < _pendingPositionInformationHandlers.size(); ++index) {
3341 auto requestAndHandler = _pendingPositionInformationHandlers[index];
3342 if (!requestAndHandler)
3343 continue;
3344
3345 if (![self _currentPositionInformationIsValidForRequest:requestAndHandler->first])
3346 continue;
3347
3348 _pendingPositionInformationHandlers[index] = std::nullopt;
3349
3350 if (requestAndHandler->second)
3351 requestAndHandler->second(updatedPositionInformation);
3352 }
3353
3354 if (--_positionInformationCallbackDepth)
3355 return;
3356
3357 for (int index = _pendingPositionInformationHandlers.size() - 1; index >= 0; --index) {
3358 if (!_pendingPositionInformationHandlers[index])
3359 _pendingPositionInformationHandlers.removeAt(index);
3360 }
3361}
3362
3363#if ENABLE(DATA_DETECTION)(defined 1 && 1)
3364- (NSArray *)_dataDetectionResults
3365{
3366 return _page->dataDetectionResults();
3367}
3368#endif
3369
3370- (BOOL)_pointIsInsideSelectionRect:(CGPoint)point outBoundingRect:(WebCore::FloatRect *)outBoundingRect
3371{
3372 BOOL pointIsInSelectionRect = NO__objc_no;
3373 for (auto& rectInfo : _lastSelectionDrawingInfo.selectionGeometries) {
3374 auto rect = rectInfo.rect();
3375 if (rect.isEmpty())
3376 continue;
3377
3378 pointIsInSelectionRect |= rect.contains(WebCore::roundedIntPoint(point));
3379 if (outBoundingRect)
3380 outBoundingRect->unite(rect);
3381 }
3382
3383 if (!pointIsInSelectionRect)
3384 return NO__objc_no;
3385
3386 if (!self.selectionHonorsOverflowScrolling)
3387 return YES__objc_yes;
3388
3389 RetainPtr hitView = [self hitTest:point withEvent:nilnullptr];
3390 if (!hitView)
3391 return NO__objc_no;
3392
3393 RetainPtr hitScroller = dynamic_objc_cast<UIScrollView>(hitView.get()) ?: [hitView _wk_parentScrollView];
3394 return hitScroller && hitScroller == self._selectionContainerViewInternal._wk_parentScrollView;
3395}
3396
3397- (BOOL)_shouldToggleEditMenuAfterTapAt:(CGPoint)point
3398{
3399 if (_lastSelectionDrawingInfo.selectionGeometries.isEmpty())
3400 return NO__objc_no;
3401
3402 WebCore::FloatRect selectionBoundingRect;
3403 BOOL pointIsInSelectionRect = [self _pointIsInsideSelectionRect:point outBoundingRect:&selectionBoundingRect];
3404 WebCore::FloatRect unobscuredContentRect = self.unobscuredContentRect;
3405 selectionBoundingRect.intersect(unobscuredContentRect);
3406
3407 float unobscuredArea = unobscuredContentRect.area();
3408 float ratioForConsideringSelectionRectToCoverVastMajorityOfContent = 0.75;
3409 if (!unobscuredArea || selectionBoundingRect.area() / unobscuredArea > ratioForConsideringSelectionRectToCoverVastMajorityOfContent)
3410 return NO__objc_no;
3411
3412 return pointIsInSelectionRect;
3413}
3414
3415- (BOOL)_hasEnclosingScrollView:(UIView *)firstView matchingCriteria:(Function<BOOL(UIScrollView *)>&&)matchFunction
3416{
3417 RetainPtr view = firstView ?: self.webView.scrollView;
3418 for (; view; view = view.get().superview) {
3419 if (RetainPtr scrollView = dynamic_objc_cast<UIScrollView>(view.get()); scrollView && matchFunction(scrollView.get()))
3420 return YES__objc_yes;
3421 }
3422 return NO__objc_no;
3423}
3424
3425- (BOOL)_isPanningScrollViewOrAncestor:(UIScrollView *)scrollView
3426{
3427 return [self _hasEnclosingScrollView:scrollView matchingCriteria:[](UIScrollView *scrollView) {
3428 if (scrollView.dragging || scrollView.decelerating)
3429 return YES__objc_yes;
3430
3431 auto *panGesture = scrollView.panGestureRecognizer;
3432 ASSERT(panGesture)((void)0);
3433 return [panGesture _wk_hasRecognizedOrEnded];
3434 }];
3435}
3436
3437- (BOOL)_isInterruptingDecelerationForScrollViewOrAncestor:(UIScrollView *)scrollView
3438{
3439 return [self _hasEnclosingScrollView:scrollView matchingCriteria:[](UIScrollView *scrollView) {
3440 return scrollView._wk_isInterruptingDeceleration;
3441 }];
3442}
3443
3444- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
3445{
3446 CGPoint point = [gestureRecognizer locationInView:self];
3447
3448 auto ignoreTapGestureReason = [&](WKScrollViewTrackingTapGestureRecognizer *tapGesture) -> WebKit::IgnoreTapGestureReason {
3449 if ([self _shouldToggleEditMenuAfterTapAt:point])
3450 return WebKit::IgnoreTapGestureReason::ToggleEditMenu;
3451
3452 RetainPtr scrollView = [tapGesture lastTouchedScrollView];
3453 if ([self _isPanningScrollViewOrAncestor:scrollView.get()] || [self _isInterruptingDecelerationForScrollViewOrAncestor:scrollView.get()])
3454 return WebKit::IgnoreTapGestureReason::DeferToScrollView;
3455
3456 return WebKit::IgnoreTapGestureReason::None;
3457 };
3458
3459 if (gestureRecognizer == _singleTapGestureRecognizer) {
3460 switch (ignoreTapGestureReason(_singleTapGestureRecognizer.get())) {
3461 case WebKit::IgnoreTapGestureReason::ToggleEditMenu:
3462 protect(_page)->clearSelectionAfterTappingSelectionHighlightIfNeeded(point);
3463 [[fallthrough]];
3464 case WebKit::IgnoreTapGestureReason::DeferToScrollView:
3465 return NO__objc_no;
3466 case WebKit::IgnoreTapGestureReason::None:
3467 return YES__objc_yes;
3468 }
3469 }
3470
3471#if ENABLE(MODEL_PROCESS)(defined 0 && 0)
3472 if (gestureRecognizer == _modelInteractionPanGestureRecognizer) {
3473 if (!_page->hasModelElement())
3474 return NO__objc_no;
3475
3476 WebKit::InteractionInformationRequest request(WebCore::roundedIntPoint(point));
3477 if (![self ensurePositionInformationIsUpToDate:request])
3478 return NO__objc_no;
3479
3480 if (self._hasFocusedElement) {
3481 // Prevent the gesture if it is the same node.
3482 if (_positionInformation.elementContext && _positionInformation.elementContext->isSameElement(_focusedElementInformation.elementContext))
3483 return NO__objc_no;
3484 } else {
3485 // Prevent the gesture if there is no action for the node.
3486 return _positionInformation.isInteractiveModel;
3487 }
3488 }
3489#endif
3490
3491 if (gestureRecognizer == _keyboardDismissalGestureRecognizer) {
3492 auto tapIsInEditableRoot = [&] {
3493 auto& state = protect(_page)->editorState();
3494 return state.hasVisualData() && state.visualData->editableRootBounds.contains(WebCore::roundedIntPoint(point));
3495 };
3496 return self._hasFocusedElement
3497 && !self.hasHiddenContentEditable
3498 && !tapIsInEditableRoot()
3499 && ignoreTapGestureReason(_keyboardDismissalGestureRecognizer.get()) == WebKit::IgnoreTapGestureReason::None;
3500 }
3501
3502 if (gestureRecognizer == _doubleTapGestureRecognizerForDoubleClick) {
3503 // Do not start the double-tap-for-double-click gesture recognizer unless we've got a dblclick event handler on the node at the tap location.
3504 WebKit::InteractionInformationRequest request(WebCore::roundedIntPoint(point));
3505 if (![self _currentPositionInformationIsApproximatelyValidForRequest:request radiusForApproximation:[_doubleTapGestureRecognizerForDoubleClick allowableMovement]]) {
3506 if (![self ensurePositionInformationIsUpToDate:request])
3507 return NO__objc_no;
3508 }
3509 return _positionInformation.hitNodeOrWindowHasDoubleClickListener.value_or(false);
3510 }
3511
3512 if (gestureRecognizer == _highlightLongPressGestureRecognizer
3513 || gestureRecognizer == _doubleTapGestureRecognizer
3514 || gestureRecognizer == _nonBlockingDoubleTapGestureRecognizer
3515 || gestureRecognizer == _twoFingerDoubleTapGestureRecognizer) {
3516
3517 if (self._hasFocusedElement) {
3518 // Request information about the position with sync message.
3519 // If the focused element is the same, prevent the gesture.
3520 if (![self ensurePositionInformationIsUpToDate:WebKit::InteractionInformationRequest(WebCore::roundedIntPoint(point))])
3521 return NO__objc_no;
3522 if (_positionInformation.elementContext && _positionInformation.elementContext->isSameElement(_focusedElementInformation.elementContext))
3523 return NO__objc_no;
3524 }
3525 }
3526
3527 if (gestureRecognizer == _highlightLongPressGestureRecognizer) {
3528 if ([self _isInterruptingDecelerationForScrollViewOrAncestor:[_highlightLongPressGestureRecognizer lastTouchedScrollView]])
3529 return NO__objc_no;
3530
3531 if (self._hasFocusedElement) {
3532 // This is a different element than the focused one.
3533 // Prevent the gesture if there is no node.
3534 // Allow the gesture if it is a node that wants highlight or if there is an action for it.
3535 if (!_positionInformation.isElement)
3536 return NO__objc_no;
3537 return [self _actionForLongPress] != nilnullptr;
3538 }
3539 // We still have no idea about what is at the location.
3540 // Send an async message to find out.
3541 _hasValidPositionInformation = NO__objc_no;
3542 WebKit::InteractionInformationRequest request(WebCore::roundedIntPoint(point));
3543
3544 // If 3D Touch is enabled, asynchronously collect snapshots in the hopes that
3545 // they'll arrive before we have to synchronously request them in
3546 // _interactionShouldBeginFromPreviewItemController.
3547 if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {
3548 request.includeSnapshot = true;
3549 request.includeLinkIndicator = true;
3550 request.linkIndicatorShouldHaveLegacyMargins = !self._shouldUseContextMenus;
3551 request.gatherAnimations = [self.webView _allowAnimationControls];
3552 }
3553
3554 [self requestAsynchronousPositionInformationUpdate:request];
3555 return YES__objc_yes;
3556
3557 }
3558
3559 if (gestureRecognizer == _longPressGestureRecognizer) {
3560 // Use the information retrieved with one of the previous calls
3561 // to gestureRecognizerShouldBegin.
3562 // Force a sync call if not ready yet.
3563 WebKit::InteractionInformationRequest request(WebCore::roundedIntPoint(point));
3564 if (![self ensurePositionInformationIsUpToDate:request])
3565 return NO__objc_no;
3566
3567 if (self._hasFocusedElement) {
3568 // Prevent the gesture if it is the same node.
3569 if (_positionInformation.elementContext && _positionInformation.elementContext->isSameElement(_focusedElementInformation.elementContext))
3570 return NO__objc_no;
3571 } else {
3572 // Prevent the gesture if there is no action for the node.
3573 return [self _actionForLongPress] != nilnullptr;
3574 }
3575 }
3576
3577 return YES__objc_yes;
3578}
3579
3580- (void)_cancelInteraction
3581{
3582 _isTapHighlightIDValid = NO__objc_no;
3583 [_tapHighlightView removeFromSuperview];
3584}
3585
3586- (void)_finishInteraction
3587{
3588 _isTapHighlightIDValid = NO__objc_no;
3589 [self _fadeTapHighlightViewIfNeeded];
3590}
3591
3592- (void)_fadeTapHighlightViewIfNeeded
3593{
3594 if (![_tapHighlightView superview] || _isTapHighlightFading)
3595 return;
3596
3597 _isTapHighlightFading = YES__objc_yes;
3598 CGFloat tapHighlightFadeDuration = _showDebugTapHighlightsForFastClicking ? 0.25 : 0.1;
3599 [UIView animateWithDuration:tapHighlightFadeDuration
3600 animations:^{
3601 [_tapHighlightView setAlpha:0];
3602 }
3603 completion:^(BOOL finished) {
3604 if (finished)
3605 [_tapHighlightView removeFromSuperview];
3606 _isTapHighlightFading = NO__objc_no;
3607 }];
3608}
3609
3610- (BOOL)canShowNonEmptySelectionView
3611{
3612 if (_suppressSelectionAssistantReasons)
3613 return NO__objc_no;
3614
3615 auto& state = protect(_page)->editorState();
3616 return state.hasPostLayoutData() && state.selectionType != WebCore::SelectionType::None;
3617}
3618
3619- (BOOL)hasSelectablePositionAtPoint:(CGPoint)point
3620{
3621#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
3622 if ([_imageAnalysisInteraction interactableItemExistsAtPoint:point])
3623 return NO__objc_no;
3624#endif
3625
3626ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
3627 if (!self.webView.configuration._textInteractionGesturesEnabled)
3628 return NO__objc_no;
3629ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
3630
3631 if (!protect(_page->preferences())->textInteractionEnabled())
3632 return NO__objc_no;
3633
3634 if (_suppressSelectionAssistantReasons)
3635 return NO__objc_no;
3636
3637 if (_inspectorNodeSearchEnabled)
3638 return NO__objc_no;
3639
3640 WebKit::InteractionInformationRequest request(WebCore::roundedIntPoint(point));
3641 if (![self ensurePositionInformationIsUpToDate:request])
3642 return NO__objc_no;
3643
3644#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
3645 if (_elementPendingImageAnalysis && _positionInformation.hostImageOrVideoElementContext == _elementPendingImageAnalysis)
3646 return YES__objc_yes;
3647#endif
3648
3649 return _positionInformation.isSelectable();
3650}
3651
3652- (BOOL)pointIsNearMarkedText:(CGPoint)point
3653{
3654#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
3655 if ([_imageAnalysisInteraction interactableItemExistsAtPoint:point])
3656 return NO__objc_no;
3657#endif
3658
3659ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
3660 if (!self.webView.configuration._textInteractionGesturesEnabled)
3661 return NO__objc_no;
3662ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
3663
3664 if (!protect(_page->preferences())->textInteractionEnabled())
3665 return NO__objc_no;
3666
3667 if (_suppressSelectionAssistantReasons)
3668 return NO__objc_no;
3669
3670 WebKit::InteractionInformationRequest request(WebCore::roundedIntPoint(point));
3671 if (![self ensurePositionInformationIsUpToDate:request])
3672 return NO__objc_no;
3673 return _positionInformation.isNearMarkedText;
3674}
3675
3676- (BOOL)textInteractionGesture:(WKBEGestureTypeBEGestureType)gesture shouldBeginAtPoint:(CGPoint)point
3677{
3678#if USE(BROWSERENGINEKIT)(defined 1 && 1)
3679 if (gesture == WKBEGestureTypeForceTouchBEGestureTypeForceTouch)
3680 return [self hasSelectablePositionAtPoint:point];
3681#endif
3682
3683#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
3684 if ([_imageAnalysisInteraction interactableItemExistsAtPoint:point])
3685 return NO__objc_no;
3686#endif
3687
3688ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
3689 if (!self.webView.configuration._textInteractionGesturesEnabled)
3690 return NO__objc_no;
3691ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
3692
3693 if (!protect(_page->preferences())->textInteractionEnabled())
3694 return NO__objc_no;
3695
3696 if (_domPasteRequestHandler)
3697 return NO__objc_no;
3698
3699 if (_suppressSelectionAssistantReasons)
3700 return NO__objc_no;
3701
3702 if (!self.isFocusingElement) {
3703 if (gesture == WKBEGestureTypeDoubleTapBEGestureTypeDoubleTap) {
3704 // Don't allow double tap text gestures in noneditable content.
3705 return NO__objc_no;
3706 }
3707
3708 if (gesture == WKBEGestureTypeOneFingerTapBEGestureTypeOneFingerTap) {
3709 ASSERT(_suppressNonEditableSingleTapTextInteractionCount >= 0)((void)0);
3710 if (_suppressNonEditableSingleTapTextInteractionCount > 0)
3711 return NO__objc_no;
3712
3713 if (self.textInteractionLoupeGestureRecognizer._wk_hasRecognizedOrEnded) {
3714 // Avoid handling one-finger taps while the web process is processing certain selection changes.
3715 // This works around a scenario where UIKeyboardImpl blocks the main thread while handling a one-
3716 // finger tap, which subsequently prevents the UI process from handling any incoming IPC messages.
3717 return NO__objc_no;
3718 }
3719 return protect(_page)->editorState().selectionType == WebCore::SelectionType::Range;
3720 }
3721 }
3722
3723 WebKit::InteractionInformationRequest request(WebCore::roundedIntPoint(point));
3724 if (![self ensurePositionInformationIsUpToDate:request])
3725 return NO__objc_no;
3726
3727 if (gesture == WKBEGestureTypeLoupeBEGestureTypeLoupe && _positionInformation.selectability == WebKit::InteractionInformationAtPosition::Selectability::UnselectableDueToUserSelectNoneOrQuirk)
3728 return NO__objc_no;
3729
3730 if (_positionInformation.preventTextInteraction)
3731 return NO__objc_no;
3732
3733#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
3734 if (_elementPendingImageAnalysis && _positionInformation.hostImageOrVideoElementContext == _elementPendingImageAnalysis)
3735 return YES__objc_yes;
3736#endif
3737
3738 // If we're currently focusing an editable element, only allow the selection to move within that focused element.
3739 if (self.isFocusingElement)
3740 return _positionInformation.elementContext && _positionInformation.elementContext->isSameElement(_focusedElementInformation.elementContext);
3741
3742 if (_positionInformation.prefersDraggingOverTextSelection)
3743 return NO__objc_no;
3744
3745 // If we're selecting something, don't activate highlight.
3746 if (gesture == WKBEGestureTypeLoupeBEGestureTypeLoupe && [self hasSelectablePositionAtPoint:point])
3747 [self _cancelLongPressGestureRecognizer];
3748
3749 // Otherwise, if we're using a text interaction assistant outside of editing purposes (e.g. the selection mode
3750 // is character granularity) then allow text selection.
3751 return YES__objc_yes;
3752}
3753
3754- (NSArray *)webSelectionRectsForSelectionGeometries:(const Vector<WebCore::SelectionGeometry>&)selectionGeometries
3755{
3756 if (selectionGeometries.isEmpty())
3757 return nilnullptr;
3758
3759 return createNSArray(selectionGeometries, [] (auto& geometry) {
3760 auto webRect = [WebSelectionRect selectionRect];
3761 webRect.rect = geometry.rect();
3762 webRect.writingDirection = geometry.direction() == WebCore::TextDirection::LTR ? WKWritingDirectionLeftToRight : WKWritingDirectionRightToLeft;
3763 webRect.isLineBreak = geometry.isLineBreak();
3764 webRect.isFirstOnLine = geometry.isFirstOnLine();
3765 webRect.isLastOnLine = geometry.isLastOnLine();
3766 webRect.containsStart = geometry.containsStart();
3767 webRect.containsEnd = geometry.containsEnd();
3768 webRect.isInFixedPosition = geometry.isInFixedPosition();
3769 webRect.isHorizontal = geometry.isHorizontal();
3770 return webRect;
3771 }).autorelease();
3772}
3773
3774- (NSArray *)webSelectionRects
3775{
3776 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG163"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(3776, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
3777
3778 if (!protect(_page)->editorState().hasPostLayoutAndVisualData() || protect(_page)->editorState().selectionType == WebCore::SelectionType::None)
3779 return nilnullptr;
3780 const auto& selectionGeometries = protect(_page)->editorState().visualData->selectionGeometries;
3781 return [self webSelectionRectsForSelectionGeometries:selectionGeometries];
3782}
3783
3784- (WebKit::TapIdentifier)nextTapIdentifier
3785{
3786 _latestTapID = WebKit::TapIdentifier::generate();
3787 return *_latestTapID;
3788}
3789
3790- (void)_highlightLongPressRecognized:(UILongPressGestureRecognizer *)gestureRecognizer
3791{
3792 ASSERT(gestureRecognizer == _highlightLongPressGestureRecognizer)((void)0);
3793 [self _resetIsDoubleTapPending];
3794
3795 auto startPoint = [gestureRecognizer startPoint];
3796
3797 _lastInteractionLocation = startPoint;
3798
3799 switch ([gestureRecognizer state]) {
3800 case UIGestureRecognizerStateBegan:
3801 _longPressCanClick = YES__objc_yes;
3802 cancelPotentialTapIfNecessary(self);
3803 protect(_page)->tapHighlightAtPosition(startPoint, [self nextTapIdentifier]);
3804 _isTapHighlightIDValid = YES__objc_yes;
3805 break;
3806 case UIGestureRecognizerStateEnded:
3807 if (_longPressCanClick && _positionInformation.isElement) {
3808 [self _attemptSyntheticClickAtLocation:startPoint modifierFlags:gestureRecognizer.modifierFlags];
3809 [self _finishInteraction];
3810 } else
3811 [self _cancelInteraction];
3812 _longPressCanClick = NO__objc_no;
3813 break;
3814 case UIGestureRecognizerStateCancelled:
3815 [self _cancelInteraction];
3816 _longPressCanClick = NO__objc_no;
3817 break;
3818 default:
3819 break;
3820 }
3821}
3822
3823- (void)_doubleTapRecognizedForDoubleClick:(UITapGestureRecognizer *)gestureRecognizer
3824{
3825 RELEASE_ASSERT(_layerTreeTransactionIdAtLastInteractionStart)do { if (__builtin_expect(!!(!(_layerTreeTransactionIdAtLastInteractionStart
)), 0)) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(3825, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
3826 protect(_page)->handleDoubleTapForDoubleClickAtPoint(WebCore::IntPoint([gestureRecognizer locationInView:self]), WebKit::webEventModifierFlags(gestureRecognizer.modifierFlags), *_layerTreeTransactionIdAtLastInteractionStart);
3827}
3828
3829- (void)_twoFingerSingleTapGestureRecognized:(UITapGestureRecognizer *)gestureRecognizer
3830{
3831 _isTapHighlightIDValid = YES__objc_yes;
3832 _isExpectingFastSingleTapCommit = YES__objc_yes;
3833 protect(_page)->handleTwoFingerTapAtPoint(WebCore::roundedIntPoint([gestureRecognizer locationInView:self]), WebKit::webEventModifierFlags(gestureRecognizer.modifierFlags | UIKeyModifierCommand), [self nextTapIdentifier]);
3834}
3835
3836- (void)_longPressRecognized:(UILongPressGestureRecognizer *)gestureRecognizer
3837{
3838 ASSERT(gestureRecognizer == _longPressGestureRecognizer)((void)0);
3839 [self _resetIsDoubleTapPending];
3840 [self _cancelTouchEventGestureRecognizer];
3841
3842 protect(_page)->didRecognizeLongPress();
3843
3844 _lastInteractionLocation = [gestureRecognizer startPoint];
3845
3846 if ([gestureRecognizer state] == UIGestureRecognizerStateBegan) {
3847 SEL action = [self _actionForLongPress];
3848 if (action) {
3849 [self performSelector:action];
3850 [self _cancelLongPressGestureRecognizer];
3851 }
3852 }
3853}
3854
3855- (void)_endPotentialTapAndEnableDoubleTapGesturesIfNecessary
3856{
3857 if (self.webView._allowsDoubleTapGestures) {
3858 RELEASE_LOG(ViewGestures, "ending potential tap - double taps are back. (%p, pageProxyID=%llu)", self, _page->identifier().toUInt64())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogViewGestures
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("ending potential tap - double taps are back. (%p, pageProxyID=%llu)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG164"
) = "ending potential tap - double taps are back. (%p, pageProxyID=%llu)"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("ending potential tap - double taps are back. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64())]; _os_log_impl(&
__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format
(_os_fmt_buf, "ending potential tap - double taps are back. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64()), (uint32_t)sizeof(
_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
3859
3860 [self _setDoubleTapGesturesEnabled:YES__objc_yes];
3861 }
3862
3863 RELEASE_LOG(ViewGestures, "Ending potential tap. (%p, pageProxyID=%llu)", self, _page->identifier().toUInt64())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogViewGestures
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Ending potential tap. (%p, pageProxyID=%llu)"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG165"
) = "Ending potential tap. (%p, pageProxyID=%llu)"; uint8_t _Alignas
(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Ending potential tap. (%p, pageProxyID=%llu)", self, _page->
identifier().toUInt64())]; _os_log_impl(&__dso_handle, _log_tmp
, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format(
_os_fmt_buf, "Ending potential tap. (%p, pageProxyID=%llu)", self
, _page->identifier().toUInt64()), (uint32_t)sizeof(_os_fmt_buf
)) clang diagnostic pop ; }); } }) clang diagnostic pop
;
3864
3865 _potentialTapInProgress = NO__objc_no;
3866}
3867
3868- (BOOL)isPotentialTapInProgress
3869{
3870 return _potentialTapInProgress;
3871}
3872
3873- (void)_singleTapIdentified:(UITapGestureRecognizer *)gestureRecognizer
3874{
3875 auto position = [gestureRecognizer locationInView:self];
3876
3877 if ([self _handleTapOverInteractiveControl:position])
3878 return;
3879
3880 ASSERT(gestureRecognizer == _singleTapGestureRecognizer)((void)0);
3881 ASSERT(!_potentialTapInProgress)((void)0);
3882 [self _resetIsDoubleTapPending];
3883
3884 [_inputPeripheral setSingleTapShouldEndEditing:[_inputPeripheral isEditing]];
3885
3886 bool shouldRequestMagnificationInformation = protect(_page->preferences())->fasterClicksEnabled();
3887 if (shouldRequestMagnificationInformation)
3888 RELEASE_LOG(ViewGestures, "Single tap identified. Request details on potential zoom. (%p, pageProxyID=%llu)", self, _page->identifier().toUInt64())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogViewGestures
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Single tap identified. Request details on potential zoom. (%p, pageProxyID=%llu)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG166"
) = "Single tap identified. Request details on potential zoom. (%p, pageProxyID=%llu)"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Single tap identified. Request details on potential zoom. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64())]; _os_log_impl(&
__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format
(_os_fmt_buf, "Single tap identified. Request details on potential zoom. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64()), (uint32_t)sizeof(
_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
3889
3890 protect(_page)->potentialTapAtPosition(std::nullopt, position, shouldRequestMagnificationInformation, [self nextTapIdentifier], WebKit::WebMouseEventInputSource::UserDriven);
3891 _potentialTapInProgress = YES__objc_yes;
3892 _isTapHighlightIDValid = YES__objc_yes;
3893 _isExpectingFastSingleTapCommit = !_doubleTapGestureRecognizer.get().enabled;
3894}
3895
3896static void cancelPotentialTapIfNecessary(WKContentView* contentView)
3897{
3898 if (contentView->_potentialTapInProgress) {
3899 [contentView _endPotentialTapAndEnableDoubleTapGesturesIfNecessary];
3900 [contentView _cancelInteraction];
3901 protect(contentView->_page)->cancelPotentialTap();
3902 }
3903}
3904
3905- (void)_singleTapDidReset:(UITapGestureRecognizer *)gestureRecognizer
3906{
3907 ASSERT(gestureRecognizer == _singleTapGestureRecognizer)((void)0);
3908 cancelPotentialTapIfNecessary(self);
3909 if (auto* singleTapTouchIdentifier = [_singleTapGestureRecognizer lastActiveTouchIdentifier]) {
3910 WebCore::PointerID pointerId = [singleTapTouchIdentifier unsignedIntValue];
3911 if (_commitPotentialTapPointerId != pointerId)
3912 protect(_page)->touchWithIdentifierWasRemoved(pointerId);
3913 }
3914
3915 if (!_isTapHighlightIDValid)
3916 [self _fadeTapHighlightViewIfNeeded];
3917}
3918
3919- (void)_keyboardDismissalGestureRecognized:(UITapGestureRecognizer *)gestureRecognizer
3920{
3921 ASSERT(gestureRecognizer == _keyboardDismissalGestureRecognizer)((void)0);
3922
3923 if (!self._hasFocusedElement)
3924 return;
3925
3926 protect(_page)->shouldDismissKeyboardAfterTapAtPoint([gestureRecognizer locationInView:self], [weakSelf = WeakObjCPtr<WKContentView>(self), element = _focusedElementInformation.elementContext](bool shouldDismiss) {
3927 if (!shouldDismiss)
3928 return;
3929
3930 RetainPtr strongSelf = weakSelf.get();
3931 if (![strongSelf _isSameAsFocusedElement:element])
3932 return;
3933
3934 RELEASE_LOG(ViewGestures, "Dismissing keyboard after tap (%p, pageProxyID=%llu)", strongSelf.get(), strongSelf->_page->identifier().toUInt64())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogViewGestures
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Dismissing keyboard after tap (%p, pageProxyID=%llu)"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG167"
) = "Dismissing keyboard after tap (%p, pageProxyID=%llu)"; uint8_t
_Alignas(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Dismissing keyboard after tap (%p, pageProxyID=%llu)", strongSelf
.get(), strongSelf->_page->identifier().toUInt64())]; _os_log_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Dismissing keyboard after tap (%p, pageProxyID=%llu)"
, strongSelf.get(), strongSelf->_page->identifier().toUInt64
()), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop ; })
; } }) clang diagnostic pop
;
3935 [strongSelf _elementDidBlur];
3936 });
3937}
3938
3939- (void)_doubleTapDidFail:(UITapGestureRecognizer *)gestureRecognizer
3940{
3941 RELEASE_LOG(ViewGestures, "Double tap was not recognized. (%p, pageProxyID=%llu)", self, _page->identifier().toUInt64())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogViewGestures
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Double tap was not recognized. (%p, pageProxyID=%llu)"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG168"
) = "Double tap was not recognized. (%p, pageProxyID=%llu)"; uint8_t
_Alignas(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Double tap was not recognized. (%p, pageProxyID=%llu)", self
, _page->identifier().toUInt64())]; _os_log_impl(&__dso_handle
, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format
(_os_fmt_buf, "Double tap was not recognized. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64()), (uint32_t)sizeof(
_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
3942 ASSERT(gestureRecognizer == _doubleTapGestureRecognizer)((void)0);
3943}
3944
3945- (void)_commitPotentialTapFailed
3946{
3947 protect(_page)->touchWithIdentifierWasRemoved(_commitPotentialTapPointerId);
3948 _commitPotentialTapPointerId = 0;
3949
3950 [self _cancelInteraction];
3951
3952 [self stopDeferringInputViewUpdates:WebKit::InputViewUpdateDeferralSource::TapGesture];
3953}
3954
3955- (void)_didNotHandleTapAsClick:(const WebCore::IntPoint&)point
3956{
3957 [self stopDeferringInputViewUpdates:WebKit::InputViewUpdateDeferralSource::TapGesture];
3958
3959 if (!_isDoubleTapPending)
3960 return;
3961
3962 protect(_smartMagnificationController)->handleSmartMagnificationGesture(_lastInteractionLocation);
3963 _isDoubleTapPending = NO__objc_no;
3964}
3965
3966- (void)_didHandleTapAsHover
3967{
3968 [self stopDeferringInputViewUpdates:WebKit::InputViewUpdateDeferralSource::TapGesture];
3969}
3970
3971- (void)_didCompleteSyntheticClick
3972{
3973 protect(_page)->touchWithIdentifierWasRemoved(_commitPotentialTapPointerId);
3974 _commitPotentialTapPointerId = 0;
3975
3976 RELEASE_LOG(ViewGestures, "Synthetic click completed. (%p, pageProxyID=%llu)", self, _page->identifier().toUInt64())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogViewGestures
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Synthetic click completed. (%p, pageProxyID=%llu)"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG169"
) = "Synthetic click completed. (%p, pageProxyID=%llu)"; uint8_t
_Alignas(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Synthetic click completed. (%p, pageProxyID=%llu)", self, _page
->identifier().toUInt64())]; _os_log_impl(&__dso_handle
, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format
(_os_fmt_buf, "Synthetic click completed. (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64()), (uint32_t)sizeof(
_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
3977 [self stopDeferringInputViewUpdates:WebKit::InputViewUpdateDeferralSource::TapGesture];
3978}
3979
3980#if ENABLE(GAMEPAD)(defined 1 && 1)
3981- (void)_gamepadInteractionGestureRecognized:(UITapGestureRecognizer *)gestureRecognizer
3982{
3983 // This space intentionally left blank.
3984}
3985#endif
3986
3987#if ENABLE(MODEL_PROCESS)(defined 0 && 0)
3988- (void)_modelInteractionPanGestureRecognized:(UIPanGestureRecognizer *)gestureRecognizer
3989{
3990 ASSERT(gestureRecognizer == _modelInteractionPanGestureRecognizer)((void)0);
3991
3992 _lastInteractionLocation = [gestureRecognizer locationInView:self];
3993
3994 switch (gestureRecognizer.state) {
3995 case UIGestureRecognizerStateBegan: {
3996 [self modelInteractionPanGestureDidBeginAtPoint:_lastInteractionLocation];
3997 break;
3998 }
3999 case UIGestureRecognizerStateChanged: {
4000 [self modelInteractionPanGestureDidUpdateWithPoint:_lastInteractionLocation];
4001 break;
4002 }
4003 case UIGestureRecognizerStateEnded:
4004 case UIGestureRecognizerStateCancelled: {
4005 [self modelInteractionPanGestureDidEnd];
4006 break;
4007 }
4008 default:
4009 break;
4010 }
4011}
4012#endif
4013
4014- (void)_singleTapRecognized:(UITapGestureRecognizer *)gestureRecognizer
4015{
4016 ASSERT(gestureRecognizer == _singleTapGestureRecognizer)((void)0);
4017
4018 if (!_potentialTapInProgress)
4019 return;
4020
4021 if (![self isFirstResponder]) {
4022 [self startDeferringInputViewUpdates:WebKit::InputViewUpdateDeferralSource::TapGesture];
4023 [self becomeFirstResponder];
4024 }
4025
4026 _lastInteractionLocation = [gestureRecognizer locationInView:self];
4027
4028 [self _endPotentialTapAndEnableDoubleTapGesturesIfNecessary];
4029
4030 if (_hasTapHighlightForPotentialTap) {
4031 [self _showTapHighlight];
4032 _hasTapHighlightForPotentialTap = NO__objc_no;
4033 }
4034
4035 if ([_inputPeripheral singleTapShouldEndEditing])
4036 [_inputPeripheral endEditing];
4037
4038 RELEASE_LOG(ViewGestures, "Single tap recognized - commit potential tap (%p, pageProxyID=%llu)", self, _page->identifier().toUInt64())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogViewGestures
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Single tap recognized - commit potential tap (%p, pageProxyID=%llu)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG170"
) = "Single tap recognized - commit potential tap (%p, pageProxyID=%llu)"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Single tap recognized - commit potential tap (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64())]; _os_log_impl(&
__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format
(_os_fmt_buf, "Single tap recognized - commit potential tap (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64()), (uint32_t)sizeof(
_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
4039
4040 WebCore::PointerID pointerId = WebCore::mousePointerID;
4041 if (auto* singleTapTouchIdentifier = [_singleTapGestureRecognizer lastActiveTouchIdentifier]) {
4042 pointerId = [singleTapTouchIdentifier unsignedIntValue];
4043 _commitPotentialTapPointerId = pointerId;
4044 }
4045 RELEASE_ASSERT(_layerTreeTransactionIdAtLastInteractionStart)do { if (__builtin_expect(!!(!(_layerTreeTransactionIdAtLastInteractionStart
)), 0)) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(4045, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
4046 protect(_page)->commitPotentialTap(std::nullopt, WebKit::webEventModifierFlags(gestureRecognizer.modifierFlags), *_layerTreeTransactionIdAtLastInteractionStart, pointerId);
4047
4048 if (!_isExpectingFastSingleTapCommit)
4049 [self _finishInteraction];
4050
4051#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
4052 if (![_imageAnalysisInteraction interactableItemExistsAtPoint:_lastInteractionLocation])
4053 [_imageAnalysisInteraction resetSelection];
4054#endif
4055}
4056
4057- (void)_doubleTapRecognized:(UITapGestureRecognizer *)gestureRecognizer
4058{
4059 RELEASE_LOG(ViewGestures, "Identified a double tap (%p, pageProxyID=%llu)", self, _page->identifier().toUInt64())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogViewGestures
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Identified a double tap (%p, pageProxyID=%llu)"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG171"
) = "Identified a double tap (%p, pageProxyID=%llu)"; uint8_t
_Alignas(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Identified a double tap (%p, pageProxyID=%llu)", self, _page
->identifier().toUInt64())]; _os_log_impl(&__dso_handle
, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format
(_os_fmt_buf, "Identified a double tap (%p, pageProxyID=%llu)"
, self, _page->identifier().toUInt64()), (uint32_t)sizeof(
_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
4060
4061 [self _resetIsDoubleTapPending];
4062
4063 auto location = [gestureRecognizer locationInView:self];
4064 _lastInteractionLocation = location;
4065 protect(_smartMagnificationController)->handleSmartMagnificationGesture(location);
4066}
4067
4068- (void)_resetIsDoubleTapPending
4069{
4070 _isDoubleTapPending = NO__objc_no;
4071}
4072
4073- (void)_nonBlockingDoubleTapRecognized:(UITapGestureRecognizer *)gestureRecognizer
4074{
4075 _lastInteractionLocation = [gestureRecognizer locationInView:self];
4076 _isDoubleTapPending = YES__objc_yes;
4077}
4078
4079- (void)_twoFingerDoubleTapRecognized:(UITapGestureRecognizer *)gestureRecognizer
4080{
4081 [self _resetIsDoubleTapPending];
4082
4083 auto location = [gestureRecognizer locationInView:self];
4084 _lastInteractionLocation = location;
4085 protect(_smartMagnificationController)->handleResetMagnificationGesture(location);
4086}
4087
4088- (void)_attemptSyntheticClickAtLocation:(CGPoint)location modifierFlags:(UIKeyModifierFlags)modifierFlags
4089{
4090 if (![self isFirstResponder])
4091 [self becomeFirstResponder];
4092
4093 [_inputPeripheral endEditing];
4094 RELEASE_ASSERT(_layerTreeTransactionIdAtLastInteractionStart)do { if (__builtin_expect(!!(!(_layerTreeTransactionIdAtLastInteractionStart
)), 0)) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(4094, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
4095 protect(_page)->attemptSyntheticClick(location, WebKit::webEventModifierFlags(modifierFlags), *_layerTreeTransactionIdAtLastInteractionStart);
4096}
4097
4098- (void)setUpTextSelectionAssistant
4099{
4100 if (!_textInteractionWrapper)
4101 _textInteractionWrapper = adoptNS([[WKTextInteractionWrapper alloc] initWithView:self]);
4102 else {
4103 // Reset the gesture recognizers in case editability has changed.
4104 [_textInteractionWrapper setGestureRecognizers];
4105 }
4106
4107 _cachedTextInteractionLoupeGestureRecognizer = nilnullptr;
4108 _cachedTextInteractionTapGestureRecognizer = nilnullptr;
4109}
4110
4111- (void)pasteWithCompletionHandler:(void (^)(void))completionHandler
4112{
4113 protect(_page)->executeEditCommand("Paste"_s, { }, [completion = makeBlockPtr(completionHandler)] {
4114 if (completion)
4115 completion();
4116 });
4117}
4118
4119- (void)clearSelection
4120{
4121 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG172"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(4121, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
4122
4123 [self _internalClearSelection];
4124}
4125
4126- (void)_internalClearSelection
4127{
4128 [self _elementDidBlur];
4129 protect(_page)->clearSelection();
4130}
4131
4132- (void)_invalidateCurrentPositionInformation
4133{
4134 _hasValidPositionInformation = NO__objc_no;
4135 _positionInformation = { };
4136}
4137
4138- (void)_positionInformationDidChange:(const WebKit::InteractionInformationAtPosition&)info
4139{
4140 if (_lastOutstandingPositionInformationRequest && info.request.isValidForRequest(*_lastOutstandingPositionInformationRequest))
4141 _lastOutstandingPositionInformationRequest = std::nullopt;
4142
4143 _isWaitingOnPositionInformation = NO__objc_no;
4144
4145 WebKit::InteractionInformationAtPosition newInfo = info;
4146 newInfo.mergeCompatibleOptionalInformation(_positionInformation);
4147
4148 _positionInformation = newInfo;
4149 _hasValidPositionInformation = _positionInformation.canBeValid;
4150 if (_actionSheetAssistant)
4151 [protect(_actionSheetAssistant) updateSheetPosition];
4152 [self _invokeAndRemovePendingHandlersValidForCurrentPositionInformation];
4153}
4154
4155- (void)_willStartScrollingOrZooming
4156{
4157 [_textInteractionWrapper willStartScrollingOrZooming];
4158 protect(_page)->setIsScrollingOrZooming(true);
4159
4160#if HAVE(PEPPER_UI_CORE)(defined HAVE_PEPPER_UI_CORE && HAVE_PEPPER_UI_CORE)
4161 [protect(_focusedFormControlView) disengageFocusedFormControlNavigation];
4162#endif
4163}
4164
4165- (void)scrollViewWillStartPanOrPinchGesture
4166{
4167 protect(_page)->hideValidationMessage();
4168
4169 [protect(_keyboardScrollingAnimator) willStartInteractiveScroll];
4170
4171 _touchEventsCanPreventNativeGestures = NO__objc_no;
4172}
4173
4174- (void)_didEndScrollingOrZooming
4175{
4176 if (!_needsDeferredEndScrollingSelectionUpdate)
4177 [_textInteractionWrapper didEndScrollingOrZooming];
4178 protect(_page)->setIsScrollingOrZooming(false);
4179
4180 [self _resetPanningPreventionFlags];
4181
4182#if HAVE(PEPPER_UI_CORE)(defined HAVE_PEPPER_UI_CORE && HAVE_PEPPER_UI_CORE)
4183 [protect(_focusedFormControlView) engageFocusedFormControlNavigation];
4184#endif
4185}
4186
4187- (BOOL)_elementTypeRequiresAccessoryView:(WebKit::InputType)type
4188{
4189 switch (type) {
4190 case WebKit::InputType::None:
4191 case WebKit::InputType::Color:
4192 case WebKit::InputType::Drawing:
4193 case WebKit::InputType::Date:
4194 case WebKit::InputType::DateTimeLocal:
4195 case WebKit::InputType::Month:
4196 case WebKit::InputType::Time:
4197#if ENABLE(INPUT_TYPE_WEEK_PICKER)(defined 1 && 1)
4198 case WebKit::InputType::Week:
4199#endif
4200 return NO__objc_no;
4201 case WebKit::InputType::Select: {
4202 if (self._shouldUseContextMenusForFormControls)
4203 return NO__objc_no;
4204 return PAL::currentUserInterfaceIdiomIsSmallScreen();
4205 }
4206 case WebKit::InputType::Text:
4207 case WebKit::InputType::Password:
4208 case WebKit::InputType::Search:
4209 case WebKit::InputType::Email:
4210 case WebKit::InputType::URL:
4211 case WebKit::InputType::Phone:
4212 case WebKit::InputType::Number:
4213 case WebKit::InputType::NumberPad:
4214 case WebKit::InputType::ContentEditable:
4215 case WebKit::InputType::TextArea:
4216#if !ENABLE(INPUT_TYPE_WEEK_PICKER)(defined 1 && 1)
4217 case WebKit::InputType::Week:
4218#endif
4219 return PAL::currentUserInterfaceIdiomIsSmallScreen();
4220 }
4221}
4222
4223- (BOOL)requiresAccessoryView
4224{
4225#if ENABLE(WRITING_TOOLS)(defined 1 && 1)
4226 if (_isPresentingWritingTools)
4227 return NO__objc_no;
4228#endif
4229
4230 if ([_formInputSession accessoryViewShouldNotShow])
4231 return NO__objc_no;
4232
4233 if ([_formInputSession customInputAccessoryView])
4234 return YES__objc_yes;
4235
4236 if ([_webView.get() _isDisplayingPDF])
4237 return NO__objc_no;
4238
4239 return [self _elementTypeRequiresAccessoryView:_focusedElementInformation.elementType];
4240}
4241
4242- (UITextInputAssistantItem *)inputAssistantItem
4243{
4244 return [_webView.get() inputAssistantItem];
4245}
4246
4247- (UITextInputAssistantItem *)inputAssistantItemForWebView
4248{
4249 return [super inputAssistantItem];
4250}
4251
4252- (UIView *)inputAccessoryView
4253{
4254 return [_webView.get() inputAccessoryView];
4255}
4256
4257- (UIView *)inputAccessoryViewForWebView
4258{
4259 if (![self requiresAccessoryView])
4260 return nilnullptr;
4261
4262 return [_formInputSession customInputAccessoryView] ?: self.formAccessoryView;
4263}
4264
4265- (NSArray *)supportedPasteboardTypesForCurrentSelection
4266{
4267 if (protect(_page)->editorState().selectionType == WebCore::SelectionType::None)
4268 return nilnullptr;
4269
4270 if (protect(_page)->editorState().isContentRichlyEditable)
4271 return WebKit::supportedRichTextPasteboardTypes();
4272
4273 return WebKit::supportedPlainTextPasteboardTypes();
4274}
4275
4276#define FORWARD_ACTION_TO_WKWEBVIEW(_action) \
4277 - (void)_action:(id)sender \
4278 { \
4279 SEL action = @selector(_action:);\
4280 [self _willPerformAction:action sender:sender];\
4281 [_webView.get() _action:sender]; \
4282 [self _didPerformAction:action sender:sender];\
4283 }
4284
4285FOR_EACH_WKCONTENTVIEW_ACTION(FORWARD_ACTION_TO_WKWEBVIEW)FORWARD_ACTION_TO_WKWEBVIEW(captureTextFromCamera) FORWARD_ACTION_TO_WKWEBVIEW
(useSelectionForFind) FORWARD_ACTION_TO_WKWEBVIEW(findSelected
) FORWARD_ACTION_TO_WKWEBVIEW(_findSelected) FORWARD_ACTION_TO_WKWEBVIEW
(addShortcut) FORWARD_ACTION_TO_WKWEBVIEW(_addShortcut) FORWARD_ACTION_TO_WKWEBVIEW
(define) FORWARD_ACTION_TO_WKWEBVIEW(_define) FORWARD_ACTION_TO_WKWEBVIEW
(lookup) FORWARD_ACTION_TO_WKWEBVIEW(_lookup) FORWARD_ACTION_TO_WKWEBVIEW
(translate) FORWARD_ACTION_TO_WKWEBVIEW(_translate) FORWARD_ACTION_TO_WKWEBVIEW
(promptForReplace) FORWARD_ACTION_TO_WKWEBVIEW(_promptForReplace
) FORWARD_ACTION_TO_WKWEBVIEW(share) FORWARD_ACTION_TO_WKWEBVIEW
(_share) FORWARD_ACTION_TO_WKWEBVIEW(transliterateChinese) FORWARD_ACTION_TO_WKWEBVIEW
(_transliterateChinese) FORWARD_ACTION_TO_WKWEBVIEW(_nextAccessoryTab
) FORWARD_ACTION_TO_WKWEBVIEW(_previousAccessoryTab) FORWARD_ACTION_TO_WKWEBVIEW
(copy) FORWARD_ACTION_TO_WKWEBVIEW(cut) FORWARD_ACTION_TO_WKWEBVIEW
(paste) FORWARD_ACTION_TO_WKWEBVIEW(replace) FORWARD_ACTION_TO_WKWEBVIEW
(select) FORWARD_ACTION_TO_WKWEBVIEW(selectAll) FORWARD_ACTION_TO_WKWEBVIEW
(toggleBoldface) FORWARD_ACTION_TO_WKWEBVIEW(toggleItalics) FORWARD_ACTION_TO_WKWEBVIEW
(toggleUnderline) FORWARD_ACTION_TO_WKWEBVIEW(increaseSize) FORWARD_ACTION_TO_WKWEBVIEW
(decreaseSize) FORWARD_ACTION_TO_WKWEBVIEW(pasteAndMatchStyle
) FORWARD_ACTION_TO_WKWEBVIEW(makeTextWritingDirectionNatural
) FORWARD_ACTION_TO_WKWEBVIEW(makeTextWritingDirectionLeftToRight
) FORWARD_ACTION_TO_WKWEBVIEW(makeTextWritingDirectionRightToLeft
) FORWARD_ACTION_TO_WKWEBVIEW(alignCenter) FORWARD_ACTION_TO_WKWEBVIEW
(alignJustified) FORWARD_ACTION_TO_WKWEBVIEW(alignLeft) FORWARD_ACTION_TO_WKWEBVIEW
(alignRight)
The return value is +1 and results in a memory leak
4286FOR_EACH_PRIVATE_WKCONTENTVIEW_ACTION(FORWARD_ACTION_TO_WKWEBVIEW)FORWARD_ACTION_TO_WKWEBVIEW(_indent) FORWARD_ACTION_TO_WKWEBVIEW
(_outdent) FORWARD_ACTION_TO_WKWEBVIEW(_toggleStrikeThrough) FORWARD_ACTION_TO_WKWEBVIEW
(_insertOrderedList) FORWARD_ACTION_TO_WKWEBVIEW(_insertUnorderedList
) FORWARD_ACTION_TO_WKWEBVIEW(_insertNestedOrderedList) FORWARD_ACTION_TO_WKWEBVIEW
(_insertNestedUnorderedList) FORWARD_ACTION_TO_WKWEBVIEW(_increaseListLevel
) FORWARD_ACTION_TO_WKWEBVIEW(_decreaseListLevel) FORWARD_ACTION_TO_WKWEBVIEW
(_changeListType) FORWARD_ACTION_TO_WKWEBVIEW(_pasteAsQuotation
) FORWARD_ACTION_TO_WKWEBVIEW(_pasteAndMatchStyle)
4287
4288#undef FORWARD_ACTION_TO_WKWEBVIEW
4289
4290- (void)_lookupForWebView:(id)sender
4291{
4292 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG173"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(4292, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
4293
4294 [self lookupForWebView:sender];
4295}
4296
4297- (void)defineForWebView:(id)sender
4298{
4299 [self lookupForWebView:sender];
4300}
4301
4302- (void)lookupForWebView:(id)sender
4303{
4304 protect(_page)->getSelectionContext([view = retainPtr(self)](const String& selectedText, const String& textBefore, const String& textAfter) {
4305 if (!selectedText)
4306 return;
4307
4308 Ref page = *view->_page;
4309 auto& editorState = page->editorState();
4310 if (!editorState.hasPostLayoutAndVisualData())
4311 return;
4312 auto& visualData = *editorState.visualData;
4313 CGRect presentationRect;
4314 if (editorState.selectionType == WebCore::SelectionType::Range && !visualData.selectionGeometries.isEmpty())
4315 presentationRect = page->selectionBoundingRectInRootViewCoordinates();
4316 else
4317 presentationRect = visualData.caretRectAtStart;
4318
4319 auto selectionContext = makeString(textBefore, selectedText, textAfter);
4320 NSRange selectedRangeInContext = NSMakeRange(textBefore.length(), selectedText.length());
4321
4322 if (auto textSelectionAssistant = view->_textInteractionWrapper)
4323 [textSelectionAssistant lookup:selectionContext.createNSString().get() withRange:selectedRangeInContext fromRect:presentationRect];
4324 });
4325}
4326
4327- (void)_shareForWebView:(id)sender
4328{
4329 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG174"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(4329, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
4330
4331 [self shareForWebView:sender];
4332}
4333
4334- (void)shareForWebView:(id)sender
4335{
4336 RetainPtr<WKContentView> view = self;
4337 protect(_page)->getSelectionOrContentsAsString([view](const String& string) {
4338 if (!view->_textInteractionWrapper || !string)
4339 return;
4340
4341 Ref page = *view->_page;
4342 if (!page->editorState().hasVisualData())
4343 return;
4344
4345 auto& selectionGeometries = page->editorState().visualData->selectionGeometries;
4346 if (selectionGeometries.isEmpty())
4347 return;
4348
4349 [view->_textInteractionWrapper showShareSheetFor:string.createNSString().get() fromRect:selectionGeometries.first().rect()];
4350 });
4351}
4352
4353- (void)_translateForWebView:(id)sender
4354{
4355 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG175"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(4355, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
4356
4357 [self translateForWebView:sender];
4358}
4359
4360- (void)translateForWebView:(id)sender
4361{
4362 protect(_page)->getSelectionOrContentsAsString([weakSelf = WeakObjCPtr<WKContentView>(self)] (const String& string) {
4363 if (!weakSelf)
4364 return;
4365
4366 if (string.isEmpty())
4367 return;
4368
4369 auto strongSelf = weakSelf.get();
4370 Ref page = *strongSelf->_page;
4371 if (!page->editorState().hasVisualData())
4372 return;
4373
4374 if (page->editorState().visualData->selectionGeometries.isEmpty())
4375 return;
4376
4377 [strongSelf->_textInteractionWrapper translate:string.createNSString().get() fromRect:page->selectionBoundingRectInRootViewCoordinates()];
4378 });
4379}
4380
4381- (void)_addShortcutForWebView:(id)sender
4382{
4383 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG176"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(4383, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
4384
4385 [self addShortcutForWebView:sender];
4386}
4387
4388- (void)addShortcutForWebView:(id)sender
4389{
4390 Ref page = *_page;
4391 if (!page->editorState().visualData)
4392 return;
4393 [_textInteractionWrapper showTextServiceFor:[self selectedText] fromRect:page->editorState().visualData->selectionGeometries[0].rect()];
4394}
4395
4396- (NSString *)selectedText
4397{
4398 Ref page = *_page;
4399 if (!page->editorState().postLayoutData)
4400 return nilnullptr;
4401 return page->editorState().postLayoutData->wordAtSelection.createNSString().autorelease();
4402}
4403
4404- (NSArray *)alternativesForSelectedText
4405{
4406 Ref page = *_page;
4407 if (!page->editorState().postLayoutData)
4408 return nilnullptr;
4409 auto& dictationContextsForSelection = page->editorState().postLayoutData->dictationContextsForSelection;
4410 return createNSArray(dictationContextsForSelection, [&] (auto& dictationContext) -> NSObject * {
4411 RetainPtr alternatives = protect(page->pageClient())->platformDictationAlternatives(dictationContext);
4412#if USE(BROWSERENGINEKIT)(defined 1 && 1)
4413 if (!self.shouldUseAsyncInteractions)
4414 return [[alternatives _nsTextAlternative] autorelease];
4415#endif
4416 return alternatives.autorelease();
4417 }).autorelease();
4418}
4419
4420- (void)makeTextWritingDirectionNaturalForWebView:(id)sender
4421{
4422 // Match platform behavior on iOS as well as legacy WebKit behavior by modifying the
4423 // base (paragraph) writing direction rather than the inline direction.
4424 protect(_page)->setBaseWritingDirection(WebCore::WritingDirection::Natural);
4425}
4426
4427- (void)makeTextWritingDirectionLeftToRightForWebView:(id)sender
4428{
4429 protect(_page)->setBaseWritingDirection(WebCore::WritingDirection::LeftToRight);
4430}
4431
4432- (void)makeTextWritingDirectionRightToLeftForWebView:(id)sender
4433{
4434 protect(_page)->setBaseWritingDirection(WebCore::WritingDirection::RightToLeft);
4435}
4436
4437- (BOOL)isReplaceAllowed
4438{
4439 Ref page = *_page;
4440 if (!page->editorState().postLayoutData)
4441 return NO__objc_no;
4442 return page->editorState().postLayoutData->isReplaceAllowed;
4443}
4444
4445- (void)replaceText:(NSString *)text withText:(NSString *)word
4446{
4447 _autocorrectionContextNeedsUpdate = YES__objc_yes;
4448 protect(_page)->replaceSelectedText(text, word);
4449}
4450
4451- (void)_promptForReplaceForWebView:(id)sender
4452{
4453 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG177"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(4453, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
4454
4455 [self promptForReplaceForWebView:sender];
4456}
4457
4458- (void)promptForReplaceForWebView:(id)sender
4459{
4460 Ref page = *_page;
4461 if (!page->editorState().postLayoutData)
4462 return;
4463 const auto& wordAtSelection = page->editorState().postLayoutData->wordAtSelection;
4464 if (wordAtSelection.isEmpty())
4465 return;
4466
4467 [_textInteractionWrapper scheduleReplacementsForText:wordAtSelection.createNSString().get()];
4468}
4469
4470- (void)_transliterateChineseForWebView:(id)sender
4471{
4472 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG178"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(4472, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
4473
4474 [self transliterateChineseForWebView:sender];
4475}
4476
4477- (void)transliterateChineseForWebView:(id)sender
4478{
4479 Ref page = *_page;
4480 if (!page->editorState().postLayoutData)
4481 return;
4482 [_textInteractionWrapper scheduleChineseTransliterationForText:page->editorState().postLayoutData->wordAtSelection.createNSString().get()];
4483}
4484
4485- (void)replaceForWebView:(id)sender
4486{
4487#if USE(BROWSERENGINEKIT)(defined 1 && 1)
4488 if (self.shouldUseAsyncInteractions) {
4489 [protect(_asyncInputDelegate) textInput:self.asBETextInput deferReplaceTextActionToSystem:sender];
4490 return;
4491 }
4492#endif
4493 [[UIKeyboardImpl sharedInstance] replaceText:sender];
4494}
4495
4496#define WEBCORE_COMMAND_FOR_WEBVIEW(command) \
4497 - (void)_ ## command ## ForWebView:(id)sender { protect(_page)->executeEditCommand(#command ## _s); } \
4498 - (void)command ## ForWebView:(id)sender { [self _ ## command ## ForWebView:sender]; }
4499WEBCORE_COMMAND_FOR_WEBVIEW(insertOrderedList);
4500WEBCORE_COMMAND_FOR_WEBVIEW(insertUnorderedList);
4501WEBCORE_COMMAND_FOR_WEBVIEW(insertNestedOrderedList);
4502WEBCORE_COMMAND_FOR_WEBVIEW(insertNestedUnorderedList);
4503WEBCORE_COMMAND_FOR_WEBVIEW(indent);
4504WEBCORE_COMMAND_FOR_WEBVIEW(outdent);
4505WEBCORE_COMMAND_FOR_WEBVIEW(alignLeft);
4506WEBCORE_COMMAND_FOR_WEBVIEW(alignRight);
4507WEBCORE_COMMAND_FOR_WEBVIEW(alignCenter);
4508WEBCORE_COMMAND_FOR_WEBVIEW(alignJustified);
4509WEBCORE_COMMAND_FOR_WEBVIEW(pasteAndMatchStyle);
4510#undef WEBCORE_COMMAND_FOR_WEBVIEW
4511
4512- (void)_increaseListLevelForWebView:(id)sender
4513{
4514 protect(_page)->increaseListLevel();
4515}
4516
4517- (void)_decreaseListLevelForWebView:(id)sender
4518{
4519 protect(_page)->decreaseListLevel();
4520}
4521
4522- (void)_changeListTypeForWebView:(id)sender
4523{
4524 protect(_page)->changeListType();
4525}
4526
4527- (void)_toggleStrikeThroughForWebView:(id)sender
4528{
4529 protect(_page)->executeEditCommand("StrikeThrough"_s);
4530}
4531
4532- (void)increaseSizeForWebView:(id)sender
4533{
4534 protect(_page)->executeEditCommand("FontSizeDelta"_s, "1"_s);
4535}
4536
4537- (void)decreaseSizeForWebView:(id)sender
4538{
4539 protect(_page)->executeEditCommand("FontSizeDelta"_s, "-1"_s);
4540}
4541
4542- (void)_setFontForWebView:(UIFont *)font sender:(id)sender
4543{
4544 WebCore::FontChanges changes;
4545 changes.setFontFamily(font.familyName);
4546 changes.setFontName(font.fontName);
4547 changes.setFontSize(font.pointSize);
4548 changes.setBold(font.traits & UIFontTraitBold);
4549 changes.setItalic(font.traits & UIFontTraitItalic);
4550
4551 if (NSString *textStyleAttribute = [font.fontDescriptor.fontAttributes objectForKey:UIFontDescriptorTextStyleAttribute])
4552 changes.setFontFamily(textStyleAttribute);
4553
4554 protect(_page)->changeFont(WTF::move(changes));
4555}
4556
4557- (void)_setFontSizeForWebView:(CGFloat)fontSize sender:(id)sender
4558{
4559 WebCore::FontChanges changes;
4560 changes.setFontSize(fontSize);
4561 protect(_page)->changeFont(WTF::move(changes));
4562}
4563
4564- (void)_setTextColorForWebView:(UIColor *)color sender:(id)sender
4565{
4566 WebCore::Color textColor(WebCore::roundAndClampToSRGBALossy(protect(protect(color).get().CGColor)));
4567 protect(_page)->executeEditCommand("ForeColor"_s, WebCore::serializationForHTML(textColor));
4568}
4569
4570- (void)toggleStrikeThroughForWebView:(id)sender
4571{
4572 [self _toggleStrikeThroughForWebView:sender];
4573}
4574
4575- (NSDictionary *)textStylingAtPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction
4576{
4577 NSMutableDictionary* result = [NSMutableDictionary dictionary];
4578 [result setObject:[UIColor blackColor] forKey:NSForegroundColorAttributeNamegetNSForegroundColorAttributeNameSingleton()];
4579 if (!position)
4580 return result;
4581
4582 Ref page = *_page;
4583 if (!page->editorState().isContentRichlyEditable)
4584 return result;
4585
4586 if (!page->editorState().postLayoutData)
4587 return result;
4588
4589 auto typingAttributes = page->editorState().postLayoutData->typingAttributes;
4590
4591 RetainPtr font = _autocorrectionData.font.get();
4592 double zoomScale = self._contentZoomScale;
4593 if (std::abs(zoomScale - 1) > FLT_EPSILON1.19209290e-7F)
4594 font = [font fontWithSize:[font pointSize] * zoomScale];
4595
4596 if (font) {
4597 auto originalTraits = [font fontDescriptor].symbolicTraits;
4598 auto newTraits = originalTraits;
4599 if (typingAttributes.contains(WebKit::TypingAttribute::Bold))
4600 newTraits |= UIFontDescriptorTraitBold;
4601
4602 if (typingAttributes.contains(WebKit::TypingAttribute::Italics))
4603 newTraits |= UIFontDescriptorTraitItalic;
4604
4605 if (originalTraits != newTraits) {
4606 RetainPtr descriptor = [protect([font fontDescriptor] ?: adoptNS([UIFontDescriptor new]).get()) fontDescriptorWithSymbolicTraits:newTraits];
4607 if (RetainPtr fontWithTraits = [UIFont fontWithDescriptor:descriptor.get() size:[font pointSize]])
4608 font = WTF::move(fontWithTraits);
4609 }
4610 [result setObject:font.get() forKey:NSFontAttributeNamegetNSFontAttributeNameSingleton()];
4611 }
4612
4613 if (typingAttributes.contains(WebKit::TypingAttribute::Underline))
4614 [result setObject:@(NSUnderlineStyleSingle) forKey:NSUnderlineStyleAttributeNamegetNSUnderlineStyleAttributeNameSingleton()];
4615
4616 return result;
4617}
4618
4619- (UIColor *)insertionPointColor
4620{
4621 // On macCatalyst we need to explicitly return the color we have calculated, rather than rely on textTraits, as on macCatalyst, UIKit ignores text traits.
4622#if PLATFORM(MACCATALYST)(defined WTF_PLATFORM_MACCATALYST && WTF_PLATFORM_MACCATALYST
)
4623 return [self _cascadeInteractionTintColor];
4624#else
4625#if USE(BROWSERENGINEKIT)(defined 1 && 1)
4626 if (!self._requiresLegacyTextInputTraits)
4627 return self.extendedTraitsDelegate.insertionPointColor;
4628#endif
4629 return [self.textInputTraits insertionPointColor];
4630#endif
4631}
4632
4633- (UIColor *)selectionBarColor
4634{
4635#if USE(BROWSERENGINEKIT)(defined 1 && 1)
4636 if (!self._requiresLegacyTextInputTraits)
4637 return self.extendedTextInputTraits.selectionHandleColor;
4638#endif
4639 return [self.textInputTraits selectionBarColor];
4640}
4641
4642- (UIColor *)selectionHighlightColor
4643{
4644#if USE(BROWSERENGINEKIT)(defined 1 && 1)
4645 if (!self._requiresLegacyTextInputTraits)
4646 return self.extendedTraitsDelegate.selectionHighlightColor;
4647#endif
4648 return [self.textInputTraits selectionHighlightColor];
4649}
4650
4651- (BOOL)_hasCustomTintColor
4652{
4653 if (!_cachedHasCustomTintColor) {
4654 auto defaultTintColor = WebCore::colorFromCocoaColor([adoptNS([UIView new]) tintColor]);
4655 _cachedHasCustomTintColor = defaultTintColor != WebCore::colorFromCocoaColor(self.tintColor);
4656 }
4657 return *_cachedHasCustomTintColor;
4658}
4659
4660- (UIColor *)_cascadeInteractionTintColor
4661{
4662ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
4663 if (!self.webView.configuration._textInteractionGesturesEnabled)
4664 return [UIColor clearColor];
4665ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
4666
4667 if (!protect(_page->preferences())->textInteractionEnabled())
4668 return [UIColor clearColor];
4669
4670 RetainPtr<UIColor> caretColorFromStyle;
4671 BOOL hasExplicitlySetCaretColorFromStyle = NO__objc_no;
4672 if (protect(_page)->editorState().hasPostLayoutData()) {
4673 auto& postLayoutData = *protect(_page)->editorState().postLayoutData;
4674 if (auto caretColor = postLayoutData.caretColor; caretColor.isValid()) {
4675 caretColorFromStyle = cocoaColor(caretColor);
4676 hasExplicitlySetCaretColorFromStyle = !postLayoutData.hasCaretColorAuto;
4677 }
4678 }
4679
4680 if (hasExplicitlySetCaretColorFromStyle)
4681 return caretColorFromStyle.autorelease();
4682
4683 auto tintColorFromNativeView = self.tintColor;
4684 if (self._hasCustomTintColor)
4685 return tintColorFromNativeView;
4686
4687 return caretColorFromStyle.autorelease() ?: tintColorFromNativeView;
4688}
4689
4690- (void)_updateTextInputTraitsForInteractionTintColor
4691{
4692#if !PLATFORM(WATCHOS)(defined WTF_PLATFORM_WATCHOS && WTF_PLATFORM_WATCHOS
)
4693 auto tintColor = [self _cascadeInteractionTintColor];
4694 [_legacyTextInputTraits _setColorsToMatchTintColor:tintColor];
4695 [_extendedTextInputTraits setSelectionColorsToMatchTintColor:tintColor];
4696#endif
4697}
4698
4699- (void)tintColorDidChange
4700{
4701 [super tintColorDidChange];
4702
4703 _cachedHasCustomTintColor = std::nullopt;
4704
4705 BOOL shouldUpdateTextSelection = self.isFirstResponder && [self canShowNonEmptySelectionView];
4706 if (shouldUpdateTextSelection)
4707 [_textInteractionWrapper deactivateSelection];
4708 [self _updateTextInputTraitsForInteractionTintColor];
4709 if (shouldUpdateTextSelection)
4710 [_textInteractionWrapper activateSelection];
4711
4712 protect(_page)->insertionPointColorDidChange();
4713}
4714
4715- (BOOL)shouldAllowHighlightLinkCreation
4716{
4717 Ref page = *_page;
4718 URL url { page->currentURL() };
4719 if (!url.isValid() || !url.protocolIsInHTTPFamily() || [_webView.get() _isDisplayingPDF])
4720 return NO__objc_no;
4721
4722 auto editorState = page->editorState();
4723 return editorState.selectionType == WebCore::SelectionType::Range && !editorState.isContentEditable && !editorState.selectionIsRangeInsideImageOverlay;
4724}
4725
4726- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
4727{
4728 if (_domPasteRequestHandler)
4729 return action == @selector(paste:);
4730
4731 auto& editorState = protect(_page)->editorState();
4732#if USE(BROWSERENGINEKIT)(defined 1 && 1)
4733 if (self.shouldUseAsyncInteractions) {
4734 if (action == @selector(moveInLayoutDirection:) || action == @selector(extendInLayoutDirection:) || action == @selector(moveInStorageDirection:byGranularity:) || action == @selector(extendInStorageDirection:byGranularity:))
4735 return editorState.selectionType != WebCore::SelectionType::None;
4736
4737 if (action == @selector(deleteInDirection:toGranularity:) || action == @selector(transposeCharactersAroundSelection))
4738 return editorState.isContentEditable;
4739 } else
4740#endif // USE(BROWSERENGINEKIT)
4741 {
4742 // These are UIKit IPI selectors. We don't want to forward them to the web view.
4743 if (action == @selector(_moveDown:withHistory:) || action == @selector(_moveLeft:withHistory:) || action == @selector(_moveRight:withHistory:)
4744 || action == @selector(_moveToEndOfDocument:withHistory:) || action == @selector(_moveToEndOfLine:withHistory:) || action == @selector(_moveToEndOfParagraph:withHistory:)
4745 || action == @selector(_moveToEndOfWord:withHistory:) || action == @selector(_moveToStartOfDocument:withHistory:) || action == @selector(_moveToStartOfLine:withHistory:)
4746 || action == @selector(_moveToStartOfParagraph:withHistory:) || action == @selector(_moveToStartOfWord:withHistory:) || action == @selector(_moveUp:withHistory:))
4747 return editorState.selectionType != WebCore::SelectionType::None;
4748
4749 if (action == @selector(_deleteByWord) || action == @selector(_deleteForwardByWord) || action == @selector(_deleteForwardAndNotify:)
4750 || action == @selector(_deleteToEndOfParagraph) || action == @selector(_deleteToStartOfLine) || action == @selector(_transpose))
4751 return editorState.isContentEditable;
4752 }
4753
4754 return [_webView.get() canPerformAction:action withSender:sender];
4755}
4756
4757- (BOOL)canPerformActionForWebView:(SEL)action withSender:(id)sender
4758{
4759 if (_domPasteRequestHandler)
4760 return action == @selector(paste:);
4761
4762 if (action == @selector(_nextAccessoryTab:))
4763 return self._hasFocusedElement && _focusedElementInformation.hasNextNode;
4764 if (action == @selector(_previousAccessoryTab:))
4765 return self._hasFocusedElement && _focusedElementInformation.hasPreviousNode;
4766
4767 auto editorState = protect(_page)->editorState();
4768 // FIXME: Some of the following checks should be removed once internal clients move to the underscore-prefixed versions.
4769 if (action == @selector(toggleBoldface:) || action == @selector(toggleItalics:) || action == @selector(toggleUnderline:) || action == @selector(_toggleStrikeThrough:)
4770 || action == @selector(_alignLeft:) || action == @selector(_alignRight:) || action == @selector(_alignCenter:) || action == @selector(_alignJustified:)
4771 || action == @selector(alignLeft:) || action == @selector(alignRight:) || action == @selector(alignCenter:) || action == @selector(alignJustified:)
4772 || action == @selector(_setTextColor:sender:) || action == @selector(_setFont:sender:) || action == @selector(_setFontSize:sender:)
4773 || action == @selector(_insertOrderedList:) || action == @selector(_insertUnorderedList:) || action == @selector(_insertNestedOrderedList:) || action == @selector(_insertNestedUnorderedList:)
4774 || action == @selector(_increaseListLevel:) || action == @selector(_decreaseListLevel:) || action == @selector(_changeListType:) || action == @selector(_indent:) || action == @selector(_outdent:)
4775 || action == @selector(increaseSize:) || action == @selector(decreaseSize:) || action == @selector(makeTextWritingDirectionNatural:)) {
4776 // FIXME: This should be more nuanced in the future, rather than returning YES for all richly editable areas. For instance, outdent: should be disabled when the selection is already
4777 // at the outermost indentation level.
4778 return editorState.isContentRichlyEditable;
4779 }
4780 if (action == @selector(cut:))
4781 return !editorState.isInPasswordField && editorState.isContentEditable && editorState.selectionType == WebCore::SelectionType::Range;
4782
4783 if (action == @selector(paste:) || action == @selector(_pasteAsQuotation:) || action == @selector(_pasteAndMatchStyle:) || action == @selector(pasteAndMatchStyle:)) {
4784 if (editorState.selectionType == WebCore::SelectionType::None || !editorState.isContentEditable)
4785 return NO__objc_no;
4786 UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
4787 NSArray *types = [self supportedPasteboardTypesForCurrentSelection];
4788 NSIndexSet *indices = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [pasteboard numberOfItems])];
4789 if ([pasteboard containsPasteboardTypes:types inItemSet:indices])
4790 return YES__objc_yes;
4791
4792#if PLATFORM(IOS)(defined 1 && 1) || PLATFORM(VISION)(defined WTF_PLATFORM_VISION && WTF_PLATFORM_VISION)
4793 if (editorState.isContentRichlyEditable && protect(_page->preferences())->attachmentElementEnabled()) {
4794 for (NSItemProvider *itemProvider in pasteboard.itemProviders) {
4795 auto preferredPresentationStyle = itemProvider.preferredPresentationStyle;
4796 if (preferredPresentationStyle == UIPreferredPresentationStyleInline)
4797 continue;
4798
4799 if (preferredPresentationStyle == UIPreferredPresentationStyleUnspecified && !itemProvider.suggestedName.length)
4800 continue;
4801
4802 if (itemProvider.web_fileUploadContentTypes.count)
4803 return YES__objc_yes;
4804 }
4805 }
4806#endif // PLATFORM(IOS) || PLATFORM(VISION)
4807 }
4808
4809 if (action == @selector(copy:)) {
4810 if (editorState.isInPasswordField && !editorState.selectionIsRangeInAutoFilledAndViewableField)
4811 return NO__objc_no;
4812 return editorState.selectionType == WebCore::SelectionType::Range;
4813 }
4814
4815 if (action == @selector(_define:) || action == @selector(define:) || action == @selector(lookup:)) {
4816 if (editorState.isInPasswordField || editorState.selectionType != WebCore::SelectionType::Range)
4817 return NO__objc_no;
4818
4819 NSUInteger textLength = editorState.postLayoutData ? editorState.postLayoutData->selectedTextLength : 0;
4820 // FIXME: We should be calling UIReferenceLibraryViewController to check if the length is
4821 // acceptable, but the interface takes a string.
4822 // <rdar://problem/15254406>
4823 if (!textLength || textLength > 200)
4824 return NO__objc_no;
4825
4826#if !PLATFORM(MACCATALYST)(defined WTF_PLATFORM_MACCATALYST && WTF_PLATFORM_MACCATALYST
)
4827 if ([(MCProfileConnection *)[PAL::getMCProfileConnectionClassSingleton() sharedConnection] effectiveBoolValueForSetting:PAL::get_ManagedConfiguration_MCFeatureDefinitionLookupAllowedSingleton()] == MCRestrictedBoolExplicitNo)
4828 return NO__objc_no;
4829#endif
4830
4831 return YES__objc_yes;
4832 }
4833
4834 if (action == @selector(_lookup:)) {
4835 if (editorState.isInPasswordField)
4836 return NO__objc_no;
4837
4838#if !PLATFORM(MACCATALYST)(defined WTF_PLATFORM_MACCATALYST && WTF_PLATFORM_MACCATALYST
)
4839 if ([(MCProfileConnection *)[PAL::getMCProfileConnectionClassSingleton() sharedConnection] effectiveBoolValueForSetting:PAL::get_ManagedConfiguration_MCFeatureDefinitionLookupAllowedSingleton()] == MCRestrictedBoolExplicitNo)
4840 return NO__objc_no;
4841#endif
4842
4843 return editorState.selectionType == WebCore::SelectionType::Range;
4844 }
4845
4846 if (action == @selector(_share:) || action == @selector(share:)) {
4847 if (editorState.isInPasswordField || editorState.selectionType != WebCore::SelectionType::Range)
4848 return NO__objc_no;
4849
4850 return editorState.postLayoutData && editorState.postLayoutData->selectedTextLength > 0;
4851 }
4852
4853 if (action == @selector(_addShortcut:) || action == @selector(addShortcut:)) {
4854 if (editorState.isInPasswordField || editorState.selectionType != WebCore::SelectionType::Range)
4855 return NO__objc_no;
4856
4857 NSString *selectedText = [self selectedText];
4858 if (![selectedText length])
4859 return NO__objc_no;
4860
4861 if (!UIKeyboardEnabledInputModesAllowOneToManyShortcuts())
4862 return NO__objc_no;
4863 if (![selectedText _containsCJScripts])
4864 return NO__objc_no;
4865 return YES__objc_yes;
4866 }
4867
4868 if (action == @selector(_promptForReplace:) || action == @selector(promptForReplace:)) {
4869 if (editorState.selectionType != WebCore::SelectionType::Range || !editorState.postLayoutData || !editorState.postLayoutData->isReplaceAllowed || ![[UIKeyboardImpl activeInstance] autocorrectSpellingEnabled])
4870 return NO__objc_no;
4871 if ([[self selectedText] _containsCJScriptsOnly])
4872 return NO__objc_no;
4873 return YES__objc_yes;
4874 }
4875
4876 if (action == @selector(_transliterateChinese:) || action == @selector(transliterateChinese:)) {
4877 if (editorState.selectionType != WebCore::SelectionType::Range || !editorState.postLayoutData || !editorState.postLayoutData->isReplaceAllowed || ![[UIKeyboardImpl activeInstance] autocorrectSpellingEnabled])
4878 return NO__objc_no;
4879 return UIKeyboardEnabledInputModesAllowChineseTransliterationForText([self selectedText]);
4880 }
4881
4882#if HAVE(TRANSLATION_UI_SERVICES)(defined 1 && 1)
4883 if (action == @selector(_translate:) || action == @selector(translate:)) {
4884 if (!PAL::isTranslationUIServicesFrameworkAvailable() || ![PAL::getLTUITranslationViewControllerClassSingleton() isAvailable])
4885 return NO__objc_no;
4886 return !editorState.isInPasswordField && editorState.selectionType == WebCore::SelectionType::Range;
4887 }
4888#endif // HAVE(TRANSLATION_UI_SERVICES)
4889
4890 if (action == @selector(select:)) {
4891 // Disable select in password fields so that you can't see word boundaries.
4892 return !editorState.isInPasswordField && editorState.selectionType != WebCore::SelectionType::Range && self._hasContent;
4893 }
4894
4895 auto isPreparingEditMenu = [&] {
4896 return [sender isKindOfClass:UIKeyCommand.class] && !_isInterpretingKeyEvent;
4897 };
4898
4899 if (action == @selector(selectAll:)) {
4900 if (isPreparingEditMenu()) {
4901 // By platform convention we don't show Select All in the edit menu for a range selection.
4902 return editorState.selectionType != WebCore::SelectionType::Range && self._hasContent;
4903 }
4904 return YES__objc_yes;
4905 }
4906
4907 if (action == @selector(replace:))
4908 return editorState.isContentEditable && !editorState.isInPasswordField;
4909
4910 if (action == @selector(makeTextWritingDirectionLeftToRight:) || action == @selector(makeTextWritingDirectionRightToLeft:)) {
4911 if (!editorState.isContentEditable)
4912 return NO__objc_no;
4913
4914 if (!editorState.postLayoutData)
4915 return NO__objc_no;
4916 auto baseWritingDirection = editorState.postLayoutData->baseWritingDirection;
4917 if (baseWritingDirection == WebCore::WritingDirection::LeftToRight && !UIKeyboardIsRightToLeftInputModeActive()) {
4918 // A keyboard is considered "active" if it is available for the user to switch to. As such, this check prevents
4919 // text direction actions from showing up in the case where a user has only added left-to-right keyboards, and
4920 // is also not editing right-to-left content.
4921 return NO__objc_no;
4922 }
4923
4924 if (action == @selector(makeTextWritingDirectionLeftToRight:))
4925 return baseWritingDirection != WebCore::WritingDirection::LeftToRight;
4926
4927 return baseWritingDirection != WebCore::WritingDirection::RightToLeft;
4928 }
4929
4930#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
4931 if (action == @selector(captureTextFromCamera:)) {
4932 if (!mayContainSelectableText(_focusedElementInformation.elementType) || _focusedElementInformation.isReadOnly)
4933 return NO__objc_no;
4934
4935 if (isPreparingEditMenu() && editorState.selectionType == WebCore::SelectionType::Range)
4936 return NO__objc_no;
4937 }
4938#endif // ENABLE(IMAGE_ANALYSIS)
4939
4940#if HAVE(UIFINDINTERACTION)(defined 1 && 1)
4941 if (action == @selector(useSelectionForFind:) || action == @selector(findSelected:) || action == @selector(_findSelected:)) {
4942 if (!self.webView._findInteractionEnabled)
4943 return NO__objc_no;
4944
4945 if (editorState.selectionType != WebCore::SelectionType::Range || !self.selectedText.length)
4946 return NO__objc_no;
4947
4948 return YES__objc_yes;
4949 }
4950#endif
4951
4952 return [super canPerformAction:action withSender:sender];
4953}
4954
4955- (id)targetForAction:(SEL)action withSender:(id)sender
4956{
4957 return [_webView.get() targetForAction:action withSender:sender];
4958}
4959
4960- (id)targetForActionForWebView:(SEL)action withSender:(id)sender
4961{
4962 BOOL hasFallbackAsyncTextInputAction = action == @selector(_define:) || action == @selector(_translate:) || action == @selector(_lookup:);
4963 if (self.shouldUseAsyncInteractions && hasFallbackAsyncTextInputAction)
4964 return nilnullptr;
4965 return [super targetForAction:action withSender:sender];
4966}
4967
4968- (void)_willHideMenu:(NSNotification *)notification
4969{
4970 [self _handleDOMPasteRequestWithResult:WebCore::DOMPasteAccessResponse::DeniedForGesture];
4971}
4972
4973- (void)_keyboardDidRequestDismissal:(NSNotification *)notification
4974{
4975 if (_isEditable && [self isFirstResponder])
4976 _keyboardDidRequestDismissal = YES__objc_yes;
4977
4978#if USE(UICONTEXTMENU)(defined 1 && 1)
4979 [_fileUploadPanel repositionContextMenuIfNeeded:WebKit::KeyboardIsDismissing::Yes];
4980#endif
4981}
4982
4983- (void)copyForWebView:(id)sender
4984{
4985 protect(_page)->executeEditCommand("copy"_s);
4986}
4987
4988- (void)cutForWebView:(id)sender
4989{
4990 [self _executeEditCommand:@"cut"];
4991}
4992
4993- (void)pasteForWebView:(id)sender
4994{
4995ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
4996 if (sender == UIMenuController.sharedMenuController && [self _handleDOMPasteRequestWithResult:WebCore::DOMPasteAccessResponse::GrantedForGesture])
4997 return;
4998ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
4999
5000 _autocorrectionContextNeedsUpdate = YES__objc_yes;
5001 protect(_page)->executeEditCommand("paste"_s);
5002}
5003
5004- (void)_pasteAsQuotationForWebView:(id)sender
5005{
5006 _autocorrectionContextNeedsUpdate = YES__objc_yes;
5007 protect(_page)->executeEditCommand("PasteAsQuotation"_s);
5008}
5009
5010- (void)selectForWebView:(id)sender
5011{
5012 if (!protect(_page->preferences())->textInteractionEnabled())
5013 return;
5014
5015 _autocorrectionContextNeedsUpdate = YES__objc_yes;
5016 [_textInteractionWrapper selectWord];
5017 // We cannot use selectWord command, because we want to be able to select the word even when it is the last in the paragraph.
5018 protect(_page)->extendSelection(WebCore::TextGranularity::WordGranularity, [] { });
5019}
5020
5021- (void)selectAllForWebView:(id)sender
5022{
5023 if (!protect(_page->preferences())->textInteractionEnabled())
5024 return;
5025
5026 _autocorrectionContextNeedsUpdate = YES__objc_yes;
5027 [_textInteractionWrapper selectAll:sender];
5028 protect(_page)->selectAll();
5029}
5030
5031- (BOOL)shouldSynthesizeKeyEvents
5032{
5033 if (_focusedElementInformation.shouldSynthesizeKeyEventsForEditing && self.hasHiddenContentEditable)
5034 return true;
5035 return false;
5036}
5037
5038- (void)toggleBoldfaceForWebView:(id)sender
5039{
5040 Ref page = *_page;
5041 if (!page->editorState().isContentRichlyEditable)
5042 return;
5043
5044 [self _executeEditCommand:@"toggleBold"];
5045
5046 if (self.shouldSynthesizeKeyEvents)
5047 page->generateSyntheticEditingCommand(WebKit::SyntheticEditingCommandType::ToggleBoldface);
5048}
5049
5050- (void)toggleItalicsForWebView:(id)sender
5051{
5052 Ref page = *_page;
5053 if (!page->editorState().isContentRichlyEditable)
5054 return;
5055
5056 [self _executeEditCommand:@"toggleItalic"];
5057
5058 if (self.shouldSynthesizeKeyEvents)
5059 page->generateSyntheticEditingCommand(WebKit::SyntheticEditingCommandType::ToggleItalic);
5060}
5061
5062- (void)toggleUnderlineForWebView:(id)sender
5063{
5064 if (!protect(_page)->editorState().isContentRichlyEditable)
5065 return;
5066
5067 [self _executeEditCommand:@"toggleUnderline"];
5068
5069 if (self.shouldSynthesizeKeyEvents)
5070 protect(_page)->generateSyntheticEditingCommand(WebKit::SyntheticEditingCommandType::ToggleUnderline);
5071}
5072
5073- (void)_defineForWebView:(id)sender
5074{
5075 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG179"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(5075, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
5076
5077 [self lookupForWebView:sender];
5078}
5079
5080- (void)accessibilityRetrieveSpeakSelectionContent
5081{
5082 RetainPtr<WKContentView> view = self;
5083 RetainPtr<WKWebView> webView = _webView.get();
5084 protect(_page)->getSelectionOrContentsAsString([view, webView](const String& string) {
5085 RetainPtr nsString = string.createNSString();
5086 [webView _accessibilityDidGetSpeakSelectionContent:nsString.get()];
5087 if ([view respondsToSelector:@selector(accessibilitySpeakSelectionSetContent:)])
5088 [view accessibilitySpeakSelectionSetContent:nsString.get()];
5089 });
5090}
5091
5092- (void)_accessibilityRetrieveRectsEnclosingSelectionOffset:(NSInteger)offset withGranularity:(UITextGranularity)granularity
5093{
5094 protect(_page)->requestRectsForGranularityWithSelectionOffset(toWKTextGranularity(granularity), offset, [view = retainPtr(self), offset, granularity](const Vector<WebCore::SelectionGeometry>& selectionGeometries) {
5095 if ([view respondsToSelector:@selector(_accessibilityDidGetSelectionRects:withGranularity:atOffset:)])
5096 [view _accessibilityDidGetSelectionRects:[view webSelectionRectsForSelectionGeometries:selectionGeometries] withGranularity:granularity atOffset:offset];
5097 });
5098}
5099
5100- (void)_accessibilityRetrieveRectsAtSelectionOffset:(NSInteger)offset withText:(NSString *)text
5101{
5102 [self _accessibilityRetrieveRectsAtSelectionOffset:offset withText:text completionHandler:nilnullptr];
5103}
5104
5105- (void)_accessibilityRetrieveRectsAtSelectionOffset:(NSInteger)offset withText:(NSString *)text completionHandler:(void (^)(const Vector<WebCore::SelectionGeometry>& geometries))completionHandler
5106{
5107 RetainPtr<WKContentView> view = self;
5108 protect(_page)->requestRectsAtSelectionOffsetWithText(offset, text, [view, offset, capturedCompletionHandler = makeBlockPtr(completionHandler)](const Vector<WebCore::SelectionGeometry>& selectionGeometries) {
5109 if (capturedCompletionHandler)
5110 capturedCompletionHandler(selectionGeometries);
5111
5112 if ([view respondsToSelector:@selector(_accessibilityDidGetSelectionRects:withGranularity:atOffset:)])
5113 [view _accessibilityDidGetSelectionRects:[view webSelectionRectsForSelectionGeometries:selectionGeometries] withGranularity:UITextGranularityWord atOffset:offset];
5114 });
5115}
5116
5117- (void)_accessibilityStoreSelection
5118{
5119 protect(_page)->storeSelectionForAccessibility(true);
5120}
5121
5122- (void)_accessibilityClearSelection
5123{
5124 protect(_page)->storeSelectionForAccessibility(false);
5125}
5126
5127static UIPasteboardName pasteboardNameForAccessCategory(WebCore::DOMPasteAccessCategory pasteAccessCategory)
5128{
5129 switch (pasteAccessCategory) {
5130 case WebCore::DOMPasteAccessCategory::General:
5131 case WebCore::DOMPasteAccessCategory::Fonts:
5132 return UIPasteboardNameGeneral;
5133 }
5134}
5135
5136static UIPasteboard *pasteboardForAccessCategory(WebCore::DOMPasteAccessCategory pasteAccessCategory)
5137{
5138 switch (pasteAccessCategory) {
5139 case WebCore::DOMPasteAccessCategory::General:
5140 case WebCore::DOMPasteAccessCategory::Fonts:
5141 return UIPasteboard.generalPasteboard;
5142 }
5143}
5144
5145- (BOOL)_handleDOMPasteRequestWithResult:(WebCore::DOMPasteAccessResponse)response
5146{
5147 if (auto pasteAccessCategory = std::exchange(_domPasteRequestCategory, std::nullopt)) {
5148 if (response == WebCore::DOMPasteAccessResponse::GrantedForCommand || response == WebCore::DOMPasteAccessResponse::GrantedForGesture) {
5149 if (auto replyID = protect(_page)->grantAccessToCurrentPasteboardData(pasteboardNameForAccessCategory(*pasteAccessCategory), [] () { }))
5150 protect(protect(protect(_page->websiteDataStore())->networkProcess())->connection())->waitForAsyncReplyAndDispatchImmediately<Messages::NetworkProcess::AllowFilesAccessFromWebProcess>(*replyID, 100_ms);
5151 }
5152 }
5153
5154 if (auto pasteHandler = WTF::move(_domPasteRequestHandler)) {
5155ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
5156 [UIMenuController.sharedMenuController hideMenuFromView:self];
5157ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
5158 pasteHandler(response);
5159 return YES__objc_yes;
5160 }
5161 return NO__objc_no;
5162}
5163
5164- (void)_willPerformAction:(SEL)action sender:(id)sender
5165{
5166 if (action != @selector(paste:))
5167 [self _handleDOMPasteRequestWithResult:WebCore::DOMPasteAccessResponse::DeniedForGesture];
5168}
5169
5170- (void)_didPerformAction:(SEL)action sender:(id)sender
5171{
5172 if (action == @selector(paste:))
5173 [self _handleDOMPasteRequestWithResult:WebCore::DOMPasteAccessResponse::DeniedForGesture];
5174}
5175
5176// UIWKInteractionViewProtocol
5177
5178static inline WebKit::GestureType toGestureType(WKBEGestureTypeBEGestureType gestureType)
5179{
5180 switch (gestureType) {
5181 case WKBEGestureTypeLoupeBEGestureTypeLoupe:
5182 return WebKit::GestureType::Loupe;
5183 case WKBEGestureTypeOneFingerTapBEGestureTypeOneFingerTap:
5184 return WebKit::GestureType::OneFingerTap;
5185 case WKBEGestureTypeDoubleTapAndHoldBEGestureTypeDoubleTapAndHold:
5186 return WebKit::GestureType::TapAndAHalf;
5187 case WKBEGestureTypeDoubleTapBEGestureTypeDoubleTap:
5188 return WebKit::GestureType::DoubleTap;
5189 case WKBEGestureTypeOneFingerDoubleTapBEGestureTypeOneFingerDoubleTap:
5190 return WebKit::GestureType::OneFingerDoubleTap;
5191 case WKBEGestureTypeOneFingerTripleTapBEGestureTypeOneFingerTripleTap:
5192 return WebKit::GestureType::OneFingerTripleTap;
5193 case WKBEGestureTypeTwoFingerSingleTapBEGestureTypeTwoFingerSingleTap:
5194 return WebKit::GestureType::TwoFingerSingleTap;
5195 case WKBEGestureTypeIMPhraseBoundaryDragBEGestureTypeIMPhraseBoundaryDrag:
5196 return WebKit::GestureType::PhraseBoundary;
5197 default:
5198 ASSERT_NOT_REACHED()((void)0);
5199 return WebKit::GestureType::Loupe;
5200 }
5201}
5202
5203static inline WKBEGestureTypeBEGestureType toWKBEGestureType(WebKit::GestureType gestureType)
5204{
5205 switch (gestureType) {
5206 case WebKit::GestureType::Loupe:
5207 return WKBEGestureTypeLoupeBEGestureTypeLoupe;
5208 case WebKit::GestureType::OneFingerTap:
5209 return WKBEGestureTypeOneFingerTapBEGestureTypeOneFingerTap;
5210 case WebKit::GestureType::TapAndAHalf:
5211 return WKBEGestureTypeDoubleTapAndHoldBEGestureTypeDoubleTapAndHold;
5212 case WebKit::GestureType::DoubleTap:
5213 return WKBEGestureTypeDoubleTapBEGestureTypeDoubleTap;
5214 case WebKit::GestureType::OneFingerDoubleTap:
5215 return WKBEGestureTypeOneFingerDoubleTapBEGestureTypeOneFingerDoubleTap;
5216 case WebKit::GestureType::OneFingerTripleTap:
5217 return WKBEGestureTypeOneFingerTripleTapBEGestureTypeOneFingerTripleTap;
5218 case WebKit::GestureType::TwoFingerSingleTap:
5219 return WKBEGestureTypeTwoFingerSingleTapBEGestureTypeTwoFingerSingleTap;
5220 case WebKit::GestureType::PhraseBoundary:
5221 return WKBEGestureTypeIMPhraseBoundaryDragBEGestureTypeIMPhraseBoundaryDrag;
5222 }
5223}
5224
5225static TextStream& operator<<(TextStream& stream, WebKit::GestureType gestureType)
5226{
5227 switch (gestureType) {
5228 case WebKit::GestureType::Loupe: stream << "Loupe"; break;
5229 case WebKit::GestureType::OneFingerTap: stream << "OneFingerTap"; break;
5230 case WebKit::GestureType::TapAndAHalf: stream << "TapAndAHalf"; break;
5231 case WebKit::GestureType::DoubleTap: stream << "DoubleTap"; break;
5232 case WebKit::GestureType::OneFingerDoubleTap: stream << "OneFingerDoubleTap"; break;
5233 case WebKit::GestureType::OneFingerTripleTap: stream << "OneFingerTripleTap"; break;
5234 case WebKit::GestureType::TwoFingerSingleTap: stream << "TwoFingerSingleTap"; break;
5235 case WebKit::GestureType::PhraseBoundary: stream << "PhraseBoundary"; break;
5236 }
5237
5238 return stream;
5239}
5240
5241static inline WebKit::SelectionTouch toSelectionTouch(WKBESelectionTouchPhaseBESelectionTouchPhase touch)
5242{
5243 switch (touch) {
5244 case WKBESelectionTouchPhaseStartedBESelectionTouchPhaseStarted:
5245 return WebKit::SelectionTouch::Started;
5246 case WKBESelectionTouchPhaseMovedBESelectionTouchPhaseMoved:
5247 return WebKit::SelectionTouch::Moved;
5248 case WKBESelectionTouchPhaseEndedBESelectionTouchPhaseEnded:
5249 return WebKit::SelectionTouch::Ended;
5250 case WKBESelectionTouchPhaseEndedMovingForwardBESelectionTouchPhaseEndedMovingForward:
5251 return WebKit::SelectionTouch::EndedMovingForward;
5252 case WKBESelectionTouchPhaseEndedMovingBackwardBESelectionTouchPhaseEndedMovingBackward:
5253 return WebKit::SelectionTouch::EndedMovingBackward;
5254 case WKBESelectionTouchPhaseEndedNotMovingBESelectionTouchPhaseEndedNotMoving:
5255 return WebKit::SelectionTouch::EndedNotMoving;
5256 }
5257 ASSERT_NOT_REACHED()((void)0);
5258 return WebKit::SelectionTouch::Ended;
5259}
5260
5261static inline WKBESelectionTouchPhaseBESelectionTouchPhase toWKBESelectionTouchPhase(WebKit::SelectionTouch touch)
5262{
5263 switch (touch) {
5264 case WebKit::SelectionTouch::Started:
5265 return WKBESelectionTouchPhaseStartedBESelectionTouchPhaseStarted;
5266 case WebKit::SelectionTouch::Moved:
5267 return WKBESelectionTouchPhaseMovedBESelectionTouchPhaseMoved;
5268 case WebKit::SelectionTouch::Ended:
5269 return WKBESelectionTouchPhaseEndedBESelectionTouchPhaseEnded;
5270 case WebKit::SelectionTouch::EndedMovingForward:
5271 return WKBESelectionTouchPhaseEndedMovingForwardBESelectionTouchPhaseEndedMovingForward;
5272 case WebKit::SelectionTouch::EndedMovingBackward:
5273 return WKBESelectionTouchPhaseEndedMovingBackwardBESelectionTouchPhaseEndedMovingBackward;
5274 case WebKit::SelectionTouch::EndedNotMoving:
5275 return WKBESelectionTouchPhaseEndedNotMovingBESelectionTouchPhaseEndedNotMoving;
5276 }
5277}
5278
5279static TextStream& operator<<(TextStream& stream, WebKit::SelectionTouch touch)
5280{
5281 switch (touch) {
5282 case WebKit::SelectionTouch::Started: stream << "Started"; break;
5283 case WebKit::SelectionTouch::Moved: stream << "Moved"; break;
5284 case WebKit::SelectionTouch::Ended: stream << "Ended"; break;
5285 case WebKit::SelectionTouch::EndedMovingForward: stream << "EndedMovingForward"; break;
5286 case WebKit::SelectionTouch::EndedMovingBackward: stream << "EndedMovingBackward"; break;
5287 case WebKit::SelectionTouch::EndedNotMoving: stream << "EndedNotMoving"; break;
5288 }
5289
5290 return stream;
5291}
5292
5293static inline WebKit::GestureRecognizerState toGestureRecognizerState(UIGestureRecognizerState state)
5294{
5295 switch (state) {
5296 case UIGestureRecognizerStatePossible:
5297 return WebKit::GestureRecognizerState::Possible;
5298 case UIGestureRecognizerStateBegan:
5299 return WebKit::GestureRecognizerState::Began;
5300 case UIGestureRecognizerStateChanged:
5301 return WebKit::GestureRecognizerState::Changed;
5302 case UIGestureRecognizerStateCancelled:
5303 return WebKit::GestureRecognizerState::Cancelled;
5304 case UIGestureRecognizerStateEnded:
5305 return WebKit::GestureRecognizerState::Ended;
5306 case UIGestureRecognizerStateFailed:
5307 return WebKit::GestureRecognizerState::Failed;
5308 }
5309}
5310
5311static inline UIGestureRecognizerState toUIGestureRecognizerState(WebKit::GestureRecognizerState state)
5312{
5313 switch (state) {
5314 case WebKit::GestureRecognizerState::Possible:
5315 return UIGestureRecognizerStatePossible;
5316 case WebKit::GestureRecognizerState::Began:
5317 return UIGestureRecognizerStateBegan;
5318 case WebKit::GestureRecognizerState::Changed:
5319 return UIGestureRecognizerStateChanged;
5320 case WebKit::GestureRecognizerState::Cancelled:
5321 return UIGestureRecognizerStateCancelled;
5322 case WebKit::GestureRecognizerState::Ended:
5323 return UIGestureRecognizerStateEnded;
5324 case WebKit::GestureRecognizerState::Failed:
5325 return UIGestureRecognizerStateFailed;
5326 }
5327}
5328
5329static TextStream& operator<<(TextStream& stream, WebKit::GestureRecognizerState state)
5330{
5331 switch (state) {
5332 case WebKit::GestureRecognizerState::Possible: stream << "Possible"; break;
5333 case WebKit::GestureRecognizerState::Began: stream << "Began"; break;
5334 case WebKit::GestureRecognizerState::Changed: stream << "Changed"; break;
5335 case WebKit::GestureRecognizerState::Cancelled: stream << "Cancelled"; break;
5336 case WebKit::GestureRecognizerState::Ended: stream << "Ended"; break;
5337 case WebKit::GestureRecognizerState::Failed: stream << "Failed"; break;
5338 }
5339
5340 return stream;
5341}
5342
5343static inline WKBESelectionFlagsBESelectionFlags toWKBESelectionFlags(OptionSet<WebKit::SelectionFlags> flags)
5344{
5345#if USE(BROWSERENGINEKIT)(defined 1 && 1)
5346 NSUInteger uiFlags = WKBESelectionFlagsNoneBESelectionFlagsNone;
5347#else
5348 NSInteger uiFlags = UIWKNone;
5349#endif
5350 if (flags.contains(WebKit::SelectionFlags::WordIsNearTap))
5351 uiFlags |= WKBEWordIsNearTapBEWordIsNearTap;
5352 if (flags.contains(WebKit::SelectionFlags::SelectionFlipped))
5353 uiFlags |= WKBESelectionFlippedBESelectionFlipped;
5354 if (flags.contains(WebKit::SelectionFlags::PhraseBoundaryChanged))
5355 uiFlags |= WKBEPhraseBoundaryChangedBEPhraseBoundaryChanged;
5356
5357 return static_cast<WKBESelectionFlagsBESelectionFlags>(uiFlags);
5358}
5359
5360static inline OptionSet<WebKit::SelectionFlags> toSelectionFlags(WKBESelectionFlagsBESelectionFlags uiFlags)
5361{
5362 OptionSet<WebKit::SelectionFlags> flags;
5363 if (uiFlags & WKBEWordIsNearTapBEWordIsNearTap)
5364 flags.add(WebKit::SelectionFlags::WordIsNearTap);
5365 if (uiFlags & WKBESelectionFlippedBESelectionFlipped)
5366 flags.add(WebKit::SelectionFlags::SelectionFlipped);
5367 if (uiFlags & WKBEPhraseBoundaryChangedBEPhraseBoundaryChanged)
5368 flags.add(WebKit::SelectionFlags::PhraseBoundaryChanged);
5369 return flags;
5370}
5371
5372static TextStream& operator<<(TextStream& stream, OptionSet<WebKit::SelectionFlags> flags)
5373{
5374 bool didAppend = false;
5375
5376 auto appendIf = [&](auto flag, auto message) {
5377 if (!flags.contains(flag))
5378 return;
5379 if (didAppend)
5380 stream << "|";
5381 stream << message;
5382 didAppend = true;
5383 };
5384
5385 appendIf(WebKit::SelectionFlags::WordIsNearTap, "WordIsNearTap");
5386 appendIf(WebKit::SelectionFlags::SelectionFlipped, "SelectionFlipped");
5387 appendIf(WebKit::SelectionFlags::PhraseBoundaryChanged, "PhraseBoundaryChanged");
5388
5389 if (!didAppend)
5390 stream << "None";
5391
5392 return stream;
5393}
5394
5395static inline WebCore::TextGranularity toWKTextGranularity(UITextGranularity granularity)
5396{
5397 switch (granularity) {
5398 case UITextGranularityCharacter:
5399 return WebCore::TextGranularity::CharacterGranularity;
5400 case UITextGranularityWord:
5401 return WebCore::TextGranularity::WordGranularity;
5402 case UITextGranularitySentence:
5403 return WebCore::TextGranularity::SentenceGranularity;
5404 case UITextGranularityParagraph:
5405 return WebCore::TextGranularity::ParagraphGranularity;
5406 case UITextGranularityLine:
5407 return WebCore::TextGranularity::LineGranularity;
5408 case UITextGranularityDocument:
5409 return WebCore::TextGranularity::DocumentGranularity;
5410 }
5411}
5412
5413static inline WebCore::SelectionDirection toWKSelectionDirection(UITextDirection direction)
5414{
5415 switch (direction) {
5416 case UITextLayoutDirectionDown:
5417 case UITextLayoutDirectionRight:
5418 return WebCore::SelectionDirection::Right;
5419 case UITextLayoutDirectionUp:
5420 case UITextLayoutDirectionLeft:
5421 return WebCore::SelectionDirection::Left;
5422 default:
5423 // UITextDirection is not an enum, but we only want to accept values from UITextLayoutDirection.
5424 ASSERT_NOT_REACHED()((void)0);
5425 return WebCore::SelectionDirection::Right;
5426 }
5427}
5428
5429static void selectionChangedWithGesture(WKTextInteractionWrapper *interaction, const WebCore::IntPoint& point, WebKit::GestureType gestureType, WebKit::GestureRecognizerState gestureState, OptionSet<WebKit::SelectionFlags> flags)
5430{
5431 [interaction selectionChangedWithGestureAt:(CGPoint)point withGesture:toWKBEGestureType(gestureType) withState:toUIGestureRecognizerState(gestureState) withFlags:toWKBESelectionFlags(flags)];
5432}
5433
5434static void selectionChangedWithTouch(WKTextInteractionWrapper *interaction, const WebCore::IntPoint& point, WebKit::SelectionTouch touch, OptionSet<WebKit::SelectionFlags> flags)
5435{
5436 [interaction selectionChangedWithTouchAt:(CGPoint)point withSelectionTouch:toWKBESelectionTouchPhase(touch) withFlags:toWKBESelectionFlags(flags)];
5437}
5438
5439- (BOOL)_hasFocusedElement
5440{
5441 return _focusedElementInformation.elementType != WebKit::InputType::None;
5442}
5443
5444- (BOOL)_isSameAsFocusedElement:(const WebCore::ElementContext&)element
5445{
5446 return [self _hasFocusedElement] && _focusedElementInformation.elementContext.isSameElement(element);
5447}
5448
5449- (void)changeSelectionWithGestureAt:(CGPoint)point withGesture:(WKBEGestureTypeBEGestureType)gestureType withState:(UIGestureRecognizerState)state
5450{
5451 [self changeSelectionWithGestureAt:point withGesture:gestureType withState:state withFlags:UIWKNone];
5452}
5453
5454- (void)changeSelectionWithGestureAt:(CGPoint)point withGesture:(WKBEGestureTypeBEGestureType)gestureType withState:(UIGestureRecognizerState)state withFlags:(WKBESelectionFlagsBESelectionFlags)flags
5455{
5456 logTextInteraction(__PRETTY_FUNCTION__, self.textInteractionLoupeGestureRecognizer, point, state, gestureType, std::nullopt, flags);
5457
5458 _autocorrectionContextNeedsUpdate = YES__objc_yes;
5459 _usingGestureForSelection = YES__objc_yes;
5460 protect(_page)->selectWithGesture(WebCore::IntPoint(point), toGestureType(gestureType), toGestureRecognizerState(state), self._hasFocusedElement, [self, strongSelf = retainPtr(self), state, flags](const WebCore::IntPoint& point, WebKit::GestureType gestureType, WebKit::GestureRecognizerState gestureState, OptionSet<WebKit::SelectionFlags> innerFlags) {
5461 selectionChangedWithGesture(_textInteractionWrapper.get(), point, gestureType, gestureState, toSelectionFlags(flags) | innerFlags);
5462 if (state == UIGestureRecognizerStateEnded || state == UIGestureRecognizerStateCancelled)
5463 _usingGestureForSelection = NO__objc_no;
5464 });
5465}
5466
5467- (void)updateSelection
5468{
5469 switch (_selectionInteractionType) {
5470 case SelectionInteractionType::None:
5471 break;
5472 case SelectionInteractionType::Touch:
5473 [self updateSelectionWithTouchAt:[self convertPoint:_lastSelectionTouch.point fromView:self.webView] withSelectionTouch:WKBESelectionTouchPhaseMovedBESelectionTouchPhaseMoved baseIsStart:_lastSelectionTouch.baseIsStart withFlags:_lastSelectionTouch.flags];
5474 break;
5475 case SelectionInteractionType::ExtentPoint:
5476 [self updateSelectionWithExtentPoint:[self convertPoint:_lastSelectionExtentPoint.point fromView:self.webView] hasFocusedElement:self._hasFocusedElement respectSelectionAnchor:_lastSelectionExtentPoint.respectSelectionAnchor completionHandler:^(BOOL selectionEndIsMoving) { }];
5477 break;
5478 case SelectionInteractionType::ExtentPointAndBoundary:
5479 [self updateSelectionWithExtentPointAndBoundary:[self convertPoint:_lastSelectionExtentPointAndBoundary.point fromView:self.webView] textGranularity:_lastSelectionExtentPointAndBoundary.granularity textInteractionSource:_lastSelectionExtentPointAndBoundary.interactionSource completionHandler:^(BOOL selectionEndIsMoving) { }];
5480 break;
5481 }
5482}
5483
5484- (void)changeSelectionWithTouchAt:(CGPoint)point withSelectionTouch:(WKBESelectionTouchPhaseBESelectionTouchPhase)touch baseIsStart:(BOOL)baseIsStart withFlags:(WKBESelectionFlagsBESelectionFlags)flags
5485{
5486 logTextInteraction(__PRETTY_FUNCTION__, self.textInteractionLoupeGestureRecognizer, point, std::nullopt, std::nullopt, touch, flags);
5487
5488 _autocorrectionContextNeedsUpdate = YES__objc_yes;
5489 _usingGestureForSelection = YES__objc_yes;
5490
5491 if (_page->isAutoscrolling()) {
5492 auto touchType = toSelectionTouch(touch);
5493 switch (touchType) {
5494 case WebKit::SelectionTouch::Started:
5495 case WebKit::SelectionTouch::Moved:
5496 _selectionInteractionType = SelectionInteractionType::Touch;
5497 _lastSelectionTouch.point = [self convertPoint:point toView:self.webView];
5498 _lastSelectionTouch.baseIsStart = baseIsStart;
5499 _lastSelectionTouch.flags = flags;
5500 break;
5501 case WebKit::SelectionTouch::Ended:
5502 case WebKit::SelectionTouch::EndedMovingForward:
5503 case WebKit::SelectionTouch::EndedMovingBackward:
5504 case WebKit::SelectionTouch::EndedNotMoving:
5505 _selectionInteractionType = SelectionInteractionType::None;
5506 break;
5507 }
5508 }
5509
5510 [self updateSelectionWithTouchAt:point withSelectionTouch:touch baseIsStart:baseIsStart withFlags:flags];
5511
5512}
5513
5514- (void)updateSelectionWithTouchAt:(CGPoint)point withSelectionTouch:(WKBESelectionTouchPhaseBESelectionTouchPhase)touch baseIsStart:(BOOL)baseIsStart withFlags:(WKBESelectionFlagsBESelectionFlags)flags
5515{
5516 protect(_page)->updateSelectionWithTouches(WebCore::IntPoint(point), toSelectionTouch(touch), baseIsStart, [self, strongSelf = retainPtr(self), flags](const WebCore::IntPoint& point, WebKit::SelectionTouch touch, OptionSet<WebKit::SelectionFlags> innerFlags) {
5517 if (_selectionInteractionType == SelectionInteractionType::Touch && innerFlags.contains(WebKit::SelectionFlags::SelectionFlipped))
5518 _lastSelectionTouch.baseIsStart = !_lastSelectionTouch.baseIsStart;
5519 selectionChangedWithTouch(_textInteractionWrapper.get(), point, touch, toSelectionFlags(flags) | innerFlags);
5520 if (toWKBESelectionTouchPhase(touch) != WKBESelectionTouchPhaseStartedBESelectionTouchPhaseStarted && toWKBESelectionTouchPhase(touch) != WKBESelectionTouchPhaseMovedBESelectionTouchPhaseMoved)
5521 _usingGestureForSelection = NO__objc_no;
5522 });
5523}
5524
5525- (void)changeSelectionWithTouchesFrom:(CGPoint)from to:(CGPoint)to withGesture:(WKBEGestureTypeBEGestureType)gestureType withState:(UIGestureRecognizerState)gestureState
5526{
5527 logTextInteraction(__PRETTY_FUNCTION__, self.textInteractionLoupeGestureRecognizer, from, gestureState, gestureType);
5528
5529 _autocorrectionContextNeedsUpdate = YES__objc_yes;
5530 _usingGestureForSelection = YES__objc_yes;
5531 protect(_page)->selectWithTwoTouches(WebCore::IntPoint(from), WebCore::IntPoint(to), toGestureType(gestureType), toGestureRecognizerState(gestureState), [self, strongSelf = retainPtr(self)](const WebCore::IntPoint& point, WebKit::GestureType gestureType, WebKit::GestureRecognizerState gestureState, OptionSet<WebKit::SelectionFlags> flags) {
5532 selectionChangedWithGesture(_textInteractionWrapper.get(), point, gestureType, gestureState, flags);
5533 if (toUIGestureRecognizerState(gestureState) == UIGestureRecognizerStateEnded || toUIGestureRecognizerState(gestureState) == UIGestureRecognizerStateCancelled)
5534 _usingGestureForSelection = NO__objc_no;
5535 });
5536}
5537
5538- (void)moveByOffset:(NSInteger)offset
5539{
5540 if (!offset)
5541 return;
5542
5543 [self _internalBeginSelectionChange];
5544 RetainPtr<WKContentView> view = self;
5545 protect(_page)->moveSelectionByOffset(offset, [view] {
5546 [view _internalEndSelectionChange];
5547 });
5548}
5549
5550- (const WebKit::WKAutoCorrectionData&)autocorrectionData
5551{
5552 return _autocorrectionData;
5553}
5554
5555// The completion handler can pass nil if input does not match the actual text preceding the insertion point.
5556- (void)requestAutocorrectionRectsForString:(NSString *)input withCompletionHandler:(void (^)(UIWKAutocorrectionRects *rectsForInput))completionHandler
5557{
5558 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG180"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(5558, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
5559
5560 if (!completionHandler) {
5561 [NSException raise:NSInvalidArgumentException format:@"Expected a nonnull completion handler in %s.", __PRETTY_FUNCTION__];
5562 return;
5563 }
5564
5565 [self _internalRequestTextRectsForString:input completion:[view = retainPtr(self), completionHandler = makeBlockPtr(completionHandler)](auto& rects) {
5566 completionHandler(!rects.isEmpty() ? [WKAutocorrectionRects autocorrectionRectsWithFirstCGRect:rects.first() lastCGRect:rects.last()] : nilnullptr);
5567 }];
5568}
5569
5570- (void)_internalRequestTextRectsForString:(NSString *)input completion:(Function<void(const Vector<WebCore::FloatRect>&)>&&)completion
5571{
5572 if (!input.length)
5573 return completion({ });
5574
5575 protect(_page)->requestAutocorrectionData(input, [view = retainPtr(self), completion = WTF::move(completion)](const WebKit::WebAutocorrectionData& data) mutable {
5576 CGRect firstRect;
5577 CGRect lastRect;
5578 auto& rects = data.textRects;
5579 if (rects.isEmpty()) {
5580 firstRect = CGRectZero;
5581 lastRect = CGRectZero;
5582 } else {
5583 firstRect = rects.first();
5584 lastRect = rects.last();
5585 }
5586
5587 view->_autocorrectionData.font = data.font;
5588 view->_autocorrectionData.textFirstRect = firstRect;
5589 view->_autocorrectionData.textLastRect = lastRect;
5590
5591 completion(rects);
5592 });
5593}
5594
5595#if HAVE(UI_EDIT_MENU_INTERACTION)(defined 1 && 1)
5596
5597- (void)requestPreferredArrowDirectionForEditMenuWithCompletionHandler:(void(^)(UIEditMenuArrowDirection))completion
5598{
5599 if (self.shouldSuppressEditMenu) {
5600 completion(UIEditMenuArrowDirectionAutomatic);
5601 return;
5602 }
5603
5604 auto requestRectsToEvadeIfNeeded = [startTime = ApproximateTime::now(), weakSelf = WeakObjCPtr<WKContentView>(self), completion = makeBlockPtr(completion)]() mutable {
5605 auto strongSelf = weakSelf.get();
5606 if (!strongSelf) {
5607 completion(UIEditMenuArrowDirectionAutomatic);
5608 return;
5609 }
5610
5611 if ([strongSelf webView]._editable) {
5612 completion(UIEditMenuArrowDirectionAutomatic);
5613 return;
5614 }
5615
5616 auto focusedElementType = strongSelf->_focusedElementInformation.elementType;
5617 if (focusedElementType != WebKit::InputType::ContentEditable && focusedElementType != WebKit::InputType::TextArea) {
5618 completion(UIEditMenuArrowDirectionAutomatic);
5619 return;
5620 }
5621
5622 // Give the page some time to present custom editing UI before attempting to detect and evade it.
5623 auto delayBeforeShowingEditMenu = std::max(0_s, 0.25_s - (ApproximateTime::now() - startTime));
5624 WorkQueue::mainSingleton().dispatchAfter(delayBeforeShowingEditMenu, [completion = WTF::move(completion), weakSelf]() mutable {
5625 auto strongSelf = weakSelf.get();
5626 if (!strongSelf) {
5627 completion(UIEditMenuArrowDirectionAutomatic);
5628 return;
5629 }
5630
5631 if (!strongSelf->_page) {
5632 completion(UIEditMenuArrowDirectionAutomatic);
5633 return;
5634 }
5635
5636 protect(strongSelf->_page)->requestEvasionRectsAboveSelection([completion = WTF::move(completion)](auto& rects) mutable {
5637 completion(rects.isEmpty() ? UIEditMenuArrowDirectionAutomatic : UIEditMenuArrowDirectionUp);
5638 });
5639 });
5640 };
5641
5642#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
5643 [self doAfterComputingImageAnalysisResultsForBackgroundRemoval:WTF::move(requestRectsToEvadeIfNeeded)];
5644#else
5645 requestRectsToEvadeIfNeeded();
5646#endif
5647}
5648
5649#endif // HAVE(UI_EDIT_MENU_INTERACTION)
5650
5651#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
5652
5653- (UIMenu *)removeBackgroundMenu
5654{
5655 if (!_page || !protect(_page->preferences())->removeBackgroundEnabled())
5656 return nilnullptr;
5657
5658 if (!protect(_page)->editorState().hasPostLayoutData() || !_removeBackgroundData)
5659 return nilnullptr;
5660
5661 if (_removeBackgroundData->element != protect(_page)->editorState().postLayoutData->selectedEditableImage)
5662 return nilnullptr;
5663
5664 return [self menuWithInlineAction:WebCore::contextMenuItemTitleRemoveBackground().createNSString().get() image:[UIImage _systemImageNamed:@"circle.rectangle.filled.pattern.diagonalline"] identifier:@"WKActionRemoveBackground" handler:[](WKContentView *view) {
5665 auto data = std::exchange(view->_removeBackgroundData, { });
5666 if (!data)
5667 return;
5668
5669 auto [elementContext, image, preferredMIMEType] = *data;
5670 if (auto [data, type] = WebKit::imageDataForRemoveBackground(image.get(), preferredMIMEType.createCFString().get()); data)
5671 protect(view->_page)->replaceImageForRemoveBackground(elementContext, { String { type.get() } }, span(data.get()));
5672 }];
5673}
5674
5675- (void)doAfterComputingImageAnalysisResultsForBackgroundRemoval:(CompletionHandler<void()>&&)completion
5676{
5677 Ref page = *_page;
5678 if (!page->editorState().hasPostLayoutData()) {
5679 completion();
5680 return;
5681 }
5682
5683 auto elementToAnalyze = page->editorState().postLayoutData->selectedEditableImage;
5684 if (_removeBackgroundData && _removeBackgroundData->element == elementToAnalyze) {
5685 completion();
5686 return;
5687 }
5688
5689 _removeBackgroundData = std::nullopt;
5690
5691 if (!elementToAnalyze) {
5692 completion();
5693 return;
5694 }
5695
5696 protect(_page)->shouldAllowRemoveBackground(*elementToAnalyze, [context = *elementToAnalyze, completion = WTF::move(completion), weakSelf = WeakObjCPtr<WKContentView>(self)](bool shouldAllow) mutable {
5697 auto strongSelf = weakSelf.get();
5698 if (!shouldAllow || !strongSelf) {
5699 completion();
5700 return;
5701 }
5702
5703 protect(strongSelf->_page)->requestImageBitmap(context, [context, completion = WTF::move(completion), weakSelf = WTF::move(weakSelf)](std::optional<WebCore::ShareableBitmapHandle>&& imageData, auto& sourceMIMEType) mutable {
5704 auto strongSelf = weakSelf.get();
5705 if (!strongSelf) {
5706 completion();
5707 return;
5708 }
5709
5710 if (!imageData) {
5711 completion();
5712 return;
5713 }
5714
5715 auto imageBitmap = WebCore::ShareableBitmap::create(WTF::move(*imageData));
5716 if (!imageBitmap) {
5717 completion();
5718 return;
5719 }
5720
5721 RetainPtr cgImage = imageBitmap->createPlatformImage(WebCore::DontCopyBackingStore);
5722 if (!cgImage) {
5723 completion();
5724 return;
5725 }
5726
5727 WebKit::requestBackgroundRemoval(cgImage.get(), [sourceMIMEType, context, completion = WTF::move(completion), weakSelf](CGImageRef result) mutable {
5728 auto strongSelf = weakSelf.get();
5729 if (!strongSelf) {
5730 completion();
5731 return;
5732 }
5733
5734 if (result)
5735 strongSelf->_removeBackgroundData = { { context, { result }, sourceMIMEType } };
5736 else
5737 strongSelf->_removeBackgroundData = std::nullopt;
5738 completion();
5739 });
5740 });
5741 });
5742}
5743
5744#endif // ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)
5745
5746- (BOOL)_handleTapOverInteractiveControl:(CGPoint)position
5747{
5748 auto *hitButton = dynamic_objc_cast<UIControl>([self hitTest:position withEvent:nilnullptr]);
5749 if (!hitButton)
5750 return NO__objc_no;
5751
5752#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
5753 UIButton *analysisButton = [_imageAnalysisInteraction analysisButton];
5754 // This has to be a class check instead of a straight equality check because the `analysisButton`
5755 // isn't in the view hierarchy, so this is the only way to disambiguate this particular button.
5756 if (analysisButton && hitButton.class == analysisButton.class)
5757 [_imageAnalysisInteraction setHighlightSelectableItems:![_imageAnalysisInteraction highlightSelectableItems]];
5758#endif
5759
5760 [hitButton sendActionsForControlEvents:UIControlEventTouchUpInside];
5761
5762 return YES__objc_yes;
5763}
5764
5765static void logTextInteraction(const char* methodName, UIGestureRecognizer *loupeGestureRecognizer, std::optional<CGPoint> location = std::nullopt, std::optional<UIGestureRecognizerState> gestureState = std::nullopt, std::optional<WKBEGestureTypeBEGestureType> gestureType = std::nullopt, std::optional<WKBESelectionTouchPhaseBESelectionTouchPhase> selectionTouch = std::nullopt, std::optional<WKBESelectionFlagsBESelectionFlags> selectionFlags = std::nullopt)
5766{
5767 TextStream selectionChangeStream(TextStream::LineMode::SingleLine);
5768 selectionChangeStream << "loupeGestureState=" << toGestureRecognizerState(loupeGestureRecognizer.state);
5769 if (location)
5770 selectionChangeStream << ", location={" << location->x << ", " << location->y << "}";
5771
5772 if (gestureState)
5773 selectionChangeStream << ", " << "gestureState=" << toGestureRecognizerState(*gestureState);
5774
5775 if (gestureType)
5776 selectionChangeStream << ", " << "gestureType=" << toGestureType(*gestureType);
5777
5778 if (selectionTouch)
5779 selectionChangeStream << ", " << "selectionTouch=" << toSelectionTouch(*selectionTouch);
5780
5781 if (selectionFlags)
5782 selectionChangeStream << ", " << "selectionFlags=" << toSelectionFlags(*selectionFlags);
5783
5784 RELEASE_LOG(TextInteraction, "Text interaction changing selection using '%s' (%s).", methodName, selectionChangeStream.release().utf8().data())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Text interaction changing selection using '%s' (%s)."), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG181"
) = "Text interaction changing selection using '%s' (%s)."; uint8_t
_Alignas(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Text interaction changing selection using '%s' (%s).", methodName
, selectionChangeStream.release().utf8().data())]; _os_log_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Text interaction changing selection using '%s' (%s)."
, methodName, selectionChangeStream.release().utf8().data()),
(uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); } }
) clang diagnostic pop
;
5785}
5786
5787- (void)selectPositionAtPoint:(CGPoint)point completionHandler:(void (^)(void))completionHandler
5788{
5789 _autocorrectionContextNeedsUpdate = YES__objc_yes;
5790 [self _selectPositionAtPoint:point stayingWithinFocusedElement:self._hasFocusedElement completionHandler:completionHandler];
5791}
5792
5793- (void)_selectPositionAtPoint:(CGPoint)point stayingWithinFocusedElement:(BOOL)stayingWithinFocusedElement completionHandler:(void (^)(void))completionHandler
5794{
5795 logTextInteraction(__PRETTY_FUNCTION__, self.textInteractionLoupeGestureRecognizer, point);
5796
5797 _autocorrectionContextNeedsUpdate = YES__objc_yes;
5798 _usingGestureForSelection = YES__objc_yes;
5799
5800 protect(_page)->selectPositionAtPoint(WebCore::IntPoint(point), stayingWithinFocusedElement, [view = retainPtr(self), completionHandler = makeBlockPtr(completionHandler)]() {
5801 completionHandler();
5802 view->_usingGestureForSelection = NO__objc_no;
5803 });
5804}
5805
5806- (void)selectPositionAtBoundary:(UITextGranularity)granularity inDirection:(UITextDirection)direction fromPoint:(CGPoint)point completionHandler:(void (^)(void))completionHandler
5807{
5808 logTextInteraction(__PRETTY_FUNCTION__, self.textInteractionLoupeGestureRecognizer, point);
5809
5810 _autocorrectionContextNeedsUpdate = YES__objc_yes;
5811 _usingGestureForSelection = YES__objc_yes;
5812 protect(_page)->selectPositionAtBoundaryWithDirection(WebCore::IntPoint(point), toWKTextGranularity(granularity), toWKSelectionDirection(direction), self._hasFocusedElement, [view = retainPtr(self), completionHandler = makeBlockPtr(completionHandler)]() {
5813 completionHandler();
5814 view->_usingGestureForSelection = NO__objc_no;
5815 });
5816}
5817
5818- (void)moveSelectionAtBoundary:(UITextGranularity)granularity inDirection:(UITextDirection)direction completionHandler:(void (^)(void))completionHandler
5819{
5820 logTextInteraction(__PRETTY_FUNCTION__, self.textInteractionLoupeGestureRecognizer);
5821
5822 _autocorrectionContextNeedsUpdate = YES__objc_yes;
5823 _usingGestureForSelection = YES__objc_yes;
5824 protect(_page)->moveSelectionAtBoundaryWithDirection(toWKTextGranularity(granularity), toWKSelectionDirection(direction), [view = retainPtr(self), completionHandler = makeBlockPtr(completionHandler)] {
5825 completionHandler();
5826 view->_usingGestureForSelection = NO__objc_no;
5827 });
5828}
5829
5830- (void)selectTextWithGranularity:(UITextGranularity)granularity atPoint:(CGPoint)point completionHandler:(void (^)(void))completionHandler
5831{
5832 logTextInteraction(__PRETTY_FUNCTION__, self.textInteractionLoupeGestureRecognizer, point);
5833
5834 _autocorrectionContextNeedsUpdate = YES__objc_yes;
5835 _usingGestureForSelection = YES__objc_yes;
5836#if HAVE(UIKIT_WITH_MOUSE_SUPPORT)(defined 1 && 1)
5837 _usingMouseDragForSelection = [_mouseInteraction mouseTouchGestureRecognizer]._wk_hasRecognizedOrEnded;
5838#endif
5839 ++_suppressNonEditableSingleTapTextInteractionCount;
5840 protect(_page)->selectTextWithGranularityAtPoint(WebCore::IntPoint(point), toWKTextGranularity(granularity), self._hasFocusedElement, [view = retainPtr(self), selectionHandler = makeBlockPtr(completionHandler)] {
5841 selectionHandler();
5842 view->_usingGestureForSelection = NO__objc_no;
5843 --view->_suppressNonEditableSingleTapTextInteractionCount;
5844 });
5845}
5846
5847- (void)beginSelectionInDirection:(UITextDirection)direction completionHandler:(void (^)(BOOL endIsMoving))completionHandler
5848{
5849 logTextInteraction(__PRETTY_FUNCTION__, self.textInteractionLoupeGestureRecognizer);
5850
5851 _autocorrectionContextNeedsUpdate = YES__objc_yes;
5852 protect(_page)->beginSelectionInDirection(toWKSelectionDirection(direction), [selectionHandler = makeBlockPtr(completionHandler)] (bool endIsMoving) {
5853 selectionHandler(endIsMoving);
5854 });
5855}
5856
5857- (void)updateSelectionWithExtentPoint:(CGPoint)point completionHandler:(void (^)(BOOL endIsMoving))completionHandler
5858{
5859 [self updateSelectionWithExtentPoint:point withBoundary:UITextGranularityCharacter completionHandler:completionHandler];
5860}
5861
5862- (void)updateSelectionWithExtentPoint:(CGPoint)point withBoundary:(UITextGranularity)granularity completionHandler:(void (^)(BOOL selectionEndIsMoving))completionHandler
5863{
5864 logTextInteraction(__PRETTY_FUNCTION__, self.textInteractionLoupeGestureRecognizer, point);
5865
5866 _autocorrectionContextNeedsUpdate = YES__objc_yes;
5867
5868 if (granularity == UITextGranularityCharacter && !_usingMouseDragForSelection) {
5869 auto triggeredByFloatingCursor = !self.textInteractionLoupeGestureRecognizer._wk_hasRecognizedOrEnded
5870#if HAVE(UIKIT_WITH_MOUSE_SUPPORT)(defined 1 && 1)
5871 && ![_mouseInteraction mouseTouchGestureRecognizer]._wk_hasRecognizedOrEnded
5872#endif
5873 && !self.textInteractionTapGestureRecognizer._wk_hasRecognizedOrEnded;
5874
5875 auto respectSelectionAnchor = triggeredByFloatingCursor ? WebKit::RespectSelectionAnchor::Yes : WebKit::RespectSelectionAnchor::No;
5876 [self updateSelectionWithExtentPoint:point hasFocusedElement:self._hasFocusedElement respectSelectionAnchor:respectSelectionAnchor completionHandler:completionHandler];
5877
5878 if (!triggeredByFloatingCursor && _page->isAutoscrolling()) {
5879 _selectionInteractionType = SelectionInteractionType::ExtentPoint;
5880 _lastSelectionExtentPoint.point = [self convertPoint:point toView:self.webView];
5881 _lastSelectionExtentPoint.respectSelectionAnchor = respectSelectionAnchor;
5882 }
5883 return;
5884 }
5885
5886 auto source = _usingMouseDragForSelection ? WebKit::TextInteractionSource::Mouse : WebKit::TextInteractionSource::Touch;
5887 [self updateSelectionWithExtentPointAndBoundary:point textGranularity:toWKTextGranularity(granularity) textInteractionSource:source completionHandler:completionHandler];
5888
5889 if (_page->isAutoscrolling()) {
5890 _selectionInteractionType = SelectionInteractionType::ExtentPointAndBoundary;
5891 _lastSelectionExtentPointAndBoundary.point = [self convertPoint:point toView:self.webView];
5892 _lastSelectionExtentPointAndBoundary.granularity = toWKTextGranularity(granularity);
5893 _lastSelectionExtentPointAndBoundary.interactionSource = source;
5894 }
5895}
5896
5897- (void)updateSelectionWithExtentPoint:(CGPoint)point hasFocusedElement:(BOOL)hasFocusedElement respectSelectionAnchor:(WebKit::RespectSelectionAnchor)respectSelectionAnchor completionHandler:(void (^)(BOOL selectionEndIsMoving))completionHandler
5898{
5899 protect(_page)->updateSelectionWithExtentPoint(WebCore::IntPoint(point), self._hasFocusedElement, respectSelectionAnchor, [completionHandler = makeBlockPtr(completionHandler)](bool endIsMoving) {
5900 completionHandler(static_cast<BOOL>(endIsMoving));
5901 });
5902}
5903
5904- (void)updateSelectionWithExtentPointAndBoundary:(CGPoint)point textGranularity:(WebCore::TextGranularity)textGranularity textInteractionSource:(WebKit::TextInteractionSource)interactionSource completionHandler:(void (^)(BOOL selectionEndIsMoving))completionHandler
5905{
5906 ++_suppressNonEditableSingleTapTextInteractionCount;
5907 protect(_page)->updateSelectionWithExtentPointAndBoundary(WebCore::IntPoint(point), textGranularity, self._hasFocusedElement, interactionSource, [completionHandler = makeBlockPtr(completionHandler), protectedSelf = retainPtr(self)] (bool endIsMoving) {
5908 completionHandler(static_cast<BOOL>(endIsMoving));
5909 --protectedSelf->_suppressNonEditableSingleTapTextInteractionCount;
5910 });
5911}
5912
5913- (UTF32Char)_characterInRelationToCaretSelection:(int)amount
5914{
5915 if (self.shouldUseAsyncInteractions)
5916 return [super _characterInRelationToCaretSelection:amount];
5917
5918 if (amount == -1 && _lastInsertedCharacterToOverrideCharacterBeforeSelection)
5919 return *_lastInsertedCharacterToOverrideCharacterBeforeSelection;
5920
5921 auto& state = protect(_page)->editorState();
5922 if (!state.isContentEditable || state.selectionType != WebCore::SelectionType::Caret || !state.postLayoutData)
5923 return 0;
5924
5925 switch (amount) {
5926 case 0:
5927 return state.postLayoutData->characterAfterSelection;
5928 case -1:
5929 return state.postLayoutData->characterBeforeSelection;
5930 case -2:
5931 return state.postLayoutData->twoCharacterBeforeSelection;
5932 default:
5933 return 0;
5934 }
5935}
5936
5937- (BOOL)_selectionAtDocumentStart
5938{
5939 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG182"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(5939, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
5940
5941 return self.selectionAtDocumentStart;
5942}
5943
5944- (CGRect)textFirstRect
5945{
5946 auto& editorState = protect(_page)->editorState();
5947 if (editorState.hasComposition) {
5948 if (!editorState.hasVisualData())
5949 return CGRectZero;
5950 auto& markedTextRects = editorState.visualData->markedTextRects;
5951 return markedTextRects.isEmpty() ? CGRectZero : markedTextRects.first().rect();
5952 }
5953 return _autocorrectionData.textFirstRect;
5954}
5955
5956- (CGRect)textLastRect
5957{
5958 auto& editorState = protect(_page)->editorState();
5959 if (editorState.hasComposition) {
5960 if (!editorState.hasVisualData())
5961 return CGRectZero;
5962 auto& markedTextRects = editorState.visualData->markedTextRects;
5963 return markedTextRects.isEmpty() ? CGRectZero : markedTextRects.last().rect();
5964 }
5965 return _autocorrectionData.textLastRect;
5966}
5967
5968- (void)willInsertFinalDictationResult
5969{
5970 protect(_page)->willInsertFinalDictationResult();
5971}
5972
5973- (void)didInsertFinalDictationResult
5974{
5975 protect(_page)->didInsertFinalDictationResult();
5976}
5977
5978- (void)replaceDictatedText:(NSString*)oldText withText:(NSString *)newText
5979{
5980 if (_isHidingKeyboard && _isChangingFocus)
5981 return;
5982
5983 _autocorrectionContextNeedsUpdate = YES__objc_yes;
5984 protect(_page)->replaceDictatedText(oldText, newText);
5985}
5986
5987// The completion handler should pass the rect of the correction text after replacing the input text, or nil if the replacement could not be performed.
5988- (void)applyAutocorrection:(NSString *)correction toString:(NSString *)input isCandidate:(BOOL)isCandidate withCompletionHandler:(void (^)(UIWKAutocorrectionRects *rectsForCorrection))completionHandler
5989{
5990 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG183"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(5990, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
5991
5992 [self _internalReplaceText:input withText:correction isCandidate:isCandidate completion:[completionHandler = makeBlockPtr(completionHandler), view = retainPtr(self)](bool wasApplied) {
5993 completionHandler(wasApplied ? [WKAutocorrectionRects autocorrectionRectsWithFirstCGRect:view->_autocorrectionData.textFirstRect lastCGRect:view->_autocorrectionData.textLastRect] : nilnullptr);
5994 }];
5995}
5996
5997- (void)_internalReplaceText:(NSString *)input withText:(NSString *)correction isCandidate:(BOOL)isCandidate completion:(Function<void(bool)>&&)completionHandler
5998{
5999 if ([self _disableAutomaticKeyboardUI]) {
6000 if (completionHandler)
6001 completionHandler(false);
6002 return;
6003 }
6004
6005 // FIXME: Remove the synchronous call when <rdar://problem/16207002> is fixed.
6006 const bool useSyncRequest = true;
6007
6008 if (useSyncRequest) {
6009 if (completionHandler)
6010 completionHandler(protect(_page)->applyAutocorrection(correction, input, isCandidate));
6011 return;
6012 }
6013
6014 protect(_page)->applyAutocorrection(correction, input, isCandidate, [view = retainPtr(self), completionHandler = WTF::move(completionHandler)](auto& string) {
6015 if (completionHandler)
6016 completionHandler(!string.isNull());
6017 });
6018}
6019
6020- (void)applyAutocorrection:(NSString *)correction toString:(NSString *)input withCompletionHandler:(void (^)(UIWKAutocorrectionRects *rectsForCorrection))completionHandler
6021{
6022 [self applyAutocorrection:correction toString:input isCandidate:NO__objc_no withCompletionHandler:completionHandler];
6023}
6024
6025- (void)applyAutocorrection:(NSString *)correction toString:(NSString *)input shouldUnderline:(BOOL)shouldUnderline withCompletionHandler:(void (^)(UIWKAutocorrectionRects *rectsForCorrection))completionHandler
6026{
6027 [self applyAutocorrection:correction toString:input isCandidate:shouldUnderline withCompletionHandler:completionHandler];
6028}
6029
6030- (void)_cancelPendingAutocorrectionContextHandler
6031{
6032 if (auto handler = WTF::move(_pendingAutocorrectionContextHandler))
6033 handler(WebKit::RequestAutocorrectionContextResult::Empty);
6034}
6035
6036- (void)requestAutocorrectionContextWithCompletionHandler:(void (^)(UIWKAutocorrectionContext *autocorrectionContext))completionHandler
6037{
6038 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG184"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(6038, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
6039
6040 if (!completionHandler) {
6041 [NSException raise:NSInvalidArgumentException format:@"Expected a nonnull completion handler in %s.", __PRETTY_FUNCTION__];
6042 return;
6043 }
6044
6045 [self _internalRequestAutocorrectionContextWithCompletionHandler:[completionHandler = makeBlockPtr(completionHandler), strongSelf = retainPtr(self)](WebKit::RequestAutocorrectionContextResult result) {
6046 switch (result) {
6047 case WebKit::RequestAutocorrectionContextResult::Empty:
6048 completionHandler(WKAutocorrectionContext.emptyAutocorrectionContext);
6049 break;
6050 case WebKit::RequestAutocorrectionContextResult::LastContext:
6051 completionHandler([WKAutocorrectionContext autocorrectionContextWithWebContext:strongSelf->_lastAutocorrectionContext]);
6052 break;
6053 default:
6054 ASSERT_NOT_REACHED()((void)0);
6055 break;
6056 }
6057 }];
6058}
6059
6060- (void)_internalRequestAutocorrectionContextWithCompletionHandler:(CompletionHandler<void(WebKit::RequestAutocorrectionContextResult)>&&)completionHandler
6061{
6062 Ref page = *_page;
6063 // FIXME: We can remove this code and unconditionally ignore autocorrection context requests when
6064 // out-of-process keyboard is enabled, once rdar://111936621 is addressed; we'll also be able to
6065 // remove `EditorState::PostLayoutData::hasGrammarDocumentMarkers` then.
6066 bool requiresContextToShowGrammarCheckingResults = [&] {
6067 auto& state = page->editorState();
6068 return state.hasPostLayoutData() && state.postLayoutData->hasGrammarDocumentMarkers;
6069 }();
6070
6071 if (UIKeyboard.usesInputSystemUI && !requiresContextToShowGrammarCheckingResults)
6072 return completionHandler(WebKit::RequestAutocorrectionContextResult::Empty);
6073
6074 if (self._disableAutomaticKeyboardUI)
6075 return completionHandler(WebKit::RequestAutocorrectionContextResult::Empty);
6076
6077 if (!page->hasRunningProcess())
6078 return completionHandler(WebKit::RequestAutocorrectionContextResult::Empty);
6079
6080 bool respondWithLastKnownAutocorrectionContext = ([&] {
6081 if (page->shouldAvoidSynchronouslyWaitingToPreventDeadlock())
6082 return true;
6083
6084 if (_domPasteRequestHandler)
6085 return true;
6086
6087 if (_isUnsuppressingSoftwareKeyboardUsingLastAutocorrectionContext)
6088 return true;
6089
6090 return !_autocorrectionContextNeedsUpdate;
6091 })();
6092
6093 if (respondWithLastKnownAutocorrectionContext)
6094 return completionHandler(WebKit::RequestAutocorrectionContextResult::LastContext);
6095
6096 if (_pendingAutocorrectionContextHandler)
6097 return completionHandler(WebKit::RequestAutocorrectionContextResult::Empty);
6098
6099 _pendingAutocorrectionContextHandler = WTF::move(completionHandler);
6100 protect(_page)->requestAutocorrectionContext();
6101
6102 if (protect(_page->legacyMainFrameProcess().connection())->waitForAndDispatchImmediately<Messages::WebPageProxy::HandleAutocorrectionContext>(_page->webPageIDInMainFrameProcess(), 1_s, IPC::WaitForOption::DispatchIncomingSyncMessagesWhileWaiting) != IPC::Error::NoError)
6103 RELEASE_LOG(TextInput, "Timed out while waiting for autocorrection context.")clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInput
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Timed out while waiting for autocorrection context."), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG185"
) = "Timed out while waiting for autocorrection context."; uint8_t
_Alignas(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Timed out while waiting for autocorrection context.")]; _os_log_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Timed out while waiting for autocorrection context."
), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); }
}) clang diagnostic pop
;
6104
6105 if (_autocorrectionContextNeedsUpdate)
6106 [self _cancelPendingAutocorrectionContextHandler];
6107 else if (auto handler = WTF::move(_pendingAutocorrectionContextHandler))
6108 handler(WebKit::RequestAutocorrectionContextResult::LastContext);
6109}
6110
6111- (void)_handleAutocorrectionContext:(const WebKit::WebAutocorrectionContext&)context
6112{
6113 _lastAutocorrectionContext = context;
6114 _autocorrectionContextNeedsUpdate = NO__objc_no;
6115 [self unsuppressSoftwareKeyboardUsingLastAutocorrectionContextIfNeeded];
6116}
6117
6118- (void)updateSoftwareKeyboardSuppressionStateFromWebView
6119{
6120 BOOL webViewIsSuppressingSoftwareKeyboard = [_webView.get() _suppressSoftwareKeyboard];
6121 if (webViewIsSuppressingSoftwareKeyboard) {
6122 _unsuppressSoftwareKeyboardAfterNextAutocorrectionContextUpdate = NO__objc_no;
6123 self._suppressSoftwareKeyboard = webViewIsSuppressingSoftwareKeyboard;
6124 return;
6125 }
6126
6127 if (self._suppressSoftwareKeyboard == webViewIsSuppressingSoftwareKeyboard)
6128 return;
6129
6130 if (!std::exchange(_unsuppressSoftwareKeyboardAfterNextAutocorrectionContextUpdate, YES__objc_yes))
6131 protect(_page)->requestAutocorrectionContext();
6132}
6133
6134- (void)unsuppressSoftwareKeyboardUsingLastAutocorrectionContextIfNeeded
6135{
6136 if (!std::exchange(_unsuppressSoftwareKeyboardAfterNextAutocorrectionContextUpdate, NO__objc_no))
6137 return;
6138
6139 SetForScope unsuppressSoftwareKeyboardScope { _isUnsuppressingSoftwareKeyboardUsingLastAutocorrectionContext, YES__objc_yes };
6140 self._suppressSoftwareKeyboard = NO__objc_no;
6141}
6142
6143- (void)runModalJavaScriptDialog:(CompletionHandler<void()>&&)callback
6144{
6145 if (_isFocusingElementWithKeyboard)
6146 _pendingRunModalJavaScriptDialogCallback = WTF::move(callback);
6147 else
6148 callback();
6149}
6150
6151- (void)_didStartProvisionalLoadForMainFrame
6152{
6153 // Reset the double tap gesture recognizer to prevent any double click that is in the process of being recognized.
6154 [_doubleTapGestureRecognizerForDoubleClick _wk_cancel];
6155 // We also need to disable the double-tap gesture recognizers that are enabled for double-tap-to-zoom and which
6156 // are enabled when a single tap is first recognized. This avoids tests running in sequence and simulating taps
6157 // in the same location to trigger double-tap recognition.
6158 [self _setDoubleTapGesturesEnabled:NO__objc_no];
6159 [_twoFingerDoubleTapGestureRecognizer _wk_cancel];
6160#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
6161 [self _cancelImageAnalysis];
6162#endif
6163}
6164
6165- (void)_didCommitLoadForMainFrame
6166{
6167 [protect(_keyboardScrollingAnimator) stopScrollingImmediately];
6168
6169 _seenHardwareKeyDownInNonEditableElement = NO__objc_no;
6170
6171 [self _elementDidBlur];
6172 [self _cancelLongPressGestureRecognizer];
6173#if USE(UICONTEXTMENU)(defined 1 && 1)
6174 [self _removeContextMenuHintContainerIfPossible];
6175#endif
6176 [self _removeContainerForDragPreviews];
6177 [self _removeContainerForDropPreviews];
6178 [_webView.get() _didCommitLoadForMainFrame];
6179
6180 _textInteractionDidChangeFocusedElement = NO__objc_no;
6181 _activeTextInteractionCount = 0;
6182 _treatAsContentEditableUntilNextEditorStateUpdate = NO__objc_no;
6183 [self _invalidateCurrentPositionInformation];
6184
6185#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
6186 [self uninstallImageAnalysisInteraction];
6187#endif
6188
6189 [_textInteractionWrapper reset];
6190
6191 _keyboardDismissedInCurrentPresentationUpdate = NO__objc_no;
6192 _editingEndedByUser = YES__objc_yes;
6193}
6194
6195- (void)_nextAccessoryTabForWebView:(id)sender
6196{
6197 [self accessoryTab:YES__objc_yes];
6198}
6199
6200- (void)_previousAccessoryTabForWebView:(id)sender
6201{
6202 [self accessoryTab:NO__objc_no];
6203}
6204
6205- (void)_becomeFirstResponderWithSelectionMovingForward:(BOOL)selectingForward completionHandler:(void (^)(BOOL didBecomeFirstResponder))completionHandler
6206{
6207 constexpr bool isKeyboardEventValid = false;
6208 protect(_page)->setInitialFocus(selectingForward, isKeyboardEventValid, { }, [protectedSelf = retainPtr(self), completionHandler = makeBlockPtr(completionHandler)] {
6209 if (completionHandler)
6210 completionHandler([protectedSelf becomeFirstResponder]);
6211 });
6212}
6213
6214- (WebCore::Color)_tapHighlightColorForFastClick:(BOOL)forFastClick
6215{
6216 ASSERT(_showDebugTapHighlightsForFastClicking)((void)0);
6217 return forFastClick ? WebCore::SRGBA<uint8_t> { 0, 225, 0, 127 } : WebCore::SRGBA<uint8_t> { 225, 0, 0, 127 };
6218}
6219
6220- (void)_setDoubleTapGesturesEnabled:(BOOL)enabled
6221{
6222 if (enabled && ![_doubleTapGestureRecognizer isEnabled]) {
6223 // The first tap recognized after re-enabling double tap gestures will not wait for the
6224 // second tap before committing. To fix this, we use a new double tap gesture recognizer.
6225 [self _createAndConfigureDoubleTapGestureRecognizer];
6226 }
6227
6228 if (_showDebugTapHighlightsForFastClicking && !enabled)
6229 _tapHighlightInformation.color = [self _tapHighlightColorForFastClick:YES__objc_yes];
6230
6231 _doubleTapGesturesAreDisabledTemporarilyForFastTap = !enabled;
6232 [self _updateDoubleTapGestureRecognizerEnablement];
6233}
6234
6235- (void)_updateDoubleTapGestureRecognizerEnablement
6236{
6237 [_doubleTapGestureRecognizer setEnabled:!_doubleTapGesturesAreDisabledTemporarilyForFastTap && [_webView.get() _allowsMagnification]];
6238 [_nonBlockingDoubleTapGestureRecognizer setEnabled:_doubleTapGesturesAreDisabledTemporarilyForFastTap && [_webView.get() _allowsMagnification]];
6239 [self _resetIsDoubleTapPending];
6240}
6241
6242// MARK: WKFormAccessoryViewDelegate protocol and accessory methods
6243
6244- (void)accessoryDone
6245{
6246 [self accessoryViewDone:_formAccessoryView.get()];
6247}
6248
6249- (void)accessoryViewDone:(WKFormAccessoryView *)view
6250{
6251 [_webView.get() _resetFocusPreservationCountAndReleaseActiveFocusState];
6252 [self stopRelinquishingFirstResponderToFocusedElement];
6253 [self endEditingAndUpdateFocusAppearanceWithReason:EndEditingReasonAccessoryDone];
6254 protect(_page)->setIsShowingInputViewForFocusedElement(false);
6255}
6256
6257- (void)updateFocusedElementValue:(NSString *)value
6258{
6259 protect(_page)->setFocusedElementValue(_focusedElementInformation.elementContext, value);
6260 _focusedElementInformation.value = value;
6261}
6262
6263- (void)updateFocusedElementValueAsColor:(UIColor *)value
6264{
6265 auto color = [&] {
6266 if (protect(_page->preferences())->inputTypeColorEnhancementsEnabled())
6267 return WebCore::Color::createAndPreserveColorSpace(protect(protect(value).get().CGColor));
6268 return WebCore::Color(WebCore::roundAndClampToSRGBALossy(protect(protect(value).get().CGColor)));
6269 }();
6270 auto valueAsString = WebCore::serializationForHTML(color);
6271
6272 protect(_page)->setFocusedElementValue(_focusedElementInformation.elementContext, valueAsString);
6273 _focusedElementInformation.value = valueAsString;
6274 _focusedElementInformation.colorValue = color;
6275}
6276
6277- (void)updateFocusedElementSelectedIndex:(uint32_t)index allowsMultipleSelection:(bool)allowsMultipleSelection
6278{
6279 protect(_page)->setFocusedElementSelectedIndex(_focusedElementInformation.elementContext, index, allowsMultipleSelection);
6280}
6281
6282- (void)updateFocusedElementFocusedWithDataListDropdown:(BOOL)value
6283{
6284 _focusedElementInformation.isFocusingWithDataListDropdown = value;
6285 [self reloadInputViews];
6286}
6287
6288- (void)accessoryTab:(BOOL)isNext
6289{
6290 auto direction = isNext ? WebKit::TabDirection::Next : WebKit::TabDirection::Previous;
6291 [self accessoryView:_formAccessoryView.get() tabInDirection:direction];
6292}
6293
6294- (void)accessoryView:(WKFormAccessoryView *)view tabInDirection:(WebKit::TabDirection)direction
6295{
6296 // The input peripheral may need to update the focused DOM node before we switch focus. The UI process does
6297 // not maintain a handle to the actual focused DOM node – only the web process has such a handle. So, we need
6298 // to end the editing session now before we tell the web process to switch focus. Once the web process tells
6299 // us the newly focused element we are no longer are in a position to effect the previously focused element.
6300 // See <https://bugs.webkit.org/show_bug.cgi?id=134409>.
6301 [self _endEditing];
6302 _inputPeripheral = nilnullptr; // Nullify so that we don't tell the input peripheral to end editing again in -_elementDidBlur.
6303
6304 _isChangingFocusUsingAccessoryTab = YES__objc_yes;
6305 [self _internalBeginSelectionChange];
6306 protect(_page)->focusNextFocusedElement(direction == WebKit::TabDirection::Next, [protectedSelf = retainPtr(self)] {
6307 [protectedSelf _internalEndSelectionChange];
6308 [protectedSelf reloadInputViews];
6309 protectedSelf->_isChangingFocusUsingAccessoryTab = NO__objc_no;
6310 });
6311}
6312
6313- (void)accessoryViewAutoFill:(WKFormAccessoryView *)view
6314{
6315 RetainPtr inputDelegate = [_webView.get() _inputDelegate];
6316 if ([inputDelegate respondsToSelector:@selector(_webView:accessoryViewCustomButtonTappedInFormInputSession:)])
6317 [inputDelegate _webView:self.webView accessoryViewCustomButtonTappedInFormInputSession:_formInputSession.get()];
6318}
6319
6320- (WKFormAccessoryView *)formAccessoryView
6321{
6322#if PLATFORM(APPLETV)(defined WTF_PLATFORM_APPLETV && WTF_PLATFORM_APPLETV
)
6323 return nilnullptr;
6324#else
6325#if HAVE(UI_USER_INTERFACE_IDIOM_VISION)(defined 1 && 1)
6326 if (self.traitCollection.userInterfaceIdiom == UIUserInterfaceIdiomVision)
6327 return nilnullptr;
6328#endif
6329
6330 if (!_formAccessoryView)
6331 _formAccessoryView = adoptNS([[WKFormAccessoryView alloc] initWithInputAssistantItem:self.inputAssistantItem delegate:self]);
6332
6333 return _formAccessoryView.get();
6334#endif
6335}
6336
6337- (void)accessoryOpen
6338{
6339 if (!_inputPeripheral)
6340 return;
6341 [self _zoomToRevealFocusedElement];
6342 [self _updateAccessory];
6343 [_inputPeripheral beginEditing];
6344}
6345
6346- (void)_updateAccessory
6347{
6348 if (_isUpdatingAccessoryView)
6349 return;
6350
6351 SetForScope updateAccessoryScope { _isUpdatingAccessoryView, YES__objc_yes };
6352
6353 auto* accessoryView = self.formAccessoryView; // Creates one, if needed.
6354
6355 if ([accessoryView respondsToSelector:@selector(setNextPreviousItemsVisible:)])
6356 [accessoryView setNextPreviousItemsVisible:!self.webView._editable];
6357
6358 [accessoryView setNextEnabled:_focusedElementInformation.hasNextNode];
6359 [accessoryView setPreviousEnabled:_focusedElementInformation.hasPreviousNode];
6360}
6361
6362// MARK: Keyboard interaction
6363// UITextInput protocol implementation
6364
6365- (BOOL)_allowAnimatedUpdateSelectionRectViews
6366{
6367 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG186"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(6367, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
6368
6369 return NO__objc_no;
6370}
6371
6372- (void)beginSelectionChange
6373{
6374 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG187"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(6374, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
6375
6376 [self _internalBeginSelectionChange];
6377}
6378
6379- (void)_internalBeginSelectionChange
6380{
6381 [self _updateInternalStateBeforeSelectionChange];
6382
6383#if USE(BROWSERENGINEKIT)(defined 1 && 1)
6384 if (self.shouldUseAsyncInteractions) {
6385 [protect(_asyncInputDelegate) selectionWillChangeForTextInput:self.asBETextInput];
6386 return;
6387 }
6388#endif
6389
6390 [self.inputDelegate selectionWillChange:self];
6391}
6392
6393- (void)_updateInternalStateBeforeSelectionChange
6394{
6395 _autocorrectionContextNeedsUpdate = YES__objc_yes;
6396 _selectionChangeNestingLevel++;
6397}
6398
6399- (void)endSelectionChange
6400{
6401 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG188"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(6401, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
6402
6403 [self _internalEndSelectionChange];
6404}
6405
6406- (void)_internalEndSelectionChange
6407{
6408#if USE(BROWSERENGINEKIT)(defined 1 && 1)
6409 if (self.shouldUseAsyncInteractions)
6410 [protect(_asyncInputDelegate) selectionDidChangeForTextInput:self.asBETextInput];
6411 else
6412#endif // USE(BROWSERENGINEKIT)
6413 [self.inputDelegate selectionDidChange:self];
6414
6415 [self _updateInternalStateAfterSelectionChange];
6416}
6417
6418- (void)_updateInternalStateAfterSelectionChange
6419{
6420 if (_selectionChangeNestingLevel) {
6421 // FIXME (228083): Some layout tests end up triggering unbalanced calls to -endSelectionChange.
6422 // We should investigate why this happens, (ideally) prevent it from happening, and then assert
6423 // that `_selectionChangeNestingLevel` is nonzero when calling -endSelectionChange.
6424 _selectionChangeNestingLevel--;
6425 }
6426}
6427
6428- (void)willFinishIgnoringCalloutBarFadeAfterPerformingAction
6429{
6430 _ignoreSelectionCommandFadeCount++;
6431 protect(_page)->scheduleFullEditorStateUpdate();
6432 protect(_page)->callAfterNextPresentationUpdate([weakSelf = WeakObjCPtr<WKContentView>(self)] {
6433 if (auto strongSelf = weakSelf.get())
6434 strongSelf->_ignoreSelectionCommandFadeCount--;
6435 });
6436}
6437
6438- (void)_didChangeWebViewEditability
6439{
6440 BOOL webViewIsEditable = self.webView._editable;
6441 RetainPtr formAccessoryView = _formAccessoryView;
6442 if ([formAccessoryView respondsToSelector:@selector(setNextPreviousItemsVisible:)])
6443 [formAccessoryView setNextPreviousItemsVisible:!webViewIsEditable];
6444
6445 [_twoFingerSingleTapGestureRecognizer setEnabled:!webViewIsEditable];
6446
6447 if (webViewIsEditable) {
6448 static dispatch_once_t onceToken;
6449 dispatch_once_dispatch_once(&onceToken, ^{
6450 class_addProtocol(self.class, @protocol(UITextInputMultiDocument));
6451 });
6452 }
6453}
6454
6455- (void)insertTextSuggestion:(id)textSuggestion
6456{
6457 _autocorrectionContextNeedsUpdate = YES__objc_yes;
6458
6459 Ref page = *_page;
6460 if (RetainPtr autoFillSuggestion = dynamic_objc_cast<UITextAutofillSuggestion>(textSuggestion)) {
6461 // Maintain binary compatibility with UITextAutofillSuggestion, even when using the ServiceExtensions text input.
6462 page->autofillLoginCredentials([autoFillSuggestion username], [autoFillSuggestion password]);
6463 return;
6464 }
6465
6466#if USE(BROWSERENGINEKIT)(defined 1 && 1)
6467 if (RetainPtr autoFillSuggestion = dynamic_objc_cast<BEAutoFillTextSuggestion>(textSuggestion)) {
6468 RetainPtr contents = [autoFillSuggestion contents];
6469 page->autofillLoginCredentials([contents objectForKey:UITextContentTypeUsername], [contents objectForKey:UITextContentTypePassword]);
6470 return;
6471 }
6472#endif
6473
6474 if ([_dataListTextSuggestions count] && ![[_formInputSession suggestions] count]) {
6475 RetainPtr inputText = [textSuggestion inputText];
6476 for (WKBETextSuggestionBETextSuggestion *dataListTextSuggestion in _dataListTextSuggestions.get()) {
6477 if ([inputText isEqualToString:dataListTextSuggestion.inputText]) {
6478 page->setFocusedElementValue(_focusedElementInformation.elementContext, inputText.get());
6479 return;
6480 }
6481 }
6482 }
6483
6484 RetainPtr inputDelegate = [_webView.get() _inputDelegate];
6485 if ([inputDelegate respondsToSelector:@selector(_webView:insertTextSuggestion:inInputSession:)]) {
6486 auto uiTextSuggestion = [&]() -> RetainPtr<UITextSuggestion> {
6487#if USE(BROWSERENGINEKIT)(defined 1 && 1)
6488 if (auto beTextSuggestion = dynamic_objc_cast<BETextSuggestion>(textSuggestion))
6489 return beTextSuggestion._uikitTextSuggestion;
6490#endif
6491 return textSuggestion;
6492 }();
6493 [inputDelegate _webView:self.webView insertTextSuggestion:uiTextSuggestion.get() inInputSession:_formInputSession.get()];
6494 }
6495}
6496
6497- (NSString *)textInRange:(UITextRange *)range
6498{
6499 if (!_page)
6500 return nilnullptr;
6501
6502 auto& editorState = protect(_page)->editorState();
6503 if (!editorState.hasPostLayoutData())
6504 return nilnullptr;
6505
6506 if (self.selectedTextRange == range && editorState.selectionType == WebCore::SelectionType::Range)
6507 return editorState.postLayoutData->wordAtSelection.createNSString().autorelease();
6508
6509 if (auto relativeRange = dynamic_objc_cast<WKRelativeTextRange>(range))
6510 return textRelativeToSelectionStart(relativeRange, *editorState.postLayoutData, _lastInsertedCharacterToOverrideCharacterBeforeSelection).autorelease();
6511
6512 return nilnullptr;
6513}
6514
6515- (void)replaceRange:(UITextRange *)range withText:(NSString *)text
6516{
6517}
6518
6519- (NSArray<WKTextSelectionRect *> *)_textSelectionRects:(const Vector<WebCore::SelectionGeometry>&)rects
6520{
6521 return createNSArray(rects, [&](auto& rect) {
6522 return adoptNS([[WKTextSelectionRect alloc] initWithSelectionGeometry:rect delegate:self]);
6523 }).autorelease();
6524}
6525
6526- (CGFloat)scaleFactorForSelectionRect:(WKTextSelectionRect *)rect
6527{
6528 return self._contentZoomScale;
6529}
6530
6531- (WebCore::FloatQuad)selectionRect:(WKTextSelectionRect *)rect convertQuadToSelectionContainer:(const WebCore::FloatQuad&)quad
6532{
6533 return [self _wk_convertQuad:quad toCoordinateSpace:[self _selectionContainerViewInternal]];
6534}
6535
6536- (UITextRange *)selectedTextRange
6537{
6538 Ref page = *_page;
6539 auto& editorState = page->editorState();
6540 auto hasSelection = editorState.selectionType != WebCore::SelectionType::None;
6541 if (!hasSelection || !editorState.hasPostLayoutAndVisualData())
6542 return nilnullptr;
6543
6544 auto isRange = editorState.selectionType == WebCore::SelectionType::Range;
6545 auto isContentEditable = editorState.isContentEditable;
6546 // UIKit does not expect caret selections in non-editable content.
6547 if (!isContentEditable && !isRange)
6548 return nilnullptr;
6549
6550 if (_cachedSelectedTextRange)
6551 return _cachedSelectedTextRange.get();
6552
6553 auto caretStartRect = page->editorState().visualData->caretRectAtStart;
6554 auto caretEndRect = page->editorState().visualData->caretRectAtEnd;
6555 auto selectionRects = [self _textSelectionRects:page->editorState().visualData->selectionGeometries];
6556 auto selectedTextLength = editorState.postLayoutData->selectedTextLength;
6557
6558 _cachedSelectedTextRange = [WKTextRange textRangeWithState:!hasSelection isRange:isRange isEditable:isContentEditable startRect:caretStartRect endRect:caretEndRect selectionRects:selectionRects selectedTextLength:selectedTextLength];
6559 return _cachedSelectedTextRange.get();
6560}
6561
6562- (CGRect)caretRectForPosition:(UITextPosition *)position
6563{
6564 return dynamic_objc_cast<WKTextPosition>(position).positionRect;
6565}
6566
6567- (NSArray *)selectionRectsForRange:(UITextRange *)range
6568{
6569 return dynamic_objc_cast<WKTextRange>(range).selectionRects;
6570}
6571
6572- (void)setSelectedTextRange:(UITextRange *)range
6573{
6574 if (range)
6575 return;
6576#if !PLATFORM(MACCATALYST)(defined WTF_PLATFORM_MACCATALYST && WTF_PLATFORM_MACCATALYST
)
6577 if (!self._hasFocusedElement)
6578 return;
6579#endif
6580 [self _internalClearSelection];
6581}
6582
6583- (BOOL)hasMarkedText
6584{
6585 return [_markedText length];
6586}
6587
6588- (NSString *)markedText
6589{
6590 return _markedText.get();
6591}
6592
6593- (UITextRange *)markedTextRange
6594{
6595 auto& editorState = protect(_page)->editorState();
6596 bool hasComposition = editorState.hasComposition;
6597 if (!hasComposition || !editorState.hasPostLayoutAndVisualData())
6598 return nilnullptr;
6599 auto& postLayoutData = *editorState.postLayoutData;
6600 auto& visualData = *editorState.visualData;
6601 auto caretStartRect = visualData.markedTextCaretRectAtStart;
6602 auto caretEndRect = visualData.markedTextCaretRectAtEnd;
6603 auto isRange = caretStartRect != caretEndRect;
6604 auto isContentEditable = editorState.isContentEditable;
6605 auto selectionRects = [self _textSelectionRects:visualData.markedTextRects];
6606 auto selectedTextLength = postLayoutData.markedText.length();
6607 return [WKTextRange textRangeWithState:!hasComposition isRange:isRange isEditable:isContentEditable startRect:caretStartRect endRect:caretEndRect selectionRects:selectionRects selectedTextLength:selectedTextLength];
6608}
6609
6610- (NSDictionary *)markedTextStyle
6611{
6612 return nilnullptr;
6613}
6614
6615- (void)setMarkedTextStyle:(NSDictionary *)styleDictionary
6616{
6617}
6618
6619#if HAVE(REDESIGNED_TEXT_CURSOR)(defined 1 && 1)
6620static BOOL shouldUseHighlightsForMarkedText(NSAttributedString *string)
6621{
6622 __block__attribute__((__blocks__(byref))) BOOL result = NO__objc_no;
6623
6624 [string enumerateAttributesInRange:NSMakeRange(0, string.length) options:0 usingBlock:^(NSDictionary<NSAttributedStringKey, id> *attributes, NSRange, BOOL *stop) {
6625 BOOL hasUnderlineStyle = !![attributes objectForKey:NSUnderlineStyleAttributeNamegetNSUnderlineStyleAttributeNameSingleton()];
6626 BOOL hasUnderlineColor = !![attributes objectForKey:NSUnderlineColorAttributeName];
6627
6628 BOOL hasBackgroundColor = !![attributes objectForKey:NSBackgroundColorAttributeNamegetNSBackgroundColorAttributeNameSingleton()];
6629 BOOL hasForegroundColor = !![attributes objectForKey:NSForegroundColorAttributeNamegetNSForegroundColorAttributeNameSingleton()];
6630
6631 // Marked text may be represented either as an underline or a highlight; this mode is dictated
6632 // by the attributes it has, and therefore having both types of attributes is not allowed.
6633 ASSERT(!((hasUnderlineStyle || hasUnderlineColor) && (hasBackgroundColor || hasForegroundColor)))((void)0);
6634
6635 if (hasUnderlineStyle || hasUnderlineColor) {
6636 result = NO__objc_no;
6637 *stop = YES__objc_yes;
6638 } else if (hasBackgroundColor || hasForegroundColor) {
6639 result = YES__objc_yes;
6640 *stop = YES__objc_yes;
6641 }
6642 }];
6643
6644 return result;
6645}
6646
6647static Vector<WebCore::CompositionUnderline> extractUnderlines(NSAttributedString *string)
6648{
6649 if (!string.length)
6650 return { };
6651
6652 Vector<WebCore::CompositionUnderline> underlines;
6653 [string enumerateAttributesInRange:NSMakeRange(0, string.length) options:0 usingBlock:[&underlines](NSDictionary<NSAttributedStringKey, id> *attributes, NSRange range, BOOL *) {
6654 underlines.append({
6655 static_cast<unsigned>(range.location),
6656 static_cast<unsigned>(NSMaxRange(range)),
6657 WebCore::CompositionUnderlineColor::GivenColor,
6658 WebCore::Color::black,
6659 [attributes[NSUnderlineStyleAttributeNamegetNSUnderlineStyleAttributeNameSingleton()] isEqual:@(NSUnderlineStyleThick)] || attributes[NSBackgroundColorAttributeNamegetNSBackgroundColorAttributeNameSingleton()]
6660 });
6661 }];
6662
6663 std::ranges::sort(underlines);
6664
6665 Vector<WebCore::CompositionUnderline> mergedUnderlines;
6666 if (!underlines.isEmpty())
6667 mergedUnderlines.append({ underlines.first().startOffset, underlines.last().endOffset, WebCore::CompositionUnderlineColor::GivenColor, WebCore::Color::black, false });
6668
6669 for (auto& underline : underlines) {
6670 if (underline.thick)
6671 mergedUnderlines.append(underline);
6672 }
6673
6674 return mergedUnderlines;
6675}
6676#endif
6677
6678static Vector<WebCore::CompositionHighlight> compositionHighlights(NSAttributedString *string)
6679{
6680 if (!string.length)
6681 return { };
6682
6683 Vector<WebCore::CompositionHighlight> highlights;
6684 [string enumerateAttributesInRange:NSMakeRange(0, string.length) options:0 usingBlock:[&highlights](NSDictionary<NSAttributedStringKey, id> *attributes, NSRange range, BOOL *) {
6685 WebCore::Color backgroundHighlightColor { WebCore::CompositionHighlight::defaultCompositionFillColor };
6686 if (UIColor *backgroundColor = attributes[NSBackgroundColorAttributeNamegetNSBackgroundColorAttributeNameSingleton()])
6687 backgroundHighlightColor = WebCore::colorFromCocoaColor(backgroundColor);
6688
6689 std::optional<WebCore::Color> foregroundHighlightColor;
6690 if (UIColor *foregroundColor = attributes[NSForegroundColorAttributeNamegetNSForegroundColorAttributeNameSingleton()])
6691 foregroundHighlightColor = WebCore::colorFromCocoaColor(foregroundColor);
6692
6693 highlights.append({ static_cast<unsigned>(range.location), static_cast<unsigned>(NSMaxRange(range)), backgroundHighlightColor, foregroundHighlightColor });
6694 }];
6695
6696 std::ranges::sort(highlights);
6697
6698 Vector<WebCore::CompositionHighlight> mergedHighlights;
6699 mergedHighlights.reserveInitialCapacity(highlights.size());
6700 for (auto& highlight : highlights) {
6701 if (mergedHighlights.isEmpty() || mergedHighlights.last().backgroundColor != highlight.backgroundColor || mergedHighlights.last().foregroundColor != highlight.foregroundColor)
6702 mergedHighlights.append(highlight);
6703 else
6704 mergedHighlights.last().endOffset = highlight.endOffset;
6705 }
6706
6707 return mergedHighlights;
6708}
6709
6710- (void)setAttributedMarkedText:(NSAttributedString *)markedText selectedRange:(NSRange)selectedRange
6711{
6712 BOOL hasTextCompletion = ^{
6713 if (!markedText.length)
6714 return NO__objc_no;
6715
6716 // UIKit doesn't include the `NSTextCompletionAttributeName`, so the next best way to detect if this method
6717 // is being used for a text completion is to check if the attributes match these hard-coded ones.
6718 RetainPtr textCompletionAttributes = @{
6719 NSForegroundColorAttributeNamegetNSForegroundColorAttributeNameSingleton() : UIColor.systemGrayColor,
6720 NSBackgroundColorAttributeNamegetNSBackgroundColorAttributeNameSingleton() : UIColor.clearColor,
6721 };
6722
6723 RetainPtr markedTextAttributes = [markedText attributesAtIndex:0 effectiveRange:nilnullptr];
6724
6725 RetainPtr foregroundColor = [markedTextAttributes objectForKey:NSForegroundColorAttributeNamegetNSForegroundColorAttributeNameSingleton()];
6726 if (![foregroundColor isEqual:UIColor.systemGrayColor])
6727 return NO__objc_no;
6728
6729 RetainPtr backgroundColor = [markedTextAttributes objectForKey:NSBackgroundColorAttributeNamegetNSBackgroundColorAttributeNameSingleton()];
6730 if (![backgroundColor isEqual:UIColor.clearColor])
6731 return NO__objc_no;
6732
6733 return YES__objc_yes;
6734 }();
6735
6736 if (hasTextCompletion) {
6737 protect(_page)->setWritingSuggestion([markedText string], { 0, 0 });
6738 return;
6739 }
6740
6741 Vector<WebCore::CompositionUnderline> underlines;
6742 Vector<WebCore::CompositionHighlight> highlights;
6743
6744#if HAVE(REDESIGNED_TEXT_CURSOR)(defined 1 && 1)
6745 if (!shouldUseHighlightsForMarkedText(markedText))
6746 underlines = extractUnderlines(markedText);
6747 else
6748#endif
6749 highlights = compositionHighlights(markedText);
6750
6751 [self _setMarkedText:markedText.string underlines:underlines highlights:highlights selectedRange:selectedRange];
6752}
6753
6754- (void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange
6755{
6756 Vector<WebCore::CompositionUnderline> underlines;
6757
6758#if HAVE(REDESIGNED_TEXT_CURSOR)(defined 1 && 1)
6759 underlines.append(WebCore::CompositionUnderline(0, [_markedText length], WebCore::CompositionUnderlineColor::GivenColor, WebCore::Color::black, false));
6760#endif
6761
6762 [self _setMarkedText:markedText underlines:underlines highlights:Vector<WebCore::CompositionHighlight> { } selectedRange:selectedRange];
6763}
6764
6765- (void)_setMarkedText:(NSString *)markedText underlines:(const Vector<WebCore::CompositionUnderline>&)underlines highlights:(const Vector<WebCore::CompositionHighlight>&)highlights selectedRange:(NSRange)selectedRange
6766{
6767 _autocorrectionContextNeedsUpdate = YES__objc_yes;
6768 _candidateViewNeedsUpdate = !self.hasMarkedText && _isDeferringKeyEventsToInputMethod;
6769 _markedText = markedText;
6770 protect(_page)->setCompositionAsync(markedText, underlines, highlights, { }, selectedRange, { });
6771}
6772
6773- (void)unmarkText
6774{
6775 _isDeferringKeyEventsToInputMethod = NO__objc_no;
6776 _markedText = nilnullptr;
6777 protect(_page)->confirmCompositionAsync();
6778}
6779
6780- (UITextPosition *)beginningOfDocument
6781{
6782 return nilnullptr;
6783}
6784
6785- (UITextPosition *)endOfDocument
6786{
6787 return nilnullptr;
6788}
6789
6790- (BOOL)_isAnchoredToCurrentSelection:(UITextPosition *)position
6791{
6792 return [position isKindOfClass:WKRelativeTextPosition.class] || [position isEqual:self.selectedTextRange.start] || [position isEqual:self.selectedTextRange.end];
6793}
6794
6795- (UITextRange *)textRangeFromPosition:(UITextPosition *)fromPosition toPosition:(UITextPosition *)toPosition
6796{
6797 if (!self.shouldUseAsyncInteractions)
6798 return nilnullptr;
6799
6800 if (![self _isAnchoredToCurrentSelection:fromPosition] || ![self _isAnchoredToCurrentSelection:toPosition])
6801 return nilnullptr;
6802
6803 return adoptNS([[WKRelativeTextRange alloc] initWithStart:fromPosition end:toPosition]).autorelease();
6804}
6805
6806- (UITextPosition *)positionFromPosition:(UITextPosition *)position offset:(NSInteger)offset
6807{
6808 if (!self.shouldUseAsyncInteractions)
6809 return nilnullptr;
6810
6811 if (![self _isAnchoredToCurrentSelection:position])
6812 return nilnullptr;
6813
6814 return positionWithOffsetFrom(position, offset);
6815}
6816
6817- (UITextPosition *)positionFromPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction offset:(NSInteger)offset
6818{
6819 return nilnullptr;
6820}
6821
6822- (NSComparisonResult)comparePosition:(UITextPosition *)position toPosition:(UITextPosition *)other
6823{
6824 return NSOrderedSame;
6825}
6826
6827- (NSInteger)offsetFromPosition:(UITextPosition *)from toPosition:(UITextPosition *)to
6828{
6829#if HAVE(UIFINDINTERACTION)(defined 1 && 1)
6830 if ([from isKindOfClass:[WKFoundDOMTextPosition class]] && [to isKindOfClass:[WKFoundDOMTextPosition class]]) {
6831 WKFoundDOMTextPosition *fromPosition = (WKFoundDOMTextPosition *)from;
6832 WKFoundDOMTextPosition *toPosition = (WKFoundDOMTextPosition *)to;
6833
6834 if (fromPosition.order != toPosition.order)
6835 return fromPosition.order - toPosition.order;
6836
6837 return fromPosition.offset - toPosition.offset;
6838 }
6839
6840 if ([from isKindOfClass:[WKFoundPDFTextPosition class]] && [to isKindOfClass:[WKFoundPDFTextPosition class]]) {
6841 WKFoundPDFTextPosition *fromPosition = (WKFoundPDFTextPosition *)from;
6842 WKFoundPDFTextPosition *toPosition = (WKFoundPDFTextPosition *)to;
6843
6844 if (fromPosition.order != toPosition.order)
6845 return fromPosition.order - toPosition.order;
6846
6847 if (fromPosition.page == toPosition.page)
6848 return fromPosition.offset - toPosition.offset;
6849 return fromPosition.page - toPosition.page;
6850 }
6851
6852 if ([from isKindOfClass:[WKFoundTextPosition class]] && [to isKindOfClass:[WKFoundTextPosition class]]) {
6853 WKFoundTextPosition *fromPosition = (WKFoundTextPosition *)from;
6854 WKFoundTextPosition *toPosition = (WKFoundTextPosition *)to;
6855
6856 return fromPosition.order - toPosition.order;
6857 }
6858#endif
6859
6860 return 0;
6861}
6862
6863- (id <UITextInputTokenizer>)tokenizer
6864{
6865 return nilnullptr;
6866}
6867
6868- (UITextPosition *)positionWithinRange:(UITextRange *)range farthestInDirection:(UITextLayoutDirection)direction
6869{
6870 return nilnullptr;
6871}
6872
6873- (UITextRange *)characterRangeByExtendingPosition:(UITextPosition *)position inDirection:(UITextLayoutDirection)direction
6874{
6875 return nilnullptr;
6876}
6877
6878- (NSWritingDirection)baseWritingDirectionForPosition:(UITextPosition *)position inDirection:(UITextStorageDirection)direction
6879{
6880 return NSWritingDirectionLeftToRight;
6881}
6882
6883static WebKit::WritingDirection coreWritingDirection(NSWritingDirection direction)
6884{
6885 switch (direction) {
6886 case NSWritingDirectionNatural:
6887 return WebCore::WritingDirection::Natural;
6888 case NSWritingDirectionLeftToRight:
6889 return WebCore::WritingDirection::LeftToRight;
6890 case NSWritingDirectionRightToLeft:
6891 return WebCore::WritingDirection::RightToLeft;
6892 default:
6893 ASSERT_NOT_REACHED()((void)0);
6894 return WebCore::WritingDirection::Natural;
6895 }
6896}
6897
6898- (void)setBaseWritingDirection:(NSWritingDirection)direction forRange:(UITextRange *)range
6899{
6900 if (!_page->isEditable())
6901 return;
6902
6903 if (range && ![range isEqual:self.selectedTextRange]) {
6904 // We currently only support changing the base writing direction at the selection.
6905 return;
6906 }
6907 protect(_page)->setBaseWritingDirection(coreWritingDirection(direction));
6908}
6909
6910- (CGRect)firstRectForRange:(UITextRange *)range
6911{
6912 return CGRectZero;
6913}
6914
6915/* Hit testing. */
6916- (UITextPosition *)closestPositionToPoint:(CGPoint)point
6917{
6918#if PLATFORM(MACCATALYST)(defined WTF_PLATFORM_MACCATALYST && WTF_PLATFORM_MACCATALYST
)
6919 WebKit::InteractionInformationRequest request(WebCore::roundedIntPoint(point));
6920 [self requestAsynchronousPositionInformationUpdate:request];
6921 if ([self _currentPositionInformationIsApproximatelyValidForRequest:request radiusForApproximation:2] && _positionInformation.isSelectable())
6922 return [WKTextPosition textPositionWithRect:_positionInformation.caretRect];
6923#endif
6924 return nilnullptr;
6925}
6926
6927- (UITextPosition *)closestPositionToPoint:(CGPoint)point withinRange:(UITextRange *)range
6928{
6929 return nilnullptr;
6930}
6931
6932- (UITextRange *)characterRangeAtPoint:(CGPoint)point
6933{
6934 return nilnullptr;
6935}
6936
6937- (void)deleteBackward
6938{
6939 protect(_page)->executeEditCommand("deleteBackward"_s);
6940}
6941
6942- (BOOL)_shouldSimulateKeyboardInputOnTextInsertion
6943{
6944#if HAVE(PENCILKIT_TEXT_INPUT)(defined 1 && 1)
6945 return [_scribbleInteraction isHandlingWriting];
6946#else
6947 return NO__objc_no;
6948#endif
6949}
6950
6951// Inserts the given string, replacing any selected or marked text.
6952- (void)insertText:(NSString *)aStringValue
6953{
6954 if (_isHidingKeyboard && _isChangingFocus)
6955 return;
6956
6957 Ref page = *_page;
6958 WebKit::InsertTextOptions options;
6959 options.processingUserGesture = _isHandlingActiveKeyEvent || _isHandlingActivePressesEvent;
6960 options.shouldSimulateKeyboardInput = [self _shouldSimulateKeyboardInputOnTextInsertion];
6961 options.directionFromCurrentInputMode = [self] -> std::optional<WebCore::TextDirection> {
6962 NSString *inputLanguage = self.textInputMode.primaryLanguage;
6963 if (!inputLanguage.length)
6964 return { };
6965
6966 switch ([NSLocale characterDirectionForLanguage:inputLanguage]) {
6967 case NSLocaleLanguageDirectionRightToLeft:
6968 return WebCore::TextDirection::RTL;
6969 case NSLocaleLanguageDirectionLeftToRight:
6970 return WebCore::TextDirection::LTR;
6971 case NSLocaleLanguageDirectionTopToBottom:
6972 case NSLocaleLanguageDirectionBottomToTop:
6973 case NSLocaleLanguageDirectionUnknown:
6974 return { };
6975 }
6976 ASSERT_NOT_REACHED()((void)0);
6977 return { };
6978 }();
6979 page->insertTextAsync(aStringValue, { }, WTF::move(options));
6980
6981 if (_focusedElementInformation.autocapitalizeType == WebCore::AutocapitalizeType::Words && aStringValue.length) {
6982 _lastInsertedCharacterToOverrideCharacterBeforeSelection = [aStringValue characterAtIndex:aStringValue.length - 1];
6983 page->scheduleFullEditorStateUpdate();
6984 }
6985
6986 _autocorrectionContextNeedsUpdate = YES__objc_yes;
6987}
6988
6989- (void)insertText:(NSString *)aStringValue alternatives:(NSArray<NSString *> *)alternatives style:(UITextAlternativeStyle)style
6990{
6991 if (!alternatives.count) {
6992 [self insertText:aStringValue];
6993 return;
6994 }
6995
6996 BOOL isLowConfidence = style == UITextAlternativeStyleLowConfidence;
6997 auto nsAlternatives = adoptNS([[NSTextAlternatives alloc] initWithPrimaryString:aStringValue alternativeStrings:alternatives isLowConfidence:isLowConfidence]);
6998#if USE(BROWSERENGINEKIT)(defined 1 && 1)
6999 auto textAlternatives = adoptNS([[PlatformTextAlternativesBETextAlternatives alloc] _initWithNSTextAlternatives:nsAlternatives.get()]);
7000#else
7001 auto textAlternatives = nsAlternatives;
7002#endif
7003 WebCore::TextAlternativeWithRange textAlternativeWithRange { textAlternatives.get(), NSMakeRange(0, aStringValue.length) };
7004
7005 WebKit::InsertTextOptions options;
7006 options.shouldSimulateKeyboardInput = [self _shouldSimulateKeyboardInputOnTextInsertion];
7007 protect(_page)->insertDictatedTextAsync(aStringValue, { }, { textAlternativeWithRange }, WTF::move(options));
7008
7009 _autocorrectionContextNeedsUpdate = YES__objc_yes;
7010}
7011
7012- (BOOL)hasText
7013{
7014 if (_isFocusingElementWithKeyboard || _page->waitingForPostLayoutEditorStateUpdateAfterFocusingElement())
7015 return _focusedElementInformation.hasPlainText;
7016
7017 auto& editorState = protect(_page)->editorState();
7018 return editorState.hasPostLayoutData() && editorState.postLayoutData->hasPlainText;
7019}
7020
7021// Accepts either NSTextAlternatives, or an equivalent type that's currently defined as PlatformTextAlternatives.
7022- (void)addTextAlternatives:(NSObject *)alternatives
7023{
7024 RetainPtr platformAlternatives = dynamic_objc_cast<PlatformTextAlternativesBETextAlternatives>(alternatives);
7025
7026#if USE(BROWSERENGINEKIT)(defined 1 && 1)
7027 if (!platformAlternatives) {
7028 if (RetainPtr nsAlternatives = dynamic_objc_cast<NSTextAlternatives>(alternatives))
7029 platformAlternatives = adoptNS([[PlatformTextAlternativesBETextAlternatives alloc] _initWithNSTextAlternatives:nsAlternatives.get()]);
7030 }
7031#endif
7032
7033 if (!platformAlternatives)
7034 return;
7035
7036 protect(_page)->addDictationAlternative({ platformAlternatives.get(), NSMakeRange(0, [platformAlternatives primaryString].length) });
7037}
7038
7039- (void)removeEmojiAlternatives
7040{
7041 protect(_page)->dictationAlternativesAtSelection([weakSelf = WeakObjCPtr<WKContentView>(self)](auto&& contexts) {
7042 auto strongSelf = weakSelf.get();
7043 if (!strongSelf || !strongSelf->_page)
7044 return;
7045
7046 RefPtr page = strongSelf->_page;
7047 Vector<WebCore::DictationContext> contextsToRemove;
7048 for (auto context : contexts) {
7049 auto alternatives = protect(page->pageClient())->platformDictationAlternatives(context);
7050 if (!alternatives)
7051 continue;
7052
7053 auto originalAlternatives = alternatives.alternativeStrings;
7054 auto nonEmojiAlternatives = [NSMutableArray arrayWithCapacity:originalAlternatives.count];
7055 for (NSString *alternative in originalAlternatives) {
7056 if (!alternative._containsEmojiOnly)
7057 [nonEmojiAlternatives addObject:alternative];
7058 }
7059
7060 if (nonEmojiAlternatives.count == originalAlternatives.count)
7061 continue;
7062
7063 RetainPtr<NSTextAlternatives> nsReplacement;
7064 if (nonEmojiAlternatives.count)
7065 nsReplacement = adoptNS([[NSTextAlternatives alloc] initWithPrimaryString:alternatives.primaryString alternativeStrings:nonEmojiAlternatives isLowConfidence:alternatives.isLowConfidence]);
7066 else
7067 contextsToRemove.append(context);
7068
7069 RetainPtr<PlatformTextAlternativesBETextAlternatives> platformReplacement;
7070#if USE(BROWSERENGINEKIT)(defined 1 && 1)
7071 platformReplacement = adoptNS([[PlatformTextAlternativesBETextAlternatives alloc] _initWithNSTextAlternatives:nsReplacement.get()]);
7072#else
7073 platformReplacement = nsReplacement;
7074#endif
7075 if (RefPtr pageClient = page->pageClient())
7076 pageClient->replaceDictationAlternatives(platformReplacement.get(), context);
7077 }
7078 page->clearDictationAlternatives(WTF::move(contextsToRemove));
7079 });
7080}
7081
7082// end of UITextInput protocol implementation
7083
7084static UITextAutocapitalizationType toUITextAutocapitalize(WebCore::AutocapitalizeType webkitType)
7085{
7086 switch (webkitType) {
7087 case WebCore::AutocapitalizeType::Default:
7088 return UITextAutocapitalizationTypeSentences;
7089 case WebCore::AutocapitalizeType::None:
7090 return UITextAutocapitalizationTypeNone;
7091 case WebCore::AutocapitalizeType::Words:
7092 return UITextAutocapitalizationTypeWords;
7093 case WebCore::AutocapitalizeType::Sentences:
7094 return UITextAutocapitalizationTypeSentences;
7095 case WebCore::AutocapitalizeType::AllCharacters:
7096 return UITextAutocapitalizationTypeAllCharacters;
7097 }
7098
7099 return UITextAutocapitalizationTypeSentences;
7100}
7101
7102- (NSString *)contentTypeFromFieldName:(WebCore::AutofillFieldName)fieldName
7103{
7104 switch (fieldName) {
7105 case WebCore::AutofillFieldName::Name:
7106 return UITextContentTypeName;
7107 case WebCore::AutofillFieldName::HonorificPrefix:
7108 return UITextContentTypeNamePrefix;
7109 case WebCore::AutofillFieldName::GivenName:
7110 return UITextContentTypeGivenName;
7111 case WebCore::AutofillFieldName::AdditionalName:
7112 return UITextContentTypeMiddleName;
7113 case WebCore::AutofillFieldName::FamilyName:
7114 return UITextContentTypeFamilyName;
7115 case WebCore::AutofillFieldName::HonorificSuffix:
7116 return UITextContentTypeNameSuffix;
7117 case WebCore::AutofillFieldName::Nickname:
7118 return UITextContentTypeNickname;
7119 case WebCore::AutofillFieldName::OrganizationTitle:
7120 return UITextContentTypeJobTitle;
7121 case WebCore::AutofillFieldName::Organization:
7122 return UITextContentTypeOrganizationName;
7123 case WebCore::AutofillFieldName::StreetAddress:
7124 return UITextContentTypeFullStreetAddress;
7125 case WebCore::AutofillFieldName::AddressLine1:
7126 return UITextContentTypeStreetAddressLine1;
7127 case WebCore::AutofillFieldName::AddressLine2:
7128 return UITextContentTypeStreetAddressLine2;
7129 case WebCore::AutofillFieldName::AddressLevel3:
7130 return UITextContentTypeSublocality;
7131 case WebCore::AutofillFieldName::AddressLevel2:
7132 return UITextContentTypeAddressCity;
7133 case WebCore::AutofillFieldName::AddressLevel1:
7134 return UITextContentTypeAddressState;
7135 case WebCore::AutofillFieldName::CountryName:
7136 return UITextContentTypeCountryName;
7137 case WebCore::AutofillFieldName::PostalCode:
7138 return UITextContentTypePostalCode;
7139 case WebCore::AutofillFieldName::Tel:
7140 return UITextContentTypeTelephoneNumber;
7141 case WebCore::AutofillFieldName::Email:
7142 return UITextContentTypeEmailAddress;
7143 case WebCore::AutofillFieldName::URL:
7144 return UITextContentTypeURL;
7145 case WebCore::AutofillFieldName::Username:
7146 case WebCore::AutofillFieldName::WebAuthn:
7147 return UITextContentTypeUsername;
7148 case WebCore::AutofillFieldName::OneTimeCode:
7149 return UITextContentTypeOneTimeCode;
7150#if HAVE(ESIM_AUTOFILL_SYSTEM_SUPPORT)(defined 1 && 1)
7151 case WebCore::AutofillFieldName::DeviceEID:
7152 return protect(_page)->shouldAllowAutoFillForCellularIdentifiers() ? UITextContentTypeCellularEID : nilnullptr;
7153 case WebCore::AutofillFieldName::DeviceIMEI:
7154 return protect(_page)->shouldAllowAutoFillForCellularIdentifiers() ? UITextContentTypeCellularIMEI : nilnullptr;
7155#else
7156 case WebCore::AutofillFieldName::DeviceEID:
7157 case WebCore::AutofillFieldName::DeviceIMEI:
7158#endif
7159 case WebCore::AutofillFieldName::None:
7160 case WebCore::AutofillFieldName::NewPassword:
7161 case WebCore::AutofillFieldName::CurrentPassword:
7162 case WebCore::AutofillFieldName::AddressLine3:
7163 case WebCore::AutofillFieldName::AddressLevel4:
7164 case WebCore::AutofillFieldName::Country:
7165 case WebCore::AutofillFieldName::CcName:
7166 case WebCore::AutofillFieldName::CcGivenName:
7167 case WebCore::AutofillFieldName::CcAdditionalName:
7168 case WebCore::AutofillFieldName::CcFamilyName:
7169 case WebCore::AutofillFieldName::CcNumber:
7170 case WebCore::AutofillFieldName::CcExp:
7171 case WebCore::AutofillFieldName::CcExpMonth:
7172 case WebCore::AutofillFieldName::CcExpYear:
7173 case WebCore::AutofillFieldName::CcCsc:
7174 case WebCore::AutofillFieldName::CcType:
7175 case WebCore::AutofillFieldName::TransactionCurrency:
7176 case WebCore::AutofillFieldName::TransactionAmount:
7177 case WebCore::AutofillFieldName::Language:
7178 case WebCore::AutofillFieldName::Bday:
7179 case WebCore::AutofillFieldName::BdayDay:
7180 case WebCore::AutofillFieldName::BdayMonth:
7181 case WebCore::AutofillFieldName::BdayYear:
7182 case WebCore::AutofillFieldName::Sex:
7183 case WebCore::AutofillFieldName::Photo:
7184 case WebCore::AutofillFieldName::TelCountryCode:
7185 case WebCore::AutofillFieldName::TelNational:
7186 case WebCore::AutofillFieldName::TelAreaCode:
7187 case WebCore::AutofillFieldName::TelLocal:
7188 case WebCore::AutofillFieldName::TelLocalPrefix:
7189 case WebCore::AutofillFieldName::TelLocalSuffix:
7190 case WebCore::AutofillFieldName::TelExtension:
7191 case WebCore::AutofillFieldName::Impp:
7192 break;
7193 };
7194
7195 return nilnullptr;
7196}
7197
7198- (BOOL)_requiresLegacyTextInputTraits
7199{
7200 if (_cachedRequiresLegacyTextInputTraits.has_value())
7201 return *_cachedRequiresLegacyTextInputTraits;
7202
7203 _cachedRequiresLegacyTextInputTraits = [&]() -> BOOL {
7204 if (!self.shouldUseAsyncInteractions)
7205 return YES__objc_yes;
7206
7207 if ([_webView.get() class] == WKWebView.class)
7208 return NO__objc_no;
7209
7210 static auto defaultTextInputTraitsMethod = class_getMethodImplementation(WKWebView.class, @selector(_textInputTraits));
7211 return defaultTextInputTraitsMethod != class_getMethodImplementation([_webView.get() class], @selector(_textInputTraits));
7212 }();
7213 return *_cachedRequiresLegacyTextInputTraits;
7214}
7215
7216// UITextInputPrivate protocol
7217// Direct access to the (private) UITextInputTraits object.
7218- (UITextInputTraits *)textInputTraits
7219{
7220 if (!self._requiresLegacyTextInputTraits)
7221 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG189"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(7221, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
7222
7223 _legacyTextInputTraits = [_webView.get() _textInputTraits];
7224 return _legacyTextInputTraits.get();
7225}
7226
7227- (UITextInputTraits *)textInputTraitsForWebView
7228{
7229 if (!_legacyTextInputTraits)
7230 _legacyTextInputTraits = adoptNS([UITextInputTraits new]);
7231
7232 // Do not change traits when dismissing the keyboard.
7233 if (!_isBlurringFocusedElement)
7234 [self _updateTextInputTraits:_legacyTextInputTraits.get()];
7235
7236 return _legacyTextInputTraits.get();
7237}
7238
7239- (void)_updateTextInputTraits:(id<UITextInputTraits>)traits
7240{
7241 traits.secureTextEntry = _focusedElementInformation.elementType == WebKit::InputType::Password || [_formInputSession forceSecureTextEntry];
7242
7243 switch (_focusedElementInformation.enterKeyHint) {
7244 case WebCore::EnterKeyHint::Enter:
7245 traits.returnKeyType = UIReturnKeyDefault;
7246 break;
7247 case WebCore::EnterKeyHint::Done:
7248 traits.returnKeyType = UIReturnKeyDone;
7249 break;
7250 case WebCore::EnterKeyHint::Go:
7251 traits.returnKeyType = UIReturnKeyGo;
7252 break;
7253 case WebCore::EnterKeyHint::Next:
7254 traits.returnKeyType = UIReturnKeyNext;
7255 break;
7256 case WebCore::EnterKeyHint::Search:
7257 traits.returnKeyType = UIReturnKeySearch;
7258 break;
7259 case WebCore::EnterKeyHint::Send:
7260 traits.returnKeyType = UIReturnKeySend;
7261 break;
7262 default: {
7263 if (!_focusedElementInformation.formAction.isEmpty())
7264 traits.returnKeyType = _focusedElementInformation.elementType == WebKit::InputType::Search ? UIReturnKeySearch : UIReturnKeyGo;
7265 }
7266 }
7267
7268#if HAVE(UI_CONVERSATION_CONTEXT)(defined 1 && 1)
7269 if ([traits respondsToSelector:@selector(setConversationContext:)])
7270 traits.conversationContext = [_webView.get() conversationContext];
7271#endif
7272
7273 BOOL disableAutocorrectAndAutocapitalize = _focusedElementInformation.elementType == WebKit::InputType::Password || _focusedElementInformation.elementType == WebKit::InputType::Email
7274 || _focusedElementInformation.elementType == WebKit::InputType::URL || _focusedElementInformation.formAction.contains("login"_s);
7275 if ([traits respondsToSelector:@selector(setAutocapitalizationType:)])
7276 traits.autocapitalizationType = disableAutocorrectAndAutocapitalize ? UITextAutocapitalizationTypeNone : toUITextAutocapitalize(_focusedElementInformation.autocapitalizeType);
7277 if ([traits respondsToSelector:@selector(setAutocorrectionType:)])
7278 traits.autocorrectionType = disableAutocorrectAndAutocapitalize ? UITextAutocorrectionTypeNo : (_focusedElementInformation.isAutocorrect ? UITextAutocorrectionTypeYes : UITextAutocorrectionTypeNo);
7279
7280 if (!_focusedElementInformation.isSpellCheckingEnabled) {
7281 if ([traits respondsToSelector:@selector(setSmartQuotesType:)])
7282 traits.smartQuotesType = UITextSmartQuotesTypeNo;
7283 if ([traits respondsToSelector:@selector(setSmartDashesType:)])
7284 traits.smartDashesType = UITextSmartDashesTypeNo;
7285 if ([traits respondsToSelector:@selector(setSpellCheckingType:)])
7286 traits.spellCheckingType = UITextSpellCheckingTypeNo;
7287 }
7288
7289 switch (_focusedElementInformation.inputMode) {
7290 case WebCore::InputMode::None:
7291 case WebCore::InputMode::Unspecified:
7292 switch (_focusedElementInformation.elementType) {
7293 case WebKit::InputType::Phone:
7294 traits.keyboardType = UIKeyboardTypePhonePad;
7295 break;
7296 case WebKit::InputType::URL:
7297 traits.keyboardType = UIKeyboardTypeURL;
7298 break;
7299 case WebKit::InputType::Email:
7300 traits.keyboardType = UIKeyboardTypeEmailAddress;
7301 break;
7302 case WebKit::InputType::Number:
7303 traits.keyboardType = UIKeyboardTypeNumbersAndPunctuation;
7304 break;
7305 case WebKit::InputType::NumberPad:
7306 traits.keyboardType = UIKeyboardTypeNumberPad;
7307 break;
7308 case WebKit::InputType::None:
7309 case WebKit::InputType::ContentEditable:
7310 case WebKit::InputType::Text:
7311 case WebKit::InputType::Password:
7312 case WebKit::InputType::TextArea:
7313 case WebKit::InputType::Search:
7314 case WebKit::InputType::Date:
7315 case WebKit::InputType::DateTimeLocal:
7316 case WebKit::InputType::Month:
7317 case WebKit::InputType::Week:
7318 case WebKit::InputType::Time:
7319 case WebKit::InputType::Select:
7320 case WebKit::InputType::Drawing:
7321 case WebKit::InputType::Color:
7322 traits.keyboardType = UIKeyboardTypeDefault;
7323 }
7324 break;
7325 case WebCore::InputMode::Text:
7326 traits.keyboardType = UIKeyboardTypeDefault;
7327 break;
7328 case WebCore::InputMode::Telephone:
7329 traits.keyboardType = UIKeyboardTypePhonePad;
7330 break;
7331 case WebCore::InputMode::Url:
7332 traits.keyboardType = UIKeyboardTypeURL;
7333 break;
7334 case WebCore::InputMode::Email:
7335 traits.keyboardType = UIKeyboardTypeEmailAddress;
7336 break;
7337 case WebCore::InputMode::Numeric:
7338 traits.keyboardType = UIKeyboardTypeNumberPad;
7339 break;
7340 case WebCore::InputMode::Decimal:
7341 traits.keyboardType = UIKeyboardTypeDecimalPad;
7342 break;
7343 case WebCore::InputMode::Search:
7344 traits.keyboardType = UIKeyboardTypeWebSearch;
7345 break;
7346 }
7347
7348#if HAVE(PEPPER_UI_CORE)(defined HAVE_PEPPER_UI_CORE && HAVE_PEPPER_UI_CORE)
7349 traits.textContentType = self.textContentTypeForQuickboard;
7350#else
7351 traits.textContentType = [self contentTypeFromFieldName:_focusedElementInformation.autofillFieldName];
7352#endif
7353
7354 auto extendedTraits = dynamic_objc_cast<WKExtendedTextInputTraits>(traits);
7355 auto privateTraits = (id <UITextInputTraits_Private>)traits;
7356
7357 BOOL isSingleLineDocument = ^{
7358 switch (_focusedElementInformation.elementType) {
7359 case WebKit::InputType::ContentEditable:
7360 case WebKit::InputType::TextArea:
7361 case WebKit::InputType::None:
7362 return NO__objc_no;
7363 case WebKit::InputType::Color:
7364 case WebKit::InputType::Date:
7365 case WebKit::InputType::DateTimeLocal:
7366 case WebKit::InputType::Drawing:
7367 case WebKit::InputType::Email:
7368 case WebKit::InputType::Month:
7369 case WebKit::InputType::Number:
7370 case WebKit::InputType::NumberPad:
7371 case WebKit::InputType::Password:
7372 case WebKit::InputType::Phone:
7373 case WebKit::InputType::Search:
7374 case WebKit::InputType::Select:
7375 case WebKit::InputType::Text:
7376 case WebKit::InputType::Time:
7377 case WebKit::InputType::URL:
7378 case WebKit::InputType::Week:
7379 return YES__objc_yes;
7380 }
7381 }();
7382
7383 if ([extendedTraits respondsToSelector:@selector(setSingleLineDocument:)])
7384 extendedTraits.singleLineDocument = isSingleLineDocument;
7385 else if ([privateTraits respondsToSelector:@selector(setIsSingleLineDocument:)])
7386 privateTraits.isSingleLineDocument = isSingleLineDocument;
7387
7388 if (_focusedElementInformation.hasEverBeenPasswordField) {
7389 if ([privateTraits respondsToSelector:@selector(setLearnsCorrections:)])
7390 privateTraits.learnsCorrections = NO__objc_no;
7391 extendedTraits.typingAdaptationEnabled = NO__objc_no;
7392 }
7393
7394 if ([privateTraits respondsToSelector:@selector(setShortcutConversionType:)])
7395 privateTraits.shortcutConversionType = _focusedElementInformation.elementType == WebKit::InputType::Password ? UITextShortcutConversionTypeNo : UITextShortcutConversionTypeDefault;
7396
7397#if HAVE(INLINE_PREDICTIONS)(defined 1 && 1)
7398 bool allowsInlinePredictions = [&] {
7399#if PLATFORM(MACCATALYST)(defined WTF_PLATFORM_MACCATALYST && WTF_PLATFORM_MACCATALYST
)
7400 return false;
7401#else
7402 if (self.webView.configuration.allowsInlinePredictions)
7403 return true;
7404 if (auto& state = protect(_page)->editorState(); state.hasPostLayoutData() && !_isFocusingElementWithKeyboard && !protect(_page)->waitingForPostLayoutEditorStateUpdateAfterFocusingElement())
7405 return state.postLayoutData->canEnableWritingSuggestions;
7406 return _focusedElementInformation.isWritingSuggestionsEnabled;
7407#endif
7408 }();
7409 traits.inlinePredictionType = allowsInlinePredictions ? UITextInlinePredictionTypeDefault : UITextInlinePredictionTypeNo;
7410#endif
7411
7412 [self _updateTextInputTraitsForInteractionTintColor];
7413}
7414
7415- (UITextInteractionAssistant *)interactionAssistant
7416{
7417 if (!self.shouldUseAsyncInteractions)
7418 return [_textInteractionWrapper textInteractionAssistant];
7419 return super.interactionAssistant;
7420}
7421
7422// NSRange support. Would like to deprecate to the extent possible, although some support
7423// (i.e. selectionRange) has shipped as API.
7424- (NSRange)selectionRange
7425{
7426 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG190"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(7426, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
7427
7428 return NSMakeRange(NSNotFound, 0);
7429}
7430
7431- (CGRect)rectForNSRange:(NSRange)range
7432{
7433 return CGRectZero;
7434}
7435
7436- (NSRange)_markedTextNSRange
7437{
7438 return NSMakeRange(NSNotFound, 0);
7439}
7440
7441// DOM range support.
7442- (DOMRange *)selectedDOMRange
7443{
7444 return nilnullptr;
7445}
7446
7447- (void)setSelectedDOMRange:(DOMRange *)range affinityDownstream:(BOOL)affinityDownstream
7448{
7449}
7450
7451// Modify text without starting a new undo grouping.
7452- (void)replaceRangeWithTextWithoutClosingTyping:(UITextRange *)range replacementText:(NSString *)text
7453{
7454 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG191"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(7454, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
7455}
7456
7457// Caret rect support. Shouldn't be necessary, but firstRectForRange doesn't offer precisely
7458// the same functionality.
7459- (CGRect)rectContainingCaretSelection
7460{
7461 return CGRectZero;
7462}
7463
7464- (BOOL)_isTextInputContextFocused:(_WKTextInputContext *)context
7465{
7466 if (!context) {
7467 ASSERT_NOT_REACHED()((void)0);
7468 return NO__objc_no;
7469 }
7470 // We ignore bounding rect changes as the bounding rect of the focused element is not kept up-to-date.
7471 return [self _isSameAsFocusedElement:context._textInputContext];
7472}
7473
7474- (void)_focusTextInputContext:(_WKTextInputContext *)context placeCaretAt:(CGPoint)point completionHandler:(void (^)(UIResponder<UITextInput> *))completionHandler
7475{
7476 ASSERT(context)((void)0);
7477 // This function can be called more than once during a text interaction (e.g. <rdar://problem/59430806>).
7478 if (![self becomeFirstResponder]) {
7479 completionHandler(nilnullptr);
7480 return;
7481 }
7482 if ([self _isTextInputContextFocused:context]) {
7483 completionHandler(_focusedElementInformation.isReadOnly ? nilnullptr : self);
7484 return;
7485 }
7486 _autocorrectionContextNeedsUpdate = YES__objc_yes;
7487 _usingGestureForSelection = YES__objc_yes;
7488 auto checkFocusedElement = [weakSelf = WeakObjCPtr<WKContentView> { self }, context = adoptNS([context copy]), completionHandler = makeBlockPtr(completionHandler)] (bool success) {
7489 auto strongSelf = weakSelf.get();
7490 if (!strongSelf) {
7491 completionHandler(nilnullptr);
7492 return;
7493 }
7494 bool isFocused = success && [strongSelf _isTextInputContextFocused:context.get()];
7495 bool isEditable = success && !strongSelf->_focusedElementInformation.isReadOnly;
7496 strongSelf->_textInteractionDidChangeFocusedElement |= isFocused;
7497 strongSelf->_usingGestureForSelection = NO__objc_no;
7498 completionHandler(isFocused && isEditable ? strongSelf.get() : nilnullptr);
7499 };
7500 protect(_page)->focusTextInputContextAndPlaceCaret(context._textInputContext, WebCore::IntPoint { point }, WTF::move(checkFocusedElement));
7501}
7502
7503- (void)_requestTextInputContextsInRect:(CGRect)rect completionHandler:(void (^)(NSArray<_WKTextInputContext *> *))completionHandler
7504{
7505 WebCore::FloatRect searchRect { rect };
7506#if ENABLE(EDITABLE_REGION)(defined 1 && 1)
7507 bool hitInteractionRect = self._hasFocusedElement && searchRect.inclusivelyIntersects(_focusedElementInformation.interactionRect);
7508 if (!self.webView._editable && !hitInteractionRect && !WebKit::mayContainEditableElementsInRect(self, rect)) {
7509 completionHandler(@[ ]);
7510 return;
7511 }
7512#endif
7513 protect(_page)->textInputContextsInRect(searchRect, [weakSelf = WeakObjCPtr<WKContentView>(self), completionHandler = makeBlockPtr(completionHandler)] (const Vector<WebCore::ElementContext>& contexts) {
7514 auto strongSelf = weakSelf.get();
7515 if (!strongSelf || contexts.isEmpty()) {
7516 completionHandler(@[ ]);
7517 return;
7518 }
7519 completionHandler(createNSArray(contexts, [] (const auto& context) {
7520 return adoptNS([[_WKTextInputContext alloc] _initWithTextInputContext:context]);
7521 }).get());
7522 });
7523}
7524
7525- (void)_willBeginTextInteractionInTextInputContext:(_WKTextInputContext *)context
7526{
7527 ASSERT(context)((void)0);
7528
7529 protect(_page)->setCanShowPlaceholder(context._textInputContext, false);
7530
7531 ++_activeTextInteractionCount;
7532 if (_activeTextInteractionCount > 1)
7533 return;
7534
7535 _textInteractionDidChangeFocusedElement = NO__objc_no;
7536 protect(_page)->setShouldRevealCurrentSelectionAfterInsertion(false);
7537 _autocorrectionContextNeedsUpdate = YES__objc_yes;
7538 _usingGestureForSelection = YES__objc_yes;
7539}
7540
7541- (void)_didFinishTextInteractionInTextInputContext:(_WKTextInputContext *)context
7542{
7543 ASSERT(context)((void)0);
7544
7545 protect(_page)->setCanShowPlaceholder(context._textInputContext, true);
7546
7547 ASSERT(_activeTextInteractionCount > 0)((void)0);
7548 --_activeTextInteractionCount;
7549 if (_activeTextInteractionCount)
7550 return;
7551
7552 _usingGestureForSelection = NO__objc_no;
7553
7554 if (_textInteractionDidChangeFocusedElement) {
7555 // Mark to zoom to reveal the newly focused element on the next editor state update.
7556 // Then tell the web process to reveal the current selection, which will send us (the
7557 // UI process) an editor state update.
7558 _revealFocusedElementDeferrer = WebKit::RevealFocusedElementDeferrer::create(self, WebKit::RevealFocusedElementDeferralReason::EditorState);
7559 _page->setWaitingForPostLayoutEditorStateUpdateAfterFocusingElement(true);
7560 _textInteractionDidChangeFocusedElement = NO__objc_no;
7561 }
7562
7563 protect(_page)->setShouldRevealCurrentSelectionAfterInsertion(true);
7564}
7565
7566- (void)modifierFlagsDidChangeFrom:(UIKeyModifierFlags)oldFlags to:(UIKeyModifierFlags)newFlags
7567{
7568 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG192"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(7568, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
7569
7570 auto dispatchSyntheticFlagsChangedEvents = [&] (UIKeyModifierFlags flags, bool keyDown) {
7571 if (flags & UIKeyModifierShift)
7572 [self handleKeyWebEvent:adoptNS([[WKSyntheticFlagsChangedWebEvent alloc] initWithShiftState:keyDown]).get()];
7573 if (flags & UIKeyModifierAlphaShift)
7574 [self handleKeyWebEvent:adoptNS([[WKSyntheticFlagsChangedWebEvent alloc] initWithCapsLockState:keyDown]).get()];
7575 };
7576
7577 if (UIKeyModifierFlags removedFlags = oldFlags & ~newFlags)
7578 dispatchSyntheticFlagsChangedEvents(removedFlags, false);
7579 if (UIKeyModifierFlags addedFlags = newFlags & ~oldFlags)
7580 dispatchSyntheticFlagsChangedEvents(addedFlags, true);
7581}
7582
7583- (BOOL)shouldSuppressUpdateCandidateView
7584{
7585 return _candidateViewNeedsUpdate;
7586}
7587
7588// Web events.
7589- (BOOL)requiresKeyEvents
7590{
7591 return YES__objc_yes;
7592}
7593
7594- (BOOL)_tryToHandlePressesEvent:(UIPressesEvent *)event
7595{
7596 bool isHardwareKeyboardEvent = !!event._hidEvent;
7597 // We only want to handle key event from the hardware keyboard when we are
7598 // first responder and we are not interacting with editable content.
7599 if (self.isFirstResponder && isHardwareKeyboardEvent && (_inputPeripheral || !protect(_page)->editorState().isContentEditable)) {
7600 if ([_inputPeripheral respondsToSelector:@selector(handleKeyEvent:)]) {
7601 if ([_inputPeripheral handleKeyEvent:event])
7602 return YES__objc_yes;
7603 }
7604 if (!_seenHardwareKeyDownInNonEditableElement) {
7605 _seenHardwareKeyDownInNonEditableElement = YES__objc_yes;
7606 [self reloadInputViews];
7607 }
7608 }
7609 return NO__objc_no;
7610}
7611
7612- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
7613{
7614 if ([self _tryToHandlePressesEvent:event])
7615 return;
7616
7617 _isHandlingActivePressesEvent = YES__objc_yes;
7618 [super pressesBegan:presses withEvent:event];
7619}
7620
7621- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
7622{
7623 if ([self _tryToHandlePressesEvent:event])
7624 return;
7625
7626 _isHandlingActivePressesEvent = NO__objc_no;
7627 [super pressesEnded:presses withEvent:event];
7628}
7629
7630- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
7631{
7632 if ([self _tryToHandlePressesEvent:event])
7633 return;
7634
7635 [super pressesChanged:presses withEvent:event];
7636}
7637
7638- (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
7639{
7640 if ([self _tryToHandlePressesEvent:event])
7641 return;
7642
7643 _isHandlingActivePressesEvent = NO__objc_no;
7644 [super pressesCancelled:presses withEvent:event];
7645}
7646
7647- (void)generateSyntheticEditingCommand:(WebKit::SyntheticEditingCommandType)command
7648{
7649 protect(_page)->generateSyntheticEditingCommand(command);
7650}
7651
7652- (void)handleKeyWebEvent:(::WebEvent *)theEvent
7653{
7654 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG193"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(7654, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
7655
7656 [self _internalHandleKeyWebEvent:theEvent];
7657}
7658
7659- (void)_internalHandleKeyWebEvent:(::WebEvent *)theEvent
7660{
7661 protect(_page)->handleKeyboardEvent(WebKit::NativeWebKeyboardEvent(theEvent, WebKit::NativeWebKeyboardEvent::HandledByInputMethod::No));
7662}
7663
7664- (void)handleKeyWebEvent:(::WebEvent *)event withCompletionHandler:(void (^)(::WebEvent *theEvent, BOOL wasHandled))completionHandler
7665{
7666 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG194"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(7666, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
7667
7668 [self _internalHandleKeyWebEvent:event withCompletionHandler:completionHandler];
7669}
7670
7671- (BOOL)_deferKeyEventToInputMethodEditing:(::WebEvent *)event
7672{
7673 if (!protect(_page)->editorState().isContentEditable && !_treatAsContentEditableUntilNextEditorStateUpdate)
7674 return NO__objc_no;
7675
7676#if USE(BROWSERENGINEKIT)(defined 1 && 1)
7677 if (self.shouldUseAsyncInteractions) {
7678 RetainPtr inputDelegate = _asyncInputDelegate;
7679 [self _logMissingSystemInputDelegateIfNeeded:__PRETTY_FUNCTION__];
7680 if (!inputDelegate)
7681 return NO__objc_no;
7682
7683 auto context = adoptNS([[BEKeyEntryContext alloc] initWithKeyEntry:event.originalKeyEntry]);
7684 [context setDocumentEditable:YES__objc_yes];
7685 [context setShouldEvaluateForInputSystemHandling:YES__objc_yes];
7686 return [inputDelegate shouldDeferEventHandlingToSystemForTextInput:self.asBETextInput context:context.get()];
7687 }
7688#endif // USE(BROWSERENGINEKIT)
7689
7690 return [[UIKeyboardImpl sharedInstance] handleKeyInputMethodCommandForCurrentEvent];
7691}
7692
7693- (void)_internalHandleKeyWebEvent:(::WebEvent *)event withCompletionHandler:(void (^)(::WebEvent *event, BOOL wasHandled))completionHandler
7694{
7695 if (!isUIThread()) {
7696 RELEASE_LOG_FAULT(KeyHandling, "%s was invoked on a background thread.", __PRETTY_FUNCTION__)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogKeyHandling
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_FAULT; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("%s was invoked on a background thread."), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG195"
) = "%s was invoked on a background thread."; uint8_t _Alignas
(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("%s was invoked on a background thread.", __PRETTY_FUNCTION__
)]; _os_log_fault_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "%s was invoked on a background thread.", __PRETTY_FUNCTION__
), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); }
}) clang diagnostic pop
;
7697 completionHandler(event, NO__objc_no);
7698 return;
7699 }
7700
7701#if PLATFORM(MACCATALYST)(defined WTF_PLATFORM_MACCATALYST && WTF_PLATFORM_MACCATALYST
)
7702 bool hasPendingArrowKey = _keyWebEventHandlers.containsIf([](auto& eventAndCompletion) {
7703 switch ([eventAndCompletion.event keyCode]) {
7704 case VK_RIGHT0x27:
7705 case VK_LEFT0x25:
7706 case VK_DOWN0x28:
7707 case VK_UP0x26:
7708 return true;
7709 default:
7710 return false;
7711 }
7712 });
7713
7714 if (hasPendingArrowKey) {
7715 RELEASE_LOG_ERROR(KeyHandling, "Ignoring incoming key event due to pending arrow key event")clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogKeyHandling
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Ignoring incoming key event due to pending arrow key event"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG196"
) = "Ignoring incoming key event due to pending arrow key event"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Ignoring incoming key event due to pending arrow key event"
)]; _os_log_error_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "Ignoring incoming key event due to pending arrow key event"
), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); }
}) clang diagnostic pop
;
7716 completionHandler(event, NO__objc_no);
7717 return;
7718 }
7719#endif // PLATFORM(MACCATALYST)
7720
7721 if (event.type == WebEventKeyDown)
7722 _isHandlingActiveKeyEvent = YES__objc_yes;
7723
7724 [self _handleDOMPasteRequestWithResult:WebCore::DOMPasteAccessResponse::DeniedForGesture];
7725
7726 using HandledByInputMethod = WebKit::NativeWebKeyboardEvent::HandledByInputMethod;
7727 if ([self _deferKeyEventToInputMethodEditing:event]) {
7728 completionHandler(event, YES__objc_yes);
7729 _isDeferringKeyEventsToInputMethod = YES__objc_yes;
7730 protect(_page)->handleKeyboardEvent(WebKit::NativeWebKeyboardEvent(event, HandledByInputMethod::Yes));
7731 return;
7732 }
7733
7734 if (protect(_page)->handleKeyboardEvent(WebKit::NativeWebKeyboardEvent(event, HandledByInputMethod::No)))
7735 _keyWebEventHandlers.append({ event, makeBlockPtr(completionHandler) });
7736 else
7737 completionHandler(event, NO__objc_no);
7738}
7739
7740- (void)_didHandleKeyEvent:(::WebEvent *)event eventWasHandled:(BOOL)eventWasHandled
7741{
7742 if ([event isKindOfClass:[WKSyntheticFlagsChangedWebEvent class]])
7743 return;
7744
7745 if (!(event.keyboardFlags & WebEventKeyboardInputModifierFlagsChanged))
7746 [protect(_keyboardScrollingAnimator) handleKeyEvent:event];
7747
7748 if (event.type == WebEventKeyUp)
7749 _isHandlingActiveKeyEvent = NO__objc_no;
7750
7751 auto indexOfHandlerToCall = _keyWebEventHandlers.findIf([event](auto& entry) {
7752 return entry.event == event;
7753 });
7754
7755 if (indexOfHandlerToCall == notFound)
7756 return;
7757
7758 auto handler = _keyWebEventHandlers[indexOfHandlerToCall].completionBlock;
7759 if (!handler) {
7760 ASSERT_NOT_REACHED()((void)0);
7761 return;
7762 }
7763
7764 _keyWebEventHandlers.removeAt(indexOfHandlerToCall);
7765 handler(event, eventWasHandled);
7766}
7767
7768- (BOOL)_interpretKeyEvent:(::WebEvent *)event withContext:(WebKit::KeyEventInterpretationContext&&)context
7769{
7770 SetForScope interpretKeyEventScope { _isInterpretingKeyEvent, YES__objc_yes };
7771
7772 BOOL isCharEvent = context.isCharEvent;
7773
7774 RetainPtr scrollView = [self _scrollViewForScrollingNodeID:context.scrollingNode];
7775 RetainPtr keyboardScrollingAnimator = _keyboardScrollingAnimator;
7776 if ([keyboardScrollingAnimator beginWithEvent:event scrollView:protect((WKBaseScrollView *)scrollView.get() ?: self.webView._scrollViewInternal)] || [keyboardScrollingAnimator scrollTriggeringKeyIsPressed])
7777 return YES__objc_yes;
7778
7779#if USE(BROWSERENGINEKIT)(defined 1 && 1)
7780 if (self.shouldUseAsyncInteractions) {
7781 RetainPtr systemDelegate = _asyncInputDelegate;
7782 [self _logMissingSystemInputDelegateIfNeeded:__PRETTY_FUNCTION__];
7783 if (!systemDelegate)
7784 return NO__objc_no;
7785
7786 auto context = adoptNS([[BEKeyEntryContext alloc] initWithKeyEntry:event.originalKeyEntry]);
7787 [context setDocumentEditable:protect(_page)->editorState().isContentEditable];
7788 [context setShouldInsertCharacter:isCharEvent];
7789 return [systemDelegate shouldDeferEventHandlingToSystemForTextInput:self.asBETextInput context:context.get()];
7790 }
7791#endif // USE(BROWSERENGINEKIT)
7792
7793 if (event.keyboardFlags & WebEventKeyboardInputModifierFlagsChanged)
7794 return NO__objc_no;
7795
7796 BOOL contentEditable = protect(_page)->editorState().isContentEditable;
7797
7798 if (!contentEditable && event.isTabKey)
7799 return NO__objc_no;
7800
7801 UIKeyboardImpl *keyboard = [UIKeyboardImpl sharedInstance];
7802
7803 if (!isCharEvent && [keyboard handleKeyTextCommandForCurrentEvent])
7804 return YES__objc_yes;
7805 if (isCharEvent && [keyboard handleKeyAppCommandForCurrentEvent])
7806 return YES__objc_yes;
7807
7808 // Don't insert character for an unhandled Command-key key command. This matches iOS and Mac platform conventions.
7809 if (event.modifierFlags & WebEventFlagMaskCommandKey)
7810 return NO__objc_no;
7811
7812 NSString *characters = event.characters;
7813 if (!characters.length)
7814 return NO__objc_no;
7815
7816 switch ([characters characterAtIndex:0]) {
7817 case NSBackspaceCharacter:
7818 case NSDeleteCharacter:
7819 if (contentEditable) {
7820 [keyboard deleteFromInputWithFlags:event.keyboardFlags];
7821 return YES__objc_yes;
7822 }
7823 break;
7824 case NSEnterCharacter:
7825 case NSCarriageReturnCharacter:
7826 if (contentEditable && isCharEvent) {
7827 // Map \r from HW keyboard to \n to match the behavior of the soft keyboard.
7828 [keyboard addInputString:@"\n" withFlags:0 withInputManagerHint:nilnullptr];
7829 return YES__objc_yes;
7830 }
7831 break;
7832 default:
7833 if (contentEditable && isCharEvent) {
7834 [keyboard addInputString:event.characters withFlags:event.keyboardFlags withInputManagerHint:event.inputManagerHint];
7835 return YES__objc_yes;
7836 }
7837 break;
7838 }
7839
7840 return NO__objc_no;
7841}
7842
7843- (NSArray<NSString *> *)filePickerAcceptedTypeIdentifiers
7844{
7845 if (!_fileUploadPanel)
7846 return @[];
7847
7848 return [_fileUploadPanel acceptedTypeIdentifiers];
7849}
7850
7851- (void)dismissFilePicker
7852{
7853 [_fileUploadPanel dismissIfNeededWithReason:WebKit::PickerDismissalReason::Testing];
7854}
7855
7856- (BOOL)isScrollableForKeyboardScrollViewAnimator:(WKKeyboardScrollViewAnimator *)animator
7857{
7858 if (protect(_page)->editorState().isContentEditable)
7859 return NO__objc_no;
7860
7861 if (_focusedElementInformation.elementType == WebKit::InputType::Select)
7862 return NO__objc_no;
7863
7864 RetainPtr scrollView = animator.scrollView ?: self.webView.scrollView;
7865 if (!scrollView.get().scrollEnabled)
7866 return NO__objc_no;
7867
7868#if HAVE(UISCROLLVIEW_ALLOWS_KEYBOARD_SCROLLING)(defined 1 && 1)
7869 if (!scrollView.get().allowsKeyboardScrolling)
7870 return NO__objc_no;
7871#endif
7872
7873 return YES__objc_yes;
7874}
7875
7876- (CGFloat)keyboardScrollViewAnimator:(WKKeyboardScrollViewAnimator *)animator distanceForIncrement:(WebCore::ScrollGranularity)increment inDirection:(WebCore::ScrollDirection)direction
7877{
7878 BOOL directionIsHorizontal = direction == WebCore::ScrollDirection::ScrollLeft || direction == WebCore::ScrollDirection::ScrollRight;
7879
7880 switch (increment) {
7881 case WebCore::ScrollGranularity::Document: {
7882 CGSize documentSize = [self convertRect:self.bounds toView:self.webView].size;
7883 return directionIsHorizontal ? documentSize.width : documentSize.height;
7884 }
7885 case WebCore::ScrollGranularity::Page: {
7886 CGSize pageSize = [self convertSize:CGSizeMake(0, WebCore::Scrollbar::pageStep(protect(_page)->unobscuredContentRect().height(), self.bounds.size.height)) toView:self.webView];
7887 return directionIsHorizontal ? pageSize.width : pageSize.height;
7888 }
7889 case WebCore::ScrollGranularity::Line:
7890 return [self convertSize:CGSizeMake(0, WebCore::Scrollbar::pixelsPerLineStep()) toView:self.webView].height;
7891 case WebCore::ScrollGranularity::Pixel:
7892 return 0;
7893 }
7894 ASSERT_NOT_REACHED()((void)0);
7895 return 0;
7896}
7897
7898- (void)keyboardScrollViewAnimatorWillScroll:(WKKeyboardScrollViewAnimator *)animator
7899{
7900 _isKeyboardScrollingAnimationRunning = YES__objc_yes;
7901 [self willStartZoomOrScroll];
7902}
7903
7904- (void)keyboardScrollViewAnimatorDidFinishScrolling:(WKKeyboardScrollViewAnimator *)animator
7905{
7906 [_webView.get() _didFinishScrolling:animator.scrollView];
7907 _isKeyboardScrollingAnimationRunning = NO__objc_no;
7908}
7909
7910- (BOOL)isKeyboardScrollingAnimationRunning
7911{
7912 return _isKeyboardScrollingAnimationRunning;
7913}
7914
7915- (void)_executeEditCommand:(NSString *)commandName
7916{
7917 [self _executeEditCommand:commandName notifyDelegate:WebKit::NotifyInputDelegate::Yes];
7918}
7919
7920- (void)_executeEditCommand:(NSString *)commandName notifyDelegate:(WebKit::NotifyInputDelegate)notifyDelegate
7921{
7922 _autocorrectionContextNeedsUpdate = YES__objc_yes;
7923 // FIXME: Editing commands are not considered by WebKit as user initiated even if they are the result
7924 // of keydown or keyup. We need to query the keyboard to determine if this was called from the keyboard
7925 // or not to know whether to tell WebKit to treat this command as user initiated or not.
7926 if (notifyDelegate == WebKit::NotifyInputDelegate::Yes)
7927 [self _internalBeginSelectionChange];
7928 protect(_page)->executeEditCommand(commandName, { }, [view = retainPtr(self), notifyDelegate] {
7929 if (notifyDelegate == WebKit::NotifyInputDelegate::Yes)
7930 [view _internalEndSelectionChange];
7931 });
7932}
7933
7934- (void)_deleteByWord
7935{
7936 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG197"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(7936, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
7937
7938 [self _executeEditCommand:@"deleteWordBackward"];
7939}
7940
7941- (void)_deleteForwardByWord
7942{
7943 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG198"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(7943, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
7944
7945 [self _executeEditCommand:@"deleteWordForward"];
7946}
7947
7948- (void)_deleteToStartOfLine
7949{
7950 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG199"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(7950, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
7951
7952 [self _executeEditCommand:@"deleteToBeginningOfLine"];
7953}
7954
7955- (void)_deleteToEndOfLine
7956{
7957 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG200"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(7957, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
7958
7959 [self _executeEditCommand:@"deleteToEndOfLine"];
7960}
7961
7962- (void)_deleteForwardAndNotify:(BOOL)notify
7963{
7964 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG201"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(7964, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
7965
7966 [self _executeEditCommand:@"deleteForward"];
7967}
7968
7969- (void)_deleteToEndOfParagraph
7970{
7971 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG202"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(7971, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
7972
7973 [self _executeEditCommand:@"deleteToEndOfParagraph"];
7974}
7975
7976- (void)_transpose
7977{
7978 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG203"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(7978, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
7979
7980 [self transposeCharactersAroundSelection];
7981}
7982
7983- (UITextInputArrowKeyHistory *)_moveUp:(BOOL)extending withHistory:(UITextInputArrowKeyHistory *)history
7984{
7985 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG204"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(7985, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
7986
7987 [self _executeEditCommand:extending ? @"moveUpAndModifySelection" : @"moveUp"];
7988 return nilnullptr;
7989}
7990
7991- (UITextInputArrowKeyHistory *)_moveDown:(BOOL)extending withHistory:(UITextInputArrowKeyHistory *)history
7992{
7993 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG205"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(7993, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
7994
7995 [self _executeEditCommand:extending ? @"moveDownAndModifySelection" : @"moveDown"];
7996 return nilnullptr;
7997}
7998
7999- (UITextInputArrowKeyHistory *)_moveLeft:(BOOL)extending withHistory:(UITextInputArrowKeyHistory *)history
8000{
8001 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG206"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(8001, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
8002
8003 [self _executeEditCommand:extending? @"moveLeftAndModifySelection" : @"moveLeft"];
8004 return nilnullptr;
8005}
8006
8007- (UITextInputArrowKeyHistory *)_moveRight:(BOOL)extending withHistory:(UITextInputArrowKeyHistory *)history
8008{
8009 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG207"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(8009, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
8010
8011 [self _executeEditCommand:extending ? @"moveRightAndModifySelection" : @"moveRight"];
8012 return nilnullptr;
8013}
8014
8015- (UITextInputArrowKeyHistory *)_moveToStartOfWord:(BOOL)extending withHistory:(UITextInputArrowKeyHistory *)history
8016{
8017 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG208"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(8017, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
8018
8019 [self _executeEditCommand:extending ? @"moveWordBackwardAndModifySelection" : @"moveWordBackward"];
8020 return nilnullptr;
8021}
8022
8023- (UITextInputArrowKeyHistory *)_moveToStartOfParagraph:(BOOL)extending withHistory:(UITextInputArrowKeyHistory *)history
8024{
8025 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG209"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(8025, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
8026
8027 [self _executeEditCommand:extending ? @"moveBackwardAndModifySelection" : @"moveBackward"];
8028 [self _executeEditCommand:extending ? @"moveToBeginningOfParagraphAndModifySelection" : @"moveToBeginningOfParagraph"];
8029 return nilnullptr;
8030}
8031
8032- (UITextInputArrowKeyHistory *)_moveToStartOfLine:(BOOL)extending withHistory:(UITextInputArrowKeyHistory *)history
8033{
8034 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG210"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(8034, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
8035
8036 [self _executeEditCommand:extending ? @"moveToBeginningOfLineAndModifySelection" : @"moveToBeginningOfLine"];
8037 return nilnullptr;
8038}
8039
8040- (UITextInputArrowKeyHistory *)_moveToStartOfDocument:(BOOL)extending withHistory:(UITextInputArrowKeyHistory *)history
8041{
8042 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG211"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(8042, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
8043
8044 [self _executeEditCommand:extending ? @"moveToBeginningOfDocumentAndModifySelection" : @"moveToBeginningOfDocument"];
8045 return nilnullptr;
8046}
8047
8048- (UITextInputArrowKeyHistory *)_moveToEndOfWord:(BOOL)extending withHistory:(UITextInputArrowKeyHistory *)history
8049{
8050 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG212"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(8050, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
8051
8052 [self _executeEditCommand:extending ? @"moveWordForwardAndModifySelection" : @"moveWordForward"];
8053 return nilnullptr;
8054}
8055
8056- (UITextInputArrowKeyHistory *)_moveToEndOfParagraph:(BOOL)extending withHistory:(UITextInputArrowKeyHistory *)history
8057{
8058 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG213"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(8058, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
8059
8060 [self _executeEditCommand:extending ? @"moveForwardAndModifySelection" : @"moveForward"];
8061 [self _executeEditCommand:extending ? @"moveToEndOfParagraphAndModifySelection" : @"moveToEndOfParagraph"];
8062 return nilnullptr;
8063}
8064
8065- (UITextInputArrowKeyHistory *)_moveToEndOfLine:(BOOL)extending withHistory:(UITextInputArrowKeyHistory *)history
8066{
8067 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG214"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(8067, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
8068
8069 [self _executeEditCommand:extending ? @"moveToEndOfLineAndModifySelection" : @"moveToEndOfLine"];
8070 return nilnullptr;
8071}
8072
8073- (UITextInputArrowKeyHistory *)_moveToEndOfDocument:(BOOL)extending withHistory:(UITextInputArrowKeyHistory *)history
8074{
8075 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG215"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(8075, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
8076
8077 [self _executeEditCommand:extending ? @"moveToEndOfDocumentAndModifySelection" : @"moveToEndOfDocument"];
8078 return nilnullptr;
8079}
8080
8081// Sets a buffer to make room for autocorrection views
8082- (void)setBottomBufferHeight:(CGFloat)bottomBuffer
8083{
8084 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG216"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(8084, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
8085}
8086
8087- (UIView *)automaticallySelectedOverlay
8088{
8089 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG217"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(8089, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
8090
8091 return [self unscaledView];
8092}
8093
8094- (UITextGranularity)selectionGranularity
8095{
8096 return UITextGranularityCharacter;
8097}
8098
8099// The can all be (and have been) trivially implemented in terms of UITextInput. Deprecate and remove.
8100- (void)moveBackward:(unsigned)count
8101{
8102}
8103
8104- (void)moveForward:(unsigned)count
8105{
8106}
8107
8108- (unichar)characterBeforeCaretSelection
8109{
8110 return 0;
8111}
8112
8113- (NSString *)wordContainingCaretSelection
8114{
8115 return nilnullptr;
8116}
8117
8118- (DOMRange *)wordRangeContainingCaretSelection
8119{
8120 return nilnullptr;
8121}
8122
8123- (void)setMarkedText:(NSString *)text
8124{
8125}
8126
8127- (BOOL)hasContent
8128{
8129 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG218"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(8129, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
8130
8131 return self._hasContent;
8132}
8133
8134- (BOOL)_hasContent
8135{
8136 auto& editorState = protect(_page)->editorState();
8137 return editorState.selectionType != WebCore::SelectionType::None && editorState.postLayoutData && editorState.postLayoutData->hasContent;
8138}
8139
8140- (void)selectAll
8141{
8142 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG219"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(8142, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
8143}
8144
8145- (BOOL)hasSelection
8146{
8147 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG220"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(8147, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
8148
8149 return NO__objc_no;
8150}
8151
8152- (BOOL)isPosition:(UITextPosition *)position atBoundary:(UITextGranularity)granularity inDirection:(UITextDirection)direction
8153{
8154 if (granularity == UITextGranularityParagraph) {
8155 Ref page = *_page;
8156 if (!page->editorState().postLayoutData)
8157 return NO__objc_no;
8158
8159 if (direction == UITextStorageDirectionBackward && [position isEqual:self.selectedTextRange.start])
8160 return page->editorState().postLayoutData->selectionStartIsAtParagraphBoundary;
8161
8162 if (direction == UITextStorageDirectionForward && [position isEqual:self.selectedTextRange.end])
8163 return page->editorState().postLayoutData->selectionEndIsAtParagraphBoundary;
8164 }
8165
8166 return NO__objc_no;
8167}
8168
8169- (UITextPosition *)positionFromPosition:(UITextPosition *)position toBoundary:(UITextGranularity)granularity inDirection:(UITextDirection)direction
8170{
8171 return nilnullptr;
8172}
8173
8174- (BOOL)isPosition:(UITextPosition *)position withinTextUnit:(UITextGranularity)granularity inDirection:(UITextDirection)direction
8175{
8176 return NO__objc_no;
8177}
8178
8179- (UITextRange *)rangeEnclosingPosition:(UITextPosition *)position withGranularity:(UITextGranularity)granularity inDirection:(UITextDirection)direction
8180{
8181 return nilnullptr;
8182}
8183
8184- (void)takeTraitsFrom:(UITextInputTraits *)traits
8185{
8186 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG221"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(8186, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
8187
8188 [[self textInputTraits] takeTraitsFrom:traits];
8189}
8190
8191- (void)_showKeyboard
8192{
8193 [self setUpTextSelectionAssistant];
8194
8195 if (self.isFirstResponder && !_suppressSelectionAssistantReasons)
8196 [_textInteractionWrapper activateSelection];
8197
8198 [self reloadInputViews];
8199}
8200
8201- (void)_hideKeyboard:(BOOL)editableChanged
8202{
8203 SetForScope isHidingKeyboardScope { _isHidingKeyboard, YES__objc_yes };
8204
8205 if (editableChanged) {
8206 _keyboardDismissedInCurrentPresentationUpdate = YES__objc_yes;
8207 protect(_page)->callAfterNextPresentationUpdate([weakSelf = WeakObjCPtr<WKContentView>(self)] {
8208 if (RetainPtr strongSelf = weakSelf.get())
8209 strongSelf->_keyboardDismissedInCurrentPresentationUpdate = NO__objc_no;
8210 });
8211 }
8212
8213 self.inputDelegate = nilnullptr;
8214 [self setUpTextSelectionAssistant];
8215
8216 [_textInteractionWrapper deactivateSelection];
8217 [protect(_formAccessoryView) hideAutoFillButton];
8218
8219 // FIXME: Does it make sense to call -reloadInputViews on watchOS?
8220 [self reloadInputViews];
8221 if (_formAccessoryView)
8222 [self _updateAccessory];
8223}
8224
8225- (BOOL)_formControlRefreshEnabled
8226{
8227 if (!_page)
8228 return NO__objc_no;
8229
8230 return YES__objc_yes;
8231}
8232
8233- (const WebKit::FocusedElementInformation&)focusedElementInformation
8234{
8235 return _focusedElementInformation;
8236}
8237
8238- (Vector<WebKit::OptionItem>&)focusedSelectElementOptions
8239{
8240 return _focusedElementInformation.selectOptions;
8241}
8242
8243// Note that selectability is also affected by the CSS property user-select.
8244static bool mayContainSelectableText(WebKit::InputType type)
8245{
8246 switch (type) {
8247 case WebKit::InputType::None:
8248 // The following types have custom UI and do not look or behave like a text field.
8249 case WebKit::InputType::Color:
8250 case WebKit::InputType::Date:
8251 case WebKit::InputType::DateTimeLocal:
8252 case WebKit::InputType::Drawing:
8253 case WebKit::InputType::Month:
8254 case WebKit::InputType::Select:
8255 case WebKit::InputType::Time:
8256#if ENABLE(INPUT_TYPE_WEEK_PICKER)(defined 1 && 1)
8257 case WebKit::InputType::Week:
8258#endif
8259 return false;
8260 // The following types look and behave like a text field.
8261 case WebKit::InputType::ContentEditable:
8262 case WebKit::InputType::Email:
8263 case WebKit::InputType::Number:
8264 case WebKit::InputType::NumberPad:
8265 case WebKit::InputType::Password:
8266 case WebKit::InputType::Phone:
8267 case WebKit::InputType::Search:
8268 case WebKit::InputType::Text:
8269 case WebKit::InputType::TextArea:
8270 case WebKit::InputType::URL:
8271#if !ENABLE(INPUT_TYPE_WEEK_PICKER)(defined 1 && 1)
8272 case WebKit::InputType::Week:
8273#endif
8274 return true;
8275 }
8276}
8277
8278- (BOOL)_shouldShowKeyboardForElement:(const WebKit::FocusedElementInformation&)information
8279{
8280 if (information.inputMode == WebCore::InputMode::None)
8281 return NO__objc_no;
8282
8283 return [self _shouldShowKeyboardForElementIgnoringInputMode:information];
8284}
8285
8286- (BOOL)_shouldShowKeyboardForElementIgnoringInputMode:(const WebKit::FocusedElementInformation&)information
8287{
8288 return mayContainSelectableText(information.elementType) || [self _elementTypeRequiresAccessoryView:information.elementType];
8289}
8290
8291static RetainPtr<NSObject <WKFormPeripheral>> createInputPeripheralWithView(WebKit::InputType type, WKContentView *view)
8292{
8293#if PLATFORM(WATCHOS)(defined WTF_PLATFORM_WATCHOS && WTF_PLATFORM_WATCHOS
)
8294 UNUSED_PARAM(type)(void)type;
8295 UNUSED_PARAM(view)(void)view;
8296 return nilnullptr;
8297#else
8298 switch (type) {
8299 case WebKit::InputType::Select:
8300 // Don't create native iOS picker for appearance: base selects
8301 if (view.focusedElementInformation.usesBaseAppearancePicker)
8302 return nilnullptr;
8303
8304 return adoptNS([[WKFormSelectControl alloc] initWithView:view]);
8305 case WebKit::InputType::Color:
8306#if PLATFORM(APPLETV)(defined WTF_PLATFORM_APPLETV && WTF_PLATFORM_APPLETV
)
8307 return nilnullptr;
8308#else
8309 return adoptNS([[WKFormColorControl alloc] initWithView:view]);
8310#endif
8311 case WebKit::InputType::Date:
8312 case WebKit::InputType::DateTimeLocal:
8313 case WebKit::InputType::Month:
8314 case WebKit::InputType::Time:
8315#if ENABLE(INPUT_TYPE_WEEK_PICKER)(defined 1 && 1)
8316 case WebKit::InputType::Week:
8317#endif
8318 return adoptNS([[WKDateTimeInputControl alloc] initWithView:view]);
8319 default:
8320 return nilnullptr;
8321 }
8322#endif
8323}
8324
8325- (void)startDeferringInputViewUpdates:(WebKit::InputViewUpdateDeferralSources)sources
8326{
8327 ASSERT(!sources.isEmpty())((void)0);
8328 if (_inputViewUpdateDeferralSources.isEmpty()) {
8329 RELEASE_LOG(TextInput, "Started deferring input view updates (%02x)", sources.toRaw())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInput
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Started deferring input view updates (%02x)"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG222"
) = "Started deferring input view updates (%02x)"; uint8_t _Alignas
(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Started deferring input view updates (%02x)", sources.toRaw
())]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str
, (uint8_t *)__builtin_os_log_format(_os_fmt_buf, "Started deferring input view updates (%02x)"
, sources.toRaw()), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop
;
8330 [self _beginPinningInputViews];
8331 }
8332
8333 _inputViewUpdateDeferralSources.add(sources);
8334}
8335
8336- (void)stopDeferringInputViewUpdates:(WebKit::InputViewUpdateDeferralSources)sources
8337{
8338 ASSERT(!sources.isEmpty())((void)0);
8339 if (!_inputViewUpdateDeferralSources.containsAny(sources))
8340 return;
8341
8342 _inputViewUpdateDeferralSources.remove(sources);
8343
8344 if (_inputViewUpdateDeferralSources.isEmpty()) {
8345 [self _cancelPreviousResetInputViewDeferralRequest];
8346 RELEASE_LOG(TextInput, "Stopped deferring input view updates (%02x)", sources.toRaw())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInput
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Stopped deferring input view updates (%02x)"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG223"
) = "Stopped deferring input view updates (%02x)"; uint8_t _Alignas
(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Stopped deferring input view updates (%02x)", sources.toRaw
())]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str
, (uint8_t *)__builtin_os_log_format(_os_fmt_buf, "Stopped deferring input view updates (%02x)"
, sources.toRaw()), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop
;
8347 [self _endPinningInputViews];
8348 }
8349}
8350
8351- (void)stopDeferringInputViewUpdatesForAllSources
8352{
8353 if (_inputViewUpdateDeferralSources.isEmpty())
8354 return;
8355
8356 RELEASE_LOG(TextInput, "Stopped deferring all input view updates (%02x)", _inputViewUpdateDeferralSources.toRaw())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInput
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Stopped deferring all input view updates (%02x)"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG224"
) = "Stopped deferring all input view updates (%02x)"; uint8_t
_Alignas(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Stopped deferring all input view updates (%02x)", _inputViewUpdateDeferralSources
.toRaw())]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "Stopped deferring all input view updates (%02x)", _inputViewUpdateDeferralSources
.toRaw()), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop
; }); } }) clang diagnostic pop
;
8357 [self _cancelPreviousResetInputViewDeferralRequest];
8358 _inputViewUpdateDeferralSources = { };
8359 [self _endPinningInputViews];
8360}
8361
8362- (void)_elementDidFocus:(const WebKit::FocusedElementInformation&)information userIsInteracting:(BOOL)userIsInteracting blurPreviousNode:(BOOL)blurPreviousNode activityStateChanges:(OptionSet<WebCore::ActivityState>)activityStateChanges userObject:(NSObject <NSSecureCoding> *)userObject
8363{
8364 CompletionHandlerCallingScope restoreValues([
8365 weakSelf = WeakObjCPtr { self },
8366 changingFocusValueToRestore = _isChangingFocus,
8367 focusingElementWithKeyboardValueToRestore = _isFocusingElementWithKeyboard
8368 ] {
8369 RetainPtr strongSelf = weakSelf.get();
8370 if (!strongSelf)
8371 return;
8372 strongSelf->_isChangingFocus = changingFocusValueToRestore;
8373 strongSelf->_isFocusingElementWithKeyboard = focusingElementWithKeyboardValueToRestore;
8374
8375 if (auto callback = std::exchange(strongSelf->_pendingRunModalJavaScriptDialogCallback, { }))
8376 callback();
8377
8378 constexpr OptionSet sourcesToStopDeferring {
8379 WebKit::InputViewUpdateDeferralSource::ChangingFocusedElement,
8380 WebKit::InputViewUpdateDeferralSource::BecomeFirstResponder
8381 };
8382 [strongSelf stopDeferringInputViewUpdates:sourcesToStopDeferring];
8383 });
8384
8385 _isChangingFocus = self._hasFocusedElement;
8386 _isFocusingElementWithKeyboard = [self _shouldShowKeyboardForElement:information];
8387
8388 _autocorrectionContextNeedsUpdate = YES__objc_yes;
8389 _didAccessoryTabInitiateFocus = _isChangingFocusUsingAccessoryTab;
8390
8391 Ref page = *_page;
8392 RetainPtr inputDelegate = [_webView.get() _inputDelegate];
8393 RetainPtr<WKFocusedElementInfo> focusedElementInfo = adoptNS([[WKFocusedElementInfo alloc] initWithFocusedElementInformation:information isUserInitiated:userIsInteracting webView:_webView.get().get() userObject:userObject]);
8394
8395 _WKFocusStartsInputSessionPolicy startInputSessionPolicy = _WKFocusStartsInputSessionPolicyAuto;
8396
8397 if ([inputDelegate respondsToSelector:@selector(_webView:focusShouldStartInputSession:)]) {
8398 if ([inputDelegate _webView:self.webView focusShouldStartInputSession:focusedElementInfo.get()])
8399 startInputSessionPolicy = _WKFocusStartsInputSessionPolicyAllow;
8400 else
8401 startInputSessionPolicy = _WKFocusStartsInputSessionPolicyDisallow;
8402 }
8403
8404 if ([inputDelegate respondsToSelector:@selector(_webView:decidePolicyForFocusedElement:)])
8405 startInputSessionPolicy = [inputDelegate _webView:self.webView decidePolicyForFocusedElement:focusedElementInfo.get()];
8406
8407 BOOL shouldShowInputView = [&] {
8408 switch (startInputSessionPolicy) {
8409 case _WKFocusStartsInputSessionPolicyAuto:
8410 // The default behavior is to allow node assistance if the user is interacting.
8411 // We also allow node assistance if the keyboard already is showing, unless we're in extra zoom mode.
8412 if (userIsInteracting)
8413 return YES__objc_yes;
8414
8415 if (_keyboardDismissedInCurrentPresentationUpdate && !_editingEndedByUser)
8416 return YES__objc_yes;
8417
8418 if (self.isFirstResponder || _becomingFirstResponder) {
8419 // When the software keyboard is being used to enter an url, only the focus activity state is changing.
8420 // In this case, auto focus on the page being navigated to should be disabled, unless a hardware
8421 // keyboard is attached.
8422 if (activityStateChanges && activityStateChanges != WebCore::ActivityState::IsFocused)
8423 return YES__objc_yes;
8424
8425#if HAVE(PEPPER_UI_CORE)(defined HAVE_PEPPER_UI_CORE && HAVE_PEPPER_UI_CORE)
8426 if (_isChangingFocus && ![protect(_focusedFormControlView) isHidden])
8427 return YES__objc_yes;
8428#else
8429 if (_isChangingFocus)
8430 return YES__objc_yes;
8431
8432 if ([self _shouldShowKeyboardForElementIgnoringInputMode:information] && UIKeyboard.isInHardwareKeyboardMode)
8433 return YES__objc_yes;
8434#endif
8435 }
8436 return NO__objc_no;
8437 case _WKFocusStartsInputSessionPolicyAllow:
8438 return YES__objc_yes;
8439 case _WKFocusStartsInputSessionPolicyDisallow:
8440 return NO__objc_no;
8441 default:
8442 ASSERT_NOT_REACHED()((void)0);
8443 return NO__objc_no;
8444 }
8445 }();
8446
8447 // Do not present input peripherals if a validation message is being displayed.
8448 if (information.isFocusingWithValidationMessage && !_isFocusingElementWithKeyboard)
8449 shouldShowInputView = NO__objc_no;
8450
8451 if (blurPreviousNode) {
8452 // Defer view updates until the end of this function to avoid a noticeable flash when switching focus
8453 // between elements that require the keyboard.
8454 [self startDeferringInputViewUpdates:WebKit::InputViewUpdateDeferralSource::ChangingFocusedElement];
8455 [self _elementDidBlur];
8456 }
8457
8458 if (shouldShowInputView)
8459 _editingEndedByUser = NO__objc_no;
8460
8461 if (!shouldShowInputView || information.elementType == WebKit::InputType::None) {
8462 page->setIsShowingInputViewForFocusedElement(false);
8463 return;
8464 }
8465
8466 page->setIsShowingInputViewForFocusedElement(true);
8467
8468 // FIXME: We should remove this check when we manage to send ElementDidFocus from the WebProcess
8469 // only when it is truly time to show the keyboard.
8470 if ([self _isSameAsFocusedElement:information.elementContext]) {
8471 if (_inputPeripheral) {
8472 if (!self.isFirstResponder)
8473 [self becomeFirstResponder];
8474 [self accessoryOpen];
8475 }
8476 return;
8477 }
8478
8479 [_webView.get() _resetFocusPreservationCountAndReleaseActiveFocusState];
8480
8481 _focusRequiresStrongPasswordAssistance = NO__objc_no;
8482 _additionalContextForStrongPasswordAssistance = nilnullptr;
8483
8484 _pendingFocusedElementIdentifier = information.identifier;
8485
8486 if (mayContainSelectableText(information.elementType))
8487 _page->setWaitingForPostLayoutEditorStateUpdateAfterFocusingElement(true);
8488
8489 if ([inputDelegate respondsToSelector:@selector(_webView:focusRequiresStrongPasswordAssistance:)]) {
8490 [self _continueElementDidFocus:information
8491 requiresStrongPasswordAssistance:[inputDelegate _webView:self.webView focusRequiresStrongPasswordAssistance:focusedElementInfo.get()]
8492 focusedElementInfo:focusedElementInfo
8493 activityStateChanges:activityStateChanges
8494 restoreValues:WTF::move(restoreValues)];
8495 } else if ([inputDelegate respondsToSelector:@selector(_webView:focusRequiresStrongPasswordAssistance:completionHandler:)]) {
8496 auto checker = WebKit::CompletionHandlerCallChecker::create(inputDelegate, @selector(_webView:focusRequiresStrongPasswordAssistance:completionHandler:));
8497 [inputDelegate _webView:self.webView focusRequiresStrongPasswordAssistance:focusedElementInfo.get() completionHandler:makeBlockPtr([
8498 weakSelf = RetainPtr { self },
8499 checker = WTF::move(checker),
8500 information,
8501 focusedElementInfo,
8502 activityStateChanges,
8503 restoreValues = WTF::move(restoreValues)
8504 ] (BOOL result) mutable {
8505 if (checker->completionHandlerHasBeenCalled())
8506 return;
8507 checker->didCallCompletionHandler();
8508 RetainPtr strongSelf = weakSelf.get();
8509 if (!strongSelf)
8510 return;
8511 [strongSelf _continueElementDidFocus:information
8512 requiresStrongPasswordAssistance:result
8513 focusedElementInfo:focusedElementInfo
8514 activityStateChanges:activityStateChanges
8515 restoreValues:WTF::move(restoreValues)];
8516 }).get()];
8517 } else {
8518 [self _continueElementDidFocus:information
8519 requiresStrongPasswordAssistance:NO__objc_no
8520 focusedElementInfo:focusedElementInfo
8521 activityStateChanges:activityStateChanges
8522 restoreValues:WTF::move(restoreValues)];
8523 }
8524}
8525
8526- (void)_continueElementDidFocus:(const WebKit::FocusedElementInformation&)information requiresStrongPasswordAssistance:(BOOL)requiresStrongPasswordAssistance focusedElementInfo:(RetainPtr<WKFocusedElementInfo>)focusedElementInfo activityStateChanges:(OptionSet<WebCore::ActivityState>)activityStateChanges restoreValues:(CompletionHandlerCallingScope&&)restoreValues
8527{
8528 if (_pendingFocusedElementIdentifier != information.identifier)
8529 return;
8530
8531 _focusRequiresStrongPasswordAssistance = requiresStrongPasswordAssistance;
8532
8533 RetainPtr inputDelegate = [_webView.get() _inputDelegate];
8534
8535 if ([inputDelegate respondsToSelector:@selector(_webViewAdditionalContextForStrongPasswordAssistance:)])
8536 _additionalContextForStrongPasswordAssistance = [inputDelegate _webViewAdditionalContextForStrongPasswordAssistance:self.webView];
8537 else
8538 _additionalContextForStrongPasswordAssistance = @{ };
8539
8540 bool delegateImplementsWillStartInputSession = [inputDelegate respondsToSelector:@selector(_webView:willStartInputSession:)];
8541 bool delegateImplementsDidStartInputSession = [inputDelegate respondsToSelector:@selector(_webView:didStartInputSession:)];
8542
8543 if (delegateImplementsWillStartInputSession || delegateImplementsDidStartInputSession) {
8544 [_formInputSession invalidate];
8545 _formInputSession = adoptNS([[WKFormInputSession alloc] initWithContentView:self focusedElementInfo:focusedElementInfo.get() requiresStrongPasswordAssistance:_focusRequiresStrongPasswordAssistance]);
8546 }
8547
8548 if (delegateImplementsWillStartInputSession)
8549 [inputDelegate _webView:self.webView willStartInputSession:_formInputSession.get()];
8550
8551 BOOL requiresKeyboard = mayContainSelectableText(information.elementType);
8552 BOOL editableChanged = [self setIsEditable:requiresKeyboard];
8553 _focusedElementInformation = information;
8554 _legacyTextInputTraits = nilnullptr;
8555 _extendedTextInputTraits = nilnullptr;
8556
8557 Ref page = *_page;
8558
8559 OptionSet<WebKit::RevealFocusedElementDeferralReason> revealFocusedElementDeferralReasons;
8560 // For elements that have selectable content (e.g. text field) we need to wait for the web process to send an up-to-date
8561 // selection rect before we can zoom and reveal the selection. Non-selectable elements (e.g. <select>) can be zoomed
8562 // immediately because they have no selection to reveal.
8563 // We create RevealFocusedElementDeferrer before callin becomeFirstResponder as the latter can result in _keyboardWillShow.
8564 if (requiresKeyboard) {
8565 bool ignorePreviousKeyboardWillShowNotification = [] {
8566 // In the case where out-of-process keyboard is enabled and the software keyboard is shown,
8567 // we end up getting two sets of "KeyboardWillShow" -> "KeyboardDidShow" notifications when
8568 // the keyboard animates up, after reloading input views. When the first set of notifications
8569 // is dispatched underneath the call to -reloadInputViews above, the keyboard hasn't yet
8570 // become full height, so attempts to reveal the focused element using the current height will
8571 // fail. The second set of keyboard notifications contains the final keyboard height, and is the
8572 // one we should use for revealing the focused element.
8573 // See also: <rdar://111704216>.
8574 if (!UIKeyboard.usesInputSystemUI)
8575 return false;
8576
8577 auto keyboard = UIKeyboard.activeKeyboard;
8578 return keyboard && !keyboard.isMinimized;
8579 }();
8580
8581 if (page->waitingForPostLayoutEditorStateUpdateAfterFocusingElement())
8582 revealFocusedElementDeferralReasons.add(WebKit::RevealFocusedElementDeferralReason::EditorState);
8583
8584 if (!self._scroller.firstResponderKeyboardAvoidanceEnabled)
8585 revealFocusedElementDeferralReasons.add(WebKit::RevealFocusedElementDeferralReason::KeyboardDidShow);
8586 else if (_waitingForKeyboardAppearanceAnimationToStart || ignorePreviousKeyboardWillShowNotification)
8587 revealFocusedElementDeferralReasons.add(WebKit::RevealFocusedElementDeferralReason::KeyboardWillShow);
8588
8589 if (!revealFocusedElementDeferralReasons.isEmpty())
8590 _revealFocusedElementDeferrer = WebKit::RevealFocusedElementDeferrer::create(self, revealFocusedElementDeferralReasons);
8591 }
8592
8593 if (![self isFirstResponder])
8594 [self becomeFirstResponder];
8595
8596#if ENABLE(CONTENT_INSET_BACKGROUND_FILL)(defined 1 && 1)
8597 if (_focusedElementInformation.shouldHideSoftTopScrollEdgeEffect && ![[_webView.get() _wkScrollView] _usesHardTopScrollEdgeEffect])
8598 [_webView.get() _addReasonToHideTopScrollPocket:WebKit::HideScrollPocketReason::SiteSpecificQuirk];
8599 else
8600 [_webView.get() _removeReasonToHideTopScrollPocket:WebKit::HideScrollPocketReason::SiteSpecificQuirk];
8601#endif
8602
8603 if (!_suppressSelectionAssistantReasons && requiresKeyboard && activityStateChanges.contains(WebCore::ActivityState::IsFocused)) {
8604 _treatAsContentEditableUntilNextEditorStateUpdate = YES__objc_yes;
8605 [_textInteractionWrapper activateSelection];
8606 page->restoreSelectionInFocusedEditableElement();
8607 page->scheduleFullEditorStateUpdate();
8608 }
8609
8610 _inputPeripheral = createInputPeripheralWithView(_focusedElementInformation.elementType, self);
8611 _waitingForKeyboardAppearanceAnimationToStart = requiresKeyboard && !_isChangingFocus;
8612
8613#if HAVE(PEPPER_UI_CORE)(defined HAVE_PEPPER_UI_CORE && HAVE_PEPPER_UI_CORE)
8614 [self addFocusedFormControlOverlay];
8615 if (!_isChangingFocus)
8616 [self presentViewControllerForCurrentFocusedElement];
8617#else
8618 if (requiresKeyboard) {
8619 [self _showKeyboard];
8620 if (!self.window.keyWindow)
8621 [self.window makeKeyWindow];
8622 } else
8623 [self reloadInputViews];
8624#endif
8625
8626 if (!UIKeyboard.activeKeyboard) {
8627 // The lack of keyboard here suggests that we're not running in a context where the keyboard can become visible
8628 // (e.g. when running API tests outside of the context of a UI application). In this scenario, don't bother waiting
8629 // for keyboard appearance notifications.
8630 _waitingForKeyboardAppearanceAnimationToStart = NO__objc_no;
8631 }
8632
8633 // The custom fixed position rect behavior is affected by -isFocusingElement, so if that changes we need to recompute rects.
8634 if (editableChanged)
8635 [_webView.get() _scheduleVisibleContentRectUpdate];
8636
8637 if (!requiresKeyboard || revealFocusedElementDeferralReasons.isEmpty())
8638 [self _zoomToRevealFocusedElement];
8639
8640 [self _updateAccessory];
8641
8642#if HAVE(PEPPER_UI_CORE)(defined HAVE_PEPPER_UI_CORE && HAVE_PEPPER_UI_CORE)
8643 if (_isChangingFocus)
8644 [protect(_focusedFormControlView) reloadData:YES__objc_yes];
8645#endif
8646
8647 // _inputPeripheral has been initialized in inputView called by reloadInputViews.
8648 [_inputPeripheral beginEditing];
8649
8650 if (delegateImplementsDidStartInputSession)
8651 [inputDelegate _webView:self.webView didStartInputSession:_formInputSession.get()];
8652
8653 [_webView.get() didStartFormControlInteraction];
8654}
8655
8656- (void)_elementDidBlur
8657{
8658 SetForScope isBlurringFocusedElementForScope { _isBlurringFocusedElement, YES__objc_yes };
8659
8660 [_webView.get() _resetFocusPreservationCountAndReleaseActiveFocusState];
8661
8662 [self _endEditing];
8663
8664#if ENABLE(CONTENT_INSET_BACKGROUND_FILL)(defined 1 && 1)
8665 if (!_isChangingFocus)
8666 [_webView.get() _removeReasonToHideTopScrollPocket:WebKit::HideScrollPocketReason::SiteSpecificQuirk];
8667#endif
8668
8669 [_formInputSession invalidate];
8670 _formInputSession = nilnullptr;
8671
8672 _dataListTextSuggestionsInputView = nilnullptr;
8673 _dataListTextSuggestions = nilnullptr;
8674
8675 _pendingFocusedElementIdentifier = { };
8676
8677 BOOL editableChanged = [self setIsEditable:NO__objc_no];
8678 // FIXME: We should completely invalidate _focusedElementInformation here, instead of a subset of individual members.
8679 _focusedElementInformation.elementType = WebKit::InputType::None;
8680 _focusedElementInformation.shouldSynthesizeKeyEventsForEditing = false;
8681 _focusedElementInformation.shouldAvoidResizingWhenInputViewBoundsChange = false;
8682 _focusedElementInformation.shouldAvoidScrollingWhenFocusedContentIsVisible = false;
8683 _focusedElementInformation.shouldHideSoftTopScrollEdgeEffect = false;
8684 _focusedElementInformation.shouldUseLegacySelectPopoverDismissalBehaviorInDataActivation = false;
8685 _focusedElementInformation.isFocusingWithValidationMessage = false;
8686 _focusedElementInformation.preventScroll = false;
8687 _inputPeripheral = nilnullptr;
8688 _focusRequiresStrongPasswordAssistance = NO__objc_no;
8689 _autocorrectionContextNeedsUpdate = YES__objc_yes;
8690 _additionalContextForStrongPasswordAssistance = nilnullptr;
8691 _waitingForKeyboardAppearanceAnimationToStart = NO__objc_no;
8692 _revealFocusedElementDeferrer = nullptr;
8693
8694 // When defocusing an editable element reset a seen keydown before calling -_hideKeyboard so that we
8695 // re-evaluate whether we still need a keyboard when UIKit calls us back in -_requiresKeyboardWhenFirstResponder.
8696 if (editableChanged)
8697 _seenHardwareKeyDownInNonEditableElement = NO__objc_no;
8698
8699 [self _hideKeyboard:editableChanged];
8700
8701#if HAVE(PEPPER_UI_CORE)(defined HAVE_PEPPER_UI_CORE && HAVE_PEPPER_UI_CORE)
8702 [self dismissAllInputViewControllers:YES__objc_yes];
8703 if (!_isChangingFocus)
8704 [self removeFocusedFormControlOverlay];
8705#endif
8706
8707 if (editableChanged) {
8708 // The custom fixed position rect behavior is affected by -isFocusingElement, so if that changes we need to recompute rects.
8709 [_webView.get() _scheduleVisibleContentRectUpdate];
8710
8711 [_webView.get() didEndFormControlInteraction];
8712 protect(_page)->setIsShowingInputViewForFocusedElement(false);
8713 }
8714
8715 _page->setWaitingForPostLayoutEditorStateUpdateAfterFocusingElement(false);
8716
8717 if (!_isChangingFocus)
8718 _didAccessoryTabInitiateFocus = NO__objc_no;
8719
8720 _lastInsertedCharacterToOverrideCharacterBeforeSelection = std::nullopt;
8721}
8722
8723- (void)_updateInputContextAfterBlurringAndRefocusingElement
8724{
8725 if (!self._hasFocusedElement || !_suppressSelectionAssistantReasons)
8726 return;
8727
8728 [self _internalInvalidateTextEntryContext];
8729}
8730
8731- (void)_didProgrammaticallyClearFocusedElement:(WebCore::ElementContext&&)context
8732{
8733 if (![self _isSameAsFocusedElement:context])
8734 return;
8735
8736 [self _internalInvalidateTextEntryContext];
8737}
8738
8739- (void)_internalInvalidateTextEntryContext
8740{
8741#if USE(BROWSERENGINEKIT)(defined 1 && 1)
8742 if (self.shouldUseAsyncInteractions) {
8743 [protect(_asyncInputDelegate) invalidateTextEntryContextForTextInput:self.asBETextInput];
8744 return;
8745 }
8746#endif
8747
8748 [UIKeyboardImpl.activeInstance updateForChangedSelection];
8749}
8750
8751- (void)_updateFocusedElementInformation:(const WebKit::FocusedElementInformation&)information
8752{
8753 if (![self _isSameAsFocusedElement:information.elementContext])
8754 return;
8755
8756 _focusedElementInformation = information;
8757 [_inputPeripheral updateEditing];
8758}
8759
8760- (BOOL)shouldIgnoreKeyboardWillHideNotification
8761{
8762 // Ignore keyboard will hide notifications sent during rotation. They're just there for
8763 // backwards compatibility reasons and processing the will hide notification would
8764 // temporarily screw up the unobscured view area.
8765 if (UIPeripheralHost.sharedInstance.rotationState)
8766 return YES__objc_yes;
8767
8768 if (_isChangingFocus && _isFocusingElementWithKeyboard)
8769 return YES__objc_yes;
8770
8771 return NO__objc_no;
8772}
8773
8774- (void)_hardwareKeyboardAvailabilityChanged
8775{
8776 _seenHardwareKeyDownInNonEditableElement = NO__objc_no;
8777 [self reloadInputViews];
8778}
8779
8780- (void)_didUpdateInputMode:(WebCore::InputMode)mode
8781{
8782 if (!self.inputDelegate || !self._hasFocusedElement)
8783 return;
8784
8785#if !PLATFORM(WATCHOS)(defined WTF_PLATFORM_WATCHOS && WTF_PLATFORM_WATCHOS
)
8786 _focusedElementInformation.inputMode = mode;
8787 [self reloadInputViews];
8788#endif
8789}
8790
8791static BOOL allPasteboardItemOriginsMatchOrigin(UIPasteboard *pasteboard, const String& originIdentifier)
8792{
8793 if (originIdentifier.isEmpty())
8794 return NO__objc_no;
8795
8796 RetainPtr indices = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [pasteboard numberOfItems])];
8797 RetainPtr allCustomData = [pasteboard dataForPasteboardType:@(WebCore::PasteboardCustomData::cocoaType().characters()) inItemSet:indices.get()];
8798 if (!allCustomData.get().count)
8799 return NO__objc_no;
8800
8801 BOOL foundAtLeastOneMatchingIdentifier = NO__objc_no;
8802 for (NSData *data in allCustomData.get()) {
8803 if (!data.length)
8804 continue;
8805
8806 auto buffer = WebCore::SharedBuffer::create(data);
8807 if (WebCore::PasteboardCustomData::fromSharedBuffer(buffer.get()).origin() != originIdentifier)
8808 return NO__objc_no;
8809
8810 foundAtLeastOneMatchingIdentifier = YES__objc_yes;
8811 }
8812
8813 return foundAtLeastOneMatchingIdentifier;
8814}
8815
8816- (void)_requestDOMPasteAccessForCategory:(WebCore::DOMPasteAccessCategory)pasteAccessCategory requiresInteraction:(WebCore::DOMPasteRequiresInteraction)requiresInteraction elementRect:(const WebCore::IntRect&)elementRect originIdentifier:(const String&)originIdentifier completionHandler:(CompletionHandler<void(WebCore::DOMPasteAccessResponse)>&&)completionHandler
8817{
8818 if (auto existingCompletionHandler = std::exchange(_domPasteRequestHandler, WTF::move(completionHandler))) {
8819 ASSERT_NOT_REACHED()((void)0);
8820 existingCompletionHandler(WebCore::DOMPasteAccessResponse::DeniedForGesture);
8821 }
8822
8823 _domPasteRequestCategory = pasteAccessCategory;
8824
8825 if (requiresInteraction == WebCore::DOMPasteRequiresInteraction::No && allPasteboardItemOriginsMatchOrigin(protect(pasteboardForAccessCategory(pasteAccessCategory)), originIdentifier)) {
8826 [self _handleDOMPasteRequestWithResult:WebCore::DOMPasteAccessResponse::GrantedForCommand];
8827 return;
8828 }
8829
8830 WebCore::IntRect menuControllerRect = elementRect;
8831
8832 const CGFloat maximumElementWidth = 300;
8833 const CGFloat maximumElementHeight = 120;
8834 if (elementRect.isEmpty() || elementRect.width() > maximumElementWidth || elementRect.height() > maximumElementHeight) {
8835 const CGFloat interactionLocationMargin = 10;
8836 menuControllerRect = { WebCore::IntPoint(_lastInteractionLocation), { } };
8837 menuControllerRect.inflate(interactionLocationMargin);
8838 }
8839ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
8840 [UIMenuController.sharedMenuController showMenuFromView:self rect:menuControllerRect];
8841ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
8842}
8843
8844- (void)doAfterEditorStateUpdateAfterFocusingElement:(dispatch_block_t)block
8845{
8846 if (!_page->waitingForPostLayoutEditorStateUpdateAfterFocusingElement()) {
8847 block();
8848 return;
8849 }
8850
8851 _actionsToPerformAfterEditorStateUpdate.append(makeBlockPtr(block));
8852}
8853
8854- (void)_reconcileEnclosingScrollViewContentOffset:(WebKit::EditorState&)state
8855{
8856 if (!state.hasVisualData())
8857 return;
8858
8859 auto scrollingNodeID = state.visualData->enclosingScrollingNodeID;
8860 RetainPtr scroller = [self _scrollViewForScrollingNodeID:scrollingNodeID];
8861 if (!scroller)
8862 return;
8863
8864 if ([_webView.get() _isInStableState:scroller.get()])
8865 return;
8866
8867 auto possiblyStaleScrollOffset = state.visualData->enclosingScrollOffset;
8868 auto scrollDelta = possiblyStaleScrollOffset - WebCore::roundedIntPoint([scroller contentOffset]);
8869
8870 static constexpr auto adjustmentThreshold = 1;
8871 if (std::abs(scrollDelta.width()) <= adjustmentThreshold && std::abs(scrollDelta.height()) <= adjustmentThreshold)
8872 return;
8873
8874 CGSize contentDelta = [scroller convertRect:CGRectMake(0, 0, scrollDelta.width(), scrollDelta.height()) toView:self].size;
8875 state.move(std::copysign(contentDelta.width, scrollDelta.width()), std::copysign(contentDelta.height, scrollDelta.height()));
8876}
8877
8878- (void)_didUpdateEditorState
8879{
8880 [self _updateInitialWritingDirectionIfNecessary];
8881
8882 // FIXME: If the initial writing direction just changed, we should wait until we get the next post-layout editor state
8883 // before zooming to reveal the selection rect.
8884 if (_revealFocusedElementDeferrer)
8885 protect(_revealFocusedElementDeferrer)->fulfill(WebKit::RevealFocusedElementDeferralReason::EditorState);
8886
8887 _treatAsContentEditableUntilNextEditorStateUpdate = NO__objc_no;
8888
8889 for (auto block : std::exchange(_actionsToPerformAfterEditorStateUpdate, { }))
8890 block();
8891}
8892
8893- (void)_updateInitialWritingDirectionIfNecessary
8894{
8895 if (!_page->isEditable())
8896 return;
8897
8898 auto& editorState = protect(_page)->editorState();
8899 if (editorState.selectionType != WebCore::SelectionType::Caret)
8900 return;
8901
8902 UIKeyboardImpl *keyboard = UIKeyboardImpl.activeInstance;
8903 if (keyboard.delegate != self)
8904 return;
8905
8906 // Synchronize the keyboard's writing direction with the newly received EditorState.
8907 [keyboard setInitialDirection];
8908}
8909
8910- (void)updateCurrentFocusedElementInformation:(Function<void(bool didUpdate)>&&)callback
8911{
8912 WeakObjCPtr<WKContentView> weakSelf { self };
8913 auto identifierBeforeUpdate = _focusedElementInformation.identifier;
8914 protect(_page)->requestFocusedElementInformation([callback = WTF::move(callback), identifierBeforeUpdate, weakSelf] (auto& info) {
8915 if (!weakSelf || !info || info->identifier != identifierBeforeUpdate) {
8916 // If the focused element may have changed in the meantime, don't overwrite focused element information.
8917 callback(false);
8918 return;
8919 }
8920
8921 weakSelf.get()->_focusedElementInformation = info.value();
8922 callback(true);
8923 });
8924}
8925
8926- (void)reloadContextViewForPresentedListViewController
8927{
8928#if HAVE(PEPPER_UI_CORE)(defined HAVE_PEPPER_UI_CORE && HAVE_PEPPER_UI_CORE)
8929 if ([_presentedFullScreenInputViewController isKindOfClass:[WKTextInputListViewController class]])
8930 [(WKTextInputListViewController *)_presentedFullScreenInputViewController.get() reloadContextView];
8931#endif
8932}
8933
8934#if HAVE(PEPPER_UI_CORE)(defined HAVE_PEPPER_UI_CORE && HAVE_PEPPER_UI_CORE)
8935
8936- (void)addFocusedFormControlOverlay
8937{
8938 if (_focusedFormControlView)
8939 return;
8940
8941 _activeFocusedStateRetainBlock = makeBlockPtr(self.webView._retainActiveFocusedState);
8942
8943 _focusedFormControlView = adoptNS([[WKFocusedFormControlView alloc] initWithFrame:self.webView.bounds delegate:self]);
8944 [protect(_focusedFormControlView) hide:NO__objc_no];
8945 [_webView.get() addSubview:_focusedFormControlView.get()];
8946 [self setInputDelegate:static_cast<id<UITextInputDelegate>>(_focusedFormControlView.get())];
8947}
8948
8949- (void)removeFocusedFormControlOverlay
8950{
8951 if (!_focusedFormControlView)
8952 return;
8953
8954 if (auto releaseActiveFocusState = WTF::move(_activeFocusedStateRetainBlock))
8955 releaseActiveFocusState();
8956
8957 [protect(_focusedFormControlView) removeFromSuperview];
8958 _focusedFormControlView = nilnullptr;
8959 [self setInputDelegate:nilnullptr];
8960}
8961
8962- (RetainPtr<PUICTextInputContext>)createQuickboardTextInputContext
8963{
8964 auto context = adoptNS([[PUICTextInputContext alloc] init]);
8965 [self _updateTextInputTraits:context.get()];
8966 [context setInitialText:_focusedElementInformation.value.createNSString().get()];
8967#if HAVE(QUICKBOARD_CONTROLLER)(defined HAVE_QUICKBOARD_CONTROLLER && HAVE_QUICKBOARD_CONTROLLER
)
8968 [context setAcceptsEmoji:YES__objc_yes];
8969 [context setShouldPresentModernTextInputUI:YES__objc_yes];
8970 [context setPlaceholder:self.inputLabelText];
8971#endif
8972 return context;
8973}
8974
8975#if HAVE(QUICKBOARD_CONTROLLER)(defined HAVE_QUICKBOARD_CONTROLLER && HAVE_QUICKBOARD_CONTROLLER
)
8976
8977- (RetainPtr<PUICQuickboardController>)_createQuickboardController:(UIViewController *)presentingViewController
8978{
8979 auto quickboardController = adoptNS([[PUICQuickboardController alloc] init]);
8980 auto context = self.createQuickboardTextInputContext;
8981 [quickboardController setQuickboardPresentingViewController:presentingViewController];
8982 [quickboardController setExcludedFromScreenCapture:[context isSecureTextEntry]];
8983 [quickboardController setTextInputContext:context.get()];
8984 [quickboardController setDelegate:self];
8985
8986 return quickboardController;
8987}
8988
8989static bool canUseQuickboardControllerFor(UITextContentType type)
8990{
8991 return [type isEqualToString:UITextContentTypePassword];
8992}
8993
8994#endif // HAVE(QUICKBOARD_CONTROLLER)
8995
8996- (void)presentViewControllerForCurrentFocusedElement
8997{
8998 [self dismissAllInputViewControllers:NO__objc_no];
8999
9000 _shouldRestoreFirstResponderStatusAfterLosingFocus = self.isFirstResponder;
9001 auto presentingViewController = self._wk_viewControllerForFullScreenPresentation;
9002
9003 ASSERT(!_presentedFullScreenInputViewController)((void)0);
9004
9005 BOOL prefersModalPresentation = NO__objc_no;
9006
9007 switch (_focusedElementInformation.elementType) {
9008 case WebKit::InputType::Select:
9009 _presentedFullScreenInputViewController = adoptNS([[WKSelectMenuListViewController alloc] initWithDelegate:self]);
9010 break;
9011 case WebKit::InputType::Time:
9012 // Time inputs are special, in that the only UI affordances for dismissal are push buttons rather than status bar chevrons.
9013 // As such, modal presentation and dismissal is preferred even if a navigation stack exists.
9014 prefersModalPresentation = YES__objc_yes;
9015 _presentedFullScreenInputViewController = adoptNS([[WKTimePickerViewController alloc] initWithDelegate:self]);
9016 break;
9017 case WebKit::InputType::Date:
9018 _presentedFullScreenInputViewController = adoptNS([[WKDatePickerViewController alloc] initWithDelegate:self]);
9019 break;
9020 case WebKit::InputType::None:
9021 break;
9022 default: {
9023#if HAVE(QUICKBOARD_CONTROLLER)(defined HAVE_QUICKBOARD_CONTROLLER && HAVE_QUICKBOARD_CONTROLLER
)
9024 if (canUseQuickboardControllerFor(self.textContentTypeForQuickboard)) {
9025 _presentedQuickboardController = [self _createQuickboardController:presentingViewController];
9026 break;
9027 }
9028#endif
9029 _presentedFullScreenInputViewController = adoptNS([[WKTextInputListViewController alloc] initWithDelegate:self]);
9030 break;
9031 }
9032 }
9033
9034#if HAVE(QUICKBOARD_CONTROLLER)(defined HAVE_QUICKBOARD_CONTROLLER && HAVE_QUICKBOARD_CONTROLLER
)
9035 ASSERT_IMPLIES(_presentedQuickboardController, !_presentedFullScreenInputViewController)((void)0);
9036 ASSERT_IMPLIES(_presentedFullScreenInputViewController, !_presentedQuickboardController)((void)0);
9037#endif // HAVE(QUICKBOARD_CONTROLLER)
9038 ASSERT(self._isPresentingFullScreenInputView)((void)0);
9039 ASSERT(presentingViewController)((void)0);
9040
9041 if (!prefersModalPresentation && [presentingViewController isKindOfClass:[UINavigationController class]])
9042 _inputNavigationViewControllerForFullScreenInputs = (UINavigationController *)presentingViewController;
9043 else
9044 _inputNavigationViewControllerForFullScreenInputs = nilnullptr;
9045
9046 RetainPtr<UIViewController> controller;
9047 if (_presentedFullScreenInputViewController) {
9048 // Present the input view controller on an existing navigation stack, if possible. If there is no navigation stack we can use, fall back to presenting modally.
9049 // This is because the HI specification (for certain scenarios) calls for navigation-style view controller presentation, but WKWebView can't make any guarantees
9050 // about clients' view controller hierarchies, so we can only try our best to avoid presenting modally. Clients can implicitly opt in to specced behavior by using
9051 // UINavigationController to present the web view.
9052 if (_inputNavigationViewControllerForFullScreenInputs)
9053 [_inputNavigationViewControllerForFullScreenInputs pushViewController:_presentedFullScreenInputViewController.get() animated:YES__objc_yes];
9054 else
9055 [presentingViewController presentViewController:_presentedFullScreenInputViewController.get() animated:YES__objc_yes completion:nilnullptr];
9056 controller = _presentedFullScreenInputViewController.get();
9057 }
9058
9059#if HAVE(QUICKBOARD_CONTROLLER)(defined HAVE_QUICKBOARD_CONTROLLER && HAVE_QUICKBOARD_CONTROLLER
)
9060 if (_presentedQuickboardController) {
9061 [_presentedQuickboardController present];
9062 controller = [presentingViewController presentedViewController];
9063 }
9064#endif // HAVE(QUICKBOARD_CONTROLLER)
9065
9066 // Presenting a fullscreen input view controller fully obscures the web view. Without taking this token, the web content process will get backgrounded.
9067 _page->legacyMainFrameProcess().startBackgroundActivityForFullscreenInput();
9068
9069 // FIXME: PUICQuickboardController does not present its view controller immediately, since it asynchronously
9070 // establishes a connection to QuickboardViewService before presenting the remote view controller.
9071 // Fixing this requires a version of `-[PUICQuickboardController present]` that takes a completion handler.
9072 [presentingViewController.transitionCoordinator animateAlongsideTransition:nilnullptr completion:[weakWebView = WeakObjCPtr<WKWebView>(_webView), controller] (id <UIViewControllerTransitionCoordinatorContext>) {
9073 auto strongWebView = weakWebView.get();
9074 id <WKUIDelegatePrivate> uiDelegate = static_cast<id <WKUIDelegatePrivate>>([strongWebView UIDelegate]);
9075 if ([uiDelegate respondsToSelector:@selector(_webView:didPresentFocusedElementViewController:)])
9076 [uiDelegate _webView:strongWebView.get() didPresentFocusedElementViewController:controller.get()];
9077 }];
9078}
9079
9080- (BOOL)_isPresentingFullScreenInputView
9081{
9082#if HAVE(QUICKBOARD_CONTROLLER)(defined HAVE_QUICKBOARD_CONTROLLER && HAVE_QUICKBOARD_CONTROLLER
)
9083 if (_presentedQuickboardController)
9084 return YES__objc_yes;
9085#endif // HAVE(QUICKBOARD_CONTROLLER)
9086 return !!_presentedFullScreenInputViewController;
9087}
9088
9089- (void)dismissAllInputViewControllers:(BOOL)animated
9090{
9091 auto navigationController = std::exchange(_inputNavigationViewControllerForFullScreenInputs, nilnullptr);
9092
9093 if (!self._isPresentingFullScreenInputView) {
9094 ASSERT(!navigationController)((void)0);
9095 return;
9096 }
9097
9098 if (auto controller = std::exchange(_presentedFullScreenInputViewController, nilnullptr)) {
9099 auto dispatchDidDismiss = makeBlockPtr([weakWebView = WeakObjCPtr<WKWebView>(_webView), controller] {
9100 auto strongWebView = weakWebView.get();
9101 id <WKUIDelegatePrivate> uiDelegate = static_cast<id <WKUIDelegatePrivate>>([strongWebView UIDelegate]);
9102 if ([uiDelegate respondsToSelector:@selector(_webView:didDismissFocusedElementViewController:)])
9103 [uiDelegate _webView:strongWebView.get() didDismissFocusedElementViewController:controller.get()];
9104 });
9105
9106 if ([navigationController viewControllers].lastObject == controller.get()) {
9107 [navigationController popViewControllerAnimated:animated];
9108 [[controller transitionCoordinator] animateAlongsideTransition:nilnullptr completion:[dispatchDidDismiss = WTF::move(dispatchDidDismiss)] (id <UIViewControllerTransitionCoordinatorContext>) {
9109 dispatchDidDismiss();
9110 }];
9111 } else if (auto presentedViewController = retainPtr([controller presentedViewController])) {
9112 [presentedViewController dismissViewControllerAnimated:animated completion:[controller, animated, dispatchDidDismiss = WTF::move(dispatchDidDismiss)] {
9113 [controller dismissViewControllerAnimated:animated completion:dispatchDidDismiss.get()];
9114 }];
9115 } else
9116 [controller dismissViewControllerAnimated:animated completion:dispatchDidDismiss.get()];
9117 }
9118
9119#if HAVE(QUICKBOARD_CONTROLLER)(defined HAVE_QUICKBOARD_CONTROLLER && HAVE_QUICKBOARD_CONTROLLER
)
9120 if (auto controller = std::exchange(_presentedQuickboardController, nilnullptr)) {
9121 auto presentedViewController = retainPtr([controller quickboardPresentingViewController].presentedViewController);
9122 [controller dismissWithCompletion:[weakWebView = WeakObjCPtr<WKWebView>(_webView), presentedViewController] {
9123 auto strongWebView = weakWebView.get();
9124 id <WKUIDelegatePrivate> uiDelegate = static_cast<id <WKUIDelegatePrivate>>([strongWebView UIDelegate]);
9125 if ([uiDelegate respondsToSelector:@selector(_webView:didDismissFocusedElementViewController:)])
9126 [uiDelegate _webView:strongWebView.get() didDismissFocusedElementViewController:presentedViewController.get()];
9127 }];
9128 }
9129#endif // HAVE(QUICKBOARD_CONTROLLER)
9130
9131 if (_shouldRestoreFirstResponderStatusAfterLosingFocus) {
9132 _shouldRestoreFirstResponderStatusAfterLosingFocus = NO__objc_no;
9133 if (!self.isFirstResponder)
9134 [self becomeFirstResponder];
9135 }
9136
9137 _page->legacyMainFrameProcess().endBackgroundActivityForFullscreenInput();
9138}
9139
9140- (void)focusedFormControlViewDidSubmit:(WKFocusedFormControlView *)view
9141{
9142 [self insertText:@"\n"];
9143 _page->blurFocusedElement();
9144}
9145
9146- (void)focusedFormControlViewDidCancel:(WKFocusedFormControlView *)view
9147{
9148 _page->blurFocusedElement();
9149}
9150
9151- (void)focusedFormControlViewDidBeginEditing:(WKFocusedFormControlView *)view
9152{
9153 [self updateCurrentFocusedElementInformation:[weakSelf = WeakObjCPtr<WKContentView>(self)] (bool didUpdate) {
9154 if (!didUpdate)
9155 return;
9156
9157 auto strongSelf = weakSelf.get();
9158 [strongSelf presentViewControllerForCurrentFocusedElement];
9159 [strongSelf->_focusedFormControlView hide:YES__objc_yes];
9160 }];
9161}
9162
9163- (CGRect)rectForFocusedFormControlView:(WKFocusedFormControlView *)view
9164{
9165 return [self convertRect:_focusedElementInformation.interactionRect toView:view];
9166}
9167
9168- (CGRect)nextRectForFocusedFormControlView:(WKFocusedFormControlView *)view
9169{
9170 if (!_focusedElementInformation.hasNextNode)
9171 return CGRectNull;
9172
9173 return [self convertRect:_focusedElementInformation.nextNodeRect toView:view];
9174}
9175
9176- (CGRect)previousRectForFocusedFormControlView:(WKFocusedFormControlView *)view
9177{
9178 if (!_focusedElementInformation.hasPreviousNode)
9179 return CGRectNull;
9180
9181 return [self convertRect:_focusedElementInformation.previousNodeRect toView:view];
9182}
9183
9184- (UIScrollView *)scrollViewForFocusedFormControlView:(WKFocusedFormControlView *)view
9185{
9186 return self._scroller;
9187}
9188
9189- (NSString *)actionNameForFocusedFormControlView:(WKFocusedFormControlView *)view
9190{
9191 if (_focusedElementInformation.formAction.isEmpty())
9192 return nilnullptr;
9193
9194 switch (_focusedElementInformation.elementType) {
9195 case WebKit::InputType::Select:
9196 case WebKit::InputType::Time:
9197 case WebKit::InputType::Date:
9198 case WebKit::InputType::Color:
9199 return nilnullptr;
9200 case WebKit::InputType::Search:
9201 return WebCore::formControlSearchButtonTitle().createNSString().autorelease();
9202 default:
9203 return WebCore::formControlGoButtonTitle().createNSString().autorelease();
9204 }
9205}
9206
9207- (void)focusedFormControlViewDidRequestNextNode:(WKFocusedFormControlView *)view
9208{
9209 if (_focusedElementInformation.hasNextNode)
9210 _page->focusNextFocusedElement(true, [] { });
9211}
9212
9213- (void)focusedFormControlViewDidRequestPreviousNode:(WKFocusedFormControlView *)view
9214{
9215 if (_focusedElementInformation.hasPreviousNode)
9216 _page->focusNextFocusedElement(false, [] { });
9217}
9218
9219- (BOOL)hasNextNodeForFocusedFormControlView:(WKFocusedFormControlView *)view
9220{
9221 return _focusedElementInformation.hasNextNode;
9222}
9223
9224- (BOOL)hasPreviousNodeForFocusedFormControlView:(WKFocusedFormControlView *)view
9225{
9226 return _focusedElementInformation.hasPreviousNode;
9227}
9228
9229- (void)focusedFormControllerDidUpdateSuggestions:(WKFocusedFormControlView *)view
9230{
9231 if (_isBlurringFocusedElement || ![_presentedFullScreenInputViewController isKindOfClass:[WKTextInputListViewController class]])
9232 return;
9233
9234 [(WKTextInputListViewController *)_presentedFullScreenInputViewController updateTextSuggestions:[protect(_focusedFormControlView) suggestions]];
9235}
9236
9237#pragma mark - WKSelectMenuListViewControllerDelegate
9238
9239- (void)selectMenu:(WKSelectMenuListViewController *)selectMenu didSelectItemAtIndex:(NSUInteger)index
9240{
9241 ASSERT(!_focusedElementInformation.isMultiSelect)((void)0);
9242 [self updateFocusedElementSelectedIndex:index allowsMultipleSelection:false];
9243}
9244
9245- (NSUInteger)numberOfItemsInSelectMenu:(WKSelectMenuListViewController *)selectMenu
9246{
9247 return self.focusedSelectElementOptions.size();
9248}
9249
9250- (NSString *)selectMenu:(WKSelectMenuListViewController *)selectMenu displayTextForItemAtIndex:(NSUInteger)index
9251{
9252 auto& options = self.focusedSelectElementOptions;
9253 if (index >= options.size()) {
9254 ASSERT_NOT_REACHED()((void)0);
9255 return @"";
9256 }
9257
9258 return options[index].text.createNSString().autorelease();
9259}
9260
9261- (void)selectMenu:(WKSelectMenuListViewController *)selectMenu didCheckItemAtIndex:(NSUInteger)index checked:(BOOL)checked
9262{
9263 ASSERT(_focusedElementInformation.isMultiSelect)((void)0);
9264 if (index >= self.focusedSelectElementOptions.size()) {
9265 ASSERT_NOT_REACHED()((void)0);
9266 return;
9267 }
9268
9269 auto& option = self.focusedSelectElementOptions[index];
9270 if (option.isSelected == checked) {
9271 ASSERT_NOT_REACHED()((void)0);
9272 return;
9273 }
9274
9275 [self updateFocusedElementSelectedIndex:index allowsMultipleSelection:true];
9276 option.isSelected = checked;
9277}
9278
9279- (BOOL)selectMenuUsesMultipleSelection:(WKSelectMenuListViewController *)selectMenu
9280{
9281 return _focusedElementInformation.isMultiSelect;
9282}
9283
9284- (BOOL)selectMenu:(WKSelectMenuListViewController *)selectMenu hasSelectedOptionAtIndex:(NSUInteger)index
9285{
9286 if (index >= self.focusedSelectElementOptions.size()) {
9287 ASSERT_NOT_REACHED()((void)0);
9288 return NO__objc_no;
9289 }
9290
9291 return self.focusedSelectElementOptions[index].isSelected;
9292}
9293
9294#if HAVE(QUICKBOARD_CONTROLLER)(defined HAVE_QUICKBOARD_CONTROLLER && HAVE_QUICKBOARD_CONTROLLER
)
9295
9296#pragma mark - PUICQuickboardControllerDelegate
9297
9298- (void)quickboardController:(PUICQuickboardController *)controller textInputValueDidChange:(NSAttributedString *)attributedText
9299{
9300 _page->setTextAsync(attributedText.string);
9301 [self dismissQuickboardViewControllerAndRevealFocusedFormOverlayIfNecessary:controller];
9302}
9303
9304- (void)quickboardControllerTextInputValueCancelled:(PUICQuickboardController *)controller
9305{
9306 [self dismissQuickboardViewControllerAndRevealFocusedFormOverlayIfNecessary:controller];
9307}
9308
9309#endif // HAVE(QUICKBOARD_CONTROLLER)
9310
9311#endif // HAVE(PEPPER_UI_CORE)
9312
9313- (void)_wheelChangedWithEvent:(UIEvent *)event
9314{
9315#if HAVE(PEPPER_UI_CORE)(defined HAVE_PEPPER_UI_CORE && HAVE_PEPPER_UI_CORE)
9316 if ([protect(_focusedFormControlView) handleWheelEvent:event])
9317 return;
9318#endif
9319 [super _wheelChangedWithEvent:event];
9320}
9321
9322- (void)_updateSelectionAssistantSuppressionState
9323{
9324 static const double minimumFocusedElementAreaForSuppressingSelectionAssistant = 4;
9325
9326 auto& editorState = protect(_page)->editorState();
9327 if (!editorState.hasPostLayoutAndVisualData())
9328 return;
9329
9330 BOOL selectionIsTransparentOrFullyClipped = NO__objc_no;
9331 BOOL focusedElementIsTooSmall = NO__objc_no;
9332 if (editorState.selectionType != WebCore::SelectionType::None) {
9333 auto& postLayoutData = *editorState.postLayoutData;
9334 auto& visualData = *editorState.visualData;
9335 if (postLayoutData.selectionIsTransparentOrFullyClipped)
9336 selectionIsTransparentOrFullyClipped = YES__objc_yes;
9337
9338 if (self._hasFocusedElement) {
9339 auto elementArea = visualData.editableRootBounds.area<RecordOverflow>();
9340 if (!elementArea.hasOverflowed() && elementArea < minimumFocusedElementAreaForSuppressingSelectionAssistant)
9341 focusedElementIsTooSmall = YES__objc_yes;
9342 }
9343 }
9344
9345 if (selectionIsTransparentOrFullyClipped)
9346 [self _startSuppressingSelectionAssistantForReason:WebKit::SelectionIsTransparentOrFullyClipped];
9347 else
9348 [self _stopSuppressingSelectionAssistantForReason:WebKit::SelectionIsTransparentOrFullyClipped];
9349
9350 if (focusedElementIsTooSmall)
9351 [self _startSuppressingSelectionAssistantForReason:WebKit::FocusedElementIsTooSmall];
9352 else
9353 [self _stopSuppressingSelectionAssistantForReason:WebKit::FocusedElementIsTooSmall];
9354}
9355
9356- (void)_selectionChanged
9357{
9358 _autocorrectionContextNeedsUpdate = YES__objc_yes;
9359
9360 [self _updateSelectionAssistantSuppressionState];
9361
9362 _cachedSelectionContainerView = nilnullptr;
9363 _cachedSelectedTextRange = nilnullptr;
9364 _selectionNeedsUpdate = YES__objc_yes;
9365 // If we are changing the selection with a gesture there is no need
9366 // to wait to paint the selection.
9367 if (_usingGestureForSelection)
9368 [self _updateChangedSelection];
9369
9370 if (_candidateViewNeedsUpdate) {
9371 _candidateViewNeedsUpdate = NO__objc_no;
9372#if USE(BROWSERENGINEKIT)(defined 1 && 1)
9373 if (self.shouldUseAsyncInteractions)
9374 [protect(_asyncInputDelegate) invalidateTextEntryContextForTextInput:self.asBETextInput];
9375 else
9376#endif // USE(BROWSERENGINEKIT)
9377 {
9378 auto inputDelegate = self.inputDelegate;
9379 if ([inputDelegate respondsToSelector:@selector(layoutHasChanged)])
9380 [(id<UITextInputDelegatePrivate>)inputDelegate layoutHasChanged];
9381 }
9382 }
9383
9384 [_webView.get() _didChangeEditorState];
9385
9386 Ref page = *_page;
9387 if (page->editorState().hasPostLayoutAndVisualData()) {
9388 _lastInsertedCharacterToOverrideCharacterBeforeSelection = std::nullopt;
9389
9390 if (!_usingGestureForSelection && !_selectionChangeNestingLevel && page->editorState().triggeredByAccessibilitySelectionChange) {
9391 // Force UIKit to reload all EditorState-based UI; in particular, this includes text candidates.
9392 [self _internalBeginSelectionChange];
9393 [self _internalEndSelectionChange];
9394 }
9395 }
9396}
9397
9398- (void)selectWordForReplacement
9399{
9400 [self _internalBeginSelectionChange];
9401 protect(_page)->extendSelectionForReplacement([weakSelf = WeakObjCPtr<WKContentView>(self)] {
9402 if (auto strongSelf = weakSelf.get())
9403 [strongSelf _internalEndSelectionChange];
9404 });
9405}
9406
9407#if ENABLE(PLATFORM_DRIVEN_TEXT_CHECKING)(defined 0 && 0)
9408- (void)replaceSelectionOffset:(NSInteger)selectionOffset length:(NSUInteger)length withAnnotatedString:(NSAttributedString *)annotatedString relativeReplacementRange:(NSRange)relativeReplacementRange
9409{
9410 _textCheckingController->replaceRelativeToSelection(annotatedString, selectionOffset, length, relativeReplacementRange.location, relativeReplacementRange.length);
9411}
9412
9413- (void)removeAnnotation:(NSAttributedStringKey)annotationName forSelectionOffset:(NSInteger)selectionOffset length:(NSUInteger)length
9414{
9415 _textCheckingController->removeAnnotationRelativeToSelection(annotationName, selectionOffset, length);
9416}
9417#endif
9418
9419- (void)_updateChangedSelection
9420{
9421 [self _updateChangedSelection:NO__objc_no];
9422}
9423
9424- (UIScrollView *)_scrollViewForScrollingNodeID:(std::optional<WebCore::ScrollingNodeID>)scrollingNodeID
9425{
9426 if (WeakPtr coordinator = downcast<WebKit::RemoteScrollingCoordinatorProxyIOS>(_page->scrollingCoordinatorProxy()))
9427 return coordinator->scrollViewForScrollingNodeID(scrollingNodeID);
9428
9429 return nilnullptr;
9430}
9431
9432- (void)_updateChangedSelection:(BOOL)force
9433{
9434 auto& editorState = protect(_page)->editorState();
9435 if (!editorState.hasPostLayoutAndVisualData())
9436 return;
9437
9438 using enum WebKit::WKSelectionDrawingInfo::ComparisonResult;
9439
9440 auto& postLayoutData = *editorState.postLayoutData;
9441 WebKit::WKSelectionDrawingInfo selectionDrawingInfo { editorState };
9442 auto comparison = selectionDrawingInfo.compare(_lastSelectionDrawingInfo);
9443 if (force || comparison != EquivalentIncludingEnclosingLayer) {
9444 LOG_WITH_STREAM(Selection, stream << "_updateChangedSelection " << selectionDrawingInfo)((void)0);
9445
9446 _cachedSelectedTextRange = nilnullptr;
9447 _lastSelectionDrawingInfo = selectionDrawingInfo;
9448
9449 if (_textInteractionWrapper) {
9450 _markedText = editorState.hasComposition ? postLayoutData.markedText.createNSString().get() : @"";
9451 if (![_markedText length])
9452 _isDeferringKeyEventsToInputMethod = NO__objc_no;
9453 RetainPtr containerView = [self _selectionContainerViewInternal];
9454 [_textInteractionWrapper prepareToMoveSelectionContainer:containerView.get()];
9455 if (comparison == VisuallyDistinct)
9456 [_textInteractionWrapper selectionChanged];
9457 _lastSelectionChildScrollViewContentOffset = [containerView] -> std::optional<WebCore::IntPoint> {
9458 RetainPtr scrollView = [containerView _wk_parentScrollView];
9459 if (is_objc<WKChildScrollView>(scrollView.get()))
9460 return WebCore::roundedIntPoint([scrollView contentOffset]);
9461 return { };
9462 }();
9463 _lastSiblingBeforeSelectionHighlight = [self _siblingBeforeSelectionHighlight];
9464 _lastSelectionContainerViewOrigin = [containerView frame].origin;
9465 }
9466
9467 _selectionNeedsUpdate = NO__objc_no;
9468 if (_shouldRestoreSelection) {
9469 [_textInteractionWrapper didEndScrollingOverflow];
9470 _shouldRestoreSelection = NO__objc_no;
9471 }
9472 } else {
9473 if (_lastSiblingBeforeSelectionHighlight != [self _siblingBeforeSelectionHighlight])
9474 [_textInteractionWrapper prepareToMoveSelectionContainer:self._selectionContainerViewInternal];
9475 [self _updateSelectionViewsIfNeeded];
9476 }
9477
9478 if (postLayoutData.isStableStateUpdate && _needsDeferredEndScrollingSelectionUpdate && protect(_page)->inStableState()) {
9479 auto firstResponder = self.firstResponder;
9480 if ((!firstResponder || self == firstResponder) && !_suppressSelectionAssistantReasons)
9481 [_textInteractionWrapper activateSelection];
9482
9483 [_textInteractionWrapper didEndScrollingOverflow];
9484
9485 _needsDeferredEndScrollingSelectionUpdate = NO__objc_no;
9486 }
9487}
9488
9489- (UIView *)_siblingBeforeSelectionHighlight
9490{
9491 return [[_textInteractionWrapper selectionHighlightView] _wk_previousSibling];
9492}
9493
9494- (void)_updateSelectionViewsIfNeeded
9495{
9496 RetainPtr selectionContainer = [self _selectionContainerViewInternal];
9497
9498 auto updateLastSelectionChildScrollViewContentOffset = [&] {
9499 if (_waitingForEditorStateAfterScrollingSelectionContainer)
9500 return NO__objc_no;
9501
9502 RetainPtr scroller = [selectionContainer _wk_parentScrollView];
9503 if (![_webView.get() _isInStableState:scroller.get()])
9504 return NO__objc_no;
9505
9506 if (!is_objc<WKChildScrollView>(scroller.get()))
9507 return NO__objc_no;
9508
9509 auto contentOffset = WebCore::roundedIntPoint([scroller contentOffset]);
9510 if (_lastSelectionChildScrollViewContentOffset == contentOffset)
9511 return NO__objc_no;
9512
9513 _lastSelectionChildScrollViewContentOffset = contentOffset;
9514 return YES__objc_yes;
9515 };
9516
9517 auto updateLastSelectionContainerViewOrigin = [&] -> BOOL {
9518 if (selectionContainer == self)
9519 return NO__objc_no;
9520
9521 auto previousOrigin = std::exchange(_lastSelectionContainerViewOrigin, [selectionContainer frame].origin);
9522 return previousOrigin && !CGPointEqualToPoint__CGPointEqualToPoint(*previousOrigin, [selectionContainer frame].origin);
9523 };
9524
9525 BOOL needsUpdateDueToScrolling = updateLastSelectionChildScrollViewContentOffset();
9526 BOOL needsUpdateDueToOriginChange = updateLastSelectionContainerViewOrigin();
9527
9528 if (needsUpdateDueToScrolling || needsUpdateDueToOriginChange)
9529 [_textInteractionWrapper setNeedsSelectionUpdate];
9530}
9531
9532- (BOOL)shouldAllowHidingSelectionCommands
9533{
9534 ASSERT(_ignoreSelectionCommandFadeCount >= 0)((void)0);
9535 return !_ignoreSelectionCommandFadeCount;
9536}
9537
9538- (BOOL)supportsTextSelectionWithCharacterGranularity
9539{
9540 return YES__objc_yes;
9541}
9542
9543#if ENABLE(REVEAL)(defined 1 && 1)
9544- (void)requestRVItemInSelectedRangeWithCompletionHandler:(void(^)(RVItem *item))completionHandler
9545{
9546 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG225"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(9546, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
9547
9548 protect(_page)->requestRVItemInCurrentSelectedRange([completionHandler = makeBlockPtr(completionHandler), weakSelf = WeakObjCPtr<WKContentView>(self)](const WebKit::RevealItem& item) {
9549 auto strongSelf = weakSelf.get();
9550 if (!strongSelf)
9551 return completionHandler(nilnullptr);
9552
9553 completionHandler(protect(item.item()));
9554 });
9555}
9556
9557- (void)prepareSelectionForContextMenuWithLocationInView:(CGPoint)locationInView completionHandler:(void(^)(BOOL shouldPresentMenu, RVItem *item))completionHandler
9558{
9559 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG226"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(9559, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
9560
9561 [self _internalSelectTextForContextMenuWithLocationInView:locationInView completionHandler:[completionHandler = makeBlockPtr(completionHandler)](BOOL shouldPresentMenu, const WebKit::RevealItem& item) {
9562 completionHandler(shouldPresentMenu, protect(item.item()));
9563 }];
9564}
9565
9566- (void)_internalSelectTextForContextMenuWithLocationInView:(CGPoint)locationInView completionHandler:(void(^)(BOOL shouldPresentMenu, const WebKit::RevealItem& item))completionHandler
9567{
9568#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
9569 _removeBackgroundData = std::nullopt;
9570#endif
9571
9572 protect(_page)->prepareSelectionForContextMenuWithLocationInView(WebCore::roundedIntPoint(locationInView), [weakSelf = WeakObjCPtr<WKContentView>(self), completionHandler = makeBlockPtr(completionHandler)](bool shouldPresentMenu, auto& item) {
9573 auto strongSelf = weakSelf.get();
9574 if (!strongSelf)
9575 return completionHandler(false, { });
9576
9577 if (shouldPresentMenu && ![strongSelf shouldSuppressEditMenu])
9578 [strongSelf->_textInteractionWrapper activateSelection];
9579
9580#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
9581 [strongSelf doAfterComputingImageAnalysisResultsForBackgroundRemoval:[completionHandler, shouldPresentMenu, item, weakSelf] {
9582 auto strongSelf = weakSelf.get();
9583 if (!strongSelf)
9584 return completionHandler(false, { });
9585
9586 completionHandler(shouldPresentMenu, item);
9587 }];
9588#else
9589 completionHandler(shouldPresentMenu, item);
9590#endif
9591 });
9592}
9593#endif
9594
9595- (BOOL)hasHiddenContentEditable
9596{
9597 return _suppressSelectionAssistantReasons.containsAny({ WebKit::SelectionIsTransparentOrFullyClipped, WebKit::FocusedElementIsTooSmall });
9598}
9599
9600- (BOOL)_shouldSuppressSelectionCommands
9601{
9602 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG227"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(9602, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
9603
9604 return self.shouldSuppressEditMenu;
9605}
9606
9607- (void)_startSuppressingSelectionAssistantForReason:(WebKit::SuppressSelectionAssistantReason)reason
9608{
9609 bool wasSuppressingSelectionAssistant = !!_suppressSelectionAssistantReasons;
9610 _suppressSelectionAssistantReasons.add(reason);
9611
9612 if (!wasSuppressingSelectionAssistant)
9613 [_textInteractionWrapper deactivateSelection];
9614}
9615
9616- (void)_stopSuppressingSelectionAssistantForReason:(WebKit::SuppressSelectionAssistantReason)reason
9617{
9618 bool wasSuppressingSelectionAssistant = !!_suppressSelectionAssistantReasons;
9619 _suppressSelectionAssistantReasons.remove(reason);
9620
9621 if (wasSuppressingSelectionAssistant && !_suppressSelectionAssistantReasons)
9622 [_textInteractionWrapper activateSelection];
9623}
9624
9625- (BOOL)_isSuppressingSelectionAssistant
9626{
9627 return !!_suppressSelectionAssistantReasons;
9628}
9629
9630- (UIView <WKFormControl> *)dataListTextSuggestionsInputView
9631{
9632 return _dataListTextSuggestionsInputView.get();
9633}
9634
9635- (NSArray<WKBETextSuggestionBETextSuggestion *> *)dataListTextSuggestions
9636{
9637 return _dataListTextSuggestions.get();
9638}
9639
9640- (void)setDataListTextSuggestionsInputView:(UIView <WKFormControl> *)suggestionsInputView
9641{
9642 if (_dataListTextSuggestionsInputView == suggestionsInputView)
9643 return;
9644
9645 _dataListTextSuggestionsInputView = suggestionsInputView;
9646
9647 if (![_formInputSession customInputView])
9648 [self reloadInputViews];
9649}
9650
9651- (void)setDataListTextSuggestions:(NSArray<WKBETextSuggestionBETextSuggestion *> *)textSuggestions
9652{
9653 if (textSuggestions == _dataListTextSuggestions || [textSuggestions isEqualToArray:_dataListTextSuggestions.get()])
9654 return;
9655
9656 _dataListTextSuggestions = textSuggestions;
9657
9658 if (![_formInputSession suggestions].count)
9659 [self updateTextSuggestionsForInputDelegate];
9660}
9661
9662- (void)updateTextSuggestionsForInputDelegate
9663{
9664 // Text suggestions vended from clients take precedence over text suggestions from a focused form control with a datalist.
9665 NSArray<UITextSuggestion *> *formInputSessionSuggestions = [_formInputSession suggestions];
9666 if (formInputSessionSuggestions.count) {
9667 [self _provideUITextSuggestionsToInputDelegate:formInputSessionSuggestions];
9668 return;
9669 }
9670
9671 if ([_dataListTextSuggestions count]) {
9672 [self _provideSuggestionsToInputDelegate:_dataListTextSuggestions.get()];
9673 return;
9674 }
9675
9676 [self _provideSuggestionsToInputDelegate:nilnullptr];
9677}
9678
9679- (void)_provideSuggestionsToInputDelegate:(NSArray<WKBETextSuggestionBETextSuggestion *> *)suggestions
9680{
9681#if USE(BROWSERENGINEKIT)(defined 1 && 1)
9682 if (self.shouldUseAsyncInteractions) {
9683 [protect(_asyncInputDelegate) textInput:self.asBETextInput setCandidateSuggestions:suggestions];
9684 return;
9685 }
9686
9687 RetainPtr uiSuggestions = [NSMutableArray arrayWithCapacity:suggestions.count];
9688 for (UITextSuggestion *suggestion in suggestions)
9689 [uiSuggestions addObject:[UITextSuggestion textSuggestionWithInputText:suggestion.inputText]];
9690#else
9691 RetainPtr uiSuggestions = suggestions;
9692#endif
9693 [(id<UITextInputSuggestionDelegate>)self.inputDelegate setSuggestions:uiSuggestions.get()];
9694}
9695
9696- (void)_provideUITextSuggestionsToInputDelegate:(NSArray<UITextSuggestion *> *)suggestions
9697{
9698#if USE(BROWSERENGINEKIT)(defined 1 && 1)
9699 if (self.shouldUseAsyncInteractions) {
9700 RetainPtr suggestionsForDelegate = [NSMutableArray arrayWithCapacity:suggestions.count];
9701 for (UITextSuggestion *suggestion in suggestions)
9702 [suggestionsForDelegate addObject:adoptNS([[WKBETextSuggestionBETextSuggestion alloc] _initWithUIKitTextSuggestion:suggestion]).get()];
9703 [protect(_asyncInputDelegate) textInput:self.asBETextInput setCandidateSuggestions:suggestionsForDelegate.get()];
9704 return;
9705 }
9706#endif // USE(BROWSERENGINEKIT)
9707
9708 [(id<UITextInputSuggestionDelegate>)self.inputDelegate setSuggestions:suggestions];
9709}
9710
9711- (void)_showPlaybackTargetPicker:(BOOL)hasVideo fromRect:(const WebCore::IntRect&)elementRect routeSharingPolicy:(WebCore::RouteSharingPolicy)routeSharingPolicy routingContextUID:(NSString *)routingContextUID
9712{
9713#if ENABLE(AIRPLAY_PICKER)(defined 1 && 1)
9714 if (!_airPlayRoutePicker)
9715 _airPlayRoutePicker = adoptNS([[WKAirPlayRoutePicker alloc] init]);
9716 [_airPlayRoutePicker showFromView:self routeSharingPolicy:routeSharingPolicy routingContextUID:routingContextUID hasVideo:hasVideo];
9717#endif
9718}
9719
9720- (void)_showRunOpenPanel:(API::OpenPanelParameters*)parameters frameInfo:(const WebKit::FrameInfoData&)frameInfo resultListener:(WebKit::WebOpenPanelResultListenerProxy*)listener
9721{
9722 ASSERT(!_fileUploadPanel)((void)0);
9723 if (_fileUploadPanel)
9724 return;
9725
9726 _frameInfoForFileUploadPanel = frameInfo;
9727 _fileUploadPanel = adoptNS([[WKFileUploadPanel alloc] initWithView:self]);
9728 [_fileUploadPanel setDelegate:self];
9729 [_fileUploadPanel presentWithParameters:parameters resultListener:listener];
9730}
9731
9732- (void)fileUploadPanelDidDismiss:(WKFileUploadPanel *)fileUploadPanel
9733{
9734 ASSERT(_fileUploadPanel.get() == fileUploadPanel)((void)0);
9735
9736 if ([self window] && ![[self window] firstResponder])
9737 [self becomeFirstResponder];
9738
9739 [_fileUploadPanel setDelegate:nilnullptr];
9740 _fileUploadPanel = nilnullptr;
9741}
9742
9743- (BOOL)fileUploadPanelDestinationIsManaged:(WKFileUploadPanel *)fileUploadPanel
9744{
9745 ASSERT(_fileUploadPanel.get() == fileUploadPanel)((void)0);
9746
9747 auto webView = _webView.get();
9748 id <WKUIDelegatePrivate> uiDelegate = static_cast<id <WKUIDelegatePrivate>>([webView UIDelegate]);
9749 return [uiDelegate respondsToSelector:@selector(_webView:fileUploadPanelContentIsManagedWithInitiatingFrame:)]
9750 && [uiDelegate _webView:webView.get() fileUploadPanelContentIsManagedWithInitiatingFrame:_frameInfoForFileUploadPanel ? wrapper(API::FrameInfo::create(*std::exchange(_frameInfoForFileUploadPanel, std::nullopt))).get() : nilnullptr];
9751}
9752
9753#if HAVE(PHOTOS_UI)(defined 1 && 1)
9754- (BOOL)fileUploadPanelPhotoPickerPrefersOriginalImageFormat:(WKFileUploadPanel *)fileUploadPanel
9755{
9756 ASSERT(_fileUploadPanel.get() == fileUploadPanel)((void)0);
9757 return protect(_page->preferences())->photoPickerPrefersOriginalImageFormat();
9758}
9759#endif
9760
9761- (void)_showShareSheet:(const WebCore::ShareDataWithParsedURL&)data inRect:(std::optional<WebCore::FloatRect>)rect completionHandler:(CompletionHandler<void(bool)>&&)completionHandler
9762{
9763#if HAVE(SHARE_SHEET_UI)(defined 1 && 1)
9764 if (_shareSheet)
9765 [_shareSheet dismissIfNeededWithReason:WebKit::PickerDismissalReason::ResetState];
9766
9767 _shareSheet = adoptNS([[WKShareSheet alloc] initWithView:self.webView]);
9768 [_shareSheet setDelegate:self];
9769
9770#if HAVE(UIKIT_WITH_MOUSE_SUPPORT)(defined 1 && 1)
9771 if (!rect) {
9772 if (auto lastLocation = [_mouseInteraction lastLocation]) {
9773 auto hoverLocationInWebView = [self convertPoint:*lastLocation toView:self.webView];
9774 rect = WebCore::FloatRect(hoverLocationInWebView.x, hoverLocationInWebView.y, 1, 1);
9775 }
9776 }
9777#endif
9778
9779 [_shareSheet presentWithParameters:data inRect:rect completionHandler:WTF::move(completionHandler)];
9780#endif // HAVE(SHARE_SHEET_UI)
9781}
9782
9783#if HAVE(SHARE_SHEET_UI)(defined 1 && 1)
9784
9785- (void)shareSheetDidDismiss:(WKShareSheet *)shareSheet
9786{
9787 ASSERT(_shareSheet == shareSheet)((void)0);
9788
9789 [_shareSheet setDelegate:nilnullptr];
9790 _shareSheet = nilnullptr;
9791}
9792
9793- (void)shareSheet:(WKShareSheet *)shareSheet willShowActivityItems:(NSArray *)activityItems
9794{
9795 ASSERT(_shareSheet == shareSheet)((void)0);
9796
9797 RetainPtr uiDelegate = static_cast<id <WKUIDelegatePrivate>>([_webView.get() UIDelegate]);
9798 if ([uiDelegate respondsToSelector:@selector(_webView:willShareActivityItems:)])
9799 [uiDelegate _webView:self.webView willShareActivityItems:activityItems];
9800}
9801
9802#endif // HAVE(SHARE_SHEET_UI)
9803
9804#if ENABLE(WEB_AUTHN)(defined 1 && 1)
9805- (void)_showDigitalCredentialsPicker:(const WebCore::DigitalCredentialsRequestData&)requestData completionHandler:(WTF::CompletionHandler<void(Expected<WebCore::DigitalCredentialsResponseData, WebCore::ExceptionData>&&)>&&)completionHandler
9806{
9807 _digitalCredentialsPicker = adoptNS([[WKDigitalCredentialsPicker alloc] initWithView:self.webView page:_page.get()]);
9808 [_digitalCredentialsPicker presentWithRequestData:requestData completionHandler:WTF::move(completionHandler)];
9809}
9810
9811- (void)_dismissDigitalCredentialsPicker:(WTF::CompletionHandler<void(bool)>&&)completionHandler
9812{
9813 if (!_digitalCredentialsPicker) {
9814 LOG(DigitalCredentials, "Digital credentials picker is not presented.")((void)0);
9815 completionHandler(false);
9816 return;
9817 }
9818 [_digitalCredentialsPicker dismissWithCompletionHandler:WTF::move(completionHandler)];
9819}
9820#endif // ENABLE(WEB_AUTHN)
9821
9822- (void)_showContactPicker:(const WebCore::ContactsRequestData&)requestData completionHandler:(WTF::CompletionHandler<void(std::optional<Vector<WebCore::ContactInfo>>&&)>&&)completionHandler
9823{
9824#if HAVE(CONTACTSUI)(defined 1 && 1)
9825 _contactPicker = adoptNS([[WKContactPicker alloc] initWithView:self.webView]);
9826 [_contactPicker setDelegate:self];
9827 [_contactPicker presentWithRequestData:requestData completionHandler:WTF::move(completionHandler)];
9828#else
9829 completionHandler(std::nullopt);
9830#endif
9831}
9832
9833#if HAVE(CONTACTSUI)(defined 1 && 1)
9834- (void)contactPickerDidPresent:(WKContactPicker *)contactPicker
9835{
9836 ASSERT(_contactPicker == contactPicker)((void)0);
9837
9838 [_webView.get() _didPresentContactPicker];
9839}
9840
9841- (void)contactPickerDidDismiss:(WKContactPicker *)contactPicker
9842{
9843 ASSERT(_contactPicker == contactPicker)((void)0);
9844
9845 [_contactPicker setDelegate:nilnullptr];
9846 _contactPicker = nilnullptr;
9847
9848 [_webView.get() _didDismissContactPicker];
9849}
9850#endif
9851
9852- (void)dismissPickersIfNeededWithReason:(WebKit::PickerDismissalReason)reason
9853{
9854 if ([_fileUploadPanel dismissIfNeededWithReason:reason])
9855 _fileUploadPanel = nilnullptr;
9856
9857#if !PLATFORM(WATCHOS)(defined WTF_PLATFORM_WATCHOS && WTF_PLATFORM_WATCHOS
)
&& !PLATFORM(APPLETV)(defined WTF_PLATFORM_APPLETV && WTF_PLATFORM_APPLETV
)
9858 if ([_shareSheet dismissIfNeededWithReason:reason])
9859 _shareSheet = nilnullptr;
9860#endif
9861
9862#if HAVE(CONTACTSUI)(defined 1 && 1)
9863 if ([_contactPicker dismissIfNeededWithReason:reason])
9864 _contactPicker = nilnullptr;
9865#endif
9866}
9867
9868#if PLATFORM(WATCHOS)(defined WTF_PLATFORM_WATCHOS && WTF_PLATFORM_WATCHOS
)
9869static String fallbackLabelTextForUnlabeledInputFieldInZoomedFormControls(WebCore::InputMode inputMode, WebKit::InputType elementType)
9870{
9871 bool isPasswordField = false;
9872
9873 auto elementTypeIsAnyOf = [elementType](std::initializer_list<WebKit::InputType>&& elementTypes) {
9874 return std::ranges::find(elementTypes, elementType) != elementTypes.end();
9875 };
9876
9877 // If unspecified, try to infer the input mode from the input type
9878 if (inputMode == WebCore::InputMode::Unspecified) {
9879 if (elementTypeIsAnyOf({ WebKit::InputType::ContentEditable, WebKit::InputType::Text, WebKit::InputType::TextArea }))
9880 inputMode = WebCore::InputMode::Text;
9881 if (elementTypeIsAnyOf({ WebKit::InputType::URL }))
9882 inputMode = WebCore::InputMode::Url;
9883 if (elementTypeIsAnyOf({ WebKit::InputType::Number, WebKit::InputType::NumberPad }))
9884 inputMode = WebCore::InputMode::Numeric;
9885 if (elementTypeIsAnyOf({ WebKit::InputType::Search }))
9886 inputMode = WebCore::InputMode::Search;
9887 if (elementTypeIsAnyOf({ WebKit::InputType::Email }))
9888 inputMode = WebCore::InputMode::Email;
9889 if (elementTypeIsAnyOf({ WebKit::InputType::Phone }))
9890 inputMode = WebCore::InputMode::Telephone;
9891 if (elementTypeIsAnyOf({ WebKit::InputType::Password }))
9892 isPasswordField = true;
9893 }
9894
9895 if (isPasswordField)
9896 return WEB_UI_STRING("Password", "Fallback label text for unlabeled password field.")WebCore::localizedString(((CFStringRef) __builtin___CFStringMakeConstantString
("" "Password" "")))
;
9897
9898 switch (inputMode) {
9899 case WebCore::InputMode::Telephone:
9900 return WEB_UI_STRING("Phone number", "Fallback label text for unlabeled telephone number input field.")WebCore::localizedString(((CFStringRef) __builtin___CFStringMakeConstantString
("" "Phone number" "")))
;
9901 case WebCore::InputMode::Url:
9902 return WEB_UI_STRING("URL", "Fallback label text for unlabeled URL input field.")WebCore::localizedString(((CFStringRef) __builtin___CFStringMakeConstantString
("" "URL" "")))
;
9903 case WebCore::InputMode::Email:
9904 return WEB_UI_STRING("Email address", "Fallback label text for unlabeled email address field.")WebCore::localizedString(((CFStringRef) __builtin___CFStringMakeConstantString
("" "Email address" "")))
;
9905 case WebCore::InputMode::Numeric:
9906 case WebCore::InputMode::Decimal:
9907 return WEB_UI_STRING("Enter a number", "Fallback label text for unlabeled numeric field.")WebCore::localizedString(((CFStringRef) __builtin___CFStringMakeConstantString
("" "Enter a number" "")))
;
9908 case WebCore::InputMode::Search:
9909 return WEB_UI_STRING("Search", "Fallback label text for unlabeled search field")WebCore::localizedString(((CFStringRef) __builtin___CFStringMakeConstantString
("" "Search" "")))
;
9910 case WebCore::InputMode::Unspecified:
9911 case WebCore::InputMode::None:
9912 case WebCore::InputMode::Text:
9913 return WEB_UI_STRING("Enter text", "Fallback label text for unlabeled text field.")WebCore::localizedString(((CFStringRef) __builtin___CFStringMakeConstantString
("" "Enter text" "")))
;
9914 }
9915}
9916#endif
9917
9918- (NSString *)inputLabelText
9919{
9920 if (!_focusedElementInformation.label.isEmpty())
9921 return _focusedElementInformation.label.createNSString().autorelease();
9922
9923 if (!_focusedElementInformation.ariaLabel.isEmpty())
9924 return _focusedElementInformation.ariaLabel.createNSString().autorelease();
9925
9926 if (!_focusedElementInformation.title.isEmpty())
9927 return _focusedElementInformation.title.createNSString().autorelease();
9928
9929#if PLATFORM(WATCHOS)(defined WTF_PLATFORM_WATCHOS && WTF_PLATFORM_WATCHOS
)
9930 if (_focusedElementInformation.placeholder.isEmpty())
9931 return fallbackLabelTextForUnlabeledInputFieldInZoomedFormControls(_focusedElementInformation.inputMode, _focusedElementInformation.elementType).createNSString().autorelease();
9932#endif
9933
9934 return _focusedElementInformation.placeholder.createNSString().autorelease();
9935}
9936
9937#pragma mark - UITextInputMultiDocument
9938
9939- (BOOL)_restoreFocusWithToken:(id <NSCopying, NSSecureCoding>)token
9940{
9941 if (_focusStateStack.isEmpty()) {
9942 ASSERT_NOT_REACHED()((void)0);
9943 return NO__objc_no;
9944 }
9945
9946 if (_focusStateStack.takeLast())
9947 [_webView.get() _decrementFocusPreservationCount];
9948
9949 // FIXME: Our current behavior in -_restoreFocusWithToken: does not force the web view to become first responder
9950 // by refocusing the currently focused element. As such, we return NO here so that UIKit will tell WKContentView
9951 // to become first responder in the future.
9952 return NO__objc_no;
9953}
9954
9955- (void)startRelinquishingFirstResponderToFocusedElement
9956{
9957 if (_isRelinquishingFirstResponderToFocusedElement)
9958 return;
9959
9960 _isRelinquishingFirstResponderToFocusedElement = YES__objc_yes;
9961 [_webView.get() _incrementFocusPreservationCount];
9962}
9963
9964- (void)stopRelinquishingFirstResponderToFocusedElement
9965{
9966 if (!_isRelinquishingFirstResponderToFocusedElement)
9967 return;
9968
9969 _isRelinquishingFirstResponderToFocusedElement = NO__objc_no;
9970 [_webView.get() _decrementFocusPreservationCount];
9971}
9972
9973- (void)_preserveFocusWithToken:(id <NSCopying, NSSecureCoding>)token destructively:(BOOL)destructively
9974{
9975 if (!_inputPeripheral) {
9976 [_webView.get() _incrementFocusPreservationCount];
9977 _focusStateStack.append(true);
9978 } else
9979 _focusStateStack.append(false);
9980}
9981
9982- (BOOL)_shouldIgnoreTouchEvent:(UIEvent *)event
9983{
9984 _touchEventsCanPreventNativeGestures = YES__objc_yes;
9985
9986#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
9987 if ([_imageAnalysisInteraction interactableItemExistsAtPoint:[_touchEventGestureRecognizer locationInView:self]])
9988 return YES__objc_yes;
9989#endif
9990
9991 return [self gestureRecognizer:_touchEventGestureRecognizer.get() isInterruptingMomentumScrollingWithEvent:event];
9992}
9993
9994- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer isInterruptingMomentumScrollingWithEvent:(UIEvent *)event
9995{
9996 NSSet<UITouch *> *touches = [event touchesForGestureRecognizer:gestureRecognizer];
9997 for (UITouch *touch in touches) {
9998 if (dynamic_objc_cast<UIScrollView>(touch.view)._wk_isInterruptingDeceleration)
9999 return YES__objc_yes;
10000 }
10001 return self._scroller._wk_isInterruptingDeceleration;
10002}
10003
10004#pragma mark - Implementation of WKActionSheetAssistantDelegate.
10005
10006- (std::optional<WebKit::InteractionInformationAtPosition>)positionInformationForActionSheetAssistant:(WKActionSheetAssistant *)assistant
10007{
10008 WebKit::InteractionInformationRequest request(_positionInformation.request.point);
10009 request.includeSnapshot = true;
10010 request.includeLinkIndicator = assistant.needsLinkIndicator;
10011 request.linkIndicatorShouldHaveLegacyMargins = !self._shouldUseContextMenus;
10012 request.gatherAnimations = [self.webView _allowAnimationControls];
10013
10014 if (![self ensurePositionInformationIsUpToDate:request])
10015 return std::nullopt;
10016
10017 return _positionInformation;
10018}
10019
10020- (void)updatePositionInformationForActionSheetAssistant:(WKActionSheetAssistant *)assistant
10021{
10022 _hasValidPositionInformation = NO__objc_no;
10023 WebKit::InteractionInformationRequest request(_positionInformation.request.point);
10024 request.includeSnapshot = true;
10025 request.includeLinkIndicator = assistant.needsLinkIndicator;
10026 request.linkIndicatorShouldHaveLegacyMargins = !self._shouldUseContextMenus;
10027 request.gatherAnimations = [self.webView _allowAnimationControls];
10028
10029 [self requestAsynchronousPositionInformationUpdate:request];
10030}
10031
10032- (void)actionSheetAssistant:(WKActionSheetAssistant *)assistant performAction:(WebKit::SheetAction)action
10033{
10034 if (action == WebKit::SheetAction::Copy && [self _tryToCopyLinkURLFromPlugin])
10035 return;
10036
10037 protect(_page)->performActionOnElement((uint32_t)action);
10038}
10039
10040- (void)_actionSheetAssistant:(WKActionSheetAssistant *)assistant performAction:(WebKit::SheetAction)action onElements:(Vector<WebCore::ElementContext>&&)elements
10041{
10042 protect(_page)->performActionOnElements((uint32_t)action, WTF::move(elements));
10043}
10044
10045- (void)actionSheetAssistant:(WKActionSheetAssistant *)assistant openElementAtLocation:(CGPoint)location
10046{
10047 [self _attemptSyntheticClickAtLocation:location modifierFlags:0];
10048}
10049
10050- (void)actionSheetAssistant:(WKActionSheetAssistant *)assistant shareElementWithURL:(NSURL *)url rect:(CGRect)boundingRect
10051{
10052 WebCore::ShareDataWithParsedURL shareData;
10053 shareData.url = { url };
10054 shareData.originator = WebCore::ShareDataOriginator::User;
10055 [self _showShareSheet:shareData inRect: { [self convertRect:boundingRect toView:self.webView] } completionHandler:nilnullptr];
10056}
10057
10058- (void)actionSheetAssistant:(WKActionSheetAssistant *)assistant shareElementWithImage:(UIImage *)image rect:(CGRect)boundingRect
10059{
10060 WebCore::ShareDataWithParsedURL shareData;
10061 RetainPtr fileName = adoptNS([[NSString alloc] initWithFormat:@"%@.png", (NSString*)WEB_UI_STRING("Shared Image", "Default name for the file created for a shared image with no explicit name.")WebCore::localizedString(((CFStringRef) __builtin___CFStringMakeConstantString
("" "Shared Image" "")))
.createNSString().get()]);
10062 shareData.files = { { fileName.get(), WebCore::SharedBuffer::create(protect(UIImagePNGRepresentation(image))) } };
10063 shareData.originator = WebCore::ShareDataOriginator::User;
10064 [self _showShareSheet:shareData inRect: { [self convertRect:boundingRect toView:self.webView] } completionHandler:nilnullptr];
10065}
10066
10067#if HAVE(APP_LINKS)(defined 1 && 1)
10068- (BOOL)actionSheetAssistant:(WKActionSheetAssistant *)assistant shouldIncludeAppLinkActionsForElement:(_WKActivatedElementInfo *)element
10069{
10070 return _page->uiClient().shouldIncludeAppLinkActionsForElement(element);
10071}
10072#endif
10073
10074- (BOOL)actionSheetAssistant:(WKActionSheetAssistant *)assistant showCustomSheetForElement:(_WKActivatedElementInfo *)element
10075{
10076 RetainPtr uiDelegate = static_cast<id <WKUIDelegatePrivate>>([_webView.get() UIDelegate]);
10077
10078 if ([uiDelegate respondsToSelector:@selector(_webView:showCustomSheetForElement:)]) {
10079ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
10080 if ([uiDelegate _webView:self.webView showCustomSheetForElement:element]) {
10081#if ENABLE(DRAG_SUPPORT)(defined 1 && 1)
10082 BOOL shouldCancelAllTouches = !_dragDropInteractionState.dragSession();
10083#else
10084 BOOL shouldCancelAllTouches = YES__objc_yes;
10085#endif
10086
10087 // Prevent tap-and-hold and panning.
10088 if (shouldCancelAllTouches)
10089 [UIApplication.sharedApplication _cancelAllTouches];
10090
10091 return YES__objc_yes;
10092 }
10093ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
10094 }
10095
10096 return NO__objc_no;
10097}
10098
10099- (BOOL)_tryToCopyLinkURLFromPlugin
10100{
10101 if (!_positionInformation.isLink || !_positionInformation.isInPlugin)
10102 return NO__objc_no;
10103
10104 RetainPtr urlToCopy = _positionInformation.url.createNSURL();
10105 if (!urlToCopy)
10106 return NO__objc_no;
10107
10108 [UIPasteboard _performAsDataOwner:[_webView.get() _effectiveDataOwner:self._dataOwnerForCopy] block:^{
10109 UIPasteboard.generalPasteboard.URL = urlToCopy.get();
10110 }];
10111 return YES__objc_yes;
10112}
10113
10114// FIXME: Likely we can remove this special case for watchOS.
10115#if !PLATFORM(WATCHOS)(defined WTF_PLATFORM_WATCHOS && WTF_PLATFORM_WATCHOS
)
10116- (CGRect)unoccludedWindowBoundsForActionSheetAssistant:(WKActionSheetAssistant *)assistant
10117{
10118 UIEdgeInsets contentInset = [[_webView.get() scrollView] adjustedContentInset];
10119 CGRect rect = UIEdgeInsetsInsetRect([_webView.get() bounds], contentInset);
10120 return [_webView.get() convertRect:rect toView:[self window]];
10121}
10122#endif
10123
10124- (RetainPtr<NSArray>)actionSheetAssistant:(WKActionSheetAssistant *)assistant decideActionsForElement:(_WKActivatedElementInfo *)element defaultActions:(RetainPtr<NSArray>)defaultActions
10125{
10126 return _page->uiClient().actionsForElement(element, WTF::move(defaultActions));
10127}
10128
10129- (void)actionSheetAssistant:(WKActionSheetAssistant *)assistant willStartInteractionWithElement:(_WKActivatedElementInfo *)element
10130{
10131 protect(_page)->startInteractionWithPositionInformation(_positionInformation);
10132}
10133
10134- (void)actionSheetAssistantDidStopInteraction:(WKActionSheetAssistant *)assistant
10135{
10136 protect(_page)->stopInteraction();
10137}
10138
10139- (NSDictionary *)dataDetectionContextForPositionInformation:(const WebKit::InteractionInformationAtPosition&)positionInformation
10140{
10141 RetainPtr<NSMutableDictionary> context;
10142 RetainPtr uiDelegate = static_cast<id <WKUIDelegatePrivate>>([_webView.get() UIDelegate]);
10143 if ([uiDelegate respondsToSelector:@selector(_dataDetectionContextForWebView:)])
10144 context = adoptNS([[uiDelegate _dataDetectionContextForWebView:self.webView] mutableCopy]);
10145
10146 if (!context)
10147 context = adoptNS([[NSMutableDictionary alloc] init]);
10148
10149#if ENABLE(DATA_DETECTION)(defined 1 && 1)
10150 if (!positionInformation.textBefore.isEmpty())
10151 context.get()[PAL::get_DataDetectorsUI_kDataDetectorsLeadingTextSingleton()] = positionInformation.textBefore.createNSString().get();
10152 if (!positionInformation.textAfter.isEmpty())
10153 context.get()[PAL::get_DataDetectorsUI_kDataDetectorsTrailingTextSingleton()] = positionInformation.textAfter.createNSString().get();
10154
10155 auto canShowPreview = ^{
10156 if (!positionInformation.url.createNSURL().get().iTunesStoreURL)
10157 return YES__objc_yes;
10158 if (!_page->websiteDataStore().isPersistent())
10159 return NO__objc_no;
10160#if ENABLE(ADVANCED_PRIVACY_PROTECTIONS)(defined 1 && 1)
10161 if (_page->advancedPrivacyProtectionsPolicies().contains(WebCore::AdvancedPrivacyProtections::BaselineProtections))
10162 return NO__objc_no;
10163#endif
10164 return YES__objc_yes;
10165 }();
10166
10167 if (!canShowPreview)
10168 context.get()[PAL::get_DataDetectorsUI_kDDContextMenuWantsPreviewKeySingleton()] = @NO__objc_no;
10169
10170 CGRect sourceRect;
10171 if (positionInformation.isLink && positionInformation.textIndicator)
10172 sourceRect = positionInformation.textIndicator->textBoundingRectInRootViewCoordinates();
10173 else if (!positionInformation.dataDetectorBounds.isEmpty())
10174 sourceRect = positionInformation.dataDetectorBounds;
10175 else
10176 sourceRect = positionInformation.bounds;
10177
10178 CGRect frameInContainerViewCoordinates = [self convertRect:sourceRect toView:self.containerForContextMenuHintPreviews];
10179 return [PAL::getDDContextMenuActionClassSingleton() updateContext:context.get() withSourceRect:frameInContainerViewCoordinates];
10180#else
10181 return context.autorelease();
10182#endif
10183}
10184
10185- (NSDictionary *)dataDetectionContextForActionSheetAssistant:(WKActionSheetAssistant *)assistant positionInformation:(const WebKit::InteractionInformationAtPosition&)positionInformation
10186{
10187 return [self dataDetectionContextForPositionInformation:positionInformation];
10188}
10189
10190- (NSString *)selectedTextForActionSheetAssistant:(WKActionSheetAssistant *)assistant
10191{
10192 return [self selectedText];
10193}
10194
10195- (void)actionSheetAssistant:(WKActionSheetAssistant *)assistant getAlternateURLForImage:(UIImage *)image completion:(void (^)(NSURL *alternateURL, NSDictionary *userInfo))completion
10196{
10197 RetainPtr uiDelegate = static_cast<id <WKUIDelegatePrivate>>([_webView.get() UIDelegate]);
10198 if ([uiDelegate respondsToSelector:@selector(_webView:getAlternateURLFromImage:completionHandler:)]) {
10199 [uiDelegate _webView:self.webView getAlternateURLFromImage:image completionHandler:^(NSURL *alternateURL, NSDictionary *userInfo) {
10200 completion(alternateURL, userInfo);
10201 }];
10202 } else
10203 completion(nilnullptr, nilnullptr);
10204}
10205
10206- (NSArray<UIMenuElement *> *)additionalMediaControlsContextMenuItemsForActionSheetAssistant:(WKActionSheetAssistant *)assistant
10207{
10208#if PLATFORM(VISION)(defined WTF_PLATFORM_VISION && WTF_PLATFORM_VISION)
10209 if (self.webView.fullscreenState == WKFullscreenStateInFullscreen)
10210 return @[ [self.webView fullScreenWindowSceneDimmingAction] ];
10211#endif
10212 return @[ ];
10213}
10214
10215#if USE(UICONTEXTMENU)(defined 1 && 1)
10216
10217- (UITargetedPreview *)createTargetedContextMenuHintForActionSheetAssistant:(WKActionSheetAssistant *)assistant
10218{
10219 return [self _createTargetedContextMenuHintPreviewIfPossible];
10220}
10221
10222- (void)removeContextMenuViewIfPossibleForActionSheetAssistant:(WKActionSheetAssistant *)assistant
10223{
10224 [self _removeContextMenuHintContainerIfPossible];
10225}
10226
10227- (void)actionSheetAssistantDidShowContextMenu:(WKActionSheetAssistant *)assistant
10228{
10229 [_webView.get() _didShowContextMenu];
10230}
10231
10232- (void)actionSheetAssistantDidDismissContextMenu:(WKActionSheetAssistant *)assistant
10233{
10234 [_webView.get() _didDismissContextMenu];
10235}
10236
10237- (void)_targetedPreviewContainerDidRemoveLastSubview:(WKTargetedPreviewContainer *)containerView
10238{
10239 if (_contextMenuHintContainerView == containerView)
10240 [self _removeContextMenuHintContainerIfPossible];
10241}
10242
10243#endif // USE(UICONTEXTMENU)
10244
10245- (BOOL)_shouldUseContextMenus
10246{
10247#if USE(UICONTEXTMENU)(defined 1 && 1)
10248 return linkedOnOrAfterSDKWithBehavior(SDKAlignedBehavior::HasUIContextMenuInteraction);
10249#endif
10250 return NO__objc_no;
10251}
10252
10253- (BOOL)_shouldUseContextMenusForFormControls
10254{
10255 return self._formControlRefreshEnabled && self._shouldUseContextMenus;
10256}
10257
10258- (BOOL)_shouldAvoidResizingWhenInputViewBoundsChange
10259{
10260 return _focusedElementInformation.shouldAvoidResizingWhenInputViewBoundsChange;
10261}
10262
10263- (BOOL)_shouldAvoidScrollingWhenFocusedContentIsVisible
10264{
10265 return _focusedElementInformation.shouldAvoidScrollingWhenFocusedContentIsVisible;
10266}
10267
10268- (BOOL)_shouldUseLegacySelectPopoverDismissalBehavior
10269{
10270 if (PAL::currentUserInterfaceIdiomIsSmallScreen())
10271 return NO__objc_no;
10272
10273 if (_focusedElementInformation.elementType != WebKit::InputType::Select)
10274 return NO__objc_no;
10275
10276 if (!_focusedElementInformation.shouldUseLegacySelectPopoverDismissalBehaviorInDataActivation)
10277 return NO__objc_no;
10278
10279 return WTF::IOSApplication::isDataActivation();
10280}
10281
10282#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
10283
10284- (BOOL)shouldDeferGestureDueToImageAnalysis:(UIGestureRecognizer *)gesture
10285{
10286 return gesture._wk_isTextInteractionLoupeGesture || gesture._wk_isTapAndAHalf;
10287}
10288
10289#endif // ENABLE(IMAGE_ANALYSIS)
10290
10291static WebCore::DataOwnerType coreDataOwnerType(_UIDataOwner platformType)
10292{
10293 switch (platformType) {
10294 case _UIDataOwnerUser:
10295 return WebCore::DataOwnerType::User;
10296 case _UIDataOwnerEnterprise:
10297 return WebCore::DataOwnerType::Enterprise;
10298 case _UIDataOwnerShared:
10299 return WebCore::DataOwnerType::Shared;
10300 case _UIDataOwnerUndefined:
10301 return WebCore::DataOwnerType::Undefined;
10302 }
10303 ASSERT_NOT_REACHED()((void)0);
10304 return WebCore::DataOwnerType::Undefined;
10305}
10306
10307- (WebCore::DataOwnerType)_dataOwnerForPasteboard:(WebKit::PasteboardAccessIntent)intent
10308{
10309 auto clientSuppliedDataOwner = intent == WebKit::PasteboardAccessIntent::Read ? self._dataOwnerForPaste : self._dataOwnerForCopy;
10310 return coreDataOwnerType([_webView.get() _effectiveDataOwner:clientSuppliedDataOwner]);
10311}
10312
10313- (RetainPtr<WKTargetedPreviewContainer>)_createPreviewContainerWithLayerName:(NSString *)layerName
10314{
10315 auto container = adoptNS([[WKTargetedPreviewContainer alloc] initWithContentView:self]);
10316 [container layer].anchorPoint = CGPointZero;
10317 [container layer].name = layerName;
10318 return container;
10319}
10320
10321- (UIView *)containerForDropPreviews
10322{
10323 if (!_dropPreviewContainerView) {
10324 _dropPreviewContainerView = [self _createPreviewContainerWithLayerName:@"Drop Preview Container"];
10325 [_interactionViewsContainerView addSubview:_dropPreviewContainerView.get()];
10326 }
10327
10328 ASSERT([_dropPreviewContainerView superview])((void)0);
10329 return _dropPreviewContainerView.get();
10330}
10331
10332- (void)_removeContainerForDropPreviews
10333{
10334 if (!_dropPreviewContainerView)
10335 return;
10336
10337 [std::exchange(_dropPreviewContainerView, nilnullptr) removeFromSuperview];
10338}
10339
10340- (UIView *)containerForDragPreviews
10341{
10342 if (!_dragPreviewContainerView) {
10343 _dragPreviewContainerView = [self _createPreviewContainerWithLayerName:@"Drag Preview Container"];
10344 [_interactionViewsContainerView addSubview:_dragPreviewContainerView.get()];
10345 }
10346
10347 ASSERT([_dragPreviewContainerView superview])((void)0);
10348 return _dragPreviewContainerView.get();
10349}
10350
10351- (void)_removeContainerForDragPreviews
10352{
10353 if (!_dragPreviewContainerView)
10354 return;
10355
10356 [std::exchange(_dragPreviewContainerView, nilnullptr) removeFromSuperview];
10357}
10358
10359- (UIView *)containerForContextMenuHintPreviews
10360{
10361 if (!_contextMenuHintContainerView) {
10362 _contextMenuHintContainerView = [self _createPreviewContainerWithLayerName:@"Context Menu Hint Preview Container"];
10363 RELEASE_LOG(ViewState, "%p - [pageProxyID=%" PRIu64 "] Created container for context menu hint previews: %p"clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogViewState
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("%p - [pageProxyID=%" "ll" "u" "] Created container for context menu hint previews: %p"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG228"
) = "%p - [pageProxyID=%" "ll" "u" "] Created container for context menu hint previews: %p"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("%p - [pageProxyID=%" "ll"
"u" "] Created container for context menu hint previews: %p"
, self, _page ? _page->identifier().toUInt64() : 0, _contextMenuHintContainerView
.get())]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "%p - [pageProxyID=%" "ll" "u" "] Created container for context menu hint previews: %p"
, self, _page ? _page->identifier().toUInt64() : 0, _contextMenuHintContainerView
.get()), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop
; }); } }) clang diagnostic pop
10364 , self, _page ? _page->identifier().toUInt64() : 0, _contextMenuHintContainerView.get())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogViewState
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("%p - [pageProxyID=%" "ll" "u" "] Created container for context menu hint previews: %p"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG228"
) = "%p - [pageProxyID=%" "ll" "u" "] Created container for context menu hint previews: %p"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("%p - [pageProxyID=%" "ll"
"u" "] Created container for context menu hint previews: %p"
, self, _page ? _page->identifier().toUInt64() : 0, _contextMenuHintContainerView
.get())]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "%p - [pageProxyID=%" "ll" "u" "] Created container for context menu hint previews: %p"
, self, _page ? _page->identifier().toUInt64() : 0, _contextMenuHintContainerView
.get()), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop
; }); } }) clang diagnostic pop
;
10365
10366 RetainPtr<UIView> containerView;
10367
10368 if (auto uiDelegate = static_cast<id<WKUIDelegatePrivate>>(self.webView.UIDelegate)) {
10369 if ([uiDelegate respondsToSelector:@selector(_contextMenuHintPreviewContainerViewForWebView:)])
10370 containerView = [uiDelegate _contextMenuHintPreviewContainerViewForWebView:self.webView];
10371 }
10372
10373 if (!containerView)
10374 containerView = _interactionViewsContainerView;
10375
10376 [containerView addSubview:_contextMenuHintContainerView.get()];
10377 }
10378
10379 ASSERT([_contextMenuHintContainerView superview])((void)0);
10380 return _contextMenuHintContainerView.get();
10381}
10382
10383- (void)_removeContainerForContextMenuHintPreviews
10384{
10385 if (!_contextMenuHintContainerView)
10386 return;
10387
10388 RELEASE_LOG(ViewState, "%p - [pageProxyID=%" PRIu64 "] Removing container for context menu hint previews: %p"clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogViewState
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("%p - [pageProxyID=%" "ll" "u" "] Removing container for context menu hint previews: %p"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG229"
) = "%p - [pageProxyID=%" "ll" "u" "] Removing container for context menu hint previews: %p"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("%p - [pageProxyID=%" "ll"
"u" "] Removing container for context menu hint previews: %p"
, self, _page ? _page->identifier().toUInt64() : 0, _contextMenuHintContainerView
.get())]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "%p - [pageProxyID=%" "ll" "u" "] Removing container for context menu hint previews: %p"
, self, _page ? _page->identifier().toUInt64() : 0, _contextMenuHintContainerView
.get()), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop
; }); } }) clang diagnostic pop
10389 , self, _page ? _page->identifier().toUInt64() : 0, _contextMenuHintContainerView.get())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogViewState
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("%p - [pageProxyID=%" "ll" "u" "] Removing container for context menu hint previews: %p"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG229"
) = "%p - [pageProxyID=%" "ll" "u" "] Removing container for context menu hint previews: %p"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("%p - [pageProxyID=%" "ll"
"u" "] Removing container for context menu hint previews: %p"
, self, _page ? _page->identifier().toUInt64() : 0, _contextMenuHintContainerView
.get())]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "%p - [pageProxyID=%" "ll" "u" "] Removing container for context menu hint previews: %p"
, self, _page ? _page->identifier().toUInt64() : 0, _contextMenuHintContainerView
.get()), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop
; }); } }) clang diagnostic pop
;
10390 [std::exchange(_contextMenuHintContainerView, nilnullptr) removeFromSuperview];
10391
10392 _scrollViewForTargetedPreview = nilnullptr;
10393 _scrollViewForTargetedPreviewInitialOffset = CGPointZero;
10394}
10395
10396- (void)_updateFrameOfContainerForContextMenuHintPreviewsIfNeeded
10397{
10398 if (!_contextMenuHintContainerView)
10399 return;
10400
10401 CGPoint newOffset = [protect(_scrollViewForTargetedPreview) convertPoint:CGPointZero toView:[protect(_contextMenuHintContainerView.get()) superview]];
10402
10403 CGRect frame = [_contextMenuHintContainerView frame];
10404 frame.origin.x = newOffset.x - _scrollViewForTargetedPreviewInitialOffset.x;
10405 frame.origin.y = newOffset.y - _scrollViewForTargetedPreviewInitialOffset.y;
10406 [_contextMenuHintContainerView setFrame:frame];
10407}
10408
10409- (void)_updateTargetedPreviewScrollViewUsingContainerScrollingNodeID:(std::optional<WebCore::ScrollingNodeID>)scrollingNodeID
10410{
10411 if (scrollingNodeID) {
10412 if (RetainPtr scrollViewForScrollingNode = [self _scrollViewForScrollingNodeID:scrollingNodeID])
10413 _scrollViewForTargetedPreview = scrollViewForScrollingNode.get();
10414 }
10415
10416 if (!_scrollViewForTargetedPreview)
10417 _scrollViewForTargetedPreview = self.webView.scrollView;
10418
10419 _scrollViewForTargetedPreviewInitialOffset = [protect(_scrollViewForTargetedPreview) convertPoint:CGPointZero toView:[protect(_contextMenuHintContainerView.get()) superview]];
10420}
10421
10422#pragma mark - WKDeferringGestureRecognizerDelegate
10423
10424- (WebKit::ShouldDeferGestures)deferringGestureRecognizer:(WKDeferringGestureRecognizer *)deferringGestureRecognizer willBeginTouchesWithEvent:(UIEvent *)event
10425{
10426 protect(self.gestureRecognizerConsistencyEnforcer)->beginTracking(deferringGestureRecognizer);
10427
10428#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
10429 if ([_imageAnalysisInteraction interactableItemExistsAtPoint:[deferringGestureRecognizer locationInView:self]])
10430 return WebKit::ShouldDeferGestures::No;
10431#endif
10432
10433 return [self gestureRecognizer:deferringGestureRecognizer isInterruptingMomentumScrollingWithEvent:event] ? WebKit::ShouldDeferGestures::No : WebKit::ShouldDeferGestures::Yes;
10434}
10435
10436- (void)deferringGestureRecognizer:(WKDeferringGestureRecognizer *)deferringGestureRecognizer didTransitionToState:(UIGestureRecognizerState)state
10437{
10438 if (state == UIGestureRecognizerStateEnded || state == UIGestureRecognizerStateFailed || state == UIGestureRecognizerStateCancelled)
10439 protect(self.gestureRecognizerConsistencyEnforcer)->endTracking(deferringGestureRecognizer);
10440}
10441
10442- (void)deferringGestureRecognizer:(WKDeferringGestureRecognizer *)deferringGestureRecognizer didEndTouchesWithEvent:(UIEvent *)event
10443{
10444 protect(protect(self).get().gestureRecognizerConsistencyEnforcer).get().endTracking(deferringGestureRecognizer);
10445
10446 if (deferringGestureRecognizer.state != UIGestureRecognizerStatePossible)
10447 return;
10448
10449 if (_page->isHandlingPreventableTouchStart() && [self _isTouchStartDeferringGesture:deferringGestureRecognizer])
10450 return;
10451
10452 if (_page->isHandlingPreventableTouchMove() && deferringGestureRecognizer == _touchMoveDeferringGestureRecognizer)
10453 return;
10454
10455 if (_page->isHandlingPreventableTouchEnd() && [self _isTouchEndDeferringGesture:deferringGestureRecognizer])
10456 return;
10457
10458 if ([_touchEventGestureRecognizer state] == UIGestureRecognizerStatePossible)
10459 return;
10460
10461 // In the case where the touch event gesture recognizer has failed or ended already and we are not in the middle of handling
10462 // an asynchronous (but preventable) touch event, this is our last chance to lift the gesture "gate" by failing the deferring
10463 // gesture recognizer.
10464 deferringGestureRecognizer.state = UIGestureRecognizerStateFailed;
10465}
10466
10467- (BOOL)deferringGestureRecognizer:(WKDeferringGestureRecognizer *)deferringGestureRecognizer shouldDeferOtherGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
10468{
10469#if ENABLE(IOS_TOUCH_EVENTS)(defined 0 && 0)
10470 if ([self _touchEventsMustRequireGestureRecognizerToFail:gestureRecognizer])
10471 return NO__objc_no;
10472
10473 if (_failedTouchStartDeferringGestures && _failedTouchStartDeferringGestures->contains(deferringGestureRecognizer)
10474 && deferringGestureRecognizer.state == UIGestureRecognizerStatePossible) {
10475 // This deferring gesture no longer has an oppportunity to defer native gestures (either because the touch region did not have any
10476 // active touch event listeners, or because any active touch event listeners on the page have already executed, and did not prevent
10477 // default). UIKit may have already reset the gesture to Possible state underneath us, in which case we still need to treat it as
10478 // if it has already failed; otherwise, we will incorrectly defer other gestures in the web view, such as scroll view pinching.
10479 return NO__objc_no;
10480 }
10481
10482 if (gestureRecognizer == _keyboardDismissalGestureRecognizer)
10483 return NO__objc_no;
10484
10485 auto webView = _webView.getAutoreleased();
10486 auto view = gestureRecognizer.view;
10487 BOOL gestureIsInstalledOnOrUnderWebView = NO__objc_no;
10488 while (view) {
10489 if (view == webView) {
10490 gestureIsInstalledOnOrUnderWebView = YES__objc_yes;
10491 break;
10492 }
10493 view = view.superview;
10494 }
10495
10496 if (!gestureIsInstalledOnOrUnderWebView && ![self _gestureRecognizerCanBePreventedByTouchEvents:gestureRecognizer])
10497 return NO__objc_no;
10498
10499 if ([gestureRecognizer isKindOfClass:WKDeferringGestureRecognizer.class])
10500 return NO__objc_no;
10501
10502 if (gestureRecognizer == _touchEventGestureRecognizer)
10503 return NO__objc_no;
10504
10505#if HAVE(UIKIT_WITH_MOUSE_SUPPORT)(defined 1 && 1)
10506 if ([_mouseInteraction hasGesture:gestureRecognizer])
10507 return NO__objc_no;
10508#endif
10509
10510#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
10511 if (deferringGestureRecognizer == _imageAnalysisDeferringGestureRecognizer)
10512 return [self shouldDeferGestureDueToImageAnalysis:gestureRecognizer];
10513#endif
10514
10515 if (deferringGestureRecognizer == _touchMoveDeferringGestureRecognizer)
10516 return [gestureRecognizer isKindOfClass:UIPanGestureRecognizer.class] || [gestureRecognizer isKindOfClass:UIPinchGestureRecognizer.class];
10517
10518 BOOL mayDelayReset = [&]() -> BOOL {
10519 if ([self _isContextMenuGestureRecognizerForFailureRelationships:gestureRecognizer])
10520 return YES__objc_yes;
10521
10522#if ENABLE(DRAG_SUPPORT)(defined 1 && 1)
10523 if ([self _isDragInitiationGestureRecognizer:gestureRecognizer])
10524 return YES__objc_yes;
10525#endif
10526
10527#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
10528 if (gestureRecognizer == _imageAnalysisGestureRecognizer)
10529 return YES__objc_yes;
10530#endif
10531
10532 if (gestureRecognizer._wk_isTapAndAHalf)
10533 return YES__objc_yes;
10534
10535 if (gestureRecognizer._wk_isTextInteractionLoupeGesture)
10536 return YES__objc_yes;
10537
10538 if (gestureRecognizer == _highlightLongPressGestureRecognizer)
10539 return YES__objc_yes;
10540
10541 if (auto *tapGesture = dynamic_objc_cast<UITapGestureRecognizer>(gestureRecognizer))
10542 return tapGesture.numberOfTapsRequired > 1 && tapGesture.numberOfTouchesRequired < 2;
10543
10544 return NO__objc_no;
10545 }();
10546
10547 BOOL isSyntheticTap = [gestureRecognizer isKindOfClass:WKSyntheticTapGestureRecognizer.class];
10548 if ([gestureRecognizer isKindOfClass:UITapGestureRecognizer.class]) {
10549 if (deferringGestureRecognizer == _touchEndDeferringGestureRecognizerForSyntheticTapGestures)
10550 return isSyntheticTap;
10551
10552 if (deferringGestureRecognizer == _touchEndDeferringGestureRecognizerForDelayedResettableGestures)
10553 return !isSyntheticTap && mayDelayReset;
10554
10555 if (deferringGestureRecognizer == _touchEndDeferringGestureRecognizerForImmediatelyResettableGestures)
10556 return !isSyntheticTap && !mayDelayReset;
10557 }
10558
10559 if (isSyntheticTap)
10560 return deferringGestureRecognizer == _touchStartDeferringGestureRecognizerForSyntheticTapGestures;
10561
10562 if (mayDelayReset)
10563 return deferringGestureRecognizer == _touchStartDeferringGestureRecognizerForDelayedResettableGestures;
10564
10565 return deferringGestureRecognizer == _touchStartDeferringGestureRecognizerForImmediatelyResettableGestures;
10566#else
10567 UNUSED_PARAM(deferringGestureRecognizer)(void)deferringGestureRecognizer;
10568 UNUSED_PARAM(gestureRecognizer)(void)gestureRecognizer;
10569 return NO__objc_no;
10570#endif
10571}
10572
10573#if ENABLE(DRAG_SUPPORT)(defined 1 && 1)
10574
10575static BOOL shouldEnableDragInteractionForPolicy(_WKDragInteractionPolicy policy)
10576{
10577 switch (policy) {
10578 case _WKDragInteractionPolicyAlwaysEnable:
10579 return YES__objc_yes;
10580 case _WKDragInteractionPolicyAlwaysDisable:
10581 return NO__objc_no;
10582 default:
10583 return [UIDragInteraction isEnabledByDefault];
10584 }
10585}
10586
10587- (void)_didChangeDragInteractionPolicy
10588{
10589 [_dragInteraction setEnabled:shouldEnableDragInteractionForPolicy(self.webView._dragInteractionPolicy)];
10590}
10591
10592- (NSTimeInterval)dragLiftDelay
10593{
10594 static const NSTimeInterval mediumDragLiftDelay = 0.5;
10595 static const NSTimeInterval longDragLiftDelay = 0.65;
10596 auto dragLiftDelay = self.webView.configuration._dragLiftDelay;
10597 if (dragLiftDelay == _WKDragLiftDelayMedium)
10598 return mediumDragLiftDelay;
10599 if (dragLiftDelay == _WKDragLiftDelayLong)
10600 return longDragLiftDelay;
10601 return _UIDragInteractionDefaultLiftDelay();
10602}
10603
10604- (id <WKUIDelegatePrivate>)webViewUIDelegate
10605{
10606 return (id <WKUIDelegatePrivate>)[_webView.get() UIDelegate];
10607}
10608
10609- (Class)_dragInteractionClass
10610{
10611#if USE(BROWSERENGINEKIT)(defined 1 && 1)
10612 if (self.shouldUseAsyncInteractions)
10613 return [BEDragInteraction class];
10614#endif
10615 return UIDragInteraction.class;
10616}
10617
10618- (void)setUpDragAndDropInteractions
10619{
10620 _dragInteraction = adoptNS([[self._dragInteractionClass alloc] initWithDelegate:self]);
10621 _dropInteraction = adoptNS([[UIDropInteraction alloc] initWithDelegate:self]);
10622 [_dragInteraction setEnabled:shouldEnableDragInteractionForPolicy(self.webView._dragInteractionPolicy)];
10623#if HAVE(UIKIT_WITH_MOUSE_SUPPORT)(defined 1 && 1)
10624 if (!self.shouldUseAsyncInteractions) {
10625 [_dragInteraction _setLiftDelay:self.dragLiftDelay];
10626 [_dragInteraction _setAllowsPointerDragBeforeLiftDelay:NO__objc_no];
10627 }
10628#endif
10629
10630 [self addInteraction:_dragInteraction.get()];
10631 [self addInteraction:_dropInteraction.get()];
10632}
10633
10634- (void)teardownDragAndDropInteractions
10635{
10636 if (_dragInteraction)
10637 [self removeInteraction:_dragInteraction.get()];
10638
10639 if (_dropInteraction)
10640 [self removeInteraction:_dropInteraction.get()];
10641
10642 _dragInteraction = nilnullptr;
10643 _dropInteraction = nilnullptr;
10644
10645 [self cleanUpDragSourceSessionState];
10646}
10647
10648- (void)_startDrag:(RetainPtr<CGImageRef>)image item:(const WebCore::DragItem&)item nodeID:(std::optional<WebCore::NodeIdentifier>)nodeID
10649{
10650 ASSERT(item.sourceAction)((void)0);
10651
10652#if ENABLE(MODEL_PROCESS)(defined 0 && 0)
10653 _dragDropInteractionState.setElementIdentifier(nodeID);
10654 if (item.modelLayerID && _page) {
10655 if (RefPtr modelPresentationManager = _page->modelPresentationManagerProxy()) {
10656 if (RetainPtr viewForDragPreview = modelPresentationManager->startDragForModel(*item.modelLayerID)) {
10657 _dragDropInteractionState.stageDragItem(item, viewForDragPreview);
10658 return;
10659 }
10660 }
10661 }
10662#endif
10663
10664 if (item.promisedAttachmentInfo)
10665 [self _prepareToDragPromisedAttachment:item.promisedAttachmentInfo];
10666
10667 auto dragImage = adoptNS([[UIImage alloc] initWithCGImage:image.get() scale:protect(_page)->deviceScaleFactor() orientation:UIImageOrientationUp]);
10668 _dragDropInteractionState.stageDragItem(item, dragImage.get());
10669}
10670
10671- (void)_didHandleAdditionalDragItemsRequest:(BOOL)added
10672{
10673 auto completion = _dragDropInteractionState.takeAddDragItemCompletionBlock();
10674 if (!completion)
10675 return;
10676
10677 auto *registrationLists = [[WebItemProviderPasteboard sharedInstance] takeRegistrationLists];
10678 if (!added || ![registrationLists count] || !_dragDropInteractionState.hasStagedDragSource()) {
10679 _dragDropInteractionState.clearStagedDragSource();
10680 completion(@[ ]);
10681 return;
10682 }
10683
10684 auto stagedDragSource = _dragDropInteractionState.stagedDragSource();
10685 NSArray *dragItemsToAdd = [self _itemsForBeginningOrAddingToSessionWithRegistrationLists:registrationLists stagedDragSource:stagedDragSource];
10686
10687 RELEASE_LOG(DragAndDrop, "Drag session: %p adding %tu items", _dragDropInteractionState.dragSession(), dragItemsToAdd.count)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Drag session: %p adding %tu items"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG230"
) = "Drag session: %p adding %tu items"; uint8_t _Alignas(16)
__attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Drag session: %p adding %tu items", _dragDropInteractionState
.dragSession(), dragItemsToAdd.count)]; _os_log_impl(&__dso_handle
, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format
(_os_fmt_buf, "Drag session: %p adding %tu items", _dragDropInteractionState
.dragSession(), dragItemsToAdd.count), (uint32_t)sizeof(_os_fmt_buf
)) clang diagnostic pop ; }); } }) clang diagnostic pop
;
10688 _dragDropInteractionState.clearStagedDragSource(dragItemsToAdd.count ? WebKit::DragDropInteractionState::DidBecomeActive::Yes : WebKit::DragDropInteractionState::DidBecomeActive::No);
10689
10690 completion(dragItemsToAdd);
10691
10692 if (dragItemsToAdd.count)
10693 protect(_page)->didStartDrag();
10694}
10695
10696- (void)_didHandleDragStartRequest:(BOOL)started
10697{
10698 BlockPtr<void()> savedCompletionBlock = _dragDropInteractionState.takeDragStartCompletionBlock();
10699 ASSERT(savedCompletionBlock)((void)0);
10700
10701 RELEASE_LOG(DragAndDrop, "Handling drag start request (started: %d, completion block: %p)", started, savedCompletionBlock.get())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Handling drag start request (started: %d, completion block: %p)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG231"
) = "Handling drag start request (started: %d, completion block: %p)"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Handling drag start request (started: %d, completion block: %p)"
, started, savedCompletionBlock.get())]; _os_log_impl(&__dso_handle
, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format
(_os_fmt_buf, "Handling drag start request (started: %d, completion block: %p)"
, started, savedCompletionBlock.get()), (uint32_t)sizeof(_os_fmt_buf
)) clang diagnostic pop ; }); } }) clang diagnostic pop
;
10702 if (savedCompletionBlock)
10703 savedCompletionBlock();
10704
10705 if (!protect(_dragDropInteractionState.dragSession()).get().items.count) {
10706 auto positionForDragEnd = WebCore::roundedIntPoint(_dragDropInteractionState.adjustedPositionForDragEnd());
10707 [self cleanUpDragSourceSessionState];
10708 if (started) {
10709 // A client of the Objective C SPI or UIKit might have prevented the drag from beginning entirely in the UI process, in which case
10710 // we need to balance the `dragstart` event with a `dragend`.
10711 protect(_page)->dragEnded(positionForDragEnd, positionForDragEnd, { });
10712 }
10713 }
10714}
10715
10716- (void)computeClientAndGlobalPointsForDropSession:(id <UIDropSession>)session outClientPoint:(CGPoint *)outClientPoint outGlobalPoint:(CGPoint *)outGlobalPoint
10717{
10718 // FIXME: This makes the behavior of drag events on iOS consistent with other synthetic mouse events on iOS (see WebPage::completeSyntheticClick).
10719 // However, we should experiment with making the client position relative to the window and the global position in document coordinates. See
10720 // https://bugs.webkit.org/show_bug.cgi?id=173855 for more details.
10721 auto locationInContentView = [session locationInView:self];
10722 if (outClientPoint)
10723 *outClientPoint = locationInContentView;
10724
10725 if (outGlobalPoint)
10726 *outGlobalPoint = locationInContentView;
10727}
10728
10729static UIDropOperation dropOperationForWebCoreDragOperation(std::optional<WebCore::DragOperation> operation)
10730{
10731 if (operation) {
10732 if (*operation == WebCore::DragOperation::Move)
10733 return UIDropOperationMove;
10734 if (*operation == WebCore::DragOperation::Copy)
10735 return UIDropOperationCopy;
10736 }
10737 return UIDropOperationCancel;
10738}
10739
10740static std::optional<WebCore::DragOperation> coreDragOperationForUIDropOperation(UIDropOperation dropOperation)
10741{
10742 switch (dropOperation) {
10743 case UIDropOperationCancel:
10744 return std::nullopt;
10745 case UIDropOperationForbidden:
10746 return WebCore::DragOperation::Private;
10747 case UIDropOperationCopy:
10748 return WebCore::DragOperation::Copy;
10749 case UIDropOperationMove:
10750 return WebCore::DragOperation::Move;
10751 }
10752 ASSERT_NOT_REACHED()((void)0);
10753 return std::nullopt;
10754}
10755
10756- (WebCore::DragData)dragDataForDropSession:(id <UIDropSession>)session dragDestinationAction:(WKDragDestinationAction)dragDestinationAction
10757{
10758 CGPoint global;
10759 CGPoint client;
10760 [self computeClientAndGlobalPointsForDropSession:session outClientPoint:&client outGlobalPoint:&global];
10761
10762 auto dragOperationMask = WebCore::anyDragOperation();
10763 if (!session.allowsMoveOperation)
10764 dragOperationMask.remove(WebCore::DragOperation::Move);
10765
10766 return {
10767 session,
10768 WebCore::roundedIntPoint(client),
10769 WebCore::roundedIntPoint(global),
10770 dragOperationMask,
10771 { },
10772 WebKit::coreDragDestinationActionMask(dragDestinationAction),
10773 _page->webPageIDInMainFrameProcess()
10774 };
10775}
10776
10777- (void)cleanUpDragSourceSessionState
10778{
10779 if (_waitingForEditDragSnapshot)
10780 return;
10781
10782 if (_dragDropInteractionState.dragSession() || _dragDropInteractionState.isPerformingDrop())
10783 RELEASE_LOG(DragAndDrop, "Cleaning up dragging state (has pending operation: %d)", [[WebItemProviderPasteboard sharedInstance] hasPendingOperation])clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Cleaning up dragging state (has pending operation: %d)"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG232"
) = "Cleaning up dragging state (has pending operation: %d)";
uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Cleaning up dragging state (has pending operation: %d)"
, [[WebItemProviderPasteboard sharedInstance] hasPendingOperation
])]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str
, (uint8_t *)__builtin_os_log_format(_os_fmt_buf, "Cleaning up dragging state (has pending operation: %d)"
, [[WebItemProviderPasteboard sharedInstance] hasPendingOperation
]), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop ; });
} }) clang diagnostic pop
;
10784
10785 if (![[WebItemProviderPasteboard sharedInstance] hasPendingOperation]) {
10786 // If we're performing a drag operation, don't clear out the pasteboard yet, since another web view may still require access to it.
10787 // The pasteboard will be cleared after the last client is finished performing a drag operation using the item providers.
10788 [[WebItemProviderPasteboard sharedInstance] setItemProviders:nilnullptr];
10789 }
10790
10791 [[WebItemProviderPasteboard sharedInstance] clearRegistrationLists];
10792 [self _restoreEditMenuIfNeeded];
10793
10794#if ENABLE(MODEL_PROCESS)(defined 0 && 0)
10795 if (_page) {
10796 if (RefPtr modelPresentationManager = _page->modelPresentationManagerProxy())
10797 modelPresentationManager->doneWithCurrentDragSession();
10798
10799 if (_dragDropInteractionState.nodeIdentifier())
10800 _page->modelDragEnded(_dragDropInteractionState.nodeIdentifier().value());
10801 }
10802#endif
10803
10804 [self _removeContainerForDragPreviews];
10805 [std::exchange(_visibleContentViewSnapshot, nilnullptr) removeFromSuperview];
10806 [self _removeDropCaret];
10807 _shouldRestoreEditMenuAfterDrop = NO__objc_no;
10808
10809 _dragDropInteractionState.dragAndDropSessionsDidBecomeInactive();
10810 _dragDropInteractionState = { };
10811}
10812
10813- (void)_insertDropCaret:(CGRect)rect
10814{
10815#if HAVE(UI_TEXT_CURSOR_DROP_POSITION_ANIMATOR)(defined 1 && 1)
10816 if (self._shouldUseTextCursorDragAnimator) {
10817 _editDropTextCursorView = [adoptNS([[UITextSelectionDisplayInteraction alloc] initWithTextInput:self delegate:self]) cursorView];
10818 [self addSubview:_editDropTextCursorView.get()];
10819 [_editDropTextCursorView setFrame:rect];
10820 _editDropCaretAnimator = adoptNS([[UITextCursorDropPositionAnimator alloc] initWithTextCursorView:_editDropTextCursorView.get() textInput:self]);
10821 [_editDropCaretAnimator setCursorVisible:YES__objc_yes animated:YES__objc_yes];
10822 [_editDropCaretAnimator placeCursorAtPosition:[WKTextPosition textPositionWithRect:rect] animated:NO__objc_no];
10823 return;
10824 }
10825#endif // HAVE(UI_TEXT_CURSOR_DROP_POSITION_ANIMATOR)
10826 _editDropCaretView = adoptNS([[_UITextDragCaretView alloc] initWithTextInputView:self]);
10827 [_editDropCaretView insertAtPosition:[WKTextPosition textPositionWithRect:rect]];
10828}
10829
10830- (void)_removeDropCaret
10831{
10832 [std::exchange(_editDropCaretView, nilnullptr) remove];
10833#if HAVE(UI_TEXT_CURSOR_DROP_POSITION_ANIMATOR)(defined 1 && 1)
10834 [std::exchange(_editDropCaretAnimator, nilnullptr) setCursorVisible:NO__objc_no animated:NO__objc_no];
10835 [std::exchange(_editDropTextCursorView, nilnullptr) removeFromSuperview];
10836#endif
10837}
10838
10839static NSArray<NSItemProvider *> *extractItemProvidersFromDragItems(NSArray<UIDragItem *> *dragItems)
10840{
10841 NSMutableArray<NSItemProvider *> *providers = [NSMutableArray array];
10842 for (UIDragItem *item in dragItems) {
10843 if (NSItemProvider *provider = item.itemProvider)
10844 [providers addObject:provider];
10845 }
10846 return providers;
10847}
10848
10849static NSArray<NSItemProvider *> *extractItemProvidersFromDropSession(id <UIDropSession> session)
10850{
10851 return extractItemProvidersFromDragItems(session.items);
10852}
10853
10854- (void)_willReceiveEditDragSnapshot
10855{
10856 _waitingForEditDragSnapshot = YES__objc_yes;
10857}
10858
10859- (void)_didReceiveEditDragSnapshot:(RefPtr<WebCore::TextIndicator>&&)textIndicator
10860{
10861 _waitingForEditDragSnapshot = NO__objc_no;
10862
10863 [self _deliverDelayedDropPreviewIfPossible:WTF::move(textIndicator)];
10864 [self cleanUpDragSourceSessionState];
10865
10866 if (auto action = WTF::move(_actionToPerformAfterReceivingEditDragSnapshot))
10867 action();
10868}
10869
10870- (void)_deliverDelayedDropPreviewIfPossible:(RefPtr<WebCore::TextIndicator>&&)textIndicator
10871{
10872 if (!_visibleContentViewSnapshot)
10873 return;
10874
10875 if (!textIndicator)
10876 return;
10877
10878 if (!textIndicator->contentImage())
10879 return;
10880
10881 RefPtr snapshotWithoutSelection = textIndicator->contentImageWithoutSelection();
10882 if (!snapshotWithoutSelection)
10883 return;
10884
10885 auto unselectedSnapshotImage = snapshotWithoutSelection->nativeImage();
10886 if (!unselectedSnapshotImage)
10887 return;
10888
10889 if (!_dropAnimationCount)
10890 return;
10891
10892 auto unselectedContentImageForEditDrag = adoptNS([[UIImage alloc] initWithCGImage:unselectedSnapshotImage->platformImage().get() scale:protect(_page)->deviceScaleFactor() orientation:UIImageOrientationUp]);
10893 _unselectedContentSnapshot = adoptNS([[UIImageView alloc] initWithImage:unselectedContentImageForEditDrag.get()]);
10894 [_unselectedContentSnapshot setFrame:textIndicator->contentImageWithoutSelectionRectInRootViewCoordinates()];
10895
10896 [self insertSubview:_unselectedContentSnapshot.get() belowSubview:_visibleContentViewSnapshot.get()];
10897 _dragDropInteractionState.deliverDelayedDropPreview(self, self.containerForDropPreviews, WTF::move(textIndicator));
10898}
10899
10900- (void)_didPerformDragOperation:(BOOL)handled
10901{
10902 RELEASE_LOG(DragAndDrop, "Finished performing drag controller operation (handled: %d)", handled)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Finished performing drag controller operation (handled: %d)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG233"
) = "Finished performing drag controller operation (handled: %d)"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Finished performing drag controller operation (handled: %d)"
, handled)]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "Finished performing drag controller operation (handled: %d)"
, handled), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop
; }); } }) clang diagnostic pop
;
10903 [[WebItemProviderPasteboard sharedInstance] decrementPendingOperationCount];
10904 RetainPtr dropSession = _dragDropInteractionState.dropSession();
10905 if ([self.webViewUIDelegate respondsToSelector:@selector(_webView:dataInteractionOperationWasHandled:forSession:itemProviders:)])
10906 [self.webViewUIDelegate _webView:self.webView dataInteractionOperationWasHandled:handled forSession:dropSession.get() itemProviders:[WebItemProviderPasteboard sharedInstance].itemProviders];
10907
10908 CGPoint global;
10909 CGPoint client;
10910 [self computeClientAndGlobalPointsForDropSession:dropSession.get() outClientPoint:&client outGlobalPoint:&global];
10911 [self cleanUpDragSourceSessionState];
10912 auto currentDragOperation = _page->currentDragOperation();
10913 protect(_page)->dragEnded(WebCore::roundedIntPoint(client), WebCore::roundedIntPoint(global), currentDragOperation ? *currentDragOperation : OptionSet<WebCore::DragOperation>({ }));
10914}
10915
10916- (void)_didChangeDragCaretRect:(CGRect)previousRect currentRect:(CGRect)rect
10917{
10918 BOOL previousRectIsEmpty = CGRectIsEmpty(previousRect);
10919 BOOL currentRectIsEmpty = CGRectIsEmpty(rect);
10920 if (previousRectIsEmpty && currentRectIsEmpty)
10921 return;
10922
10923 if (previousRectIsEmpty) {
10924 [self _insertDropCaret:rect];
10925 return;
10926 }
10927
10928 if (currentRectIsEmpty) {
10929 [self _removeDropCaret];
10930 return;
10931 }
10932
10933 RetainPtr caretPosition = [WKTextPosition textPositionWithRect:rect];
10934#if HAVE(UI_TEXT_CURSOR_DROP_POSITION_ANIMATOR)(defined 1 && 1)
10935 [_editDropCaretAnimator placeCursorAtPosition:caretPosition.get() animated:YES__objc_yes];
10936#endif
10937 [_editDropCaretView updateToPosition:caretPosition.get()];
10938}
10939
10940- (void)_prepareToDragPromisedAttachment:(const WebCore::PromisedAttachmentInfo&)info
10941{
10942 auto session = retainPtr(_dragDropInteractionState.dragSession());
10943 if (!session) {
10944 ASSERT_NOT_REACHED()((void)0);
10945 return;
10946 }
10947
10948 RELEASE_LOG(DragAndDrop, "Drag session: %p preparing to drag with attachment identifier: %s", session.get(), info.attachmentIdentifier.utf8().data())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Drag session: %p preparing to drag with attachment identifier: %s"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG234"
) = "Drag session: %p preparing to drag with attachment identifier: %s"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Drag session: %p preparing to drag with attachment identifier: %s"
, session.get(), info.attachmentIdentifier.utf8().data())]; _os_log_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Drag session: %p preparing to drag with attachment identifier: %s"
, session.get(), info.attachmentIdentifier.utf8().data()), (uint32_t
)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
10949
10950 RetainPtr<NSString> utiType;
10951 RetainPtr<NSString> fileName;
10952 if (auto attachment = protect(_page)->attachmentForIdentifier(info.attachmentIdentifier)) {
10953 utiType = attachment->utiType().createNSString();
10954 fileName = attachment->fileName().createNSString();
10955 }
10956
10957 auto registrationList = adoptNS([[WebItemProviderRegistrationInfoList alloc] init]);
10958 [registrationList setPreferredPresentationStyle:WebPreferredPresentationStyleAttachment];
10959 if ([fileName length])
10960 [registrationList setSuggestedName:fileName.get()];
10961 for (size_t index = 0; index < info.additionalTypesAndData.size(); ++index) {
10962 auto nsData = protect(info.additionalTypesAndData[index].second)->createNSData();
10963 [registrationList addData:nsData.get() forType:info.additionalTypesAndData[index].first.createNSString().get()];
10964 }
10965
10966 [registrationList addPromisedType:utiType.get() fileCallback:[session = WTF::move(session), weakSelf = WeakObjCPtr<WKContentView>(self), info] (WebItemProviderFileCallback callback) {
10967 auto strongSelf = weakSelf.get();
10968 if (!strongSelf) {
10969 callback(nilnullptr, [NSError errorWithDomain:WKErrorDomain code:WKErrorWebViewInvalidated userInfo:nilnullptr]);
10970 return;
10971 }
10972
10973 RetainPtr temporaryBlobDirectory = FileSystem::createTemporaryDirectory(@"blobs");
10974 RetainPtr destinationURL = [NSURL fileURLWithPath:[temporaryBlobDirectory.get() stringByAppendingPathComponent:[NSUUID UUID].UUIDString] isDirectory:NO__objc_no];
10975
10976 if (auto attachment = protect(strongSelf->_page)->attachmentForIdentifier(info.attachmentIdentifier); attachment && !attachment->isEmpty()) {
10977 attachment->doWithFileWrapper([&](NSFileWrapper *fileWrapper) {
10978 RELEASE_LOG(DragAndDrop, "Drag session: %p delivering promised attachment: %s at path: %@", session.get(), info.attachmentIdentifier.utf8().data(), destinationURL.get().path)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Drag session: %p delivering promised attachment: %s at path: %@"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG235"
) = "Drag session: %p delivering promised attachment: %s at path: %@"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Drag session: %p delivering promised attachment: %s at path: %@"
, session.get(), info.attachmentIdentifier.utf8().data(), destinationURL
.get().path)]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "Drag session: %p delivering promised attachment: %s at path: %@"
, session.get(), info.attachmentIdentifier.utf8().data(), destinationURL
.get().path), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop
;
10979 NSError *fileWrapperError = nilnullptr;
10980 if ([fileWrapper writeToURL:destinationURL.get() options:0 originalContentsURL:nilnullptr error:&fileWrapperError])
10981 callback(destinationURL.get(), nilnullptr);
10982 else
10983 callback(nilnullptr, fileWrapperError);
10984 });
10985 } else
10986 callback(nilnullptr, [NSError errorWithDomain:WKErrorDomain code:WKErrorWebViewInvalidated userInfo:nilnullptr]);
10987
10988 [protect(ensureLocalDragSessionContext(session.get())) addTemporaryDirectory:temporaryBlobDirectory.get()];
10989 }];
10990
10991 WebItemProviderPasteboard *pasteboard = [WebItemProviderPasteboard sharedInstance];
10992 pasteboard.itemProviders = @[ [registrationList itemProvider] ];
10993 [pasteboard stageRegistrationLists:@[ registrationList.get() ]];
10994}
10995
10996- (WKDragDestinationAction)_dragDestinationActionForDropSession:(id <UIDropSession>)session
10997{
10998 id <WKUIDelegatePrivate> uiDelegate = self.webViewUIDelegate;
10999 if ([uiDelegate respondsToSelector:@selector(_webView:dragDestinationActionMaskForDraggingInfo:)])
11000 return [uiDelegate _webView:self.webView dragDestinationActionMaskForDraggingInfo:session];
11001
11002 return WKDragDestinationActionAny & ~WKDragDestinationActionLoad;
11003}
11004
11005- (OptionSet<WebCore::DragSourceAction>)_allowedDragSourceActions
11006{
11007 auto allowedActions = WebCore::anyDragSourceAction();
11008 if (!self.isFirstResponder || !_suppressSelectionAssistantReasons.isEmpty()) {
11009 // Don't allow starting a drag on a selection when selection views are not visible.
11010 allowedActions.remove(WebCore::DragSourceAction::Selection);
11011 }
11012 return allowedActions;
11013}
11014
11015- (id <UIDragDropSession>)currentDragOrDropSession
11016{
11017 if (_dragDropInteractionState.dropSession())
11018 return _dragDropInteractionState.dropSession();
11019 return _dragDropInteractionState.dragSession();
11020}
11021
11022- (void)_restoreEditMenuIfNeeded
11023{
11024 if (!_shouldRestoreEditMenuAfterDrop)
11025 return;
11026
11027 [_textInteractionWrapper didConcludeDrop];
11028 _shouldRestoreEditMenuAfterDrop = NO__objc_no;
11029}
11030
11031- (NSArray<UIDragItem *> *)_itemsForBeginningOrAddingToSessionWithRegistrationLists:(NSArray<WebItemProviderRegistrationInfoList *> *)registrationLists stagedDragSource:(const WebKit::DragSourceState&)stagedDragSource
11032{
11033 if (!registrationLists.count)
11034 return @[ ];
11035
11036 NSMutableArray *adjustedItemProviders = [NSMutableArray array];
11037 id <WKUIDelegatePrivate> uiDelegate = self.webViewUIDelegate;
11038 if ([uiDelegate respondsToSelector:@selector(_webView:adjustedDataInteractionItemProvidersForItemProvider:representingObjects:additionalData:)]) {
11039 // FIXME: We should consider a new UI delegate hook that accepts a list of item providers, so we don't need to invoke this delegate method repeatedly for multiple items.
11040 for (WebItemProviderRegistrationInfoList *list in registrationLists) {
11041 NSItemProvider *defaultItemProvider = list.itemProvider;
11042 if (!defaultItemProvider)
11043 continue;
11044
11045 auto representingObjects = adoptNS([[NSMutableArray alloc] init]);
11046 auto additionalData = adoptNS([[NSMutableDictionary alloc] init]);
11047 [list enumerateItems:[representingObjects, additionalData] (id <WebItemProviderRegistrar> item, NSUInteger) {
11048 if ([item respondsToSelector:@selector(representingObjectForClient)])
11049 [representingObjects addObject:item.representingObjectForClient];
11050 if ([item respondsToSelector:@selector(typeIdentifierForClient)] && [item respondsToSelector:@selector(dataForClient)])
11051 [additionalData setObject:item.dataForClient forKey:item.typeIdentifierForClient];
11052 }];
11053 NSArray *adjustedItems = [uiDelegate _webView:self.webView adjustedDataInteractionItemProvidersForItemProvider:defaultItemProvider representingObjects:representingObjects.get() additionalData:additionalData.get()];
11054 if (adjustedItems.count)
11055 [adjustedItemProviders addObjectsFromArray:adjustedItems];
11056 }
11057 } else {
11058 for (WebItemProviderRegistrationInfoList *list in registrationLists) {
11059 if (auto *defaultItemProvider = list.itemProvider)
11060 [adjustedItemProviders addObject:defaultItemProvider];
11061 }
11062 }
11063
11064 NSMutableArray *dragItems = [NSMutableArray arrayWithCapacity:adjustedItemProviders.count];
11065 for (NSItemProvider *itemProvider in adjustedItemProviders) {
11066 auto item = adoptNS([[UIDragItem alloc] initWithItemProvider:itemProvider]);
11067 [item _setPrivateLocalContext:@(stagedDragSource.itemIdentifier)];
11068 [dragItems addObject:item.get()];
11069 }
11070
11071 return dragItems;
11072}
11073
11074- (void)insertTextPlaceholderWithSize:(CGSize)size completionHandler:(void (^)(UITextPlaceholder *))completionHandler
11075{
11076 protect(_page)->insertTextPlaceholder(WebCore::IntSize { size }, [weakSelf = WeakObjCPtr<WKContentView>(self), completionHandler = makeBlockPtr(completionHandler)](const std::optional<WebCore::ElementContext>& placeholder) {
11077 auto strongSelf = weakSelf.get();
11078 if (!strongSelf || ![strongSelf webView] || !placeholder) {
11079 completionHandler(nilnullptr);
11080 return;
11081 }
11082 WebCore::ElementContext placeholderToUse { *placeholder };
11083 placeholderToUse.boundingRect = [strongSelf convertRect:placeholderToUse.boundingRect fromView:[strongSelf webView]];
11084 completionHandler(adoptNS([[WKTextPlaceholder alloc] initWithElementContext:placeholderToUse]).get());
11085 });
11086}
11087
11088- (void)removeTextPlaceholder:(UITextPlaceholder *)placeholder willInsertText:(BOOL)willInsertText completionHandler:(void (^)(void))completionHandler
11089{
11090 // FIXME: Implement support for willInsertText. See <https://bugs.webkit.org/show_bug.cgi?id=208747>.
11091 if (RetainPtr wkTextPlaceholder = dynamic_objc_cast<WKTextPlaceholder>(placeholder))
11092 protect(_page)->removeTextPlaceholder([wkTextPlaceholder elementContext], makeBlockPtr(completionHandler));
11093 else
11094 completionHandler();
11095}
11096
11097static Vector<WebCore::IntSize> sizesOfPlaceholderElementsToInsertWhenDroppingItems(NSArray<NSItemProvider *> *itemProviders)
11098{
11099 Vector<WebCore::IntSize> sizes;
11100 for (NSItemProvider *item in itemProviders) {
11101 if (!WebCore::MIMETypeRegistry::isSupportedImageMIMEType(WebCore::MIMETypeFromUTI(item.web_fileUploadContentTypes.firstObject)))
11102 return { };
11103
11104 WebCore::IntSize presentationSize(item.preferredPresentationSize);
11105 if (presentationSize.isEmpty())
11106 return { };
11107
11108 sizes.append(WTF::move(presentationSize));
11109 }
11110 return sizes;
11111}
11112
11113- (BOOL)_handleDropByInsertingImagePlaceholders:(NSArray<NSItemProvider *> *)itemProviders session:(id<UIDropSession>)session
11114{
11115 if (!self.webView._editable)
11116 return NO__objc_no;
11117
11118 if (_dragDropInteractionState.dragSession())
11119 return NO__objc_no;
11120
11121 if (session.items.count != itemProviders.count)
11122 return NO__objc_no;
11123
11124 auto imagePlaceholderSizes = sizesOfPlaceholderElementsToInsertWhenDroppingItems(itemProviders);
11125 if (imagePlaceholderSizes.isEmpty())
11126 return NO__objc_no;
11127
11128 RELEASE_LOG(DragAndDrop, "Inserting dropped image placeholders for session: %p", session)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Inserting dropped image placeholders for session: %p"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG236"
) = "Inserting dropped image placeholders for session: %p"; uint8_t
_Alignas(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Inserting dropped image placeholders for session: %p", session
)]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str
, (uint8_t *)__builtin_os_log_format(_os_fmt_buf, "Inserting dropped image placeholders for session: %p"
, session), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop
; }); } }) clang diagnostic pop
;
11129
11130 protect(_page)->insertDroppedImagePlaceholders(imagePlaceholderSizes, [protectedSelf = retainPtr(self), dragItems = retainPtr(session.items)] (auto& placeholderRects, auto&& textIndicator) {
11131 auto& state = protectedSelf->_dragDropInteractionState;
11132 if (!textIndicator || !protectedSelf->_dropAnimationCount) {
11133 RELEASE_LOG(DragAndDrop, "Failed to animate image placeholders: missing text indicator data.")clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Failed to animate image placeholders: missing text indicator data."
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG237"
) = "Failed to animate image placeholders: missing text indicator data."
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Failed to animate image placeholders: missing text indicator data."
)]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str
, (uint8_t *)__builtin_os_log_format(_os_fmt_buf, "Failed to animate image placeholders: missing text indicator data."
), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); }
}) clang diagnostic pop
;
11134 return;
11135 }
11136
11137 auto snapshotWithoutSelection = textIndicator->contentImageWithoutSelection();
11138 if (!snapshotWithoutSelection) {
11139 RELEASE_LOG(DragAndDrop, "Failed to animate image placeholders: missing unselected content image.")clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Failed to animate image placeholders: missing unselected content image."
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG238"
) = "Failed to animate image placeholders: missing unselected content image."
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Failed to animate image placeholders: missing unselected content image."
)]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str
, (uint8_t *)__builtin_os_log_format(_os_fmt_buf, "Failed to animate image placeholders: missing unselected content image."
), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); }
}) clang diagnostic pop
;
11140 return;
11141 }
11142
11143 auto unselectedSnapshotImage = snapshotWithoutSelection->nativeImage();
11144 if (!unselectedSnapshotImage) {
11145 RELEASE_LOG(DragAndDrop, "Failed to animate image placeholders: could not decode unselected content image.")clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Failed to animate image placeholders: could not decode unselected content image."
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG239"
) = "Failed to animate image placeholders: could not decode unselected content image."
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Failed to animate image placeholders: could not decode unselected content image."
)]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str
, (uint8_t *)__builtin_os_log_format(_os_fmt_buf, "Failed to animate image placeholders: could not decode unselected content image."
), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); }
}) clang diagnostic pop
;
11146 return;
11147 }
11148
11149 auto unselectedContentImageForEditDrag = adoptNS([[UIImage alloc] initWithCGImage:unselectedSnapshotImage->platformImage().get() scale:protect(protectedSelf->_page)->deviceScaleFactor() orientation:UIImageOrientationUp]);
11150 auto snapshotView = adoptNS([[UIImageView alloc] initWithImage:unselectedContentImageForEditDrag.get()]);
11151 [snapshotView setFrame:textIndicator->contentImageWithoutSelectionRectInRootViewCoordinates()];
11152 [protectedSelf addSubview:snapshotView.get()];
11153 protectedSelf->_unselectedContentSnapshot = WTF::move(snapshotView);
11154 state.deliverDelayedDropPreview(protectedSelf.get(), [protectedSelf unobscuredContentRect], dragItems.get(), placeholderRects);
11155 });
11156
11157 return YES__objc_yes;
11158}
11159
11160#pragma mark - UIDragInteractionDelegate
11161
11162- (BOOL)_dragInteraction:(UIDragInteraction *)interaction shouldDelayCompetingGestureRecognizer:(UIGestureRecognizer *)competingGestureRecognizer
11163{
11164 if (_highlightLongPressGestureRecognizer == competingGestureRecognizer) {
11165 // Since 3D touch still recognizes alongside the drag lift, and also requires the highlight long press
11166 // gesture to be active to support cancelling when `touchstart` is prevented, we should also allow the
11167 // highlight long press to recognize simultaneously, and manually cancel it when the drag lift is
11168 // recognized (see _dragInteraction:prepareForSession:completion:).
11169 return NO__objc_no;
11170 }
11171 return [competingGestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]];
11172}
11173
11174- (NSInteger)_dragInteraction:(UIDragInteraction *)interaction dataOwnerForSession:(id<UIDragSession>)session
11175{
11176 id<WKUIDelegatePrivate> uiDelegate = self.webViewUIDelegate;
11177 NSInteger dataOwner = 0;
11178 if ([uiDelegate respondsToSelector:@selector(_webView:dataOwnerForDragSession:)])
11179 dataOwner = [uiDelegate _webView:self.webView dataOwnerForDragSession:session];
11180 return dataOwner;
11181}
11182
11183- (void)_dragInteraction:(UIDragInteraction *)interaction itemsForAddingToSession:(id<UIDragSession>)session withTouchAtPoint:(CGPoint)point completion:(void(^)(NSArray<UIDragItem *> *))completion
11184{
11185 if (!_dragDropInteractionState.shouldRequestAdditionalItemForDragSession(session)) {
11186 completion(@[ ]);
11187 return;
11188 }
11189
11190 _dragDropInteractionState.dragSessionWillRequestAdditionalItem(completion);
11191 protect(_page)->requestAdditionalItemsForDragSession(std::nullopt, WebCore::roundedIntPoint(point), WebCore::roundedIntPoint(point), self._allowedDragSourceActions, [weakSelf = WeakObjCPtr { self }] (bool handled) {
11192 [weakSelf.get() _didHandleAdditionalDragItemsRequest:handled];
11193 });
11194}
11195
11196- (void)_dragInteraction:(UIDragInteraction *)interaction prepareForSession:(id<UIDragSession>)session completion:(dispatch_block_t)completion
11197{
11198 RELEASE_LOG(DragAndDrop, "Preparing for drag session: %p", session)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Preparing for drag session: %p"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG240"
) = "Preparing for drag session: %p"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Preparing for drag session: %p", session)]; _os_log_impl(&
__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format
(_os_fmt_buf, "Preparing for drag session: %p", session), (uint32_t
)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
11199 if (self.currentDragOrDropSession) {
11200 // FIXME: Support multiple simultaneous drag sessions in the future.
11201 RELEASE_LOG(DragAndDrop, "Drag session failed: %p (a current drag session already exists)", session)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Drag session failed: %p (a current drag session already exists)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG241"
) = "Drag session failed: %p (a current drag session already exists)"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Drag session failed: %p (a current drag session already exists)"
, session)]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "Drag session failed: %p (a current drag session already exists)"
, session), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop
; }); } }) clang diagnostic pop
;
11202 completion();
11203 return;
11204 }
11205
11206 [self cleanUpDragSourceSessionState];
11207
11208 auto prepareForSession = [weakSelf = WeakObjCPtr<WKContentView>(self), session = retainPtr(session), completion = makeBlockPtr(completion)] (WebKit::ProceedWithTextSelectionInImage proceedWithTextSelectionInImage) {
11209 auto strongSelf = weakSelf.get();
11210 if (!strongSelf || proceedWithTextSelectionInImage == WebKit::ProceedWithTextSelectionInImage::Yes) {
11211 completion();
11212 return;
11213 }
11214
11215 auto dragOrigin = [session locationInView:strongSelf.get()];
11216 strongSelf->_dragDropInteractionState.prepareForDragSession(session.get(), completion.get());
11217 protect(strongSelf->_page)->requestDragStart(std::nullopt, WebCore::roundedIntPoint(dragOrigin), WebCore::roundedIntPoint([strongSelf convertPoint:dragOrigin toView:[strongSelf window]]), [strongSelf _allowedDragSourceActions], [weakSelf = WeakObjCPtr { strongSelf.get() }] (bool started) {
11218 [weakSelf.get() _didHandleDragStartRequest:started];
11219 });
11220 RELEASE_LOG(DragAndDrop, "Drag session requested: %p at origin: {%.0f, %.0f}", session.get(), dragOrigin.x, dragOrigin.y)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Drag session requested: %p at origin: {%.0f, %.0f}"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG242"
) = "Drag session requested: %p at origin: {%.0f, %.0f}"; uint8_t
_Alignas(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Drag session requested: %p at origin: {%.0f, %.0f}", session
.get(), dragOrigin.x, dragOrigin.y)]; _os_log_impl(&__dso_handle
, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format
(_os_fmt_buf, "Drag session requested: %p at origin: {%.0f, %.0f}"
, session.get(), dragOrigin.x, dragOrigin.y), (uint32_t)sizeof
(_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
11221 };
11222
11223#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
11224 [self _doAfterPendingImageAnalysis:prepareForSession];
11225#else
11226 prepareForSession(WebKit::ProceedWithTextSelectionInImage::No);
11227#endif
11228}
11229
11230- (NSArray<UIDragItem *> *)dragInteraction:(UIDragInteraction *)interaction itemsForBeginningSession:(id<UIDragSession>)session
11231{
11232 ASSERT(interaction == _dragInteraction)((void)0);
11233 RELEASE_LOG(DragAndDrop, "Drag items requested for session: %p", session)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Drag items requested for session: %p"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG243"
) = "Drag items requested for session: %p"; uint8_t _Alignas(
16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Drag items requested for session: %p", session)]; _os_log_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Drag items requested for session: %p"
, session), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop
; }); } }) clang diagnostic pop
;
11234 if (_dragDropInteractionState.dragSession() != session) {
11235 RELEASE_LOG(DragAndDrop, "Drag session failed: %p (delegate session does not match %p)", session, _dragDropInteractionState.dragSession())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Drag session failed: %p (delegate session does not match %p)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG244"
) = "Drag session failed: %p (delegate session does not match %p)"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Drag session failed: %p (delegate session does not match %p)"
, session, _dragDropInteractionState.dragSession())]; _os_log_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Drag session failed: %p (delegate session does not match %p)"
, session, _dragDropInteractionState.dragSession()), (uint32_t
)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
11236 return @[ ];
11237 }
11238
11239 if (!_dragDropInteractionState.hasStagedDragSource()) {
11240 RELEASE_LOG(DragAndDrop, "Drag session failed: %p (missing staged drag source)", session)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Drag session failed: %p (missing staged drag source)"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG245"
) = "Drag session failed: %p (missing staged drag source)"; uint8_t
_Alignas(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Drag session failed: %p (missing staged drag source)", session
)]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str
, (uint8_t *)__builtin_os_log_format(_os_fmt_buf, "Drag session failed: %p (missing staged drag source)"
, session), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop
; }); } }) clang diagnostic pop
;
11241 return @[ ];
11242 }
11243
11244 auto stagedDragSource = _dragDropInteractionState.stagedDragSource();
11245 auto *registrationLists = [[WebItemProviderPasteboard sharedInstance] takeRegistrationLists];
11246 NSArray *dragItems = [self _itemsForBeginningOrAddingToSessionWithRegistrationLists:registrationLists stagedDragSource:stagedDragSource];
11247 if (![dragItems count])
11248 protect(_page)->dragCancelled();
11249 else
11250 [self _cancelLongPressGestureRecognizer];
11251
11252 RELEASE_LOG(DragAndDrop, "Drag session: %p starting with %tu items", session, [dragItems count])clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Drag session: %p starting with %tu items"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG246"
) = "Drag session: %p starting with %tu items"; uint8_t _Alignas
(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Drag session: %p starting with %tu items", session, [dragItems
count])]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "Drag session: %p starting with %tu items", session, [dragItems
count]), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop
; }); } }) clang diagnostic pop
;
11253 _dragDropInteractionState.clearStagedDragSource([dragItems count] ? WebKit::DragDropInteractionState::DidBecomeActive::Yes : WebKit::DragDropInteractionState::DidBecomeActive::No);
11254
11255 return dragItems;
11256}
11257
11258- (UITargetedDragPreview *)dragInteraction:(UIDragInteraction *)interaction previewForLiftingItem:(UIDragItem *)item session:(id<UIDragSession>)session
11259{
11260 id<WKUIDelegatePrivate> uiDelegate = self.webViewUIDelegate;
11261 if ([uiDelegate respondsToSelector:@selector(_webView:previewForLiftingItem:session:)]) {
11262 UITargetedDragPreview *overriddenPreview = [uiDelegate _webView:self.webView previewForLiftingItem:item session:session];
11263 if (overriddenPreview)
11264 return overriddenPreview;
11265 }
11266 return _dragDropInteractionState.previewForLifting(item, self, self.containerForDragPreviews, WTF::move(_positionInformationLinkIndicator));
11267}
11268
11269- (void)dragInteraction:(UIDragInteraction *)interaction willAnimateLiftWithAnimator:(id<UIDragAnimating>)animator session:(id<UIDragSession>)session
11270{
11271 RELEASE_LOG(DragAndDrop, "Drag session willAnimateLiftWithAnimator: %p", session)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Drag session willAnimateLiftWithAnimator: %p"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG247"
) = "Drag session willAnimateLiftWithAnimator: %p"; uint8_t _Alignas
(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Drag session willAnimateLiftWithAnimator: %p", session)]; _os_log_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Drag session willAnimateLiftWithAnimator: %p"
, session), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop
; }); } }) clang diagnostic pop
;
11272 if (_dragDropInteractionState.anyActiveDragSourceContainsSelection()) {
11273 [self cancelActiveTextInteractionGestures];
11274 if (!_shouldRestoreEditMenuAfterDrop) {
11275 [_textInteractionWrapper willBeginDragLift];
11276 _shouldRestoreEditMenuAfterDrop = YES__objc_yes;
11277 }
11278 }
11279
11280 auto positionForDragEnd = WebCore::roundedIntPoint(_dragDropInteractionState.adjustedPositionForDragEnd());
11281 RetainPtr<WKContentView> protectedSelf(self);
11282 [animator addCompletion:[session = RetainPtr { session }, positionForDragEnd, protectedSelf, page = _page] (UIViewAnimatingPosition finalPosition) {
11283#if RELEASE_LOG_DISABLED!((defined 1 && 1) || (defined ENABLE_JOURNALD_LOG &&
ENABLE_JOURNALD_LOG) || (defined WTF_OS_ANDROID && WTF_OS_ANDROID
))
11284 UNUSED_PARAM(session)(void)session;
11285#endif
11286 if (finalPosition == UIViewAnimatingPositionStart) {
11287 RELEASE_LOG(DragAndDrop, "Drag session ended at start: %p", session.get())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Drag session ended at start: %p"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG248"
) = "Drag session ended at start: %p"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Drag session ended at start: %p", session.get())]; _os_log_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Drag session ended at start: %p"
, session.get()), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop
;
11288 // The lift was canceled, so -dropInteraction:sessionDidEnd: will never be invoked. This is the last chance to clean up.
11289 [protectedSelf cleanUpDragSourceSessionState];
11290 page->dragEnded(positionForDragEnd, positionForDragEnd, { });
11291 }
11292#if !RELEASE_LOG_DISABLED!((defined 1 && 1) || (defined ENABLE_JOURNALD_LOG &&
ENABLE_JOURNALD_LOG) || (defined WTF_OS_ANDROID && WTF_OS_ANDROID
))
11293 else
11294 RELEASE_LOG(DragAndDrop, "Drag session did not end at start: %p", session.get())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Drag session did not end at start: %p"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG249"
) = "Drag session did not end at start: %p"; uint8_t _Alignas
(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Drag session did not end at start: %p", session.get())]; _os_log_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Drag session did not end at start: %p"
, session.get()), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop
;
11295#endif
11296 }];
11297}
11298
11299- (void)dragInteraction:(UIDragInteraction *)interaction sessionWillBegin:(id<UIDragSession>)session
11300{
11301 RELEASE_LOG(DragAndDrop, "Drag session beginning: %p", session)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Drag session beginning: %p"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG250"
) = "Drag session beginning: %p"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Drag session beginning: %p", session)]; _os_log_impl(&__dso_handle
, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format
(_os_fmt_buf, "Drag session beginning: %p", session), (uint32_t
)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
11302 id<WKUIDelegatePrivate> uiDelegate = self.webViewUIDelegate;
11303 if ([uiDelegate respondsToSelector:@selector(_webView:dataInteraction:sessionWillBegin:)])
11304 [uiDelegate _webView:self.webView dataInteraction:interaction sessionWillBegin:session];
11305
11306 [protect(_actionSheetAssistant) cleanupSheet];
11307 _dragDropInteractionState.dragSessionWillBegin();
11308 protect(_page)->didStartDrag();
11309}
11310
11311- (void)dragInteraction:(UIDragInteraction *)interaction session:(id<UIDragSession>)session didEndWithOperation:(UIDropOperation)operation
11312{
11313 RELEASE_LOG(DragAndDrop, "Drag session ended: %p (with operation: %tu, performing operation: %d, began dragging: %d)", session, operation, _dragDropInteractionState.isPerformingDrop(), _dragDropInteractionState.didBeginDragging())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Drag session ended: %p (with operation: %tu, performing operation: %d, began dragging: %d)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG251"
) = "Drag session ended: %p (with operation: %tu, performing operation: %d, began dragging: %d)"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Drag session ended: %p (with operation: %tu, performing operation: %d, began dragging: %d)"
, session, operation, _dragDropInteractionState.isPerformingDrop
(), _dragDropInteractionState.didBeginDragging())]; _os_log_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Drag session ended: %p (with operation: %tu, performing operation: %d, began dragging: %d)"
, session, operation, _dragDropInteractionState.isPerformingDrop
(), _dragDropInteractionState.didBeginDragging()), (uint32_t)
sizeof(_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
11314
11315 [self _restoreEditMenuIfNeeded];
11316
11317 id<WKUIDelegatePrivate> uiDelegate = self.webViewUIDelegate;
11318 if ([uiDelegate respondsToSelector:@selector(_webView:dataInteraction:session:didEndWithOperation:)])
11319 [uiDelegate _webView:self.webView dataInteraction:interaction session:session didEndWithOperation:operation];
11320
11321 if (_dragDropInteractionState.isPerformingDrop())
11322 return;
11323
11324 [self cleanUpDragSourceSessionState];
11325 protect(_page)->dragEnded(WebCore::roundedIntPoint(_dragDropInteractionState.adjustedPositionForDragEnd()), WebCore::roundedIntPoint(_dragDropInteractionState.adjustedPositionForDragEnd()), coreDragOperationForUIDropOperation(operation));
11326}
11327
11328- (UITargetedDragPreview *)dragInteraction:(UIDragInteraction *)interaction previewForCancellingItem:(UIDragItem *)item withDefault:(UITargetedDragPreview *)defaultPreview
11329{
11330 id<WKUIDelegatePrivate> uiDelegate = self.webViewUIDelegate;
11331 if ([uiDelegate respondsToSelector:@selector(_webView:previewForCancellingItem:withDefault:)]) {
11332 UITargetedDragPreview *overriddenPreview = [uiDelegate _webView:self.webView previewForCancellingItem:item withDefault:defaultPreview];
11333 if (overriddenPreview)
11334 return overriddenPreview;
11335 }
11336 return _dragDropInteractionState.previewForCancelling(item, self, self.unscaledView);
11337}
11338
11339- (void)dragInteraction:(UIDragInteraction *)interaction item:(UIDragItem *)item willAnimateCancelWithAnimator:(id<UIDragAnimating>)animator
11340{
11341 _isAnimatingDragCancel = YES__objc_yes;
11342 RELEASE_LOG(DragAndDrop, "Drag interaction willAnimateCancelWithAnimator")clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Drag interaction willAnimateCancelWithAnimator"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG252"
) = "Drag interaction willAnimateCancelWithAnimator"; uint8_t
_Alignas(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Drag interaction willAnimateCancelWithAnimator")]; _os_log_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Drag interaction willAnimateCancelWithAnimator"
), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); }
}) clang diagnostic pop
;
11343 auto previewViews = _dragDropInteractionState.takePreviewViewsForDragCancel();
11344 for (auto& previewView : previewViews)
11345 [previewView setAlpha:0];
11346
11347 [animator addCompletion:[protectedSelf = retainPtr(self), previewViews = WTF::move(previewViews), page = _page] (UIViewAnimatingPosition finalPosition) mutable {
11348 RELEASE_LOG(DragAndDrop, "Drag interaction willAnimateCancelWithAnimator (animation completion block fired)")clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Drag interaction willAnimateCancelWithAnimator (animation completion block fired)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG253"
) = "Drag interaction willAnimateCancelWithAnimator (animation completion block fired)"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Drag interaction willAnimateCancelWithAnimator (animation completion block fired)"
)]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str
, (uint8_t *)__builtin_os_log_format(_os_fmt_buf, "Drag interaction willAnimateCancelWithAnimator (animation completion block fired)"
), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); }
}) clang diagnostic pop
;
11349 for (auto& previewView : previewViews)
11350 [previewView setAlpha:1];
11351
11352 page->dragCancelled();
11353
11354 page->callAfterNextPresentationUpdate([previewViews = WTF::move(previewViews), protectedSelf = WTF::move(protectedSelf)] {
11355 for (auto& previewView : previewViews)
11356 [previewView removeFromSuperview];
11357
11358 protectedSelf->_isAnimatingDragCancel = NO__objc_no;
11359 });
11360 }];
11361}
11362
11363- (void)dragInteraction:(UIDragInteraction *)interaction sessionDidTransferItems:(id<UIDragSession>)session
11364{
11365 [protect(existingLocalDragSessionContext(session)) cleanUpTemporaryDirectories];
11366}
11367
11368#if USE(BROWSERENGINEKIT)(defined 1 && 1)
11369
11370#pragma mark - BEDragInteractionDelegate
11371
11372- (void)dragInteraction:(BEDragInteraction *)interaction prepareDragSession:(id<UIDragSession>)session completion:(BOOL(^)(void))completion
11373{
11374 [self _dragInteraction:interaction prepareForSession:session completion:[completion = makeBlockPtr(completion)] {
11375 completion();
11376 }];
11377}
11378
11379- (void)dragInteraction:(BEDragInteraction *)interaction itemsForAddingToSession:(id<UIDragSession>)session forTouchAtPoint:(CGPoint)point completion:(BOOL(^)(NSArray<UIDragItem *> *))completion
11380{
11381 [self _dragInteraction:interaction itemsForAddingToSession:session withTouchAtPoint:point completion:[completion = makeBlockPtr(completion)](NSArray<UIDragItem *> *items) {
11382 completion(items);
11383 }];
11384}
11385
11386#endif // USE(BROWSERENGINEKIT)
11387
11388#pragma mark - UIDropInteractionDelegate
11389
11390- (NSInteger)_dropInteraction:(UIDropInteraction *)interaction dataOwnerForSession:(id<UIDropSession>)session
11391{
11392 id<WKUIDelegatePrivate> uiDelegate = self.webViewUIDelegate;
11393 NSInteger dataOwner = 0;
11394 if ([uiDelegate respondsToSelector:@selector(_webView:dataOwnerForDropSession:)])
11395 dataOwner = [uiDelegate _webView:self.webView dataOwnerForDropSession:session];
11396 return dataOwner;
11397}
11398
11399- (BOOL)dropInteraction:(UIDropInteraction *)interaction canHandleSession:(id<UIDropSession>)session
11400{
11401 // FIXME: Support multiple simultaneous drop sessions in the future.
11402 id<UIDragDropSession> dragOrDropSession = self.currentDragOrDropSession;
11403 RELEASE_LOG(DragAndDrop, "Can handle drag session: %p with local session: %p existing session: %p?", session, session.localDragSession, dragOrDropSession)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Can handle drag session: %p with local session: %p existing session: %p?"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG254"
) = "Can handle drag session: %p with local session: %p existing session: %p?"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Can handle drag session: %p with local session: %p existing session: %p?"
, session, session.localDragSession, dragOrDropSession)]; _os_log_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Can handle drag session: %p with local session: %p existing session: %p?"
, session, session.localDragSession, dragOrDropSession), (uint32_t
)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
11404
11405 return !dragOrDropSession || session.localDragSession == dragOrDropSession;
11406}
11407
11408- (void)dropInteraction:(UIDropInteraction *)interaction sessionDidEnter:(id<UIDropSession>)session
11409{
11410 RELEASE_LOG(DragAndDrop, "Drop session entered: %p with %tu items", session, session.items.count)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Drop session entered: %p with %tu items"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG255"
) = "Drop session entered: %p with %tu items"; uint8_t _Alignas
(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Drop session entered: %p with %tu items", session, session.
items.count)]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "Drop session entered: %p with %tu items", session, session
.items.count), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop
;
11411 auto dragData = [self dragDataForDropSession:session dragDestinationAction:[self _dragDestinationActionForDropSession:session]];
11412
11413 _dragDropInteractionState.dropSessionDidEnterOrUpdate(session, dragData);
11414
11415 [[WebItemProviderPasteboard sharedInstance] setItemProviders:protect(extractItemProvidersFromDropSession(session)) dropSession:session];
11416 protect(_page)->dragEntered(dragData, WebCore::Pasteboard::nameOfDragPasteboard());
11417}
11418
11419- (UIDropProposal *)dropInteraction:(UIDropInteraction *)interaction sessionDidUpdate:(id<UIDropSession>)session
11420{
11421 [[WebItemProviderPasteboard sharedInstance] setItemProviders:protect(extractItemProvidersFromDropSession(session)) dropSession:session];
11422
11423 Ref page = *_page;
11424 auto dragData = [self dragDataForDropSession:session dragDestinationAction:[self _dragDestinationActionForDropSession:session]];
11425 page->dragUpdated(dragData, WebCore::Pasteboard::nameOfDragPasteboard());
11426 _dragDropInteractionState.dropSessionDidEnterOrUpdate(session, dragData);
11427
11428 auto delegate = self.webViewUIDelegate;
11429 auto operation = dropOperationForWebCoreDragOperation(page->currentDragOperation());
11430 if ([delegate respondsToSelector:@selector(_webView:willUpdateDataInteractionOperationToOperation:forSession:)])
11431 operation = static_cast<UIDropOperation>([delegate _webView:self.webView willUpdateDataInteractionOperationToOperation:operation forSession:session]);
11432
11433 auto proposal = adoptNS([[UIDropProposal alloc] initWithDropOperation:static_cast<UIDropOperation>(operation)]);
11434 auto dragHandlingMethod = page->currentDragHandlingMethod();
11435 if (dragHandlingMethod == WebCore::DragHandlingMethod::EditPlainText || dragHandlingMethod == WebCore::DragHandlingMethod::EditRichText) {
11436 // When dragging near the top or bottom edges of an editable element, enabling precision drop mode may result in the drag session hit-testing outside of the editable
11437 // element, causing the drag to no longer be accepted. This in turn disables precision drop mode, which causes the drag session to hit-test inside of the editable
11438 // element again, which enables precision mode, thus continuing the cycle. To avoid precision mode thrashing, we forbid precision mode when dragging near the top or
11439 // bottom of the editable element.
11440 auto minimumDistanceFromVerticalEdgeForPreciseDrop = 25 / self.webView.scrollView.zoomScale;
11441 [proposal setPrecise:CGRectContainsPoint(CGRectInset(page->currentDragCaretEditableElementRect(), 0, minimumDistanceFromVerticalEdgeForPreciseDrop), [session locationInView:self])];
11442 } else
11443 [proposal setPrecise:NO__objc_no];
11444
11445 if ([delegate respondsToSelector:@selector(_webView:willUpdateDropProposalToProposal:forSession:)])
11446 proposal = [delegate _webView:self.webView willUpdateDropProposalToProposal:proposal.get() forSession:session];
11447
11448 return proposal.autorelease();
11449}
11450
11451- (void)dropInteraction:(UIDropInteraction *)interaction sessionDidExit:(id<UIDropSession>)session
11452{
11453 RELEASE_LOG(DragAndDrop, "Drop session exited: %p with %tu items", session, session.items.count)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Drop session exited: %p with %tu items"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG256"
) = "Drop session exited: %p with %tu items"; uint8_t _Alignas
(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Drop session exited: %p with %tu items", session, session.items
.count)]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "Drop session exited: %p with %tu items", session, session.
items.count), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop
;
11454 [[WebItemProviderPasteboard sharedInstance] setItemProviders:protect(extractItemProvidersFromDropSession(session)) dropSession:session];
11455
11456 Ref page = *_page;
11457 auto dragData = [self dragDataForDropSession:session dragDestinationAction:WKDragDestinationActionAny];
11458 page->dragExited(dragData);
11459 page->resetCurrentDragInformation();
11460
11461 _dragDropInteractionState.dropSessionDidExit();
11462}
11463
11464- (void)dropInteraction:(UIDropInteraction *)interaction performDrop:(id<UIDropSession>)session
11465{
11466 RetainPtr itemProviders = extractItemProvidersFromDropSession(session);
11467 id<WKUIDelegatePrivate> uiDelegate = self.webViewUIDelegate;
11468 if ([uiDelegate respondsToSelector:@selector(_webView:performDataInteractionOperationWithItemProviders:)]) {
11469 if ([uiDelegate _webView:self.webView performDataInteractionOperationWithItemProviders:itemProviders.get()])
11470 return;
11471 }
11472
11473 if ([uiDelegate respondsToSelector:@selector(_webView:willPerformDropWithSession:)]) {
11474 itemProviders = extractItemProvidersFromDragItems([uiDelegate _webView:self.webView willPerformDropWithSession:session]);
11475 if (!itemProviders.get().count)
11476 return;
11477 }
11478
11479 _dragDropInteractionState.dropSessionWillPerformDrop();
11480
11481 [[WebItemProviderPasteboard sharedInstance] setItemProviders:itemProviders.get() dropSession:session];
11482 [[WebItemProviderPasteboard sharedInstance] incrementPendingOperationCount];
11483 auto dragData = [self dragDataForDropSession:session dragDestinationAction:WKDragDestinationActionAny];
11484 BOOL shouldSnapshotView = ![self _handleDropByInsertingImagePlaceholders:itemProviders.get() session:session];
11485
11486 RELEASE_LOG(DragAndDrop, "Loading data from %tu item providers for session: %p", itemProviders.get().count, session)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Loading data from %tu item providers for session: %p"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG257"
) = "Loading data from %tu item providers for session: %p"; uint8_t
_Alignas(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Loading data from %tu item providers for session: %p", itemProviders
.get().count, session)]; _os_log_impl(&__dso_handle, _log_tmp
, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format(
_os_fmt_buf, "Loading data from %tu item providers for session: %p"
, itemProviders.get().count, session), (uint32_t)sizeof(_os_fmt_buf
)) clang diagnostic pop ; }); } }) clang diagnostic pop
;
11487 // Always loading content from the item provider ensures that the web process will be allowed to call back in to the UI
11488 // process to access pasteboard contents at a later time. Ideally, we only need to do this work if we're over a file input
11489 // or the page prevented default on `dragover`, but without this, dropping into a normal editable areas will fail due to
11490 // item providers not loading any data.
11491 RetainPtr<WKContentView> retainedSelf(self);
11492 [[WebItemProviderPasteboard sharedInstance] doAfterLoadingProvidedContentIntoFileURLs:[retainedSelf, capturedDragData = WTF::move(dragData), shouldSnapshotView] (NSArray *fileURLs) mutable {
11493 RELEASE_LOG(DragAndDrop, "Loaded data into %tu files", fileURLs.count)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Loaded data into %tu files"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG258"
) = "Loaded data into %tu files"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Loaded data into %tu files", fileURLs.count)]; _os_log_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Loaded data into %tu files"
, fileURLs.count), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop
;
11494 Vector<String> filenames;
11495 for (NSURL *fileURL in fileURLs)
11496 filenames.append([fileURL path]);
11497 capturedDragData.setFileNames(filenames);
11498
11499 Ref page = *retainedSelf->_page;
11500 WebKit::SandboxExtensionHandle sandboxExtensionHandle;
11501 Vector<WebKit::SandboxExtensionHandle> sandboxExtensionForUpload;
11502 auto dragPasteboardName = WebCore::Pasteboard::nameOfDragPasteboard();
11503 page->createSandboxExtensionsIfNeeded(filenames, sandboxExtensionHandle, sandboxExtensionForUpload);
11504 page->performDragOperation(capturedDragData, dragPasteboardName, WTF::move(sandboxExtensionHandle), WTF::move(sandboxExtensionForUpload));
11505 if (shouldSnapshotView) {
11506 retainedSelf->_visibleContentViewSnapshot = [retainedSelf snapshotViewAfterScreenUpdates:NO__objc_no];
11507 [retainedSelf->_visibleContentViewSnapshot setFrame:[retainedSelf bounds]];
11508 [retainedSelf addSubview:retainedSelf->_visibleContentViewSnapshot.get()];
11509 }
11510 }];
11511}
11512
11513- (void)dropInteraction:(UIDropInteraction *)interaction item:(UIDragItem *)item willAnimateDropWithAnimator:(id<UIDragAnimating>)animator
11514{
11515 _dropAnimationCount++;
11516 [animator addCompletion:[strongSelf = retainPtr(self)] (UIViewAnimatingPosition) {
11517 if (!--strongSelf->_dropAnimationCount)
11518 [std::exchange(strongSelf->_unselectedContentSnapshot, nilnullptr) removeFromSuperview];
11519 }];
11520}
11521
11522- (void)dropInteraction:(UIDropInteraction *)interaction concludeDrop:(id<UIDropSession>)session
11523{
11524 [self _removeContainerForDropPreviews];
11525 [std::exchange(_visibleContentViewSnapshot, nilnullptr) removeFromSuperview];
11526 [std::exchange(_unselectedContentSnapshot, nilnullptr) removeFromSuperview];
11527 protect(_page)->didConcludeDrop();
11528}
11529
11530- (UITargetedDragPreview *)dropInteraction:(UIDropInteraction *)interaction previewForDroppingItem:(UIDragItem *)item withDefault:(UITargetedDragPreview *)defaultPreview
11531{
11532 if (auto preview = _dragDropInteractionState.finalDropPreview(item))
11533 return preview;
11534
11535 _dragDropInteractionState.addDefaultDropPreview(item, defaultPreview);
11536
11537 CGRect caretRect = protect(_page)->currentDragCaretRect();
11538 if (CGRectIsEmpty(caretRect))
11539 return nilnullptr;
11540
11541 UIView *textEffectsWindow = self.textEffectsWindow;
11542 auto caretRectInWindowCoordinates = [self convertRect:caretRect toCoordinateSpace:textEffectsWindow];
11543 auto caretCenterInWindowCoordinates = CGPointMake(CGRectGetMidX(caretRectInWindowCoordinates), CGRectGetMidY(caretRectInWindowCoordinates));
11544 auto targetPreviewCenterInWindowCoordinates = CGPointMake(caretCenterInWindowCoordinates.x + defaultPreview.size.width / 2, caretCenterInWindowCoordinates.y + defaultPreview.size.height / 2);
11545 auto target = adoptNS([[UIDragPreviewTarget alloc] initWithContainer:textEffectsWindow center:targetPreviewCenterInWindowCoordinates transform:CGAffineTransformIdentity]);
11546 return [defaultPreview retargetedPreviewWithTarget:target.get()];
11547}
11548
11549- (void)dropInteraction:(UIDropInteraction *)interaction sessionDidEnd:(id<UIDropSession>)session
11550{
11551 RELEASE_LOG(DragAndDrop, "Drop session ended: %p (performing operation: %d, began dragging: %d)", session, _dragDropInteractionState.isPerformingDrop(), _dragDropInteractionState.didBeginDragging())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogDragAndDrop
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Drop session ended: %p (performing operation: %d, began dragging: %d)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG259"
) = "Drop session ended: %p (performing operation: %d, began dragging: %d)"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Drop session ended: %p (performing operation: %d, began dragging: %d)"
, session, _dragDropInteractionState.isPerformingDrop(), _dragDropInteractionState
.didBeginDragging())]; _os_log_impl(&__dso_handle, _log_tmp
, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format(
_os_fmt_buf, "Drop session ended: %p (performing operation: %d, began dragging: %d)"
, session, _dragDropInteractionState.isPerformingDrop(), _dragDropInteractionState
.didBeginDragging()), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop
;
11552 if (_dragDropInteractionState.isPerformingDrop()) {
11553 // In the case where we are performing a drop, wait until after the drop is handled in the web process to reset drag and drop interaction state.
11554 return;
11555 }
11556
11557 if (_dragDropInteractionState.didBeginDragging()) {
11558 // In the case where the content view is a source of drag items, wait until -dragInteraction:session:didEndWithOperation: to reset drag and drop interaction state.
11559 return;
11560 }
11561
11562 CGPoint global;
11563 CGPoint client;
11564 [self computeClientAndGlobalPointsForDropSession:session outClientPoint:&client outGlobalPoint:&global];
11565 [self cleanUpDragSourceSessionState];
11566 protect(_page)->dragEnded(WebCore::roundedIntPoint(client), WebCore::roundedIntPoint(global), { });
11567}
11568
11569#endif // ENABLE(DRAG_SUPPORT)
11570
11571#if HAVE(UITOOLTIPINTERACTION)(defined HAVE_UITOOLTIPINTERACTION && HAVE_UITOOLTIPINTERACTION
)
11572- (void)_toolTipChanged:(NSString *)newToolTip
11573{
11574 if (!_toolTip) {
11575 _toolTip = adoptNS([[UIToolTipInteraction alloc] init]);
11576 [_toolTip setDelegate:self];
11577 [self addInteraction:_toolTip.get()];
11578 }
11579
11580 // FIXME: rdar://156729915 ([Catalyst] Cannot update tooltip interaction on the same view)
11581 [_toolTip setDefaultToolTip:newToolTip];
11582 RetainPtr sceneView = [[UINSSharedApplicationDelegate() hostWindowForUIWindow:[self window]] sceneView];
11583 [[sceneView _dynamicToolTipManager] windowChangedKeyState];
11584}
11585
11586// MARK: UIToolTipInteractionDelegate
11587
11588- (UIToolTipConfiguration *)toolTipInteraction:(UIToolTipInteraction *)interaction configurationAtPoint:(CGPoint)point
11589{
11590 return [UIToolTipConfiguration configurationWithToolTip:interaction.defaultToolTip];
11591}
11592#endif
11593
11594#pragma mark - Model Interaction Support
11595#if ENABLE(MODEL_PROCESS)(defined 0 && 0)
11596- (void)modelInteractionPanGestureDidBeginAtPoint:(CGPoint)inputPoint
11597{
11598 if (!_stageModeSession) {
11599 _stageModeSession = { { } };
11600 _page->requestInteractiveModelElementAtPoint(WebCore::roundedIntPoint(inputPoint));
11601 }
11602}
11603
11604- (void)modelInteractionPanGestureDidUpdateWithPoint:(CGPoint)inputPoint
11605{
11606 if (_stageModeSession && !_stageModeSession->isPreparingForInteraction) {
11607 WebCore::TransformationMatrix transform;
11608 transform.translate3d(inputPoint.x, inputPoint.y, 0);
11609 _stageModeSession->transform = transform;
11610 _page->stageModeSessionDidUpdate(_stageModeSession->nodeID, _stageModeSession->transform);
11611 }
11612}
11613
11614- (void)modelInteractionPanGestureDidEnd
11615{
11616 if (_stageModeSession && !_stageModeSession->isPreparingForInteraction)
11617 _page->stageModeSessionDidEnd(_stageModeSession->nodeID);
11618
11619 [self cleanUpStageModeSessionState];
11620}
11621
11622- (void)didReceiveInteractiveModelElement:(std::optional<WebCore::NodeIdentifier>)nodeID
11623{
11624 if (!_stageModeSession || !_stageModeSession->isPreparingForInteraction)
11625 return;
11626
11627 _stageModeSession->isPreparingForInteraction = !nodeID;
11628 _stageModeSession->nodeID = nodeID;
11629}
11630
11631- (void)cleanUpStageModeSessionState
11632{
11633 _stageModeSession = std::nullopt;
11634}
11635#endif
11636
11637- (void)cancelActiveTextInteractionGestures
11638{
11639 [self.textInteractionLoupeGestureRecognizer _wk_cancel];
11640}
11641
11642- (UIView *)textEffectsWindow
11643{
11644 return [UITextEffectsWindow sharedTextEffectsWindowForWindowScene:self.window.windowScene];
11645}
11646
11647- (NSDictionary *)_autofillContext
11648{
11649 if (!self._hasFocusedElement)
11650 return nilnullptr;
11651
11652 auto context = adoptNS([[NSMutableDictionary alloc] init]);
11653 context.get()[@"_WKAutofillContextVersion"] = @(2);
11654
11655 if (_focusRequiresStrongPasswordAssistance && _focusedElementInformation.elementType == WebKit::InputType::Password) {
11656 context.get()[@"_automaticPasswordKeyboard"] = @YES__objc_yes;
11657 context.get()[@"strongPasswordAdditionalContext"] = _additionalContextForStrongPasswordAssistance.get();
11658 } else if (_focusedElementInformation.acceptsAutofilledLoginCredentials)
11659 context.get()[@"_acceptsLoginCredentials"] = @YES__objc_yes;
11660
11661 if (RetainPtr platformURL = _focusedElementInformation.representingPageURL.createNSURL())
11662 context.get()[@"_WebViewURL"] = platformURL.get();
11663
11664 if (_focusedElementInformation.nonAutofillCredentialType == WebCore::NonAutofillCredentialType::WebAuthn) {
11665 context.get()[@"_page_id"] = [NSNumber numberWithUnsignedLong:_page->webPageIDInMainFrameProcess().toUInt64()];
11666 context.get()[@"_frame_id"] = [NSNumber numberWithUnsignedLong:_focusedElementInformation.frame ? _focusedElementInformation.frame->frameID.toUInt64() : 0];
11667 context.get()[@"_credential_type"] = WebCore::nonAutofillCredentialTypeString(_focusedElementInformation.nonAutofillCredentialType).createNSString().get();
11668 }
11669 return context.autorelease();
11670}
11671
11672#if USE(UICONTEXTMENU)(defined 1 && 1)
11673
11674static RetainPtr<UIImage> uiImageForImage(WebCore::Image* image)
11675{
11676 if (!image)
11677 return nilnullptr;
11678
11679 auto nativeImage = image->nativeImage();
11680 if (!nativeImage)
11681 return nilnullptr;
11682
11683 return adoptNS([[UIImage alloc] initWithCGImage:nativeImage->platformImage().get()]);
11684}
11685
11686// FIXME: This should be merged with createTargetedDragPreview in DragDropInteractionState.
11687static RetainPtr<UITargetedPreview> createTargetedPreview(UIImage *image, UIView *rootView, UIView *previewContainer, const WebCore::FloatRect& frameInRootViewCoordinates, const Vector<WebCore::FloatRect>& clippingRectsInFrameCoordinates, UIColor *backgroundColor)
11688{
11689 if (frameInRootViewCoordinates.isEmpty() || !image || !previewContainer.window)
11690 return nilnullptr;
11691
11692 WebCore::FloatRect frameInContainerCoordinates = [rootView convertRect:frameInRootViewCoordinates toView:previewContainer];
11693 if (frameInContainerCoordinates.isEmpty())
11694 return nilnullptr;
11695
11696 auto scalingRatio = frameInContainerCoordinates.size() / frameInRootViewCoordinates.size();
11697 auto clippingRectValuesInFrameCoordinates = createNSArray(clippingRectsInFrameCoordinates, [&] (WebCore::FloatRect rect) {
11698 rect.scale(scalingRatio);
11699 return [NSValue valueWithCGRect:rect];
11700 });
11701
11702 RetainPtr<UIPreviewParameters> parameters;
11703 if ([clippingRectValuesInFrameCoordinates count])
11704 parameters = adoptNS([[UIPreviewParameters alloc] initWithTextLineRects:clippingRectValuesInFrameCoordinates.get()]);
11705 else
11706 parameters = adoptNS([[UIPreviewParameters alloc] init]);
11707
11708 [parameters setBackgroundColor:protect(backgroundColor ?: [UIColor clearColor])];
11709
11710 CGPoint centerInContainerCoordinates = { CGRectGetMidX(frameInContainerCoordinates), CGRectGetMidY(frameInContainerCoordinates) };
11711 auto target = adoptNS([[UIPreviewTarget alloc] initWithContainer:previewContainer center:centerInContainerCoordinates]);
11712
11713 auto imageView = adoptNS([[UIImageView alloc] initWithImage:image]);
11714 [imageView setFrame:frameInContainerCoordinates];
11715 return adoptNS([[UITargetedPreview alloc] initWithView:imageView.get() parameters:parameters.get() target:target.get()]);
11716}
11717
11718- (UITargetedPreview *)_createTargetedPreviewFromTextIndicator:(RefPtr<WebCore::TextIndicator>&&)textIndicator previewContainer:(UIView *)previewContainer
11719{
11720 if (!textIndicator)
11721 return nilnullptr;
11722
11723 RetainPtr textIndicatorImage = uiImageForImage(protect(textIndicator->contentImage()));
11724 RetainPtr preview = createTargetedPreview(textIndicatorImage.get(), self, previewContainer, textIndicator->textBoundingRectInRootViewCoordinates(), textIndicator->textRectsInBoundingRectCoordinates(), protect(^{
11725 if (textIndicator->estimatedBackgroundColor() != WebCore::Color::transparentBlack)
11726 return cocoaColor(textIndicator->estimatedBackgroundColor()).autorelease();
11727
11728 // In the case where background color estimation fails, it doesn't make sense to
11729 // show a text indicator preview with a clear background in light mode. Default
11730 // to the system background color instead.
11731 return UIColor.systemBackgroundColor;
11732 }()));
11733
11734 return preview.autorelease();
11735}
11736
11737static RetainPtr<UITargetedPreview> createFallbackTargetedPreview(UIView *rootView, UIView *containerView, const WebCore::FloatRect& frameInRootViewCoordinates, UIColor *backgroundColor)
11738{
11739 if (!containerView.window)
11740 return nilnullptr;
11741
11742 if (frameInRootViewCoordinates.isEmpty())
11743 return nilnullptr;
11744
11745 auto parameters = adoptNS([[UIPreviewParameters alloc] init]);
11746 if (backgroundColor)
11747 [parameters setBackgroundColor:backgroundColor];
11748
11749 RetainPtr snapshotView = [rootView resizableSnapshotViewFromRect:frameInRootViewCoordinates afterScreenUpdates:NO__objc_no withCapInsets:UIEdgeInsetsZero];
11750 if (!snapshotView)
11751 snapshotView = adoptNS([UIView new]);
11752
11753 CGRect frameInContainerViewCoordinates = [rootView convertRect:frameInRootViewCoordinates toView:containerView];
11754
11755 if (CGRectIsEmpty(frameInContainerViewCoordinates))
11756 return nilnullptr;
11757
11758 [snapshotView setFrame:frameInContainerViewCoordinates];
11759
11760 CGPoint centerInContainerViewCoordinates = CGPointMake(CGRectGetMidX(frameInContainerViewCoordinates), CGRectGetMidY(frameInContainerViewCoordinates));
11761 auto target = adoptNS([[UIPreviewTarget alloc] initWithContainer:containerView center:centerInContainerViewCoordinates]);
11762
11763 return adoptNS([[UITargetedPreview alloc] initWithView:snapshotView.get() parameters:parameters.get() target:target.get()]);
11764}
11765
11766- (UITargetedPreview *)_createTargetedContextMenuHintPreviewForFocusedElement:(WebKit::TargetedPreviewPositioning)positioning
11767{
11768 RetainPtr backgroundColor = [&]() -> UIColor * {
11769 switch (_focusedElementInformation.elementType) {
11770 case WebKit::InputType::Date:
11771 case WebKit::InputType::Month:
11772 case WebKit::InputType::DateTimeLocal:
11773 case WebKit::InputType::Time:
11774#if ENABLE(INPUT_TYPE_WEEK_PICKER)(defined 1 && 1)
11775 case WebKit::InputType::Week:
11776#endif
11777 return UIColor.clearColor;
11778 default:
11779 return nilnullptr;
11780 }
11781 }();
11782
11783 auto previewRect = _focusedElementInformation.interactionRect;
11784 if (positioning == WebKit::TargetedPreviewPositioning::LeadingOrTrailingEdge) {
11785 static constexpr auto defaultMenuWidth = 250;
11786 auto unobscuredRect = WebCore::IntRect { self.unobscuredContentRect };
11787 std::optional<int> previewOffsetX;
11788
11789 auto leftEdge = previewRect.x() - defaultMenuWidth;
11790 bool hasSpaceAfterRightEdge = previewRect.maxX() + defaultMenuWidth <= unobscuredRect.maxX();
11791 bool hasSpaceBeforeLeftEdge = leftEdge > unobscuredRect.x();
11792
11793 switch (self.effectiveUserInterfaceLayoutDirection) {
11794 case UIUserInterfaceLayoutDirectionLeftToRight:
11795 if (hasSpaceAfterRightEdge)
11796 previewOffsetX = previewRect.maxX();
11797 else if (hasSpaceBeforeLeftEdge)
11798 previewOffsetX = leftEdge;
11799 break;
11800 case UIUserInterfaceLayoutDirectionRightToLeft:
11801 if (hasSpaceBeforeLeftEdge)
11802 previewOffsetX = leftEdge;
11803 else if (hasSpaceAfterRightEdge)
11804 previewOffsetX = previewRect.maxX();
11805 break;
11806 }
11807
11808 if (previewOffsetX) {
11809 static constexpr auto additionalOffsetToDockPresentedMenuToEdge = 20;
11810 previewRect.setX(additionalOffsetToDockPresentedMenuToEdge + *previewOffsetX);
11811 previewRect.setWidth(1);
11812 }
11813 }
11814
11815 auto targetedPreview = createFallbackTargetedPreview(self, self.containerForContextMenuHintPreviews, previewRect, backgroundColor.get());
11816
11817 [self _updateTargetedPreviewScrollViewUsingContainerScrollingNodeID:_focusedElementInformation.containerScrollingNodeID];
11818
11819 _contextMenuInteractionTargetedPreview = WTF::move(targetedPreview);
11820 return _contextMenuInteractionTargetedPreview.get();
11821}
11822
11823- (BOOL)positionInformationHasImageOverlayDataDetector
11824{
11825#if ENABLE(DATA_DETECTION)(defined 1 && 1)
11826 return _positionInformation.isImageOverlayText && [_positionInformation.dataDetectorResults count];
11827#else
11828 return NO__objc_no;
11829#endif
11830}
11831
11832- (UITargetedPreview *)_createTargetedContextMenuHintPreviewIfPossible
11833{
11834 RetainPtr<UIView> containerForContextMenuHintPreviews = self.containerForContextMenuHintPreviews;
11835 if (![containerForContextMenuHintPreviews window])
11836 return nilnullptr;
11837
11838 RetainPtr<UITargetedPreview> targetedPreview;
11839
11840 if (_positionInformation.isLink && _positionInformation.textIndicator && _positionInformation.textIndicator->contentImage()) {
11841 RefPtr textIndicator = _positionInformation.textIndicator;
11842 _positionInformationLinkIndicator = textIndicator;
11843
11844 targetedPreview = [self _createTargetedPreviewFromTextIndicator:WTF::move(textIndicator) previewContainer:containerForContextMenuHintPreviews.get()];
11845 } else if ((_positionInformation.isAttachment || _positionInformation.isImage) && _positionInformation.image) {
11846 RetainPtr cgImage = protect(_positionInformation.image)->createPlatformImage();
11847 auto image = adoptNS([[UIImage alloc] initWithCGImage:cgImage.get()]);
11848 targetedPreview = createTargetedPreview(image.get(), self, containerForContextMenuHintPreviews.get(), _positionInformation.bounds, { }, nilnullptr);
11849 }
11850
11851 if (!targetedPreview) {
11852 auto boundsForFallbackPreview = [&] {
11853#if ENABLE(DATA_DETECTION)(defined 1 && 1)
11854 if (self.positionInformationHasImageOverlayDataDetector)
11855 return _positionInformation.dataDetectorBounds;
11856#endif
11857 return _positionInformation.bounds;
11858 }();
11859
11860 targetedPreview = createFallbackTargetedPreview(self, containerForContextMenuHintPreviews.get(), boundsForFallbackPreview, nilnullptr);
11861 }
11862
11863 [self _updateTargetedPreviewScrollViewUsingContainerScrollingNodeID:_positionInformation.containerScrollingNodeID];
11864
11865 _contextMenuInteractionTargetedPreview = WTF::move(targetedPreview);
11866 return _contextMenuInteractionTargetedPreview.get();
11867}
11868
11869- (void)_removeContextMenuHintContainerIfPossible
11870{
11871#if HAVE(LINK_PREVIEW)(defined 1 && 1)
11872 // If a new _contextMenuElementInfo is installed, we've started another interaction,
11873 // and removing the hint container view will cause the animation to break.
11874 if (_contextMenuElementInfo)
11875 return;
11876#endif
11877 if (_isDisplayingContextMenuWithAnimation)
11878 return;
11879
11880 if (_isPreparingToDisplayContextMenu)
11881 return;
11882
11883#if ENABLE(DATA_DETECTION)(defined 1 && 1)
11884 // We are also using this container for the action sheet assistant...
11885 if ([protect(_actionSheetAssistant) hasContextMenuInteraction])
11886 return;
11887#endif
11888 // and for the file upload panel...
11889 if (_fileUploadPanel)
11890 return;
11891
11892 // and for the date/time picker.
11893 if ([self dateTimeInputControl])
11894 return;
11895
11896 if ([self selectControl])
11897 return;
11898
11899 if ([_contextMenuHintContainerView subviews].count)
11900 return;
11901
11902 [self _removeContainerForContextMenuHintPreviews];
11903}
11904
11905#endif // USE(UICONTEXTMENU)
11906
11907#if HAVE(UI_WK_DOCUMENT_CONTEXT)(defined 1 && 1)
11908
11909static inline OptionSet<WebKit::DocumentEditingContextRequest::Options> toWebDocumentRequestOptions(WKBETextDocumentRequestOptionsBETextDocumentRequestOptions flags)
11910{
11911 OptionSet<WebKit::DocumentEditingContextRequest::Options> options;
11912
11913 if (flags & WKBETextDocumentRequestOptionTextBETextDocumentOptionText)
11914 options.add(WebKit::DocumentEditingContextRequest::Options::Text);
11915 if (flags & WKBETextDocumentRequestOptionAttributedTextBETextDocumentOptionAttributedText)
11916 options.add(WebKit::DocumentEditingContextRequest::Options::AttributedText);
11917 if (flags & WKBETextDocumentRequestOptionTextRectsBETextDocumentOptionTextRects)
11918 options.add(WebKit::DocumentEditingContextRequest::Options::Rects);
11919 if (flags & UIWKDocumentRequestSpatial)
11920 options.add(WebKit::DocumentEditingContextRequest::Options::Spatial);
11921 if (flags & UIWKDocumentRequestAnnotation)
11922 options.add(WebKit::DocumentEditingContextRequest::Options::Annotation);
11923 if (flags & WKBETextDocumentRequestOptionMarkedTextRectsBETextDocumentOptionMarkedTextRects)
11924 options.add(WebKit::DocumentEditingContextRequest::Options::MarkedTextRects);
11925 if (flags & UIWKDocumentRequestSpatialAndCurrentSelection)
11926 options.add(WebKit::DocumentEditingContextRequest::Options::SpatialAndCurrentSelection);
11927#if HAVE(AUTOCORRECTION_ENHANCEMENTS)(defined 1 && 1)
11928 if (flags & WKBETextDocumentRequestOptionAutocorrectedRangesBETextDocumentOptionAutocorrectedRanges)
11929 options.add(WebKit::DocumentEditingContextRequest::Options::AutocorrectedRanges);
11930#endif
11931
11932 return options;
11933}
11934
11935static WebKit::DocumentEditingContextRequest toWebRequest(id request)
11936{
11937 WKBETextDocumentRequestOptionsBETextDocumentRequestOptions options = WKBETextDocumentRequestOptionNoneBETextDocumentOptionNone;
11938 CGRect documentRect;
11939
11940 if (auto uiRequest = dynamic_objc_cast<UIWKDocumentRequest>(request)) {
11941 documentRect = uiRequest.documentRect;
11942 options = static_cast<WKBETextDocumentRequestOptionsBETextDocumentRequestOptions>(uiRequest.flags);
11943 }
11944#if USE(BROWSERENGINEKIT)(defined 1 && 1)
11945 else if (auto seRequest = dynamic_objc_cast<WKBETextDocumentRequestBETextDocumentRequest>(request)) {
11946 documentRect = seRequest._documentRect;
11947 options = seRequest.options;
11948 }
11949#endif
11950 WebKit::DocumentEditingContextRequest webRequest = {
11951 .options = toWebDocumentRequestOptions(options),
11952 .surroundingGranularity = toWKTextGranularity([request surroundingGranularity]),
11953 .granularityCount = [request granularityCount],
11954 .rect = documentRect
11955 };
11956 if (auto textInputContext = dynamic_objc_cast<_WKTextInputContext>([request inputElementIdentifier]))
11957 webRequest.textInputContext = [textInputContext _textInputContext];
11958
11959 return webRequest;
11960}
11961
11962- (void)adjustSelectionWithDelta:(NSRange)deltaRange completionHandler:(void (^)(void))completionHandler
11963{
11964 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG260"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(11964, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
11965
11966 // UIKit is putting casted signed integers into NSRange. Cast them back to reveal any negative values.
11967 [self _internalAdjustSelectionWithOffset:static_cast<NSInteger>(deltaRange.location) lengthDelta:static_cast<NSInteger>(deltaRange.length) completionHandler:completionHandler];
11968}
11969
11970// The completion handler is called with either a UIWKDocumentContext, or a WKBETextDocumentContext.
11971- (void)requestDocumentContext:(id)request completionHandler:(void (^)(NSObject *))completionHandler
11972{
11973 auto webRequest = toWebRequest(request);
11974 auto options = webRequest.options;
11975 protect(_page)->requestDocumentEditingContext(WTF::move(webRequest), [useAsyncInteractions = self.shouldUseAsyncInteractions, completionHandler = makeBlockPtr(completionHandler), options] (auto&& editingContext) {
11976 completionHandler(useAsyncInteractions ? editingContext.toPlatformContext(options) : editingContext.toLegacyPlatformContext(options));
11977 });
11978}
11979
11980- (void)selectPositionAtPoint:(CGPoint)point withContextRequest:(WKBETextDocumentRequestBETextDocumentRequest *)request completionHandler:(void (^)(NSObject *))completionHandler
11981{
11982 logTextInteraction(__PRETTY_FUNCTION__, self.textInteractionLoupeGestureRecognizer, point);
11983
11984 // FIXME: Reduce to 1 message.
11985 [self selectPositionAtPoint:point completionHandler:[strongSelf = retainPtr(self), request = retainPtr(request), completionHandler = makeBlockPtr(completionHandler)]() mutable {
11986 [strongSelf requestDocumentContext:request.get() completionHandler:[completionHandler = WTF::move(completionHandler)](NSObject *context) {
11987 completionHandler(context);
11988 }];
11989 }];
11990}
11991
11992#endif // HAVE(UI_WK_DOCUMENT_CONTEXT)
11993
11994#if HAVE(PEPPER_UI_CORE)(defined HAVE_PEPPER_UI_CORE && HAVE_PEPPER_UI_CORE)
11995
11996- (void)dismissQuickboardViewControllerAndRevealFocusedFormOverlayIfNecessary:(id)controller
11997{
11998 BOOL shouldRevealFocusOverlay = NO__objc_no;
11999 // In the case where there's nothing the user could potentially do besides dismiss the overlay, we can just automatically without asking the delegate.
12000 if ([self.webView._inputDelegate respondsToSelector:@selector(_webView:shouldRevealFocusOverlayForInputSession:)]
12001 && ([self actionNameForFocusedFormControlView:_focusedFormControlView.get()] || _focusedElementInformation.hasNextNode || _focusedElementInformation.hasPreviousNode))
12002 shouldRevealFocusOverlay = [self.webView._inputDelegate _webView:self.webView shouldRevealFocusOverlayForInputSession:_formInputSession.get()];
12003
12004 if (shouldRevealFocusOverlay) {
12005 [protect(_focusedFormControlView) show:NO__objc_no];
12006 [self updateCurrentFocusedElementInformation:[weakSelf = WeakObjCPtr<WKContentView>(self)] (bool didUpdate) {
12007 if (!didUpdate)
12008 return;
12009
12010 auto focusedFormController = weakSelf.get()->_focusedFormControlView;
12011 [focusedFormController reloadData:YES__objc_yes];
12012 [focusedFormController engageFocusedFormControlNavigation];
12013 }];
12014 } else
12015 _page->blurFocusedElement();
12016
12017 bool shouldDismissViewController = [controller isKindOfClass:UIViewController.class]
12018#if HAVE(QUICKBOARD_CONTROLLER)(defined HAVE_QUICKBOARD_CONTROLLER && HAVE_QUICKBOARD_CONTROLLER
)
12019 && !_presentedQuickboardController
12020#endif
12021 && controller != _presentedFullScreenInputViewController;
12022 // The Quickboard view controller passed into this delegate method is not necessarily the view controller we originally presented;
12023 // this happens in the case when the user chooses an input method (e.g. scribble) and a new Quickboard view controller is presented.
12024 if (shouldDismissViewController)
12025 [(UIViewController *)controller dismissViewControllerAnimated:YES__objc_yes completion:nilnullptr];
12026
12027 [self dismissAllInputViewControllers:controller == _presentedFullScreenInputViewController];
12028}
12029
12030- (UITextContentType)textContentTypeForQuickboard
12031{
12032 switch (_focusedElementInformation.elementType) {
12033 case WebKit::InputType::Password:
12034 return UITextContentTypePassword;
12035 case WebKit::InputType::URL:
12036 return UITextContentTypeURL;
12037 case WebKit::InputType::Email:
12038 return UITextContentTypeEmailAddress;
12039 case WebKit::InputType::Phone:
12040 return UITextContentTypeTelephoneNumber;
12041 default:
12042 // The element type alone is insufficient to infer content type; fall back to autofill data.
12043 if (auto contentType = [self contentTypeFromFieldName:_focusedElementInformation.autofillFieldName])
12044 return contentType;
12045
12046 if (_focusedElementInformation.isAutofillableUsernameField)
12047 return UITextContentTypeUsername;
12048
12049 return nilnullptr;
12050 }
12051}
12052
12053#pragma mark - PUICQuickboardViewControllerDelegate
12054
12055- (void)quickboard:(PUICQuickboardViewController *)quickboard textEntered:(NSAttributedString *)attributedText
12056{
12057 if (attributedText)
12058 _page->setTextAsync(attributedText.string);
12059
12060 [self dismissQuickboardViewControllerAndRevealFocusedFormOverlayIfNecessary:quickboard];
12061}
12062
12063- (void)quickboardInputCancelled:(PUICQuickboardViewController *)quickboard
12064{
12065 [self dismissQuickboardViewControllerAndRevealFocusedFormOverlayIfNecessary:quickboard];
12066}
12067
12068#pragma mark - WKQuickboardViewControllerDelegate
12069
12070- (BOOL)allowsLanguageSelectionForListViewController:(PUICQuickboardViewController *)controller
12071{
12072 switch (_focusedElementInformation.elementType) {
12073 case WebKit::InputType::ContentEditable:
12074 case WebKit::InputType::Text:
12075 case WebKit::InputType::TextArea:
12076 case WebKit::InputType::Search:
12077 case WebKit::InputType::Email:
12078 case WebKit::InputType::URL:
12079 return YES__objc_yes;
12080 default:
12081 return NO__objc_no;
12082 }
12083}
12084
12085- (UIView *)inputContextViewForViewController:(PUICQuickboardViewController *)controller
12086{
12087 id <_WKInputDelegate> delegate = self.webView._inputDelegate;
12088 if (![delegate respondsToSelector:@selector(_webView:focusedElementContextViewForInputSession:)])
12089 return nilnullptr;
12090
12091 return [delegate _webView:self.webView focusedElementContextViewForInputSession:_formInputSession.get()];
12092}
12093
12094- (NSString *)inputLabelTextForViewController:(PUICQuickboardViewController *)controller
12095{
12096 return [self inputLabelText];
12097}
12098
12099- (NSString *)initialValueForViewController:(PUICQuickboardViewController *)controller
12100{
12101 return _focusedElementInformation.value.createNSString().autorelease();
12102}
12103
12104- (BOOL)shouldDisplayInputContextViewForListViewController:(PUICQuickboardViewController *)controller
12105{
12106 switch (_focusedElementInformation.elementType) {
12107 case WebKit::InputType::ContentEditable:
12108 case WebKit::InputType::Text:
12109 case WebKit::InputType::Password:
12110 case WebKit::InputType::TextArea:
12111 case WebKit::InputType::Search:
12112 case WebKit::InputType::Email:
12113 case WebKit::InputType::URL:
12114 case WebKit::InputType::Phone:
12115 return YES__objc_yes;
12116 default:
12117 return NO__objc_no;
12118 }
12119}
12120
12121#pragma mark - WKTextInputListViewControllerDelegate
12122
12123- (WKNumberPadInputMode)numericInputModeForListViewController:(WKTextInputListViewController *)controller
12124{
12125 switch (_focusedElementInformation.elementType) {
12126 case WebKit::InputType::Phone:
12127 return WKNumberPadInputModeTelephone;
12128 case WebKit::InputType::Number:
12129 return WKNumberPadInputModeNumbersAndSymbols;
12130 case WebKit::InputType::NumberPad:
12131 return WKNumberPadInputModeNumbersOnly;
12132 default:
12133 return WKNumberPadInputModeNone;
12134 }
12135}
12136
12137- (PUICTextInputContext *)textInputContextForListViewController:(WKTextInputListViewController *)controller
12138{
12139 return self.createQuickboardTextInputContext.autorelease();
12140}
12141
12142- (BOOL)allowsDictationInputForListViewController:(PUICQuickboardViewController *)controller
12143{
12144 return _focusedElementInformation.elementType != WebKit::InputType::Password;
12145}
12146
12147#endif // HAVE(PEPPER_UI_CORE)
12148
12149#if HAVE(LOOKUP_GESTURE_RECOGNIZER)(defined HAVE_LOOKUP_GESTURE_RECOGNIZER && HAVE_LOOKUP_GESTURE_RECOGNIZER
)
12150- (void)_lookupGestureRecognized:(UIGestureRecognizer *)gestureRecognizer
12151{
12152 NSPoint locationInViewCoordinates = [gestureRecognizer locationInView:self];
12153 _page->performDictionaryLookupAtLocation(WebCore::FloatPoint(locationInViewCoordinates));
12154}
12155#endif
12156
12157- (void)buildMenuForWebViewWithBuilder:(id <UIMenuBuilder>)builder
12158{
12159#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
12160 if (auto menu = self.removeBackgroundMenu)
12161 [builder insertSiblingMenu:menu beforeMenuForIdentifier:UIMenuFormat];
12162#endif
12163
12164#if ENABLE(APP_HIGHLIGHTS)(defined 1 && 1)
12165 if (auto menu = self.appHighlightMenu)
12166 [builder insertChildMenu:menu atEndOfMenuForIdentifier:UIMenuRoot];
12167#endif
12168
12169 if (auto menu = self.scrollToTextFragmentGenerationMenu)
12170 [builder insertSiblingMenu:menu beforeMenuForIdentifier:UIMenuShare];
12171}
12172
12173- (UIMenu *)menuWithInlineAction:(NSString *)title image:(UIImage *)image identifier:(NSString *)identifier handler:(Function<void(WKContentView *)>&&)handler
12174{
12175 RetainPtr action = [UIAction actionWithTitle:title image:image identifier:identifier handler:makeBlockPtr([handler = WTF::move(handler), weakSelf = WeakObjCPtr<WKContentView>(self)](UIAction *) mutable {
12176 if (auto strongSelf = weakSelf.get())
12177 handler(strongSelf.get());
12178 }).get()];
12179 return [UIMenu menuWithTitle:@"" image:nilnullptr identifier:nilnullptr options:UIMenuOptionsDisplayInline children:@[ action.get() ]];
12180}
12181
12182#if ENABLE(APP_HIGHLIGHTS)(defined 1 && 1)
12183
12184- (UIMenu *)appHighlightMenu
12185{
12186 Ref page = *_page;
12187 if (!protect(page->preferences())->appHighlightsEnabled() || page->editorState().selectionType != WebCore::SelectionType::Range || !self.shouldAllowHighlightLinkCreation)
12188 return nilnullptr;
12189
12190 bool isVisible = page->appHighlightsVisibility();
12191 auto title = isVisible ? WebCore::contextMenuItemTagAddHighlightToCurrentQuickNote() : WebCore::contextMenuItemTagAddHighlightToNewQuickNote();
12192 return [self menuWithInlineAction:title.createNSString().get() image:[UIImage _systemImageNamed:@"quicknote"] identifier:@"WKActionCreateQuickNote" handler:[isVisible](WKContentView *view) mutable {
12193 protect(view->_page)->createAppHighlightInSelectedRange(isVisible ? WebCore::CreateNewGroupForHighlight::No : WebCore::CreateNewGroupForHighlight::Yes, WebCore::HighlightRequestOriginatedInApp::No);
12194 }];
12195}
12196
12197#endif // ENABLE(APP_HIGHLIGHTS)
12198
12199- (UIMenu *)scrollToTextFragmentGenerationMenu
12200{
12201 if (!protect(_page->preferences())->scrollToTextFragmentGenerationEnabled() || !self.shouldAllowHighlightLinkCreation)
12202 return nilnullptr;
12203
12204 return [self menuWithInlineAction:WebCore::contextMenuItemTagCopyLinkWithHighlight().createNSString().get() image:[UIImage systemImageNamed:@"text.quote"] identifier:@"WKActionScrollToTextFragmentGeneration" handler:[](WKContentView *view) mutable {
12205 protect(view->_page)->copyLinkWithHighlight();
12206 }];
12207}
12208
12209- (void)setContinuousSpellCheckingEnabled:(BOOL)enabled
12210{
12211 if (WebKit::TextChecker::setContinuousSpellCheckingEnabled(enabled))
12212 protect(_page->legacyMainFrameProcess())->updateTextCheckerState();
12213}
12214
12215- (void)setGrammarCheckingEnabled:(BOOL)enabled
12216{
12217 if (static_cast<bool>(enabled) == WebKit::TextChecker::state().contains(WebKit::TextCheckerState::GrammarCheckingEnabled))
12218 return;
12219
12220 WebKit::TextChecker::setGrammarCheckingEnabled(enabled);
12221 protect(_page->legacyMainFrameProcess())->updateTextCheckerState();
12222}
12223
12224#if HAVE(UIKIT_WITH_MOUSE_SUPPORT)(defined 1 && 1)
12225
12226- (BOOL)shouldUseMouseGestureRecognizer
12227{
12228 static const BOOL shouldUseMouseGestureRecognizer = []() -> BOOL {
12229 // <rdar://problem/59521967> iAd Video does not respond to mouse events, only touch events
12230 if (WTF::IOSApplication::isNews() || WTF::IOSApplication::isStocks())
12231 return NO__objc_no;
12232
12233 if (!linkedOnOrAfterSDKWithBehavior(SDKAlignedBehavior::SendsNativeMouseEvents)
12234 && WTF::IOSApplication::isEssentialSkeleton()) { // <rdar://problem/62694519>
12235WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGINclang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call"
12236 os_log_error(OS_LOG_DEFAULT, "WARNING: This application has been observed to ignore mouse events in web content; touch events will be sent until it is built against the iOS 13.4 SDK, but after that, the web content must respect mouse or pointer events in addition to touch events in order to behave correctly when a trackpad or mouse is used.")__extension__({ os_log_t _log_tmp = ((( os_log_t)&(_os_log_default
))); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if (os_log_type_enabled
(_log_tmp, _type_tmp)) { __extension__({ clang diagnostic push
clang diagnostic ignored "-Wvla" clang diagnostic error "-Wformat"
_Static_assert(__builtin_constant_p("WARNING: This application has been observed to ignore mouse events in web content; touch events will be sent until it is built against the iOS 13.4 SDK, but after that, the web content must respect mouse or pointer events in addition to touch events in order to behave correctly when a trackpad or mouse is used."
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG261"
) = "WARNING: This application has been observed to ignore mouse events in web content; touch events will be sent until it is built against the iOS 13.4 SDK, but after that, the web content must respect mouse or pointer events in addition to touch events in order to behave correctly when a trackpad or mouse is used."
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("WARNING: This application has been observed to ignore mouse events in web content; touch events will be sent until it is built against the iOS 13.4 SDK, but after that, the web content must respect mouse or pointer events in addition to touch events in order to behave correctly when a trackpad or mouse is used."
)]; _os_log_error_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "WARNING: This application has been observed to ignore mouse events in web content; touch events will be sent until it is built against the iOS 13.4 SDK, but after that, the web content must respect mouse or pointer events in addition to touch events in order to behave correctly when a trackpad or mouse is used."
), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); }
})
;
12237WTF_ALLOW_UNSAFE_BUFFER_USAGE_ENDclang diagnostic pop
12238 return NO__objc_no;
12239 }
12240
12241 return YES__objc_yes;
12242 }();
12243
12244 switch (_mouseEventPolicy) {
12245 case WebCore::MouseEventPolicy::Default:
12246 break;
12247#if ENABLE(IOS_TOUCH_EVENTS)(defined 0 && 0)
12248 case WebCore::MouseEventPolicy::SynthesizeTouchEvents:
12249 return NO__objc_no;
12250#endif
12251 }
12252
12253 return shouldUseMouseGestureRecognizer;
12254}
12255
12256- (void)setUpMouseGestureRecognizer
12257{
12258 if (_mouseInteraction)
12259 [self removeInteraction:_mouseInteraction.get()];
12260
12261 _mouseInteraction = adoptNS([[WKMouseInteraction alloc] initWithDelegate:self]);
12262 [self addInteraction:_mouseInteraction.get()];
12263
12264 [self _configureMouseGestureRecognizer];
12265}
12266
12267- (void)mouseInteraction:(WKMouseInteraction *)interaction changedWithEvent:(const WebKit::NativeWebMouseEvent&)event
12268{
12269 Ref page = *_page;
12270 if (!page->hasRunningProcess())
12271 return;
12272
12273 if (event.type() == WebKit::WebEventType::MouseDown) {
12274 _layerTreeTransactionIdAtLastInteractionStart = protect(downcast<WebKit::RemoteLayerTreeDrawingAreaProxy>(*page->drawingArea()))->lastCommittedMainFrameLayerTreeTransactionID();
12275
12276 if (auto lastLocation = interaction.lastLocation)
12277 _lastInteractionLocation = *lastLocation;
12278 } else if (event.type() == WebKit::WebEventType::MouseUp) {
12279 _usingMouseDragForSelection = NO__objc_no;
12280
12281 if (self.hasHiddenContentEditable && self._hasFocusedElement && !self.window.keyWindow)
12282 [self.window makeKeyWindow];
12283 }
12284
12285 page->handleMouseEvent(event);
12286}
12287
12288#if ENABLE(POINTER_LOCK)(defined 1 && 1)
12289- (void)mouseInteractionDidLoseMouseDeviceDuringPointerLock:(WKMouseInteraction *)interaction
12290{
12291 Ref page = *_page;
12292 if (!page->hasRunningProcess())
12293 return;
12294
12295 page->resetPointerLockState();
12296}
12297#endif
12298
12299- (void)_configureMouseGestureRecognizer
12300{
12301 [_mouseInteraction setEnabled:self.shouldUseMouseGestureRecognizer];
12302}
12303
12304- (void)_setMouseEventPolicy:(WebCore::MouseEventPolicy)policy
12305{
12306 _mouseEventPolicy = policy;
12307 [self _configureMouseGestureRecognizer];
12308}
12309
12310#endif // HAVE(UIKIT_WITH_MOUSE_SUPPORT)
12311
12312#if ENABLE(MEDIA_CONTROLS_CONTEXT_MENUS)(defined 1 && 1) && USE(UICONTEXTMENU)(defined 1 && 1)
12313
12314- (void)_showMediaControlsContextMenu:(WebCore::FloatRect&&)targetFrame items:(Vector<WebCore::MediaControlsContextMenuItem>&&)items frameInfo:(const WebKit::FrameInfoData&)frameInfo identifier:(WebCore::HTMLMediaElementIdentifier)identifier completionHandler:(CompletionHandler<void(WebCore::MediaControlsContextMenuItem::ID)>&&)completionHandler
12315{
12316 [protect(_actionSheetAssistant) showMediaControlsContextMenu:WTF::move(targetFrame) items:WTF::move(items) frameInfo:frameInfo identifier:identifier completionHandler:WTF::move(completionHandler)];
12317}
12318
12319- (void)captionStyleMenuWillOpenWithFrameInfo:(const WebKit::FrameInfoData&)frameInfo identifier:(WebCore::HTMLMediaElementIdentifier)identifier
12320{
12321 protect(_page)->showCaptionDisplaySettingsPreview(frameInfo, identifier);
12322}
12323
12324- (void)captionStyleMenuDidCloseWithFrameInfo:(const WebKit::FrameInfoData&)frameInfo identifier:(WebCore::HTMLMediaElementIdentifier)identifier
12325{
12326 protect(_page)->hideCaptionDisplaySettingsPreview(frameInfo, identifier);
12327}
12328#endif // ENABLE(MEDIA_CONTROLS_CONTEXT_MENUS) && USE(UICONTEXTMENU)
12329
12330#if ENABLE(VIDEO)(defined 1 && 1) && USE(UICONTEXTMENU)(defined 1 && 1)
12331- (void)showCaptionDisplaySettingsMenu:(WebCore::HTMLMediaElementIdentifier)identifier withOptions:(const WebCore::ResolvedCaptionDisplaySettingsOptions&)options completionHandler:(CompletionHandler<void(Expected<void, WebCore::ExceptionData>)>&&)completionHandler
12332{
12333 [protect(_actionSheetAssistant) showCaptionDisplaySettingsMenu:identifier withOptions:options completionHandler:WTF::move(completionHandler)];
12334}
12335#endif
12336
12337#if HAVE(UI_POINTER_INTERACTION)(defined 1 && 1)
12338
12339- (void)setUpPointerInteraction
12340{
12341 _pointerInteraction = adoptNS([[UIPointerInteraction alloc] initWithDelegate:self]);
12342 [self addInteraction:_pointerInteraction.get()];
12343}
12344
12345- (UIPointerRegion *)pointerInteraction:(UIPointerInteraction *)interaction regionForRequest:(UIPointerRegionRequest *)request defaultRegion:(UIPointerRegion *)defaultRegion
12346{
12347 [self _updateLastPointerRegionIfNeeded:request];
12348 return _lastPointerRegion.get();
12349}
12350
12351- (void)_updateLastPointerRegionIfNeeded:(UIPointerRegionRequest *)request
12352{
12353 WebKit::InteractionInformationRequest interactionInformationRequest;
12354 interactionInformationRequest.point = WebCore::roundedIntPoint(request.location);
12355 interactionInformationRequest.includeCursorContext = true;
12356 interactionInformationRequest.includeHasDoubleClickHandler = false;
12357
12358 if ([self _currentPositionInformationIsValidForRequest:interactionInformationRequest]) {
12359 _lastPointerRegion = [self pointerRegionForPositionInformation:_positionInformation point:request.location];
12360 [_webView.get() _setPointerTouchCompatibilitySimulatorEnabled:_positionInformation.needsPointerTouchCompatibilityQuirk];
12361 _pointerInteractionRegionNeedsUpdate = NO__objc_no;
12362 return;
12363 }
12364
12365 // Note: In this case where position information is not up-to-date, checking the last cached
12366 // position information may not yield expected results, since the client (or any other code in
12367 // WebKit) may have queried position information at a totally different location, for unrelated
12368 // reasons. However, this seems to work well in practice, since pointer updates are very frequent,
12369 // so any invalid state would only persist for a single frame.
12370 if (self.webView._editable && !_positionInformation.cursorContext.shouldNotUseIBeamInEditableContent) {
12371 auto lastRegionRect = _lastPointerRegion ? [_lastPointerRegion rect] : self.bounds;
12372 _lastPointerRegion = [UIPointerRegion regionWithRect:lastRegionRect identifier:editablePointerRegionIdentifier];
12373 }
12374
12375 if (_pointerInteractionRegionNeedsUpdate)
12376 return;
12377
12378 _pointerInteractionRegionNeedsUpdate = YES__objc_yes;
12379
12380 [self doAfterPositionInformationUpdate:[weakSelf = WeakObjCPtr<WKContentView>(self), location = request.location](WebKit::InteractionInformationAtPosition information) {
12381 auto strongSelf = weakSelf.get();
12382 if (!strongSelf)
12383 return;
12384
12385 strongSelf->_pointerInteractionRegionNeedsUpdate = NO__objc_no;
12386 strongSelf->_lastPointerRegion = [strongSelf pointerRegionForPositionInformation:information point:location];
12387 [strongSelf->_webView.get() _setPointerTouchCompatibilitySimulatorEnabled:information.needsPointerTouchCompatibilityQuirk];
12388 [strongSelf->_pointerInteraction invalidate];
12389 } forRequest:interactionInformationRequest];
12390}
12391
12392- (UIPointerRegion *)pointerRegionForPositionInformation:(const WebKit::InteractionInformationAtPosition&)interactionInformation point:(CGPoint)location
12393{
12394 WebCore::FloatRect expandedLineRect = enclosingIntRect(interactionInformation.cursorContext.lineCaretExtent);
12395
12396 // Pad lines of text in order to avoid switching back to the dot cursor between lines.
12397 // This matches the value that UIKit uses.
12398 // FIXME: Should this account for vertical writing mode?
12399 expandedLineRect.inflateY(10);
12400
12401 if (auto cursor = interactionInformation.cursorContext.cursor) {
12402 auto cursorType = cursor->type();
12403 if (cursorType == WebCore::Cursor::Type::Hand)
12404 return [UIPointerRegion regionWithRect:interactionInformation.bounds identifier:pointerRegionIdentifier];
12405
12406 if (cursorType == WebCore::Cursor::Type::IBeam && expandedLineRect.contains(location))
12407 return [UIPointerRegion regionWithRect:expandedLineRect identifier:pointerRegionIdentifier];
12408 }
12409
12410 if (self.webView._editable) {
12411 if (expandedLineRect.contains(location))
12412 return [UIPointerRegion regionWithRect:expandedLineRect identifier:pointerRegionIdentifier];
12413 return [UIPointerRegion regionWithRect:self.bounds identifier:editablePointerRegionIdentifier];
12414 }
12415
12416 return [UIPointerRegion regionWithRect:self.bounds identifier:pointerRegionIdentifier];
12417}
12418
12419- (UIPointerStyle *)pointerInteraction:(UIPointerInteraction *)interaction styleForRegion:(UIPointerRegion *)region
12420{
12421 double scaleFactor = self._contentZoomScale;
12422
12423 auto lineCaretExtent = _positionInformation.cursorContext.lineCaretExtent;
12424 UIPointerStyle *(^iBeamCursor)(void) = ^{
12425 bool isVertical = _positionInformation.cursorContext.isVerticalWritingMode;
12426 float beamLength = (isVertical ? lineCaretExtent.width() : lineCaretExtent.height()) * scaleFactor;
12427 auto axisOrientation = isVertical ? UIAxisHorizontal : UIAxisVertical;
12428 auto iBeamConstraintAxes = isVertical ? UIAxisHorizontal : UIAxisVertical;
12429 auto regionLengthInBlockAxis = isVertical ? CGRectGetWidth(region.rect) : CGRectGetHeight(region.rect);
12430
12431 // If the I-beam is so large that the magnetism is hard to fight, we should not apply any magnetism.
12432 static constexpr auto maximumBeamSnappingLength = 100;
12433 if (beamLength > maximumBeamSnappingLength || regionLengthInBlockAxis > maximumBeamSnappingLength)
12434 iBeamConstraintAxes = UIAxisNeither;
12435
12436 // If the region is the size of the view, we should not apply any magnetism.
12437 if ([region.identifier isEqual:editablePointerRegionIdentifier])
12438 iBeamConstraintAxes = UIAxisNeither;
12439
12440 return [UIPointerStyle styleWithShape:[UIPointerShape beamWithPreferredLength:beamLength axis:axisOrientation] constrainedAxes:iBeamConstraintAxes];
12441 };
12442
12443 if (self.webView._editable) {
12444 if (_positionInformation.cursorContext.shouldNotUseIBeamInEditableContent)
12445 return [UIPointerStyle systemPointerStyle];
12446 return iBeamCursor();
12447 }
12448
12449 if (auto cursor = _positionInformation.cursorContext.cursor; cursor && [region.identifier isEqual:pointerRegionIdentifier]) {
12450 auto cursorType = cursor->type();
12451 if (cursorType == WebCore::Cursor::Type::Hand)
12452 return [UIPointerStyle systemPointerStyle];
12453
12454 if (cursorType == WebCore::Cursor::Type::IBeam && lineCaretExtent.contains(_positionInformation.request.point))
12455 return iBeamCursor();
12456 }
12457
12458 return [UIPointerStyle systemPointerStyle];
12459}
12460
12461#endif // HAVE(UI_POINTER_INTERACTION)
12462
12463#if HAVE(PENCILKIT_TEXT_INPUT)(defined 1 && 1)
12464
12465- (void)setUpScribbleInteraction
12466{
12467 _scribbleInteraction = adoptNS([[UIIndirectScribbleInteraction alloc] initWithDelegate:self]);
12468 [self addInteraction:_scribbleInteraction.get()];
12469}
12470
12471- (void)cleanUpScribbleInteraction
12472{
12473 [self removeInteraction:_scribbleInteraction.get()];
12474 _scribbleInteraction = nilnullptr;
12475}
12476
12477- (_WKTextInputContext *)_textInputContextByScribbleIdentifier:(UIScribbleElementIdentifier)identifier
12478{
12479 _WKTextInputContext *textInputContext = (_WKTextInputContext *)identifier;
12480 if (![textInputContext isKindOfClass:_WKTextInputContext.class])
12481 return nilnullptr;
12482 auto elementContext = textInputContext._textInputContext;
12483 if (elementContext.webPageIdentifier != _page->webPageIDInMainFrameProcess())
12484 return nilnullptr;
12485 return textInputContext;
12486}
12487
12488- (BOOL)_elementForTextInputContextIsFocused:(_WKTextInputContext *)context
12489{
12490 // We ignore bounding rect changes as the bounding rect of the focused element is not kept up-to-date.
12491 return context && [self _isSameAsFocusedElement:context._textInputContext];
12492}
12493
12494- (void)indirectScribbleInteraction:(UIIndirectScribbleInteraction *)interaction requestElementsInRect:(CGRect)rect completion:(void(^)(NSArray<UIScribbleElementIdentifier> *))completion
12495{
12496 ASSERT(_scribbleInteraction.get() == interaction)((void)0);
12497 [self _requestTextInputContextsInRect:rect completionHandler:completion];
12498}
12499
12500- (BOOL)indirectScribbleInteraction:(UIIndirectScribbleInteraction *)interaction isElementFocused:(UIScribbleElementIdentifier)identifier
12501{
12502 ASSERT(_scribbleInteraction.get() == interaction)((void)0);
12503 return [self _elementForTextInputContextIsFocused:[self _textInputContextByScribbleIdentifier:identifier]];
12504}
12505
12506- (void)indirectScribbleInteraction:(UIIndirectScribbleInteraction *)interaction focusElementIfNeeded:(UIScribbleElementIdentifier)identifier referencePoint:(CGPoint)initialPoint completion:(void (^)(UIResponder<UITextInput> *))completionBlock
12507{
12508 ASSERT(_scribbleInteraction.get() == interaction)((void)0);
12509 if (auto *textInputContext = [self _textInputContextByScribbleIdentifier:identifier])
12510 [self _focusTextInputContext:textInputContext placeCaretAt:initialPoint completionHandler:completionBlock];
12511 else
12512 completionBlock(nilnullptr);
12513}
12514
12515- (CGRect)indirectScribbleInteraction:(UIIndirectScribbleInteraction *)interaction frameForElement:(UIScribbleElementIdentifier)identifier
12516{
12517 ASSERT(_scribbleInteraction.get() == interaction)((void)0);
12518 auto *textInputContext = [self _textInputContextByScribbleIdentifier:identifier];
12519 return textInputContext ? textInputContext.boundingRect : CGRectNull;
12520}
12521
12522- (void)indirectScribbleInteraction:(UIIndirectScribbleInteraction *)interaction willBeginWritingInElement:(UIScribbleElementIdentifier)identifier
12523{
12524 ASSERT(_scribbleInteraction.get() == interaction)((void)0);
12525 if (auto *textInputContext = [self _textInputContextByScribbleIdentifier:identifier])
12526 [self _willBeginTextInteractionInTextInputContext:textInputContext];
12527}
12528
12529- (void)indirectScribbleInteraction:(UIIndirectScribbleInteraction *)interaction didFinishWritingInElement:(UIScribbleElementIdentifier)identifier
12530{
12531 ASSERT(_scribbleInteraction.get() == interaction)((void)0);
12532 if (auto *textInputContext = [self _textInputContextByScribbleIdentifier:identifier])
12533 [self _didFinishTextInteractionInTextInputContext:textInputContext];
12534}
12535
12536#endif // HAVE(PENCILKIT_TEXT_INPUT)
12537
12538#if ENABLE(ATTACHMENT_ELEMENT)(defined 1 && 1)
12539
12540#if !PLATFORM(WATCHOS)(defined WTF_PLATFORM_WATCHOS && WTF_PLATFORM_WATCHOS
)
&& !PLATFORM(APPLETV)(defined WTF_PLATFORM_APPLETV && WTF_PLATFORM_APPLETV
)
12541
12542static RetainPtr<NSItemProvider> createItemProvider(const WebKit::WebPageProxy& page, const WebCore::PromisedAttachmentInfo& info)
12543{
12544
12545 auto attachment = page.attachmentForIdentifier(info.attachmentIdentifier);
12546 if (!attachment)
12547 return { };
12548
12549 RetainPtr utiType = attachment->utiType().createNSString();
12550 if (![utiType length])
12551 return { };
12552
12553 if (attachment->isEmpty())
12554 return { };
12555
12556 auto item = adoptNS([[NSItemProvider alloc] init]);
12557 [item setPreferredPresentationStyle:UIPreferredPresentationStyleAttachment];
12558
12559 RetainPtr fileName = attachment->fileName().createNSString();
12560 if ([fileName length])
12561 [item setSuggestedName:fileName.get()];
12562
12563 for (size_t index = 0; index < info.additionalTypesAndData.size(); ++index) {
12564 auto nsData = protect(info.additionalTypesAndData[index].second)->createNSData();
12565 [item registerDataRepresentationForTypeIdentifier:info.additionalTypesAndData[index].first.createNSString().get() visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[nsData](void (^completionHandler)(NSData *, NSError *)) -> NSProgress * {
12566 completionHandler(nsData.get(), nilnullptr);
12567 return nilnullptr;
12568 }];
12569 }
12570
12571 [item registerDataRepresentationForTypeIdentifier:utiType.get() visibility:NSItemProviderRepresentationVisibilityAll loadHandler:[attachment](void (^completionHandler)(NSData *, NSError *)) -> NSProgress * {
12572 attachment->doWithFileWrapper([&](NSFileWrapper *fileWrapper) {
12573 if (auto nsData = RetainPtr { fileWrapper.regularFileContents })
12574 completionHandler(nsData.get(), nilnullptr);
12575 else
12576 completionHandler(nilnullptr, [NSError errorWithDomain:WKErrorDomain code:WKErrorUnknown userInfo:nilnullptr]);
12577 });
12578 return nilnullptr;
12579 }];
12580
12581 return item;
12582}
12583
12584#endif // !PLATFORM(WATCHOS) && !PLATFORM(APPLETV)
12585
12586- (void)_writePromisedAttachmentToPasteboard:(WebCore::PromisedAttachmentInfo&&)info
12587{
12588#if !PLATFORM(WATCHOS)(defined WTF_PLATFORM_WATCHOS && WTF_PLATFORM_WATCHOS
)
&& !PLATFORM(APPLETV)(defined WTF_PLATFORM_APPLETV && WTF_PLATFORM_APPLETV
)
12589 auto item = createItemProvider(*protect(_page), WTF::move(info));
12590 if (!item)
12591 return;
12592
12593 [UIPasteboard _performAsDataOwner:[_webView.get() _effectiveDataOwner:self._dataOwnerForCopy] block:^{
12594 UIPasteboard.generalPasteboard.itemProviders = @[ item.get() ];
12595 }];
12596#else
12597 UNUSED_PARAM(info)(void)info;
12598#endif
12599}
12600
12601#endif // ENABLE(ATTACHMENT_ELEMENT)
12602
12603#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
12604
12605- (void)_endImageAnalysisGestureDeferral:(WebKit::ShouldPreventGestures)shouldPreventGestures
12606{
12607 [_imageAnalysisDeferringGestureRecognizer endDeferral:shouldPreventGestures];
12608}
12609
12610- (void)_doAfterPendingImageAnalysis:(void(^)(WebKit::ProceedWithTextSelectionInImage))block
12611{
12612 if (self.hasPendingImageAnalysisRequest)
12613 _actionsToPerformAfterPendingImageAnalysis.append(makeBlockPtr(block));
12614 else
12615 block(WebKit::ProceedWithTextSelectionInImage::No);
12616}
12617
12618- (void)_invokeAllActionsToPerformAfterPendingImageAnalysis:(WebKit::ProceedWithTextSelectionInImage)proceedWithTextSelectionInImage
12619{
12620 _pendingImageAnalysisRequestIdentifier = std::nullopt;
12621 _elementPendingImageAnalysis = std::nullopt;
12622 for (auto block : std::exchange(_actionsToPerformAfterPendingImageAnalysis, { }))
12623 block(proceedWithTextSelectionInImage);
12624}
12625
12626#endif // ENABLE(IMAGE_ANALYSIS)
12627
12628- (CALayer *)textIndicatorInstallationLayer
12629{
12630 return [self layer];
12631}
12632
12633- (void)setUpTextIndicator:(Ref<WebCore::TextIndicator>)textIndicator
12634{
12635 if (_textIndicator == textIndicator.ptr())
12636 return;
12637
12638 [self teardownTextIndicatorLayer];
12639 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(startFadeOut) object:nilnullptr];
12640
12641 _textIndicator = textIndicator.ptr();
12642
12643 CGRect frame = _textIndicator->textBoundingRectInRootViewCoordinates();
12644 _textIndicatorLayer = adoptNS([[WebTextIndicatorLayer alloc] initWithFrame:frame
12645 textIndicator:textIndicator.ptr() margin:CGSizeZero offset:CGPointZero]);
12646
12647 [[self layer] addSublayer:_textIndicatorLayer.get()];
12648
12649 if (_textIndicator->presentationTransition() != WebCore::TextIndicatorPresentationTransition::None)
12650 [_textIndicatorLayer present];
12651
12652 [self performSelector:@selector(startFadeOut) withObject:self afterDelay:WebCore::timeBeforeFadeStarts.value()];
12653}
12654
12655- (void)updateTextIndicator:(Ref<WebCore::TextIndicator>)textIndicator
12656{
12657 if (_textIndicator != textIndicator.ptr())
12658 return;
12659
12660 CGRect frame = _textIndicator->textBoundingRectInRootViewCoordinates();
12661 _textIndicatorLayer = adoptNS([[WebTextIndicatorLayer alloc] initWithFrame:frame
12662 textIndicator:textIndicator.ptr() margin:CGSizeZero offset:CGPointZero]);
12663
12664 [[self layer] addSublayer:_textIndicatorLayer.get()];
12665}
12666
12667- (void)clearTextIndicator:(WebCore::TextIndicatorDismissalAnimation)animation
12668{
12669 RefPtr<WebCore::TextIndicator> textIndicator = WTF::move(_textIndicator);
12670
12671 if ([_textIndicatorLayer isFadingOut])
12672 return;
12673
12674 if (textIndicator && textIndicator->wantsManualAnimation() && [_textIndicatorLayer hasCompletedAnimation] && animation == WebCore::TextIndicatorDismissalAnimation::FadeOut) {
12675 [self startFadeOut];
12676 return;
12677 }
12678
12679 [self teardownTextIndicatorLayer];
12680}
12681
12682- (void)setTextIndicatorAnimationProgress:(float)animationProgress
12683{
12684 if (!_textIndicator)
12685 return;
12686
12687 [_textIndicatorLayer setAnimationProgress:animationProgress];
12688}
12689
12690- (void)teardownTextIndicatorLayer
12691{
12692 [_textIndicatorLayer removeFromSuperlayer];
12693 _textIndicatorLayer = nilnullptr;
12694}
12695
12696- (void)startFadeOut
12697{
12698 [_textIndicatorLayer setFadingOut:YES__objc_yes];
12699
12700 [_textIndicatorLayer hideWithCompletionHandler:[weakSelf = WeakObjCPtr<WKContentView>(self)] {
12701 auto strongSelf = weakSelf.get();
12702 [strongSelf teardownTextIndicatorLayer];
12703 }];
12704}
12705
12706#if HAVE(UIFINDINTERACTION)(defined 1 && 1)
12707
12708- (void)find:(id)sender
12709{
12710 [self.webView find:sender];
12711}
12712
12713- (void)findAndReplace:(id)sender
12714{
12715 [self.webView findAndReplace:sender];
12716}
12717
12718- (void)findNext:(id)sender
12719{
12720 [self.webView findNext:sender];
12721}
12722
12723- (void)findPrevious:(id)sender
12724{
12725 [self.webView findPrevious:sender];
12726}
12727
12728- (void)useSelectionForFindForWebView:(id)sender
12729{
12730 if (!protect(_page)->hasSelectedRange())
12731 return;
12732
12733 NSString *selectedText = self.selectedText;
12734 if (selectedText.length) {
12735 [[self.webView findInteraction] setSearchText:selectedText];
12736 UIFindInteraction._globalFindBuffer = selectedText;
12737 }
12738}
12739
12740- (void)_findSelectedForWebView:(id)sender
12741{
12742 ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()do { if (self.shouldUseAsyncInteractions) [[unlikely]] { clang
diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInteraction
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Received unexpected call to %s"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG262"
) = "Received unexpected call to %s"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Received unexpected call to %s", __PRETTY_FUNCTION__)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Received unexpected call to %s"
, __PRETTY_FUNCTION__), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; if (WebKit::isFullWebBrowserOrRunningTest
()) do { WTF::isIntegralOrPointerType(); compilerFenceForCrash
(); WTFCrashWithInfo(12742, "/Volumes/Data/worker/Apple-iOS-26-Safer-CPP-Checks-EWS/build/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm"
, __PRETTY_FUNCTION__ ); } while (false); else ((void)0); } }
while (0)
;
12743
12744 [self findSelectedForWebView:sender];
12745}
12746
12747- (void)findSelectedForWebView:(id)sender
12748{
12749 [self useSelectionForFindForWebView:sender];
12750 [self.webView find:sender];
12751}
12752
12753- (void)performTextSearchWithQueryString:(NSString *)string usingOptions:(UITextSearchOptions *)options resultAggregator:(id<UITextSearchAggregator>)aggregator
12754{
12755 OptionSet<WebKit::FindOptions> findOptions;
12756 switch (options.wordMatchMethod) {
12757 case UITextSearchMatchMethodStartsWith:
12758 findOptions.add(WebKit::FindOptions::AtWordStarts);
12759 break;
12760 case UITextSearchMatchMethodFullWord:
12761 findOptions.add({ WebKit::FindOptions::AtWordStarts, WebKit::FindOptions::AtWordEnds });
12762 break;
12763 default:
12764 break;
12765 }
12766
12767 if (options.stringCompareOptions & NSCaseInsensitiveSearch)
12768 findOptions.add(WebKit::FindOptions::CaseInsensitive);
12769
12770 // The limit matches the limit set on existing WKWebView find API.
12771 constexpr auto maxMatches = 1000;
12772 protect(_page)->findTextRangesForStringMatches(string, findOptions, maxMatches, [string = retainPtr(string), aggregator = retainPtr(aggregator)](const Vector<WebKit::WebFoundTextRange> ranges) {
12773 for (auto& range : ranges) {
12774 RetainPtr textRange = [WKFoundTextRange foundTextRangeWithWebFoundTextRange:range];
12775 [aggregator foundRange:textRange.get() forSearchString:string.get() inDocument:nilnullptr];
12776 }
12777
12778 [aggregator finishedSearching];
12779 });
12780}
12781
12782- (void)replaceFoundTextInRange:(UITextRange *)range inDocument:(UITextSearchDocumentIdentifier)document withText:(NSString *)replacementText
12783{
12784 if (!self.supportsTextReplacement)
12785 return;
12786
12787 auto foundTextRange = dynamic_objc_cast<WKFoundTextRange>(range);
12788 if (!foundTextRange)
12789 return;
12790
12791 protect(_page)->replaceFoundTextRangeWithString([foundTextRange webFoundTextRange], replacementText);
12792}
12793
12794- (void)decorateFoundTextRange:(UITextRange *)range inDocument:(UITextSearchDocumentIdentifier)document usingStyle:(UITextSearchFoundTextStyle)style
12795{
12796 auto foundTextRange = dynamic_objc_cast<WKFoundTextRange>(range);
12797 if (!foundTextRange)
12798 return;
12799
12800 auto decorationStyle = WebKit::FindDecorationStyle::Normal;
12801 if (style == UITextSearchFoundTextStyleFound)
12802 decorationStyle = WebKit::FindDecorationStyle::Found;
12803 else if (style == UITextSearchFoundTextStyleHighlighted)
12804 decorationStyle = WebKit::FindDecorationStyle::Highlighted;
12805
12806 protect(_page)->decorateTextRangeWithStyle([foundTextRange webFoundTextRange], decorationStyle);
12807}
12808
12809- (void)scrollRangeToVisible:(UITextRange *)range inDocument:(UITextSearchDocumentIdentifier)document
12810{
12811 if (auto foundTextRange = dynamic_objc_cast<WKFoundTextRange>(range))
12812 protect(_page)->scrollTextRangeToVisible([foundTextRange webFoundTextRange]);
12813}
12814
12815- (void)clearAllDecoratedFoundText
12816{
12817 protect(_page)->clearAllDecoratedFoundText();
12818}
12819
12820- (void)didBeginTextSearchOperation
12821{
12822 [self.webView _showFindOverlay];
12823 protect(_page)->didBeginTextSearchOperation();
12824}
12825
12826- (void)didEndTextSearchOperation
12827{
12828 [self.webView _hideFindOverlay];
12829}
12830
12831- (BOOL)supportsTextReplacement
12832{
12833 return self.webView.supportsTextReplacement;
12834}
12835
12836- (BOOL)supportsTextReplacementForWebView
12837{
12838 return self.webView._editable;
12839}
12840
12841- (NSInteger)offsetFromPosition:(UITextPosition *)from toPosition:(UITextPosition *)toPosition inDocument:(UITextSearchDocumentIdentifier)document
12842{
12843 return [self offsetFromPosition:from toPosition:toPosition];
12844}
12845
12846- (NSComparisonResult)compareFoundRange:(UITextRange *)fromRange toRange:(UITextRange *)toRange inDocument:(UITextSearchDocumentIdentifier)document
12847{
12848 NSInteger offset = [self offsetFromPosition:fromRange.start toPosition:toRange.start];
12849
12850 if (offset < 0)
12851 return NSOrderedAscending;
12852
12853 if (offset > 0)
12854 return NSOrderedDescending;
12855
12856 return NSOrderedSame;
12857}
12858
12859- (void)requestRectForFoundTextRange:(UITextRange *)range completionHandler:(void (^)(CGRect))completionHandler
12860{
12861 if (auto* foundTextRange = dynamic_objc_cast<WKFoundTextRange>(range)) {
12862 protect(_page)->requestRectForFoundTextRange([foundTextRange webFoundTextRange], [completionHandler = makeBlockPtr(completionHandler)] (WebCore::FloatRect rect) {
12863 completionHandler(rect);
12864 });
12865 return;
12866 }
12867
12868 completionHandler(CGRectZero);
12869}
12870
12871#endif // HAVE(UIFINDINTERACTION)
12872
12873#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
12874
12875- (BOOL)hasSelectableTextForImageContextMenu
12876{
12877 return valueOrDefault(_imageAnalysisContextMenuActionData).hasSelectableText;
12878}
12879
12880- (BOOL)hasVisualSearchResultsForImageContextMenu
12881{
12882 return valueOrDefault(_imageAnalysisContextMenuActionData).hasVisualSearchResults;
12883}
12884
12885- (CGImageRef)subjectResultForImageContextMenu
12886{
12887 return valueOrDefault(_imageAnalysisContextMenuActionData).copySubjectResult.getAutoreleased();
12888}
12889
12890- (UIMenu *)machineReadableCodeSubMenuForImageContextMenu
12891{
12892 return valueOrDefault(_imageAnalysisContextMenuActionData).machineReadableCodeMenu.getAutoreleased();
12893}
12894
12895#if USE(QUICK_LOOK)(defined 1 && 1)
12896
12897- (void)presentVisualSearchPreviewControllerForImage:(UIImage *)image imageURL:(NSURL *)imageURL title:(NSString *)title imageBounds:(CGRect)imageBounds appearanceActions:(QLPreviewControllerFirstTimeAppearanceActions)appearanceActions
12898{
12899 ASSERT(self.hasSelectableTextForImageContextMenu || self.hasVisualSearchResultsForImageContextMenu)((void)0);
12900
12901 ASSERT(!_visualSearchPreviewController)((void)0);
12902 _visualSearchPreviewController = adoptNS([PAL::allocQLPreviewControllerInstance() init]);
12903 [_visualSearchPreviewController setDelegate:self];
12904 [_visualSearchPreviewController setDataSource:self];
12905 [_visualSearchPreviewController setAppearanceActions:appearanceActions];
12906 [_visualSearchPreviewController setModalPresentationStyle:UIModalPresentationOverFullScreen];
12907
12908 ASSERT(!_visualSearchPreviewImage)((void)0);
12909 _visualSearchPreviewImage = image;
12910
12911 ASSERT(!_visualSearchPreviewTitle)((void)0);
12912 _visualSearchPreviewTitle = title;
12913
12914 ASSERT(!_visualSearchPreviewImageURL)((void)0);
12915 _visualSearchPreviewImageURL = imageURL;
12916
12917 _visualSearchPreviewImageBounds = imageBounds;
12918
12919 auto currentPresentingViewController = self._wk_viewControllerForFullScreenPresentation;
12920 [currentPresentingViewController presentViewController:_visualSearchPreviewController.get() animated:YES__objc_yes completion:nilnullptr];
12921}
12922
12923#pragma mark - QLPreviewControllerDelegate
12924
12925- (CGRect)previewController:(QLPreviewController *)controller frameForPreviewItem:(id <QLPreviewItem>)item inSourceView:(UIView **)outView
12926{
12927 *outView = self;
12928 return _visualSearchPreviewImageBounds;
12929}
12930
12931- (UIImage *)previewController:(QLPreviewController *)controller transitionImageForPreviewItem:(id <QLPreviewItem>)item contentRect:(CGRect *)outContentRect
12932{
12933 // FIXME: We should remove this caching when UIKit doesn't call this delegate method twice, with
12934 // the second call being in the midst of an ongoing animation. See <rdar://problem/131368437>.
12935 if (!_cachedVisualSearchPreviewImageBoundsInWindowCoordinates)
12936 _cachedVisualSearchPreviewImageBoundsInWindowCoordinates = { CGPointZero, [self convertRect:_visualSearchPreviewImageBounds toView:nilnullptr].size };
12937 *outContentRect = *_cachedVisualSearchPreviewImageBoundsInWindowCoordinates;
12938 return _visualSearchPreviewImage.get();
12939}
12940
12941- (void)previewControllerDidDismiss:(QLPreviewController *)controller
12942{
12943 ASSERT(controller == _visualSearchPreviewController)((void)0);
12944 _visualSearchPreviewController.clear();
12945 _visualSearchPreviewImage.clear();
12946 _visualSearchPreviewTitle.clear();
12947 _visualSearchPreviewImageURL.clear();
12948 _cachedVisualSearchPreviewImageBoundsInWindowCoordinates.reset();
12949}
12950
12951#pragma mark - QLPreviewControllerDataSource
12952
12953- (NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)controller
12954{
12955 ASSERT(controller == _visualSearchPreviewController)((void)0);
12956 return 1;
12957}
12958
12959- (id <QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index
12960{
12961 ASSERT(controller == _visualSearchPreviewController)((void)0);
12962 ASSERT(!index)((void)0);
12963 auto item = adoptNS([PAL::allocQLItemInstance() initWithDataProvider:self contentType:UTTypeTIFF.identifier previewTitle:_visualSearchPreviewTitle.get()]);
12964 if ([item respondsToSelector:@selector(setPreviewOptions:)]) {
12965 auto previewOptions = adoptNS([[NSMutableDictionary alloc] initWithCapacity:2]);
12966 if (_visualSearchPreviewImageURL)
12967 [previewOptions setObject:_visualSearchPreviewImageURL.get() forKey:@"imageURL"];
12968 if (auto pageURL = URL { protect(_page)->currentURL() }; !pageURL.isEmpty())
12969 [previewOptions setObject:pageURL.createNSURL().get() forKey:@"pageURL"];
12970 if ([previewOptions count])
12971 [item setPreviewOptions:previewOptions.get()];
12972 }
12973 return item.autorelease();
12974}
12975
12976#pragma mark - QLPreviewItemDataProvider
12977
12978- (NSData *)provideDataForItem:(QLItem *)item
12979{
12980 ASSERT(_visualSearchPreviewImage)((void)0);
12981 return WebKit::transcode(protect([_visualSearchPreviewImage CGImage]), protect((__bridge CFStringRef)UTTypeTIFF.identifier).get()).autorelease();
12982}
12983
12984#pragma mark - WKActionSheetAssistantDelegate
12985
12986- (BOOL)actionSheetAssistant:(WKActionSheetAssistant *)assistant shouldIncludeShowTextActionForElement:(_WKActivatedElementInfo *)element
12987{
12988 return WebKit::isLiveTextAvailableAndEnabled() && self.hasSelectableTextForImageContextMenu;
12989}
12990
12991- (void)actionSheetAssistant:(WKActionSheetAssistant *)assistant showTextForImage:(UIImage *)image imageURL:(NSURL *)imageURL title:(NSString *)title imageBounds:(CGRect)imageBounds
12992{
12993 [self presentVisualSearchPreviewControllerForImage:image imageURL:imageURL title:title imageBounds:imageBounds appearanceActions:QLPreviewControllerFirstTimeAppearanceActionEnableVisualSearchDataDetection];
12994}
12995
12996- (BOOL)actionSheetAssistant:(WKActionSheetAssistant *)assistant shouldIncludeLookUpImageActionForElement:(_WKActivatedElementInfo *)element
12997{
12998 return WebKit::isLiveTextAvailableAndEnabled() && self.hasVisualSearchResultsForImageContextMenu;
12999}
13000
13001- (void)actionSheetAssistant:(WKActionSheetAssistant *)assistant lookUpImage:(UIImage *)image imageURL:(NSURL *)imageURL title:(NSString *)title imageBounds:(CGRect)imageBounds
13002{
13003 [self presentVisualSearchPreviewControllerForImage:image imageURL:imageURL title:title imageBounds:imageBounds appearanceActions:QLPreviewControllerFirstTimeAppearanceActionEnableVisualSearchMode];
13004}
13005
13006#endif // USE(QUICK_LOOK)
13007
13008#pragma mark - Image Extraction
13009
13010- (CocoaImageAnalyzer *)imageAnalyzer
13011{
13012 if (!_imageAnalyzer)
13013 _imageAnalyzer = WebKit::createImageAnalyzer();
13014 return _imageAnalyzer.get();
13015}
13016
13017- (BOOL)hasPendingImageAnalysisRequest
13018{
13019 return !!_pendingImageAnalysisRequestIdentifier;
13020}
13021
13022- (void)_setUpImageAnalysis
13023{
13024 if (!WebKit::isLiveTextAvailableAndEnabled())
13025 return;
13026
13027 _pendingImageAnalysisRequestIdentifier = std::nullopt;
13028 _isProceedingWithTextSelectionInImage = NO__objc_no;
13029 _elementPendingImageAnalysis = std::nullopt;
13030 _imageAnalysisGestureRecognizer = adoptNS([[WKImageAnalysisGestureRecognizer alloc] initWithImageAnalysisGestureDelegate:self]);
13031 [self addGestureRecognizer:_imageAnalysisGestureRecognizer.get()];
13032#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
13033 _removeBackgroundData = std::nullopt;
13034#endif
13035 _dynamicImageAnalysisContextMenuState = WebKit::DynamicImageAnalysisContextMenuState::NotWaiting;
13036 _imageAnalysisContextMenuActionData = std::nullopt;
13037}
13038
13039- (void)_tearDownImageAnalysis
13040{
13041 if (!WebKit::isLiveTextAvailableAndEnabled())
13042 return;
13043
13044 [_imageAnalysisGestureRecognizer setDelegate:nilnullptr];
13045 [self removeGestureRecognizer:_imageAnalysisGestureRecognizer.get()];
13046 _imageAnalysisGestureRecognizer = nilnullptr;
13047 _pendingImageAnalysisRequestIdentifier = std::nullopt;
13048 _isProceedingWithTextSelectionInImage = NO__objc_no;
13049 _elementPendingImageAnalysis = std::nullopt;
13050ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
13051 [std::exchange(_imageAnalyzer, nilnullptr) cancelAllRequests];
13052ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
13053 [self _invokeAllActionsToPerformAfterPendingImageAnalysis:WebKit::ProceedWithTextSelectionInImage::No];
13054#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
13055 [self uninstallImageAnalysisInteraction];
13056 _removeBackgroundData = std::nullopt;
13057#endif
13058 _dynamicImageAnalysisContextMenuState = WebKit::DynamicImageAnalysisContextMenuState::NotWaiting;
13059 _imageAnalysisContextMenuActionData = std::nullopt;
13060}
13061
13062- (void)_cancelImageAnalysis
13063{
13064ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
13065 [_imageAnalyzer cancelAllRequests];
13066ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
13067 RELEASE_LOG_IF(self.hasPendingImageAnalysisRequest, ImageAnalysis, "Image analysis request %" PRIu64 " cancelled.", _pendingImageAnalysisRequestIdentifier->toUInt64())do { if (self.hasPendingImageAnalysisRequest) clang diagnostic
push clang diagnostic ignored "-Wunknown-warning-option" clang
diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogImageAnalysis
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Image analysis request %" "ll" "u" " cancelled."), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG263"
) = "Image analysis request %" "ll" "u" " cancelled."; uint8_t
_Alignas(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Image analysis request %" "ll" "u" " cancelled.", _pendingImageAnalysisRequestIdentifier
->toUInt64())]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "Image analysis request %" "ll" "u" " cancelled.", _pendingImageAnalysisRequestIdentifier
->toUInt64()), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop ; } while (0)
;
13068 _pendingImageAnalysisRequestIdentifier = std::nullopt;
13069 _isProceedingWithTextSelectionInImage = NO__objc_no;
13070 _elementPendingImageAnalysis = std::nullopt;
13071}
13072
13073- (RetainPtr<CocoaImageAnalyzerRequest>)createImageAnalyzerRequest:(VKAnalysisTypes)analysisTypes image:(CGImageRef)image imageURL:(NSURL *)imageURL
13074{
13075 auto request = WebKit::createImageAnalyzerRequest(image, analysisTypes);
13076 [request setImageURL:imageURL];
13077 [request setPageURL:[NSURL _web_URLWithWTFString:protect(_page)->currentURL()]];
13078 return request;
13079}
13080
13081- (RetainPtr<CocoaImageAnalyzerRequest>)createImageAnalyzerRequest:(VKAnalysisTypes)analysisTypes image:(CGImageRef)image
13082{
13083 return [self createImageAnalyzerRequest:analysisTypes image:image imageURL:_positionInformation.imageURL.createNSURL().get()];
13084}
13085
13086
13087- (void)updateImageAnalysisForContextMenuPresentation:(CocoaImageAnalysis *)analysis elementBounds:(CGRect)elementBounds
13088{
13089#if USE(UICONTEXTMENU)(defined 1 && 1) && ENABLE(IMAGE_ANALYSIS_FOR_MACHINE_READABLE_CODES)(defined 1 && 1)
13090 analysis.presentingViewControllerForMrcAction = self._wk_viewControllerForFullScreenPresentation;
13091 if ([analysis respondsToSelector:@selector(setRectForMrcActionInPresentingViewController:)]) {
13092 CGRect boundsInPresentingViewController = [self convertRect:elementBounds toView:analysis.presentingViewControllerForMrcAction.viewIfLoaded];
13093 analysis.rectForMrcActionInPresentingViewController = boundsInPresentingViewController;
13094 }
13095#endif
13096}
13097
13098
13099- (BOOL)validateImageAnalysisRequestIdentifier:(WebKit::ImageAnalysisRequestIdentifier)identifier
13100{
13101 if (_pendingImageAnalysisRequestIdentifier == identifier)
13102 return YES__objc_yes;
13103
13104 if (!self.hasPendingImageAnalysisRequest) {
13105 // Only invoke deferred image analysis blocks if there is no ongoing request; otherwise, this would
13106 // cause these blocks to be invoked too early (i.e. in the middle of the new image analysis request).
13107 [self _invokeAllActionsToPerformAfterPendingImageAnalysis:WebKit::ProceedWithTextSelectionInImage::No];
13108 }
13109
13110 RELEASE_LOG(ImageAnalysis, "Image analysis request %" PRIu64 " invalidated.", identifier.toUInt64())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogImageAnalysis
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Image analysis request %" "ll" "u" " invalidated."), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG264"
) = "Image analysis request %" "ll" "u" " invalidated."; uint8_t
_Alignas(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Image analysis request %" "ll" "u" " invalidated.", identifier
.toUInt64())]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "Image analysis request %" "ll" "u" " invalidated.", identifier
.toUInt64()), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop
;
13111 return NO__objc_no;
13112}
13113
13114- (void)requestTextRecognition:(NSURL *)imageURL imageData:(WebCore::ShareableBitmap::Handle&&)imageData sourceLanguageIdentifier:(NSString *)sourceLanguageIdentifier targetLanguageIdentifier:(NSString *)targetLanguageIdentifier completionHandler:(CompletionHandler<void(WebCore::TextRecognitionResult&&)>&&)completion
13115{
13116 auto imageBitmap = WebCore::ShareableBitmap::create(WTF::move(imageData));
13117 if (!imageBitmap) {
13118 completion({ });
13119 return;
13120 }
13121
13122 RetainPtr cgImage = imageBitmap->createPlatformImage(WebCore::DontCopyBackingStore);
13123 if (!cgImage) {
13124 completion({ });
13125 return;
13126 }
13127
13128#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
13129 if (targetLanguageIdentifier.length)
13130 return WebKit::requestVisualTranslation(self.imageAnalyzer, imageURL, sourceLanguageIdentifier, targetLanguageIdentifier, cgImage.get(), WTF::move(completion));
13131#else
13132 UNUSED_PARAM(sourceLanguageIdentifier)(void)sourceLanguageIdentifier;
13133 UNUSED_PARAM(targetLanguageIdentifier)(void)targetLanguageIdentifier;
13134#endif
13135
13136 auto request = [self createImageAnalyzerRequest:VKAnalysisTypeText image:cgImage.get()];
13137 [self.imageAnalyzer processRequest:request.get() progressHandler:nilnullptr completionHandler:makeBlockPtr([completion = WTF::move(completion)] (CocoaImageAnalysis *result, NSError *) mutable {
13138 completion(WebKit::makeTextRecognitionResult(result));
13139 }).get()];
13140}
13141
13142#pragma mark - WKImageAnalysisGestureRecognizerDelegate
13143
13144- (void)imageAnalysisGestureDidBegin:(WKImageAnalysisGestureRecognizer *)gestureRecognizer
13145{
13146 ASSERT(WebKit::isLiveTextAvailableAndEnabled())((void)0);
13147
13148 if ([self _isPanningScrollViewOrAncestor:gestureRecognizer.lastTouchedScrollView])
13149 return;
13150
13151 auto requestIdentifier = WebKit::ImageAnalysisRequestIdentifier::generate();
13152
13153ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
13154 [_imageAnalyzer cancelAllRequests];
13155ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
13156 _pendingImageAnalysisRequestIdentifier = requestIdentifier;
13157 _isProceedingWithTextSelectionInImage = NO__objc_no;
13158 _elementPendingImageAnalysis = std::nullopt;
13159 _dynamicImageAnalysisContextMenuState = WebKit::DynamicImageAnalysisContextMenuState::NotWaiting;
13160 _imageAnalysisContextMenuActionData = std::nullopt;
13161
13162 WebKit::InteractionInformationRequest request { WebCore::roundedIntPoint([gestureRecognizer locationInView:self]) };
13163 request.includeImageData = true;
13164 [self doAfterPositionInformationUpdate:[requestIdentifier = WTF::move(requestIdentifier), weakSelf = WeakObjCPtr<WKContentView>(self), gestureDeferralToken = WebKit::ImageAnalysisGestureDeferralToken::create(self)] (WebKit::InteractionInformationAtPosition information) mutable {
13165 auto strongSelf = weakSelf.get();
13166 if (![strongSelf validateImageAnalysisRequestIdentifier:requestIdentifier])
13167 return;
13168
13169 bool shouldAnalyzeImageAtLocation = ([&] {
13170 if (!information.isImage && !canAttemptTextRecognitionForNonImageElements(information, protect(strongSelf->_page->preferences())))
13171 return false;
13172
13173 if (!information.image)
13174 return false;
13175
13176 if (!information.hostImageOrVideoElementContext)
13177 return false;
13178
13179 if (information.isAnimatedImage)
13180 return false;
13181
13182 if (information.isContentEditable)
13183 return false;
13184
13185 return true;
13186 })();
13187
13188 if (!strongSelf->_pendingImageAnalysisRequestIdentifier || !shouldAnalyzeImageAtLocation) {
13189 [strongSelf _invokeAllActionsToPerformAfterPendingImageAnalysis:WebKit::ProceedWithTextSelectionInImage::No];
13190 return;
13191 }
13192
13193 RetainPtr cgImage = protect(information.image)->createPlatformImage();
13194 if (!cgImage) {
13195 [strongSelf _invokeAllActionsToPerformAfterPendingImageAnalysis:WebKit::ProceedWithTextSelectionInImage::No];
13196 return;
13197 }
13198
13199 RELEASE_LOG(ImageAnalysis, "Image analysis preflight gesture initiated (request %" PRIu64 ").", requestIdentifier.toUInt64())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogImageAnalysis
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Image analysis preflight gesture initiated (request %" "ll"
"u" ")."), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG265"
) = "Image analysis preflight gesture initiated (request %" "ll"
"u" ")."; uint8_t _Alignas(16) __attribute__((uninitialized)
) _os_fmt_buf[__builtin_os_log_format_buffer_size("Image analysis preflight gesture initiated (request %"
"ll" "u" ").", requestIdentifier.toUInt64())]; _os_log_impl(
&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Image analysis preflight gesture initiated (request %"
"ll" "u" ").", requestIdentifier.toUInt64()), (uint32_t)sizeof
(_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
13200
13201 strongSelf->_elementPendingImageAnalysis = information.hostImageOrVideoElementContext;
13202
13203 auto requestLocation = information.request.point;
13204 WebCore::ElementContext elementContext = *information.hostImageOrVideoElementContext;
13205
13206 auto requestForTextSelection = [strongSelf createImageAnalyzerRequest:VKAnalysisTypeText image:cgImage.get()];
13207 if (information.isPausedVideo)
13208 [requestForTextSelection setImageSource:VKImageAnalyzerRequestImageSourceVideoFrame];
13209
13210 if (information.elementContainsImageOverlay) {
13211 [strongSelf _completeImageAnalysisRequestForContextMenu:cgImage.get() requestIdentifier:requestIdentifier hasTextResults:YES__objc_yes];
13212 return;
13213 }
13214
13215 auto textAnalysisStartTime = MonotonicTime::now();
13216 [[strongSelf imageAnalyzer] processRequest:requestForTextSelection.get() progressHandler:nilnullptr completionHandler:[requestIdentifier = WTF::move(requestIdentifier), weakSelf, elementContext, requestLocation, cgImage, gestureDeferralToken, textAnalysisStartTime] (CocoaImageAnalysis *result, NSError *error) mutable {
13217 auto strongSelf = weakSelf.get();
13218 if (![strongSelf validateImageAnalysisRequestIdentifier:requestIdentifier])
13219 return;
13220
13221 BOOL hasTextResults = [result hasResultsForAnalysisTypes:VKAnalysisTypeText];
13222 RELEASE_LOG(ImageAnalysis, "Image analysis completed in %.0f ms (request %" PRIu64 "; found text? %d)", (MonotonicTime::now() - textAnalysisStartTime).milliseconds(), requestIdentifier.toUInt64(), hasTextResults)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogImageAnalysis
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Image analysis completed in %.0f ms (request %" "ll" "u" "; found text? %d)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG266"
) = "Image analysis completed in %.0f ms (request %" "ll" "u"
"; found text? %d)"; uint8_t _Alignas(16) __attribute__((uninitialized
)) _os_fmt_buf[__builtin_os_log_format_buffer_size("Image analysis completed in %.0f ms (request %"
"ll" "u" "; found text? %d)", (MonotonicTime::now() - textAnalysisStartTime
).milliseconds(), requestIdentifier.toUInt64(), hasTextResults
)]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str
, (uint8_t *)__builtin_os_log_format(_os_fmt_buf, "Image analysis completed in %.0f ms (request %"
"ll" "u" "; found text? %d)", (MonotonicTime::now() - textAnalysisStartTime
).milliseconds(), requestIdentifier.toUInt64(), hasTextResults
), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); }
}) clang diagnostic pop
;
13223
13224 protect(strongSelf->_page)->updateWithTextRecognitionResult(WebKit::makeTextRecognitionResult(result), elementContext, requestLocation, [requestIdentifier = WTF::move(requestIdentifier), weakSelf, hasTextResults, cgImage, gestureDeferralToken] (WebKit::TextRecognitionUpdateResult updateResult) mutable {
13225 auto strongSelf = weakSelf.get();
13226 if (![strongSelf validateImageAnalysisRequestIdentifier:requestIdentifier])
13227 return;
13228
13229 if (updateResult == WebKit::TextRecognitionUpdateResult::Text) {
13230 strongSelf->_isProceedingWithTextSelectionInImage = YES__objc_yes;
13231 [strongSelf _invokeAllActionsToPerformAfterPendingImageAnalysis:WebKit::ProceedWithTextSelectionInImage::Yes];
13232 return;
13233 }
13234
13235 gestureDeferralToken->setShouldPreventTextSelection();
13236
13237 if (updateResult == WebKit::TextRecognitionUpdateResult::DataDetector) {
13238 [strongSelf _invokeAllActionsToPerformAfterPendingImageAnalysis:WebKit::ProceedWithTextSelectionInImage::No];
13239 return;
13240 }
13241
13242 [strongSelf _completeImageAnalysisRequestForContextMenu:cgImage.get() requestIdentifier:requestIdentifier hasTextResults:hasTextResults];
13243 });
13244 }];
13245 } forRequest:request];
13246}
13247
13248#if ENABLE(IMAGE_ANALYSIS_FOR_MACHINE_READABLE_CODES)(defined 1 && 1)
13249static BOOL shouldUseMachineReadableCodeMenuFromImageAnalysisResult(CocoaImageAnalysis *result)
13250{
13251#if HAVE(BCS_LIVE_CAMERA_ONLY_ACTION_SPI)(defined HAVE_BCS_LIVE_CAMERA_ONLY_ACTION_SPI && HAVE_BCS_LIVE_CAMERA_ONLY_ACTION_SPI
)
13252 return [result.barcodeActions indexOfObjectPassingTest:^BOOL(BCSAction *action, NSUInteger index, BOOL *stop) {
13253 return [action respondsToSelector:@selector(isLiveCameraOnlyAction)] && [(id)action isLiveCameraOnlyAction];
13254 }] == NSNotFound;
13255#else // not HAVE(BCS_LIVE_CAMERA_ONLY_ACTION_SPI)
13256 return YES__objc_yes;
13257#endif // HAVE(BCS_LIVE_CAMERA_ONLY_ACTION_SPI)
13258}
13259#endif // ENABLE(IMAGE_ANALYSIS_FOR_MACHINE_READABLE_CODES)
13260
13261- (void)_completeImageAnalysisRequestForContextMenu:(CGImageRef)image requestIdentifier:(WebKit::ImageAnalysisRequestIdentifier)requestIdentifier hasTextResults:(BOOL)hasTextResults
13262{
13263 _dynamicImageAnalysisContextMenuState = WebKit::DynamicImageAnalysisContextMenuState::WaitingForImageAnalysis;
13264 _imageAnalysisContextMenuActionData = std::nullopt;
13265 [self _invokeAllActionsToPerformAfterPendingImageAnalysis:WebKit::ProceedWithTextSelectionInImage::No];
13266
13267 auto data = Box<WebKit::ImageAnalysisContextMenuActionData>::create();
13268 data->hasSelectableText = hasTextResults;
13269
13270 auto weakSelf = WeakObjCPtr<WKContentView>(self);
13271 auto aggregator = MainRunLoopCallbackAggregator::create([weakSelf, data]() mutable {
13272 auto strongSelf = weakSelf.get();
13273 if (!strongSelf || strongSelf->_dynamicImageAnalysisContextMenuState == WebKit::DynamicImageAnalysisContextMenuState::NotWaiting)
13274 return;
13275
13276 strongSelf->_imageAnalysisContextMenuActionData = WTF::move(*data);
13277 [strongSelf _insertDynamicImageAnalysisContextMenuItemsIfPossible];
13278 });
13279
13280 auto request = [self createImageAnalyzerRequest:VKAnalysisTypeVisualSearch | VKAnalysisTypeMachineReadableCode | VKAnalysisTypeAppClip image:image];
13281 if (_positionInformation.isPausedVideo)
13282 [request setImageSource:VKImageAnalyzerRequestImageSourceVideoFrame];
13283
13284 auto elementBounds = _positionInformation.bounds;
13285 auto visualSearchAnalysisStartTime = MonotonicTime::now();
13286 [self.imageAnalyzer processRequest:request.get() progressHandler:nilnullptr completionHandler:[requestIdentifier = WTF::move(requestIdentifier), weakSelf, visualSearchAnalysisStartTime, aggregator = aggregator.copyRef(), data, elementBounds] (CocoaImageAnalysis *result, NSError *error) mutable {
13287 auto strongSelf = weakSelf.get();
13288 if (!strongSelf)
13289 return;
13290
13291#if USE(QUICK_LOOK)(defined 1 && 1)
13292 BOOL hasVisualSearchResults = [result hasResultsForAnalysisTypes:VKAnalysisTypeVisualSearch];
13293 RELEASE_LOG(ImageAnalysis, "Image analysis completed in %.0f ms (request %" PRIu64 "; found visual search results? %d)", (MonotonicTime::now() - visualSearchAnalysisStartTime).milliseconds(), requestIdentifier.toUInt64(), hasVisualSearchResults)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogImageAnalysis
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Image analysis completed in %.0f ms (request %" "ll" "u" "; found visual search results? %d)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG267"
) = "Image analysis completed in %.0f ms (request %" "ll" "u"
"; found visual search results? %d)"; uint8_t _Alignas(16) __attribute__
((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Image analysis completed in %.0f ms (request %" "ll" "u" "; found visual search results? %d)"
, (MonotonicTime::now() - visualSearchAnalysisStartTime).milliseconds
(), requestIdentifier.toUInt64(), hasVisualSearchResults)]; _os_log_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "Image analysis completed in %.0f ms (request %"
"ll" "u" "; found visual search results? %d)", (MonotonicTime
::now() - visualSearchAnalysisStartTime).milliseconds(), requestIdentifier
.toUInt64(), hasVisualSearchResults), (uint32_t)sizeof(_os_fmt_buf
)) clang diagnostic pop ; }); } }) clang diagnostic pop
;
13294#else
13295 UNUSED_PARAM(requestIdentifier)(void)requestIdentifier;
13296 UNUSED_PARAM(visualSearchAnalysisStartTime)(void)visualSearchAnalysisStartTime;
13297#endif
13298 if (!result || error)
13299 return;
13300
13301 [strongSelf updateImageAnalysisForContextMenuPresentation:result elementBounds:elementBounds];
13302
13303#if ENABLE(IMAGE_ANALYSIS_FOR_MACHINE_READABLE_CODES)(defined 1 && 1)
13304 if (shouldUseMachineReadableCodeMenuFromImageAnalysisResult(result))
13305 data->machineReadableCodeMenu = result.mrcMenu;
13306#endif
13307#if USE(QUICK_LOOK)(defined 1 && 1)
13308 data->hasVisualSearchResults = hasVisualSearchResults;
13309#endif
13310 }];
13311
13312#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
13313 if (protect(_page->preferences())->removeBackgroundEnabled()) {
13314 WebKit::requestBackgroundRemoval(image, [weakSelf = WeakObjCPtr<WKContentView>(self), aggregator = aggregator.copyRef(), data](CGImageRef result) mutable {
13315 if (auto strongSelf = weakSelf.get())
13316 data->copySubjectResult = result;
13317 });
13318 }
13319#endif
13320}
13321
13322- (void)_insertDynamicImageAnalysisContextMenuItemsIfPossible
13323{
13324 bool updated = false;
13325 [self.contextMenuInteraction updateVisibleMenuWithBlock:makeBlockPtr([&, strongSelf = RetainPtr { self }](UIMenu *menu) -> UIMenu * {
13326 updated = true;
13327 __block__attribute__((__blocks__(byref))) BOOL foundRevealImageItem = NO__objc_no;
13328 __block__attribute__((__blocks__(byref))) BOOL foundShowTextItem = NO__objc_no;
13329 RetainPtr revealImageIdentifier = elementActionTypeToUIActionIdentifier(_WKElementActionTypeRevealImage);
13330 RetainPtr showTextIdentifier = elementActionTypeToUIActionIdentifier(_WKElementActionTypeImageExtraction);
13331 [menu.children enumerateObjectsUsingBlock:^(UIMenuElement *child, NSUInteger index, BOOL* stop) {
13332 auto *action = dynamic_objc_cast<UIAction>(child);
13333 if ([action.identifier isEqualToString:revealImageIdentifier.get()])
13334 foundRevealImageItem = YES__objc_yes;
13335 else if ([action.identifier isEqualToString:showTextIdentifier.get()])
13336 foundShowTextItem = YES__objc_yes;
13337 }];
13338
13339 auto adjustedChildren = adoptNS(menu.children.mutableCopy);
13340 auto newItems = adoptNS([NSMutableArray<UIMenuElement *> new]);
13341
13342 for (UIMenuElement *child in adjustedChildren.get()) {
13343 RetainPtr action = dynamic_objc_cast<UIAction>(child);
13344 if (!action)
13345 continue;
13346
13347 if ([action.get().identifier isEqual:protect(elementActionTypeToUIActionIdentifier(_WKElementActionTypeCopyCroppedImage)).get()]) {
13348 if (self.subjectResultForImageContextMenu)
13349 action.get().attributes &= ~UIMenuElementAttributesDisabled;
13350
13351 continue;
13352 }
13353
13354 if ([action.get().identifier isEqual:revealImageIdentifier.get()]) {
13355 if (self.hasVisualSearchResultsForImageContextMenu)
13356 action.get().attributes &= ~UIMenuElementAttributesDisabled;
13357
13358 continue;
13359 }
13360 }
13361
13362 if (!foundShowTextItem && self.hasSelectableTextForImageContextMenu) {
13363 // Dynamically insert the "Show Text" menu item, if it wasn't already inserted.
13364 // FIXME: This should probably be inserted unconditionally, and enabled if needed
13365 // like Look Up or Copy Subject.
13366 auto *elementInfo = [_WKActivatedElementInfo activatedElementInfoWithInteractionInformationAtPosition:_positionInformation userInfo:nilnullptr];
13367 auto *elementAction = [_WKElementAction _elementActionWithType:_WKElementActionTypeImageExtraction info:elementInfo assistant:_actionSheetAssistant.get()];
13368 [newItems addObject:[elementAction uiActionForElementInfo:elementInfo]];
13369 }
13370
13371 if (foundRevealImageItem) {
13372 // Only dynamically insert machine-readable code items if the client didn't explicitly
13373 // remove the Look Up ("reveal image") item.
13374 if (UIMenu *subMenu = self.machineReadableCodeSubMenuForImageContextMenu)
13375 [newItems addObject:subMenu];
13376 }
13377
13378 RELEASE_LOG(ImageAnalysis, "Dynamically inserting %zu context menu action(s)", [newItems count])clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogImageAnalysis
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Dynamically inserting %zu context menu action(s)"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG268"
) = "Dynamically inserting %zu context menu action(s)"; uint8_t
_Alignas(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Dynamically inserting %zu context menu action(s)", [newItems
count])]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "Dynamically inserting %zu context menu action(s)", [newItems
count]), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop
; }); } }) clang diagnostic pop
;
13379 [adjustedChildren addObjectsFromArray:newItems.get()];
13380 return [menu menuByReplacingChildren:adjustedChildren.get()];
13381 }).get()];
13382
13383 _dynamicImageAnalysisContextMenuState = updated ? WebKit::DynamicImageAnalysisContextMenuState::NotWaiting : WebKit::DynamicImageAnalysisContextMenuState::WaitingForVisibleMenu;
13384}
13385
13386- (void)imageAnalysisGestureDidFail:(WKImageAnalysisGestureRecognizer *)gestureRecognizer
13387{
13388 [self _endImageAnalysisGestureDeferral:WebKit::ShouldPreventGestures::No];
13389}
13390
13391- (void)captureTextFromCameraForWebView:(id)sender
13392{
13393 [super captureTextFromCamera:sender];
13394}
13395
13396#endif // ENABLE(IMAGE_ANALYSIS)
13397
13398#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
13399
13400- (BOOL)actionSheetAssistantShouldIncludeCopySubjectAction:(WKActionSheetAssistant *)assistant
13401{
13402 return !!self.subjectResultForImageContextMenu;
13403}
13404
13405- (void)actionSheetAssistant:(WKActionSheetAssistant *)assistant copySubject:(UIImage *)image sourceMIMEType:(NSString *)sourceMIMEType
13406{
13407 if (!self.subjectResultForImageContextMenu)
13408 return;
13409
13410 auto [data, type] = WebKit::imageDataForRemoveBackground(protect(self.subjectResultForImageContextMenu), protect((__bridge CFStringRef)sourceMIMEType).get());
13411 if (!data)
13412 return;
13413
13414 [UIPasteboard _performAsDataOwner:self._dataOwnerForCopy block:[data = WTF::move(data), type = WTF::move(type)] {
13415 [UIPasteboard.generalPasteboard setData:data.get() forPasteboardType:(__bridge NSString *)type.get()];
13416 }];
13417}
13418
13419#pragma mark - VKCImageAnalysisInteractionDelegate
13420
13421- (CGRect)contentsRectForImageAnalysisInteraction:(VKCImageAnalysisInteraction *)interaction
13422{
13423 auto unitInteractionRect = _imageAnalysisInteractionBounds;
13424 WebCore::FloatRect contentViewBounds = self.bounds;
13425 unitInteractionRect.moveBy(-contentViewBounds.location());
13426 unitInteractionRect.scale(1 / contentViewBounds.size());
13427 return unitInteractionRect;
13428}
13429
13430- (BOOL)imageAnalysisInteraction:(VKCImageAnalysisInteraction *)interaction shouldBeginAtPoint:(CGPoint)point forAnalysisType:(VKImageAnalysisInteractionTypes)analysisType
13431{
13432 return interaction.hasActiveTextSelection || [interaction interactableItemExistsAtPoint:point];
13433}
13434
13435#endif // ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)
13436
13437- (void)beginTextRecognitionForFullscreenVideo:(WebCore::ShareableBitmap::Handle&&)imageData playerViewController:(AVPlayerViewController *)controller
13438{
13439#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
13440 ASSERT(_page->preferences().textRecognitionInVideosEnabled())((void)0);
13441
13442 if (_fullscreenVideoImageAnalysisRequestIdentifier)
13443 return;
13444
13445 auto imageBitmap = WebCore::ShareableBitmap::create(WTF::move(imageData));
13446 if (!imageBitmap)
13447 return;
13448
13449 RetainPtr cgImage = imageBitmap->createPlatformImage(WebCore::DontCopyBackingStore);
13450 if (!cgImage)
13451 return;
13452
13453 auto request = [self createImageAnalyzerRequest:WebKit::analysisTypesForFullscreenVideo() image:cgImage.get()];
13454 [request setImageSource:VKImageAnalyzerRequestImageSourceVideoFrame];
13455 _fullscreenVideoImageAnalysisRequestIdentifier = [self.imageAnalyzer processRequest:request.get() progressHandler:nilnullptr completionHandler:makeBlockPtr([weakSelf = WeakObjCPtr<WKContentView>(self), controller = RetainPtr { controller }] (CocoaImageAnalysis *result, NSError *) mutable {
13456 auto strongSelf = weakSelf.get();
13457 if (!strongSelf)
13458 return;
13459
13460 strongSelf->_fullscreenVideoImageAnalysisRequestIdentifier = 0;
13461
13462 if ([controller respondsToSelector:@selector(setImageAnalysis:)])
13463 [controller setImageAnalysis:result];
13464 }).get()];
13465#endif // ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)
13466}
13467
13468- (void)cancelTextRecognitionForFullscreenVideo:(AVPlayerViewController *)controller
13469{
13470#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
13471 if (auto identifier = std::exchange(_fullscreenVideoImageAnalysisRequestIdentifier, 0))
13472 [_imageAnalyzer cancelRequestID:identifier];
13473
13474 if ([controller respondsToSelector:@selector(setImageAnalysis:)])
13475 [controller setImageAnalysis:nilnullptr];
13476#endif
13477}
13478
13479- (BOOL)isTextRecognitionInFullscreenVideoEnabled
13480{
13481#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
13482 return protect(_page->preferences())->textRecognitionInVideosEnabled();
13483#else
13484 return NO__objc_no;
13485#endif
13486}
13487
13488- (void)beginTextRecognitionForVideoInElementFullscreen:(WebCore::ShareableBitmap::Handle&&)bitmapHandle bounds:(WebCore::FloatRect)bounds
13489{
13490#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
13491 auto imageBitmap = WebCore::ShareableBitmap::create(WTF::move(bitmapHandle));
13492 if (!imageBitmap)
13493 return;
13494
13495 RetainPtr image = imageBitmap->createPlatformImage(WebCore::DontCopyBackingStore);
13496 if (!image)
13497 return;
13498
13499 auto request = WebKit::createImageAnalyzerRequest(image.get(), WebKit::analysisTypesForElementFullscreenVideo());
13500 [request setImageSource:VKImageAnalyzerRequestImageSourceVideoFrame];
13501 _fullscreenVideoImageAnalysisRequestIdentifier = [self.imageAnalyzer processRequest:request.get() progressHandler:nilnullptr completionHandler:[weakSelf = WeakObjCPtr<WKContentView>(self), bounds](CocoaImageAnalysis *result, NSError *error) {
13502 auto strongSelf = weakSelf.get();
13503 if (!strongSelf || !strongSelf->_fullscreenVideoImageAnalysisRequestIdentifier)
13504 return;
13505
13506 strongSelf->_fullscreenVideoImageAnalysisRequestIdentifier = 0;
13507 if (error || !result)
13508 return;
13509
13510 strongSelf->_imageAnalysisInteractionBounds = bounds;
13511 [strongSelf installImageAnalysisInteraction:result];
13512 }];
13513#endif // ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)
13514}
13515
13516- (void)cancelTextRecognitionForVideoInElementFullscreen
13517{
13518#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
13519 [self uninstallImageAnalysisInteraction];
13520
13521 if (auto previousIdentifier = std::exchange(_fullscreenVideoImageAnalysisRequestIdentifier, 0))
13522 [self.imageAnalyzer cancelRequestID:previousIdentifier];
13523#endif
13524}
13525
13526#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
13527
13528- (void)installImageAnalysisInteraction:(VKCImageAnalysis *)analysis
13529{
13530 if (!_imageAnalysisInteraction) {
13531 _imageAnalysisActionButtons = adoptNS([[NSMutableSet alloc] initWithCapacity:1]);
13532 _imageAnalysisInteraction = adoptNS([PAL::allocVKCImageAnalysisInteractionInstance() init]);
13533 [_imageAnalysisInteraction setDelegate:self];
13534 [_imageAnalysisInteraction setAnalysisButtonRequiresVisibleContentGating:YES__objc_yes];
13535 [_imageAnalysisInteraction setQuickActionConfigurationUpdateHandler:[weakSelf = WeakObjCPtr<WKContentView>(self)] (UIButton *button) {
13536 if (auto strongSelf = weakSelf.get())
13537 [strongSelf->_imageAnalysisActionButtons addObject:button];
13538 }];
13539 WebKit::prepareImageAnalysisForOverlayView(_imageAnalysisInteraction.get());
13540 [self addInteraction:_imageAnalysisInteraction.get()];
13541 RELEASE_LOG(ImageAnalysis, "Installing image analysis interaction at {{ %.0f, %.0f }, { %.0f, %.0f }}",clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogImageAnalysis
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Installing image analysis interaction at {{ %.0f, %.0f }, { %.0f, %.0f }}"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG269"
) = "Installing image analysis interaction at {{ %.0f, %.0f }, { %.0f, %.0f }}"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Installing image analysis interaction at {{ %.0f, %.0f }, { %.0f, %.0f }}"
, _imageAnalysisInteractionBounds.x(), _imageAnalysisInteractionBounds
.y(), _imageAnalysisInteractionBounds.width(), _imageAnalysisInteractionBounds
.height())]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "Installing image analysis interaction at {{ %.0f, %.0f }, { %.0f, %.0f }}"
, _imageAnalysisInteractionBounds.x(), _imageAnalysisInteractionBounds
.y(), _imageAnalysisInteractionBounds.width(), _imageAnalysisInteractionBounds
.height()), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop
; }); } }) clang diagnostic pop
13542 _imageAnalysisInteractionBounds.x(), _imageAnalysisInteractionBounds.y(), _imageAnalysisInteractionBounds.width(), _imageAnalysisInteractionBounds.height())clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogImageAnalysis
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Installing image analysis interaction at {{ %.0f, %.0f }, { %.0f, %.0f }}"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG269"
) = "Installing image analysis interaction at {{ %.0f, %.0f }, { %.0f, %.0f }}"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Installing image analysis interaction at {{ %.0f, %.0f }, { %.0f, %.0f }}"
, _imageAnalysisInteractionBounds.x(), _imageAnalysisInteractionBounds
.y(), _imageAnalysisInteractionBounds.width(), _imageAnalysisInteractionBounds
.height())]; _os_log_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "Installing image analysis interaction at {{ %.0f, %.0f }, { %.0f, %.0f }}"
, _imageAnalysisInteractionBounds.x(), _imageAnalysisInteractionBounds
.y(), _imageAnalysisInteractionBounds.width(), _imageAnalysisInteractionBounds
.height()), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop
; }); } }) clang diagnostic pop
;
13543 }
13544 [_imageAnalysisInteraction setAnalysis:analysis];
13545 [_imageAnalysisDeferringGestureRecognizer setEnabled:NO__objc_no];
13546 [_imageAnalysisGestureRecognizer setEnabled:NO__objc_no];
13547}
13548
13549- (void)uninstallImageAnalysisInteraction
13550{
13551 if (!_imageAnalysisInteraction)
13552 return;
13553
13554 RELEASE_LOG(ImageAnalysis, "Uninstalling image analysis interaction")clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogImageAnalysis
.osLogChannel); os_log_type_t _type_tmp = (OS_LOG_TYPE_DEFAULT
); if (os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__
({ clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Uninstalling image analysis interaction"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG270"
) = "Uninstalling image analysis interaction"; uint8_t _Alignas
(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("Uninstalling image analysis interaction")]; _os_log_impl(&
__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t *)__builtin_os_log_format
(_os_fmt_buf, "Uninstalling image analysis interaction"), (uint32_t
)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); } }) clang diagnostic
pop
;
13555
13556 [self removeInteraction:_imageAnalysisInteraction.get()];
13557 [_imageAnalysisInteraction setDelegate:nilnullptr];
13558 [_imageAnalysisInteraction setQuickActionConfigurationUpdateHandler:nilnullptr];
13559 _imageAnalysisInteraction = nilnullptr;
13560 _imageAnalysisActionButtons = nilnullptr;
13561 _imageAnalysisInteractionBounds = { };
13562 [_imageAnalysisDeferringGestureRecognizer setEnabled:WebKit::isLiveTextAvailableAndEnabled()];
13563 [_imageAnalysisGestureRecognizer setEnabled:WebKit::isLiveTextAvailableAndEnabled()];
13564}
13565
13566#endif // ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)
13567
13568- (BOOL)_shouldAvoidSecurityHeuristicScoreUpdates
13569{
13570 // FIXME: The whole security heuristic thing should be a USE/HAVE.
13571#if PLATFORM(VISION)(defined WTF_PLATFORM_VISION && WTF_PLATFORM_VISION)
13572 return YES__objc_yes;
13573#elif ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)(defined 1 && 1)
13574 return [_imageAnalysisInteraction hasActiveTextSelection];
13575#else
13576 return NO__objc_no;
13577#endif
13578}
13579
13580#pragma mark - _UITextInputTranslationSupport
13581
13582- (BOOL)isImageBacked
13583{
13584 return _page && protect(_page)->editorState().selectionIsRangeInsideImageOverlay;
13585}
13586
13587#if HAVE(UI_EDIT_MENU_INTERACTION)(defined 1 && 1)
13588
13589- (void)willPresentEditMenuWithAnimator:(id<UIEditMenuInteractionAnimating>)animator
13590{
13591 [animator addCompletion:[weakSelf = WeakObjCPtr<WKContentView>(self)] {
13592 if (auto strongSelf = weakSelf.get())
13593 strongSelf->_isPresentingEditMenu = YES__objc_yes;
13594 }];
13595
13596 auto delegate = self.webView.UIDelegate;
13597 if (![delegate respondsToSelector:@selector(webView:willPresentEditMenuWithAnimator:)])
13598 return;
13599
13600 [delegate webView:self.webView willPresentEditMenuWithAnimator:animator];
13601}
13602
13603- (void)willDismissEditMenuWithAnimator:(id<UIEditMenuInteractionAnimating>)animator
13604{
13605 [animator addCompletion:[weakSelf = WeakObjCPtr<WKContentView>(self)] {
13606 if (auto strongSelf = weakSelf.get())
13607 strongSelf->_isPresentingEditMenu = NO__objc_no;
13608 }];
13609
13610 auto delegate = self.webView.UIDelegate;
13611 if (![delegate respondsToSelector:@selector(webView:willDismissEditMenuWithAnimator:)])
13612 return;
13613
13614 [delegate webView:self.webView willDismissEditMenuWithAnimator:animator];
13615}
13616
13617#endif // HAVE(UI_EDIT_MENU_INTERACTION)
13618
13619- (BOOL)isPresentingEditMenu
13620{
13621 return _isPresentingEditMenu;
13622}
13623
13624- (CGSize)sizeForLegacyFormControlPickerViews
13625{
13626 auto size = self.window.bounds.size;
13627 size.height = 0; // Fall back to the default input view height.
13628 return size;
13629}
13630
13631#if USE(BROWSERENGINEKIT)(defined 1 && 1)
13632
13633#pragma mark - BETextInput (and related)
13634
13635- (id<BETextInput>)asBETextInput
13636{
13637 ASSERT([self conformsToProtocol:@protocol(BETextInput)])((void)0);
13638 return static_cast<id<BETextInput>>(self);
13639}
13640
13641- (void)_logMissingSystemInputDelegateIfNeeded:(const char*)methodName
13642{
13643 if (_asyncInputDelegate)
13644 return;
13645
13646 static constexpr auto delayBetweenLogStatements = 10_s;
13647 static ApproximateTime lastLoggingTimestamp;
13648 if (auto timestamp = ApproximateTime::now(); timestamp - lastLoggingTimestamp > delayBetweenLogStatements) {
13649 RELEASE_LOG_ERROR(TextInput, "%{public}s - system input delegate is nil", methodName)clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInput
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("%{public}s - system input delegate is nil"), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG271"
) = "%{public}s - system input delegate is nil"; uint8_t _Alignas
(16) __attribute__((uninitialized)) _os_fmt_buf[__builtin_os_log_format_buffer_size
("%{public}s - system input delegate is nil", methodName)]; _os_log_error_impl
(&__dso_handle, _log_tmp, _type_tmp, _os_fmt_str, (uint8_t
*)__builtin_os_log_format(_os_fmt_buf, "%{public}s - system input delegate is nil"
, methodName), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic
pop ; }); } }) clang diagnostic pop
;
13650 lastLoggingTimestamp = timestamp;
13651 }
13652}
13653
13654- (void)shiftKeyStateChangedFromState:(BEKeyModifierFlags)oldState toState:(BEKeyModifierFlags)newState
13655{
13656 ASSERT(oldState != newState)((void)0);
13657 if (_isHandlingActivePressesEvent) {
13658 // UIKit will call into us to handle the individual events, so there's no need to dispatch
13659 // these synthetic modifier change key events.
13660 return;
13661 }
13662
13663 auto dispatchSyntheticFlagsChangedEvents = [&] (BEKeyModifierFlags state, bool keyDown) {
13664 RetainPtr<WKSyntheticFlagsChangedWebEvent> syntheticEvent;
13665 switch (state) {
13666 case BEKeyModifierFlagNone:
13667 return;
13668 case BEKeyModifierFlagShift:
13669 syntheticEvent = adoptNS([[WKSyntheticFlagsChangedWebEvent alloc] initWithShiftState:keyDown]);
13670 break;
13671 case BEKeyModifierFlagCapsLock:
13672 syntheticEvent = adoptNS([[WKSyntheticFlagsChangedWebEvent alloc] initWithCapsLockState:keyDown]);
13673 break;
13674 }
13675 [self _internalHandleKeyWebEvent:syntheticEvent.get()];
13676 };
13677
13678 dispatchSyntheticFlagsChangedEvents(oldState, false);
13679 dispatchSyntheticFlagsChangedEvents(newState, true);
13680}
13681
13682- (void)systemWillPresentEditMenuWithAnimator:(id<UIEditMenuInteractionAnimating>)animator
13683{
13684 [self willPresentEditMenuWithAnimator:animator];
13685}
13686
13687- (void)systemWillDismissEditMenuWithAnimator:(id<UIEditMenuInteractionAnimating>)animator
13688{
13689 [self willDismissEditMenuWithAnimator:animator];
13690}
13691
13692- (void)insertTextAlternatives:(PlatformTextAlternativesBETextAlternatives *)alternatives
13693{
13694 auto text = alternatives.primaryString;
13695 if (!alternatives.alternativeStrings.count) {
13696 [self insertText:text];
13697 return;
13698 }
13699
13700 WebCore::TextAlternativeWithRange textAlternativeWithRange { alternatives, NSMakeRange(0, text.length) };
13701
13702 protect(_page)->insertDictatedTextAsync(text, { }, { textAlternativeWithRange }, WebKit::InsertTextOptions {
13703 .shouldSimulateKeyboardInput = static_cast<bool>([self _shouldSimulateKeyboardInputOnTextInsertion])
13704 });
13705
13706 _autocorrectionContextNeedsUpdate = YES__objc_yes;
13707}
13708
13709- (void)insertText:(NSString *)text textAlternatives:(PlatformTextAlternativesBETextAlternatives *)alternatives style:(UITextAlternativeStyle)style
13710{
13711 [self insertTextAlternatives:alternatives];
13712}
13713
13714- (BOOL)isPointNearMarkedText:(CGPoint)point
13715{
13716 return [self pointIsNearMarkedText:point];
13717}
13718
13719- (void)replaceSelectedText:(NSString *)text withText:(NSString *)replacementText
13720{
13721 [self replaceText:text withText:replacementText];
13722}
13723
13724- (void)updateCurrentSelectionTo:(CGPoint)point fromGesture:(WKBEGestureTypeBEGestureType)gestureType inState:(UIGestureRecognizerState)state
13725{
13726 [self changeSelectionWithGestureAt:point withGesture:gestureType withState:state];
13727}
13728
13729- (void)setSelectionFromPoint:(CGPoint)from toPoint:(CGPoint)to gesture:(WKBEGestureTypeBEGestureType)gestureType state:(UIGestureRecognizerState)gestureState
13730{
13731 [self changeSelectionWithTouchesFrom:from to:to withGesture:gestureType withState:gestureState];
13732}
13733
13734- (void)adjustSelectionBoundaryToPoint:(CGPoint)point touchPhase:(WKBESelectionTouchPhaseBESelectionTouchPhase)touch baseIsStart:(BOOL)boundaryIsStart flags:(WKBESelectionFlagsBESelectionFlags)flags
13735{
13736 [self changeSelectionWithTouchAt:point withSelectionTouch:touch baseIsStart:boundaryIsStart withFlags:flags];
13737}
13738
13739- (void)updateSelectionWithExtentPoint:(CGPoint)point boundary:(UITextGranularity)granularity completionHandler:(void (^)(BOOL selectionEndIsMoving))completionHandler
13740{
13741 [self updateSelectionWithExtentPoint:point withBoundary:granularity completionHandler:completionHandler];
13742}
13743
13744- (void)selectTextInGranularity:(UITextGranularity)granularity atPoint:(CGPoint)point completionHandler:(void (^)(void))completionHandler
13745{
13746 [self selectTextWithGranularity:granularity atPoint:point completionHandler:completionHandler];
13747}
13748
13749- (void)moveSelectionAtBoundary:(UITextGranularity)granularity inStorageDirection:(UITextStorageDirection)direction completionHandler:(void (^)(void))completionHandler
13750{
13751 [self moveSelectionAtBoundary:granularity inDirection:direction completionHandler:completionHandler];
13752}
13753
13754- (id<BEExtendedTextInputTraits>)extendedTextInputTraits
13755{
13756 return [self extendedTraitsDelegate];
13757}
13758
13759#if ENABLE(REVEAL)(defined 1 && 1)
13760
13761- (void)selectTextForEditMenuWithLocationInView:(CGPoint)locationInView completionHandler:(void(^)(BOOL shouldPresentMenu, NSString * _Nullable contextString, NSRange selectedRangeInContextString))completionHandler
13762{
13763 [self selectTextForContextMenuWithLocationInView:locationInView completionHandler:completionHandler];
13764}
13765
13766#endif // ENABLE(REVEAL)
13767
13768- (BOOL)isSelectionAtDocumentStart
13769{
13770 return self.selectionAtDocumentStart;
13771}
13772
13773- (BOOL)automaticallyPresentEditMenu
13774{
13775 return _suppressSelectionAssistantReasons.isEmpty();
13776}
13777
13778- (id<BETextInputDelegate>)asyncInputDelegate
13779{
13780 return _asyncInputDelegate;
13781}
13782
13783- (void)setAsyncInputDelegate:(id<BETextInputDelegate>)delegate
13784{
13785 _asyncInputDelegate = delegate;
13786}
13787
13788- (void)handleKeyEntry:(BEKeyEntry *)event withCompletionHandler:(void (^)(BEKeyEntry *, BOOL))completionHandler
13789{
13790 auto webEvent = adoptNS([[::WebEvent alloc] initWithKeyEntry:event]);
13791 [self _internalHandleKeyWebEvent:webEvent.get() withCompletionHandler:[originalEvent = retainPtr(event), completionHandler = makeBlockPtr(completionHandler)](::WebEvent *webEvent, BOOL handled) {
13792 ASSERT(webEvent.originalKeyEntry == originalEvent)((void)0);
13793 completionHandler(originalEvent.get(), handled);
13794 }];
13795}
13796
13797- (void)replaceText:(NSString *)originalText withText:(NSString *)replacementText options:(BETextReplacementOptions)options completionHandler:(void (^)(NSArray<UITextSelectionRect *> *rects))completionHandler
13798{
13799 [self _internalReplaceText:originalText withText:replacementText isCandidate:options & BETextReplacementOptionsAddUnderline completion:[view = retainPtr(self), completionHandler = makeBlockPtr(completionHandler)](bool wasReplaced) {
13800 if (!wasReplaced)
13801 return completionHandler(@[ ]);
13802
13803 auto& data = view->_autocorrectionData;
13804 RetainPtr firstSelectionRect = [WKUITextSelectionRect selectionRectWithCGRect:data.textFirstRect];
13805 if (CGRectEqualToRect(data.textFirstRect, data.textLastRect))
13806 return completionHandler(@[ firstSelectionRect.get() ]);
13807
13808 completionHandler(@[ firstSelectionRect.get(), [WKUITextSelectionRect selectionRectWithCGRect:data.textLastRect] ]);
13809 }];
13810}
13811
13812- (void)requestTextRectsForString:(NSString *)input withCompletionHandler:(void (^)(NSArray<UITextSelectionRect *> *rects))completionHandler
13813{
13814 [self _internalRequestTextRectsForString:input completion:[view = retainPtr(self), completionHandler = makeBlockPtr(completionHandler)](auto& rects) mutable {
13815 auto selectionRects = createNSArray(rects, [](auto& rect) {
13816 return [WKUITextSelectionRect selectionRectWithCGRect:rect];
13817 });
13818 completionHandler(selectionRects.get());
13819 }];
13820}
13821
13822- (UIView *)textInputView
13823{
13824 return self;
13825}
13826
13827- (void)autoscrollToPoint:(CGPoint)pointInDocument
13828{
13829 protect(_page)->startAutoscrollAtPosition(pointInDocument);
13830}
13831
13832- (void)requestTextContextForAutocorrectionWithCompletionHandler:(void (^)(WKBETextDocumentContextBETextDocumentContext *context))completion
13833{
13834 if (!completion) {
13835 [NSException raise:NSInvalidArgumentException format:@"Expected a nonnull completion handler in %s.", __PRETTY_FUNCTION__];
13836 return;
13837 }
13838
13839 [self _internalRequestAutocorrectionContextWithCompletionHandler:[completion = makeBlockPtr(completion), strongSelf = retainPtr(self)](WebKit::RequestAutocorrectionContextResult result) {
13840 WebKit::DocumentEditingContext context;
13841 switch (result) {
13842 case WebKit::RequestAutocorrectionContextResult::Empty:
13843 break;
13844 case WebKit::RequestAutocorrectionContextResult::LastContext:
13845 auto& webContext = strongSelf->_lastAutocorrectionContext;
13846 context.contextBefore.string = webContext.contextBefore;
13847 context.markedText.string = webContext.markedText;
13848 context.selectedText.string = webContext.selectedText;
13849 context.contextAfter.string = webContext.contextAfter;
13850 NSRange selectedRangeInMarkedText = webContext.selectedRangeInMarkedText;
13851 context.selectedRangeInMarkedText = {
13852 .location = selectedRangeInMarkedText.location,
13853 .length = selectedRangeInMarkedText.length
13854 };
13855 break;
13856 }
13857 completion(protect(context.toPlatformContext({ WebKit::DocumentEditingContextRequest::Options::Text })).get());
13858 }];
13859}
13860
13861#if ENABLE(REVEAL)(defined 1 && 1)
13862
13863- (void)selectTextForContextMenuWithLocationInView:(CGPoint)locationInView completionHandler:(void(^)(BOOL shouldPresentMenu, NSString *contextString, NSRange selectedRangeInContextString))completionHandler
13864{
13865 [self _internalSelectTextForContextMenuWithLocationInView:locationInView completionHandler:[completionHandler = makeBlockPtr(completionHandler)](BOOL shouldPresentMenu, const WebKit::RevealItem& item) {
13866 auto& selectedRange = item.selectedRange();
13867 completionHandler(shouldPresentMenu, item.text().createNSString().get(), NSMakeRange(selectedRange.location, selectedRange.length));
13868 }];
13869}
13870
13871#endif // ENABLE(REVEAL)
13872
13873inline static NSArray<NSString *> *deleteSelectionCommands(UITextStorageDirection direction, UITextGranularity granularity)
13874{
13875 BOOL backward = direction == UITextStorageDirectionBackward;
13876 switch (granularity) {
13877 case UITextGranularityCharacter:
13878 return @[ backward ? @"DeleteBackward" : @"DeleteForward" ];
13879 case UITextGranularityWord:
13880 return @[ backward ? @"DeleteWordBackward" : @"DeleteWordForward" ];
13881 case UITextGranularitySentence:
13882 return @[ backward ? @"MoveToBeginningOfSentenceAndModifySelection" : @"MoveToEndOfSentenceAndModifySelection", @"DeleteBackward" ];
13883 case UITextGranularityParagraph:
13884 return @[ backward ? @"DeleteToBeginningOfParagraph" : @"DeleteToEndOfParagraph" ];
13885 case UITextGranularityLine:
13886 return @[ backward ? @"DeleteToBeginningOfLine" : @"DeleteToEndOfLine" ];
13887 case UITextGranularityDocument:
13888 return @[ backward ? @"MoveToBeginningOfDocumentAndModifySelection" : @"MoveToEndOfDocumentAndModifySelection", @"DeleteBackward" ];
13889 }
13890 ASSERT_NOT_REACHED()((void)0);
13891 return @[ ];
13892}
13893
13894inline static NSArray<NSString *> *moveSelectionCommand(UITextStorageDirection direction, UITextGranularity granularity)
13895{
13896 BOOL backward = direction == UITextStorageDirectionBackward;
13897 switch (granularity) {
13898 case UITextGranularityCharacter:
13899 return @[ backward ? @"MoveBackward" : @"MoveForward" ];
13900 case UITextGranularityWord:
13901 return @[ backward ? @"MoveWordBackward" : @"MoveWordForward" ];
13902 case UITextGranularitySentence:
13903 return @[ backward ? @"MoveToBeginningOfSentence" : @"MoveToEndOfSentence" ];
13904 case UITextGranularityParagraph:
13905 return @[
13906 backward ? @"MoveBackward" : @"MoveForward",
13907 backward ? @"MoveToBeginningOfParagraph" : @"MoveToEndOfParagraph"
13908 ];
13909 case UITextGranularityLine:
13910 return @[ backward ? @"MoveToBeginningOfLine" : @"MoveToEndOfLine" ];
13911 case UITextGranularityDocument:
13912 return @[ backward ? @"MoveToBeginningOfDocument" : @"MoveToEndOfDocument" ];
13913 }
13914 ASSERT_NOT_REACHED()((void)0);
13915 return nilnullptr;
13916}
13917
13918inline static NSArray<NSString *> *extendSelectionCommand(UITextStorageDirection direction, UITextGranularity granularity)
13919{
13920 BOOL backward = direction == UITextStorageDirectionBackward;
13921 switch (granularity) {
13922 case UITextGranularityCharacter:
13923 return @[ backward ? @"MoveBackwardAndModifySelection" : @"MoveForwardAndModifySelection" ];
13924 case UITextGranularityWord:
13925 return @[ backward ? @"MoveWordBackwardAndModifySelection" : @"MoveWordForwardAndModifySelection" ];
13926 case UITextGranularitySentence:
13927 return @[ backward ? @"MoveToBeginningOfSentenceAndModifySelection" : @"MoveToEndOfSentenceAndModifySelection" ];
13928 case UITextGranularityParagraph:
13929 return @[
13930 backward ? @"MoveBackwardAndModifySelection" : @"MoveForwardAndModifySelection",
13931 backward ? @"MoveToBeginningOfParagraphAndModifySelection" : @"MoveToEndOfParagraphAndModifySelection"
13932 ];
13933 case UITextGranularityLine:
13934 return @[ backward ? @"MoveToBeginningOfLineAndModifySelection" : @"MoveToEndOfLineAndModifySelection" ];
13935 case UITextGranularityDocument:
13936 return @[ backward ? @"MoveToBeginningOfDocumentAndModifySelection" : @"MoveToEndOfDocumentAndModifySelection" ];
13937 }
13938 ASSERT_NOT_REACHED()((void)0);
13939 return nilnullptr;
13940}
13941
13942inline static NSString *moveSelectionCommand(UITextLayoutDirection direction)
13943{
13944 switch (direction) {
13945 case UITextLayoutDirectionRight:
13946 return @"MoveRight";
13947 case UITextLayoutDirectionLeft:
13948 return @"MoveLeft";
13949 case UITextLayoutDirectionUp:
13950 return @"MoveUp";
13951 case UITextLayoutDirectionDown:
13952 return @"MoveDown";
13953 }
13954 ASSERT_NOT_REACHED()((void)0);
13955 return nilnullptr;
13956}
13957
13958inline static NSString *extendSelectionCommand(UITextLayoutDirection direction)
13959{
13960 switch (direction) {
13961 case UITextLayoutDirectionRight:
13962 return @"MoveRightAndModifySelection";
13963 case UITextLayoutDirectionLeft:
13964 return @"MoveLeftAndModifySelection";
13965 case UITextLayoutDirectionUp:
13966 return @"MoveUpAndModifySelection";
13967 case UITextLayoutDirectionDown:
13968 return @"MoveDownAndModifySelection";
13969 }
13970 ASSERT_NOT_REACHED()((void)0);
13971 return nilnullptr;
13972}
13973
13974- (void)deleteInDirection:(UITextStorageDirection)direction toGranularity:(UITextGranularity)granularity
13975{
13976 auto notifyDelegate = granularity == UITextGranularityCharacter && direction == UITextStorageDirectionBackward
13977 ? WebKit::NotifyInputDelegate::No
13978 : WebKit::NotifyInputDelegate::Yes;
13979
13980 for (NSString *command in deleteSelectionCommands(direction, granularity))
13981 [self _executeEditCommand:command notifyDelegate:notifyDelegate];
13982}
13983
13984- (void)moveInStorageDirection:(UITextStorageDirection)direction byGranularity:(UITextGranularity)granularity
13985{
13986 for (NSString *command in moveSelectionCommand(direction, granularity))
13987 [self _executeEditCommand:command];
13988}
13989
13990- (void)moveInLayoutDirection:(UITextLayoutDirection)direction
13991{
13992 [self _executeEditCommand:protect(moveSelectionCommand(direction)).get()];
13993}
13994
13995- (void)extendInStorageDirection:(UITextStorageDirection)direction byGranularity:(UITextGranularity)granularity
13996{
13997 for (NSString *command in extendSelectionCommand(direction, granularity))
13998 [self _executeEditCommand:command];
13999}
14000
14001- (void)extendInLayoutDirection:(UITextLayoutDirection)direction
14002{
14003 [self _executeEditCommand:protect(extendSelectionCommand(direction)).get()];
14004}
14005
14006- (void)adjustSelectionByRange:(BEDirectionalTextRange)range completionHandler:(void (^)(void))completionHandler
14007{
14008 [self _internalAdjustSelectionWithOffset:range.offset lengthDelta:range.length completionHandler:completionHandler];
14009}
14010
14011- (id<BEExtendedTextInputTraits>)extendedTraitsDelegate
14012{
14013 if (self._requiresLegacyTextInputTraits)
14014 return static_cast<id<BEExtendedTextInputTraits>>(self.textInputTraits);
14015
14016 if (!_extendedTextInputTraits)
14017 _extendedTextInputTraits = adoptNS([WKExtendedTextInputTraits new]);
14018
14019 if (!self._hasFocusedElement && !_isFocusingElementWithKeyboard) {
14020 [_extendedTextInputTraits restoreDefaultValues];
14021 [_extendedTextInputTraits setSelectionColorsToMatchTintColor:[self _cascadeInteractionTintColor]];
14022 } else if (!_isBlurringFocusedElement)
14023 [self _updateTextInputTraits:_extendedTextInputTraits.get()];
14024
14025 return _extendedTextInputTraits.get();
14026}
14027
14028#endif // USE(BROWSERENGINEKIT)
14029
14030- (void)_internalAdjustSelectionWithOffset:(NSInteger)offset lengthDelta:(NSInteger)lengthDelta completionHandler:(void (^)(void))completionHandler
14031{
14032 protect(_page)->updateSelectionWithDelta(offset, lengthDelta, [capturedCompletionHandler = makeBlockPtr(completionHandler)] {
14033 capturedCompletionHandler();
14034 });
14035}
14036
14037- (CGRect)selectionClipRect
14038{
14039 Ref page = *_page;
14040 if (page->waitingForPostLayoutEditorStateUpdateAfterFocusingElement())
14041 return _focusedElementInformation.interactionRect;
14042
14043 if (page->editorState().hasVisualData() && !page->editorState().visualData->selectionClipRect.isEmpty())
14044 return page->editorState().visualData->selectionClipRect;
14045
14046 return CGRectNull;
14047}
14048
14049- (UIView *)selectionContainerViewBelowText
14050{
14051 return self._selectionContainerViewInternal;
14052}
14053
14054- (UIView *)selectionContainerViewAboveText
14055{
14056 return self._selectionContainerViewInternal;
14057}
14058
14059- (void)transposeCharactersAroundSelection
14060{
14061 [self _executeEditCommand:@"transpose"];
14062}
14063
14064- (BOOL)selectionAtDocumentStart
14065{
14066 Ref page = *_page;
14067 if (!page->editorState().postLayoutData)
14068 return NO__objc_no;
14069 return !page->editorState().postLayoutData->characterBeforeSelection;
14070}
14071
14072- (BOOL)shouldSuppressEditMenu
14073{
14074 return !!_suppressSelectionAssistantReasons;
14075}
14076
14077#pragma mark - WKTextAnimationSourceDelegate
14078
14079#if ENABLE(WRITING_TOOLS)(defined 1 && 1)
14080- (void)targetedPreviewForID:(NSUUID *)uuid completionHandler:(void (^)(UITargetedPreview *))completionHandler
14081{
14082 auto animationID = WTF::UUID::fromNSUUID(uuid);
14083
14084 protect(_page)->getTextIndicatorForID(*animationID, [protectedSelf = retainPtr(self), completionHandler = makeBlockPtr(completionHandler)] (auto&& textIndicator) {
14085 if (!textIndicator) {
14086 completionHandler(nilnullptr);
14087 return;
14088 }
14089
14090 RetainPtr targetedPreview = [protectedSelf _createTargetedPreviewFromTextIndicator:WTF::move(textIndicator) previewContainer:[protectedSelf containerForContextMenuHintPreviews]];
14091 completionHandler(targetedPreview.get());
14092 });
14093}
14094
14095- (void)updateUnderlyingTextVisibilityForTextAnimationID:(NSUUID *)uuid visible:(BOOL)visible completionHandler:(void (^)(void))completionHandler
14096{
14097 NSUUID *destinationUUID = _sourceAnimationIDtoDestinationAnimationID.get()[uuid];
14098 auto textUUID = WTF::UUID::fromNSUUID(uuid);
14099 if (destinationUUID)
14100 textUUID = WTF::UUID::fromNSUUID(destinationUUID);
14101
14102 protect(_page)->updateUnderlyingTextVisibilityForTextAnimationID(*textUUID, visible, [completionHandler = makeBlockPtr(completionHandler)] () {
14103 completionHandler();
14104 });
14105}
14106
14107- (UIView *)containingViewForTextAnimationType
14108{
14109 return self;
14110}
14111
14112- (void)callCompletionHandlerForAnimationID:(NSUUID *)uuid
14113{
14114 NSUUID *destinationUUID = _sourceAnimationIDtoDestinationAnimationID.get()[uuid];
14115
14116 if (!destinationUUID)
14117 return;
14118
14119 auto animationUUID = WTF::UUID::fromNSUUID(destinationUUID);
14120 protect(_page)->callCompletionHandlerForAnimationID(*animationUUID, WebCore::TextAnimationRunMode::RunAnimation);
14121}
14122
14123- (void)callCompletionHandlerForAnimationID:(NSUUID *)uuid completionHandler:(void (^)(UITargetedPreview * _Nullable))completionHandler
14124{
14125 auto animationUUID = WTF::UUID::fromNSUUID(uuid);
14126
14127 // Store this completion handler so that it can be called after the execution of the next
14128 // call to replace the text and eventually use this completion handler to pass the
14129 // text indicator to UIKit.
14130 protect(_page)->storeDestinationCompletionHandlerForAnimationID(*animationUUID, [protectedSelf = retainPtr(self), completionHandler = makeBlockPtr(completionHandler)](RefPtr<WebCore::TextIndicator>&& textIndicator) {
14131 if (!textIndicator) {
14132 completionHandler(nilnullptr);
14133 return;
14134 }
14135
14136 RetainPtr targetedPreview = [protectedSelf _createTargetedPreviewFromTextIndicator:WTF::move(textIndicator) previewContainer:[protectedSelf containerForContextMenuHintPreviews]];
14137 completionHandler(targetedPreview.get());
14138 });
14139
14140 protect(_page)->callCompletionHandlerForAnimationID(*animationUUID, WebCore::TextAnimationRunMode::RunAnimation);
14141}
14142
14143- (void)replacementEffectDidComplete
14144{
14145 protect(_page)->didEndPartialIntelligenceTextAnimationImpl();
14146}
14147
14148#endif
14149
14150#pragma mark - BETextInteractionDelegate
14151
14152#if USE(BROWSERENGINEKIT)(defined 1 && 1)
14153
14154- (void)systemWillChangeSelectionForInteraction:(BETextInteraction *)interaction
14155{
14156 [self _updateInternalStateBeforeSelectionChange];
14157}
14158
14159- (void)systemDidChangeSelectionForInteraction:(BETextInteraction *)interaction
14160{
14161 [self _updateInternalStateAfterSelectionChange];
14162}
14163
14164#endif // USE(BROWSERENGINEKIT)
14165
14166#if ENABLE(WRITING_TOOLS)(defined 1 && 1)
14167
14168- (void)willPresentWritingTools
14169{
14170 _isPresentingWritingTools = YES__objc_yes;
14171 // FIXME (rdar://problem/136376688): Stop manually hiding the accessory view once UIKit fixes rdar://136304542.
14172 self.formAccessoryView.hidden = YES__objc_yes;
14173 [self reloadInputViews];
14174}
14175
14176- (void)didDismissWritingTools
14177{
14178 _isPresentingWritingTools = NO__objc_no;
14179 // FIXME (rdar://problem/136376688): Stop manually unhiding the accessory view once UIKit fixes rdar://136304542.
14180 self.formAccessoryView.hidden = NO__objc_no;
14181 [self reloadInputViews];
14182}
14183
14184- (CocoaWritingToolsResultOptions)allowedWritingToolsResultOptions
14185{
14186 return [_webView.get() allowedWritingToolsResultOptions];
14187}
14188
14189- (UIWritingToolsBehavior)writingToolsBehavior
14190{
14191 return [_webView.get() writingToolsBehavior];
14192}
14193
14194- (void)willBeginWritingToolsSession:(WTSession *)session requestContexts:(void (^)(NSArray<WTContext *> *))completion
14195{
14196 [_webView.get() willBeginWritingToolsSession:session requestContexts:completion];
14197}
14198
14199- (void)willBeginWritingToolsSession:(WTSession *)session forProofreadingReview:(BOOL)proofreadingReview requestContexts:(void (^)(NSArray<WTContext *> *))completion
14200{
14201 // FIXME - Staging: rdar://170159369
14202 [(id)_webView.get() willBeginWritingToolsSession:session forProofreadingReview:proofreadingReview requestContexts:completion];
14203}
14204
14205- (void)didBeginWritingToolsSession:(WTSession *)session contexts:(NSArray<WTContext *> *)contexts
14206{
14207 [_webView.get() didBeginWritingToolsSession:session contexts:contexts];
14208}
14209
14210- (void)proofreadingSession:(WTSession *)session didReceiveSuggestions:(NSArray<WTTextSuggestion *> *)suggestions processedRange:(NSRange)range inContext:(WTContext *)context finished:(BOOL)finished
14211{
14212 [_webView.get() proofreadingSession:session didReceiveSuggestions:suggestions processedRange:range inContext:context finished:finished];
14213}
14214
14215- (void)proofreadingSession:(WTSession *)session didUpdateState:(WTTextSuggestionState)state forSuggestionWithUUID:(NSUUID *)suggestionUUID inContext:(WTContext *)context
14216{
14217 [_webView.get() proofreadingSession:session didUpdateState:state forSuggestionWithUUID:suggestionUUID inContext:context];
14218}
14219
14220- (void)didEndWritingToolsSession:(WTSession *)session accepted:(BOOL)accepted
14221{
14222 [_webView.get() didEndWritingToolsSession:session accepted:accepted];
14223}
14224
14225- (void)compositionSession:(WTSession *)session didReceiveText:(NSAttributedString *)attributedText replacementRange:(NSRange)range inContext:(WTContext *)context finished:(BOOL)finished
14226{
14227 [_webView.get() compositionSession:session didReceiveText:attributedText replacementRange:range inContext:context finished:finished];
14228}
14229
14230- (void)writingToolsSession:(WTSession *)session didReceiveAction:(WTAction)action
14231{
14232 [_webView.get() writingToolsSession:session didReceiveAction:action];
14233}
14234
14235static inline WKTextAnimationType toWKTextAnimationType(WebCore::TextAnimationType style)
14236{
14237 switch (style) {
14238 case WebCore::TextAnimationType::Initial:
14239 return WKTextAnimationTypeInitial;
14240 case WebCore::TextAnimationType::Source:
14241 return WKTextAnimationTypeSource;
14242 case WebCore::TextAnimationType::Final:
14243 return WKTextAnimationTypeFinal;
14244 }
14245}
14246
14247- (void)addTextAnimationForAnimationID:(NSUUID *)uuid withData:(const WebCore::TextAnimationData&)data
14248{
14249 if (!protect(_page->preferences())->textAnimationsEnabled())
14250 return;
14251
14252 if (data.style == WebCore::TextAnimationType::Final)
14253 [_sourceAnimationIDtoDestinationAnimationID setObject:uuid forKey:data.sourceAnimationUUID.value_or(WTF::UUID(WTF::UUID::emptyValue)).createNSUUID().get()];
14254
14255 if (!_textAnimationManager)
14256 _textAnimationManager = adoptNS([WebKit::allocWKTextAnimationManagerInstance() initWithDelegate:self]);
14257
14258 [_textAnimationManager addTextAnimationForAnimationID:uuid withStyleType:toWKTextAnimationType(data.style)];
14259}
14260
14261- (void)removeTextAnimationForAnimationID:(NSUUID *)uuid
14262{
14263 if (!uuid)
14264 return;
14265
14266 if (!protect(_page->preferences())->textAnimationsEnabled())
14267 return;
14268
14269 if (!_textAnimationManager)
14270 return;
14271
14272 [_textAnimationManager removeTextAnimationForAnimationID:uuid];
14273}
14274
14275#endif
14276
14277#if ENABLE(MULTI_REPRESENTATION_HEIC)(defined ENABLE_MULTI_REPRESENTATION_HEIC && ENABLE_MULTI_REPRESENTATION_HEIC
)
14278
14279- (BOOL)supportsAdaptiveImageGlyph
14280{
14281 if (self.webView._isEditable || self.webView.configuration._multiRepresentationHEICInsertionEnabled)
14282 return _page->editorState().isContentRichlyEditable;
14283
14284 return NO__objc_no;
14285}
14286
14287- (void)insertAdaptiveImageGlyph:(NSAdaptiveImageGlyph *)adaptiveImageGlyph replacementRange:(UITextRange *)replacementRange
14288{
14289 _page->insertMultiRepresentationHEIC(adaptiveImageGlyph.imageContent, adaptiveImageGlyph.contentDescription);
14290}
14291
14292#endif
14293
14294- (void)_closeCurrentTypingCommand
14295{
14296 if (!_page)
14297 return;
14298
14299 protect(_page)->closeCurrentTypingCommand();
14300}
14301
14302- (UIView *)_selectionContainerViewAboveText
14303{
14304 // FIXME: Consider adding ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()
14305 // once the changes in rdar://150645383 are in all relevant builds.
14306 return self._selectionContainerViewInternal;
14307}
14308
14309- (UIView *)selectionContainerView
14310{
14311 // FIXME: Consider adding ASSERT_ASYNC_TEXT_INTERACTIONS_DISABLED()
14312 // once the changes in rdar://150645383 are in all relevant builds.
14313 return self._selectionContainerViewInternal;
14314}
14315
14316- (UIView *)_selectionContainerViewInternal
14317{
14318 if (_cachedSelectionContainerView)
14319 return _cachedSelectionContainerView;
14320
14321 _cachedSelectionContainerView = [&] -> UIView * {
14322 if (!self.selectionHonorsOverflowScrolling)
14323 return self;
14324
14325 Ref page = *_page;
14326 if (!page->editorState().hasVisualData())
14327 return self;
14328
14329 RetainPtr enclosingView = [self _viewForLayerID:page->editorState().visualData->enclosingLayerID];
14330 if (!enclosingView)
14331 return self;
14332
14333 for (UIView *selectedView in self.allViewsIntersectingSelectionRange) {
14334 if (enclosingView != selectedView && ![enclosingView _wk_isAncestorOf:selectedView])
14335 return self;
14336 }
14337 return enclosingView.autorelease();
14338 }();
14339
14340 ASSERT(_cachedSelectionContainerView)((void)0);
14341 return _cachedSelectionContainerView;
14342}
14343
14344- (UIView *)_viewForLayerID:(std::optional<WebCore::PlatformLayerIdentifier>)layerID
14345{
14346 WeakPtr drawingArea = downcast<WebKit::RemoteLayerTreeDrawingAreaProxy>(_page->drawingArea());
14347 if (!drawingArea)
14348 return nilnullptr;
14349
14350 WeakPtr layerTreeNode = drawingArea->remoteLayerTreeHost().nodeForID(layerID);
14351 if (!layerTreeNode)
14352 return nilnullptr;
14353
14354 return layerTreeNode->uiView();
14355}
14356
14357- (NSArray<UIView *> *)allViewsIntersectingSelectionRange
14358{
14359 if (!self.selectionHonorsOverflowScrolling)
14360 return @[ ];
14361
14362 if (!protect(_page)->editorState().hasVisualData())
14363 return @[ ];
14364
14365 return createNSArray(protect(_page)->editorState().visualData->intersectingLayerIDs, [&](auto& layerID) {
14366 return [self _viewForLayerID:layerID];
14367 }).autorelease();
14368}
14369
14370- (BOOL)_shouldHideSelectionDuringOverflowScroll:(UIScrollView *)scrollView
14371{
14372 if (self._selectionContainerViewInternal == self)
14373 return YES__objc_yes;
14374
14375 auto& state = protect(_page)->editorState();
14376 if (!state.hasVisualData())
14377 return NO__objc_no;
14378
14379 auto enclosingScrollingNodeID = state.visualData->enclosingScrollingNodeID;
14380 RetainPtr enclosingScroller = [self _scrollViewForScrollingNodeID:enclosingScrollingNodeID] ?: self._scroller;
14381 if (!enclosingScroller || ![enclosingScroller _wk_isAncestorOf:scrollView])
14382 return NO__objc_no;
14383
14384 auto isInSeparateScrollView = [&](std::optional<WebCore::ScrollingNodeID> endpointScrollingNodeID) -> bool {
14385 if (endpointScrollingNodeID == enclosingScrollingNodeID)
14386 return false;
14387
14388 RetainPtr endpointScroller = [self _scrollViewForScrollingNodeID:endpointScrollingNodeID] ?: self._scroller;
14389 return endpointScroller == scrollView || [scrollView _wk_isAncestorOf:endpointScroller.get()];
14390 };
14391
14392 if (isInSeparateScrollView(state.visualData->scrollingNodeIDAtStart))
14393 return YES__objc_yes;
14394
14395 if (isInSeparateScrollView(state.visualData->scrollingNodeIDAtEnd))
14396 return YES__objc_yes;
14397
14398 return NO__objc_no;
14399}
14400
14401- (BOOL)_canStartNavigationSwipeAtLastInteractionLocation
14402{
14403 RetainPtr lastHitView = [self hitTest:_lastInteractionLocation withEvent:nilnullptr];
14404 if (!lastHitView)
14405 return YES__objc_yes;
14406
14407 RetainPtr mainScroller = [_webView.get() scrollView];
14408 RetainPtr innerScroller = dynamic_objc_cast<UIScrollView>(lastHitView.get()) ?: [lastHitView _wk_parentScrollView];
14409 for (RetainPtr scroller = innerScroller; scroller; scroller = [scroller _wk_parentScrollView]) {
14410 if ([scroller isDragging])
14411 return NO__objc_no;
14412
14413 if ([scroller panGestureRecognizer]._wk_hasRecognizedOrEnded)
14414 return NO__objc_no;
14415
14416 if (scroller == mainScroller)
14417 break;
14418 }
14419
14420 auto touchActions = WebKit::touchActionsForPoint(self, WebCore::roundedIntPoint(_lastInteractionLocation));
14421 using enum WebCore::TouchAction;
14422 return touchActions.containsAny({ Auto, PanX, Manipulation });
14423}
14424
14425- (BOOL)allowsTouchPanningAtPoint:(CGPoint)point
14426{
14427 using enum WebCore::TouchAction;
14428 auto touchActions = WebKit::touchActionsForPoint(self, WebCore::roundedIntPoint(point));
14429 return touchActions.containsAny({ Auto, PanX, PanY, Manipulation });
14430}
14431
14432#if ENABLE(MODEL_PROCESS)(defined 0 && 0)
14433- (void)_willInvalidateDraggedModelWithContainerView:(UIView *)containerView
14434{
14435 // The model is being removed while it's in the middle of a drag.
14436 // We need to make sure it stays in a window by adding it to the
14437 // WKContentView's container for drag previews, but keep it hidden.
14438 [containerView setFrame:CGRectZero];
14439 containerView.hidden = YES__objc_yes;
14440 [self.containerForDragPreviews addSubview:containerView];
14441}
14442#endif
14443
14444#if HAVE(UI_CONVERSATION_CONTEXT)(defined 1 && 1)
14445
14446- (UIConversationContext *)_conversationContext
14447{
14448 if (self._requiresLegacyTextInputTraits)
14449 return self.textInputTraits.conversationContext;
14450
14451 return self.extendedTraitsDelegate.conversationContext;
14452}
14453
14454- (void)_setConversationContext:(UIConversationContext *)context
14455{
14456 [_legacyTextInputTraits setConversationContext:context];
14457 [_extendedTextInputTraits setConversationContext:context];
14458
14459 [self.inputDelegate conversationContext:context didChange:self];
14460}
14461
14462- (void)insertInputSuggestion:(UIInputSuggestion *)suggestion
14463{
14464 RetainPtr webView = _webView.get();
14465 RetainPtr delegate = [webView UIDelegate];
14466
14467 if (![delegate respondsToSelector:@selector(webView:insertInputSuggestion:)]) {
14468 RELEASE_LOG_ERROR(TextInput, "Ignored input suggestion (UI delegate does not implement -webView:insertInputSuggestion:)")clang diagnostic push clang diagnostic ignored "-Wunknown-warning-option"
clang diagnostic ignored "-Wunsafe-buffer-usage" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-libc-call" clang diagnostic
ignored "-Wunsafe-buffer-usage-in-format-attr-call" [[clang
::suppress]] __extension__({ os_log_t _log_tmp = (WebKit2LogTextInput
.osLogChannel); os_log_type_t _type_tmp = OS_LOG_TYPE_ERROR; if
(os_log_type_enabled(_log_tmp, _type_tmp)) { __extension__({
clang diagnostic push clang diagnostic ignored "-Wvla" clang
diagnostic error "-Wformat" _Static_assert(__builtin_constant_p
("Ignored input suggestion (UI delegate does not implement -webView:insertInputSuggestion:)"
), "format/label/description argument must be a string constant"
); __attribute__((section("__TEXT,__oslogstring,cstring_literals"
),internal_linkage)) static const char _os_fmt_str[] __asm("LOS_LOG272"
) = "Ignored input suggestion (UI delegate does not implement -webView:insertInputSuggestion:)"
; uint8_t _Alignas(16) __attribute__((uninitialized)) _os_fmt_buf
[__builtin_os_log_format_buffer_size("Ignored input suggestion (UI delegate does not implement -webView:insertInputSuggestion:)"
)]; _os_log_error_impl(&__dso_handle, _log_tmp, _type_tmp
, _os_fmt_str, (uint8_t *)__builtin_os_log_format(_os_fmt_buf
, "Ignored input suggestion (UI delegate does not implement -webView:insertInputSuggestion:)"
), (uint32_t)sizeof(_os_fmt_buf)) clang diagnostic pop ; }); }
}) clang diagnostic pop
;
14469 return;
14470 }
14471
14472 [delegate webView:webView.get() insertInputSuggestion:suggestion];
14473}
14474
14475#endif // HAVE(UI_CONVERSATION_CONTEXT)
14476
14477@end
14478
14479#if ENABLE(POINTER_LOCK)(defined 1 && 1)
14480
14481@implementation WKContentView (PointerLock)
14482
14483- (void)_beginPointerLockMouseTracking
14484{
14485#if HAVE(UIKIT_WITH_MOUSE_SUPPORT)(defined 1 && 1)
14486 [_mouseInteraction beginPointerLockMouseTracking];
14487#endif
14488}
14489
14490- (void)_endPointerLockMouseTracking
14491{
14492#if HAVE(UIKIT_WITH_MOUSE_SUPPORT)(defined 1 && 1)
14493 [_mouseInteraction endPointerLockMouseTracking];
14494#endif
14495}
14496
14497@end
14498
14499#endif // ENABLE(POINTER_LOCK)
14500
14501@implementation WKContentView (WKTesting)
14502
14503- (void)selectWordBackwardForTesting
14504{
14505 _autocorrectionContextNeedsUpdate = YES__objc_yes;
14506 protect(_page)->selectWordBackward();
14507}
14508
14509- (void)_doAfterReceivingEditDragSnapshotForTesting:(dispatch_block_t)action
14510{
14511#if ENABLE(DRAG_SUPPORT)(defined 1 && 1)
14512 ASSERT(!_actionToPerformAfterReceivingEditDragSnapshot)((void)0);
14513 if (_waitingForEditDragSnapshot) {
14514 _actionToPerformAfterReceivingEditDragSnapshot = action;
14515 return;
14516 }
14517#endif
14518 action();
14519}
14520
14521#if !PLATFORM(WATCHOS)(defined WTF_PLATFORM_WATCHOS && WTF_PLATFORM_WATCHOS
)
14522- (WKDateTimeInputControl *)dateTimeInputControl
14523{
14524 if ([_inputPeripheral isKindOfClass:WKDateTimeInputControl.class])
14525 return (WKDateTimeInputControl *)_inputPeripheral.get();
14526 return nilnullptr;
14527}
14528#endif
14529
14530- (WKFormSelectControl *)selectControl
14531{
14532 if ([_inputPeripheral isKindOfClass:WKFormSelectControl.class])
14533 return (WKFormSelectControl *)_inputPeripheral.get();
14534 return nilnullptr;
14535}
14536
14537#if ENABLE(DRAG_SUPPORT)(defined 1 && 1)
14538
14539- (BOOL)isAnimatingDragCancel
14540{
14541 return _isAnimatingDragCancel;
14542}
14543
14544#endif // ENABLE(DRAG_SUPPORT)
14545
14546- (void)_simulateTextEntered:(NSString *)text
14547{
14548#if HAVE(PEPPER_UI_CORE)(defined HAVE_PEPPER_UI_CORE && HAVE_PEPPER_UI_CORE)
14549 if ([_presentedFullScreenInputViewController isKindOfClass:[WKTextInputListViewController class]]) {
14550 [(WKTextInputListViewController *)_presentedFullScreenInputViewController.get() enterText:text];
14551 return;
14552 }
14553
14554#if HAVE(QUICKBOARD_CONTROLLER)(defined HAVE_QUICKBOARD_CONTROLLER && HAVE_QUICKBOARD_CONTROLLER
)
14555 if (_presentedQuickboardController) {
14556 id <PUICQuickboardControllerDelegate> delegate = [_presentedQuickboardController delegate];
14557 ASSERT(delegate == self)((void)0);
14558 auto string = adoptNS([[NSAttributedString alloc] initWithString:text]);
14559 [delegate quickboardController:_presentedQuickboardController.get() textInputValueDidChange:string.get()];
14560 return;
14561 }
14562#endif // HAVE(QUICKBOARD_CONTROLLER)
14563#endif // HAVE(PEPPER_UI_CORE)
14564
14565 [self insertText:text];
14566}
14567
14568- (void)_simulateElementAction:(_WKElementActionType)actionType atLocation:(CGPoint)location
14569{
14570 _layerTreeTransactionIdAtLastInteractionStart = protect(downcast<WebKit::RemoteLayerTreeDrawingAreaProxy>(*_page->drawingArea()))->lastCommittedMainFrameLayerTreeTransactionID();
14571 [self doAfterPositionInformationUpdate:[actionType, self, protectedSelf = retainPtr(self)] (WebKit::InteractionInformationAtPosition info) {
14572 _WKActivatedElementInfo *elementInfo = [_WKActivatedElementInfo activatedElementInfoWithInteractionInformationAtPosition:info userInfo:nilnullptr];
14573 _WKElementAction *action = [_WKElementAction _elementActionWithType:actionType info:elementInfo assistant:_actionSheetAssistant.get()];
14574 [action runActionWithElementInfo:elementInfo];
14575 } forRequest:WebKit::InteractionInformationRequest(WebCore::roundedIntPoint(location))];
14576}
14577
14578- (void)_simulateLongPressActionAtLocation:(CGPoint)location
14579{
14580 RetainPtr<WKContentView> protectedSelf = self;
14581 [self doAfterPositionInformationUpdate:[protectedSelf] (WebKit::InteractionInformationAtPosition) {
14582 if (SEL action = [protectedSelf _actionForLongPress])
14583 [protectedSelf performSelector:action];
14584 } forRequest:WebKit::InteractionInformationRequest(WebCore::roundedIntPoint(location))];
14585}
14586
14587- (void)selectFormAccessoryPickerRow:(NSInteger)rowIndex
14588{
14589#if HAVE(PEPPER_UI_CORE)(defined HAVE_PEPPER_UI_CORE && HAVE_PEPPER_UI_CORE)
14590 if ([_presentedFullScreenInputViewController isKindOfClass:[WKSelectMenuListViewController class]])
14591 [(WKSelectMenuListViewController *)_presentedFullScreenInputViewController.get() selectItemAtIndex:rowIndex];
14592#else
14593 if ([_inputPeripheral isKindOfClass:[WKFormSelectControl class]])
14594 [(WKFormSelectControl *)_inputPeripheral selectRow:rowIndex inComponent:0 extendingSelection:NO__objc_no];
14595#endif
14596}
14597
14598- (BOOL)selectFormAccessoryHasCheckedItemAtRow:(long)rowIndex
14599{
14600#if !HAVE(PEPPER_UI_CORE)(defined HAVE_PEPPER_UI_CORE && HAVE_PEPPER_UI_CORE)
14601 if ([_inputPeripheral isKindOfClass:[WKFormSelectControl self]])
14602 return [(WKFormSelectControl *)_inputPeripheral selectFormAccessoryHasCheckedItemAtRow:rowIndex];
14603#endif
14604 return NO__objc_no;
14605}
14606
14607- (void)setSelectedColorForColorPicker:(UIColor *)color
14608{
14609 if ([_inputPeripheral isKindOfClass:[WKFormColorControl class]])
14610 [(WKFormColorControl *)_inputPeripheral selectColor:color];
14611}
14612
14613- (NSString *)textContentTypeForTesting
14614{
14615#if HAVE(PEPPER_UI_CORE)(defined HAVE_PEPPER_UI_CORE && HAVE_PEPPER_UI_CORE)
14616 if ([_presentedFullScreenInputViewController isKindOfClass:[WKTextInputListViewController class]])
14617 return [(WKTextInputListViewController *)_presentedFullScreenInputViewController textInputContext].textContentType;
14618#if HAVE(QUICKBOARD_CONTROLLER)(defined HAVE_QUICKBOARD_CONTROLLER && HAVE_QUICKBOARD_CONTROLLER
)
14619 if (_presentedQuickboardController)
14620 return [_presentedQuickboardController textInputContext].textContentType;
14621#endif // HAVE(QUICKBOARD_CONTROLLER)
14622#endif // HAVE(PEPPER_UI_CORE)
14623#if USE(BROWSERENGINEKIT)(defined 1 && 1)
14624 if (!self._requiresLegacyTextInputTraits)
14625 return self.extendedTraitsDelegate.textContentType;
14626#endif
14627 return self.textInputTraits.textContentType;
14628}
14629
14630- (NSString *)selectFormPopoverTitle
14631{
14632 if (![_inputPeripheral isKindOfClass:[WKFormSelectControl class]])
14633 return nilnullptr;
14634
14635 return [(WKFormSelectControl *)_inputPeripheral selectFormPopoverTitle];
14636}
14637
14638- (NSString *)formInputLabel
14639{
14640#if HAVE(PEPPER_UI_CORE)(defined HAVE_PEPPER_UI_CORE && HAVE_PEPPER_UI_CORE)
14641 return [self inputLabelTextForViewController:_presentedFullScreenInputViewController.get()];
14642#else
14643 return nilnullptr;
14644#endif
14645}
14646
14647- (void)setTimePickerValueToHour:(NSInteger)hour minute:(NSInteger)minute
14648{
14649#if HAVE(PEPPER_UI_CORE)(defined HAVE_PEPPER_UI_CORE && HAVE_PEPPER_UI_CORE)
14650 if ([_presentedFullScreenInputViewController isKindOfClass:[WKTimePickerViewController class]])
14651 [(WKTimePickerViewController *)_presentedFullScreenInputViewController.get() setHour:hour minute:minute];
14652#else
14653 if ([_inputPeripheral isKindOfClass:[WKDateTimeInputControl class]])
14654 [(WKDateTimeInputControl *)_inputPeripheral.get() setTimePickerHour:hour minute:minute];
14655#endif
14656}
14657
14658- (double)timePickerValueHour
14659{
14660#if !PLATFORM(WATCHOS)(defined WTF_PLATFORM_WATCHOS && WTF_PLATFORM_WATCHOS
)
14661 if ([_inputPeripheral isKindOfClass:[WKDateTimeInputControl class]])
14662 return [(WKDateTimeInputControl *)_inputPeripheral.get() timePickerValueHour];
14663#endif
14664 return -1;
14665}
14666
14667- (double)timePickerValueMinute
14668{
14669#if !PLATFORM(WATCHOS)(defined WTF_PLATFORM_WATCHOS && WTF_PLATFORM_WATCHOS
)
14670 if ([_inputPeripheral isKindOfClass:[WKDateTimeInputControl class]])
14671 return [(WKDateTimeInputControl *)_inputPeripheral.get() timePickerValueMinute];
14672#endif
14673 return -1;
14674}
14675
14676- (NSDictionary *)_contentsOfUserInterfaceItem:(NSString *)userInterfaceItem
14677{
14678 if ([userInterfaceItem isEqualToString:@"actionSheet"])
14679 return @{ userInterfaceItem: [protect(_actionSheetAssistant) currentlyAvailableActionTitles] };
14680
14681#if HAVE(LINK_PREVIEW)(defined 1 && 1)
14682 if ([userInterfaceItem isEqualToString:@"contextMenu"]) {
14683 auto itemTitles = adoptNS([NSMutableArray<NSString *> new]);
14684 [self.contextMenuInteraction updateVisibleMenuWithBlock:[&itemTitles](UIMenu *menu) -> UIMenu * {
14685 for (UIMenuElement *child in menu.children)
14686 [itemTitles addObject:child.title];
14687 return menu;
14688 }];
14689 if (self._shouldUseContextMenus) {
14690 return @{ userInterfaceItem: @{
14691 @"url": _positionInformation.url.isValid() ? WTF::userVisibleString(_positionInformation.url.createNSURL().get()) : @"",
14692 @"isLink": [NSNumber numberWithBool:_positionInformation.isLink],
14693 @"isImage": [NSNumber numberWithBool:_positionInformation.isImage],
14694 @"imageURL": _positionInformation.imageURL.isValid() ? WTF::userVisibleString(_positionInformation.imageURL.createNSURL().get()) : @"",
14695 @"items": itemTitles.get()
14696 } };
14697 }
14698 NSString *url = [_previewItemController previewData][UIPreviewDataLink];
14699 return @{ userInterfaceItem: @{
14700 @"url": url,
14701 @"isLink": [NSNumber numberWithBool:_positionInformation.isLink],
14702 @"isImage": [NSNumber numberWithBool:_positionInformation.isImage],
14703 @"imageURL": _positionInformation.imageURL.isValid() ? WTF::userVisibleString(_positionInformation.imageURL.createNSURL().get()) : @"",
14704 @"items": itemTitles.get()
14705 } };
14706 }
14707#endif
14708
14709#if ENABLE(MEDIA_CONTROLS_CONTEXT_MENUS)(defined 1 && 1) && USE(UICONTEXTMENU)(defined 1 && 1)
14710 if ([userInterfaceItem isEqualToString:@"mediaControlsContextMenu"])
14711 return @{ userInterfaceItem: [protect(_actionSheetAssistant) currentlyAvailableMediaControlsContextMenuItems] };
14712#endif // ENABLE(MEDIA_CONTROLS_CONTEXT_MENUS) && USE(UICONTEXTMENU)
14713
14714 if ([userInterfaceItem isEqualToString:@"fileUploadPanelMenu"]) {
14715 if (!_fileUploadPanel)
14716 return @{ userInterfaceItem: @[] };
14717 return @{ userInterfaceItem: [_fileUploadPanel currentAvailableActionTitles] };
14718 }
14719
14720 if ([userInterfaceItem isEqualToString:@"selectMenu"]) {
14721 if (auto *menuItemTitles = [self.selectControl menuItemTitles])
14722 return @{ userInterfaceItem: menuItemTitles };
14723 return @{ userInterfaceItem: @[] };
14724 }
14725
14726 return nilnullptr;
14727}
14728
14729- (void)_dismissContactPickerWithContacts:(NSArray *)contacts
14730{
14731#if HAVE(CONTACTSUI)(defined 1 && 1)
14732 [_contactPicker dismissWithContacts:contacts];
14733#endif
14734}
14735
14736#if ENABLE(MODEL_PROCESS)(defined 0 && 0)
14737- (void)_simulateModelInteractionPanGestureBeginAtPoint:(CGPoint)hitPoint
14738{
14739 [self modelInteractionPanGestureDidBeginAtPoint:hitPoint];
14740}
14741
14742- (void)_simulateModelInteractionPanGestureUpdateAtPoint:(CGPoint)hitPoint
14743{
14744 [self modelInteractionPanGestureDidUpdateWithPoint:hitPoint];
14745}
14746
14747- (NSDictionary *)_stageModeInfoForTesting
14748{
14749 if (!_stageModeSession)
14750 return @{ };
14751
14752 return @{
14753 @"awaitingResult" : @(_stageModeSession->isPreparingForInteraction),
14754 @"hitTestSuccessful" : @(_stageModeSession->nodeID.has_value()),
14755 };
14756}
14757#endif
14758
14759- (UITapGestureRecognizer *)singleTapGestureRecognizer
14760{
14761 return _singleTapGestureRecognizer.get();
14762}
14763
14764- (void)_simulateSelectionStart
14765{
14766 _usingGestureForSelection = YES__objc_yes;
14767 _lastSelectionDrawingInfo.type = WebCore::SelectionType::Range;
14768}
14769
14770#if ENABLE(ACCESSIBILITY_ANIMATION_CONTROL)(defined 1 && 1)
14771- (BOOL)_allowAnimationControls
14772{
14773 return self.webView._allowAnimationControls;
14774}
14775#endif
14776
14777- (void)dismissFormAccessoryView
14778{
14779#if !PLATFORM(WATCHOS)(defined WTF_PLATFORM_WATCHOS && WTF_PLATFORM_WATCHOS
)
14780 if (auto dateInput = self.dateTimeInputControl; [dateInput dismissWithAnimationForTesting])
14781 return;
14782#endif
14783 [self accessoryDone];
14784}
14785
14786- (void)_selectDataListOption:(NSInteger)optionIndex
14787{
14788 [_dataListSuggestionsControl.get() didSelectOptionAtIndex:optionIndex];
14789}
14790
14791- (void)_setDataListSuggestionsControl:(WKDataListSuggestionsControl *)control
14792{
14793 _dataListSuggestionsControl = control;
14794}
14795
14796- (BOOL)isShowingDataListSuggestions
14797{
14798 return [_dataListSuggestionsControl.get() isShowingSuggestions];
14799}
14800
14801- (UIWKTextInteractionAssistant *)textInteractionAssistant
14802{
14803 return [_textInteractionWrapper textInteractionAssistant];
14804}
14805
14806@end
14807
14808#if HAVE(LINK_PREVIEW)(defined 1 && 1)
14809
14810static NSString *previewIdentifierForElementAction(_WKElementAction *action)
14811{
14812ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
14813 switch (action.type) {
14814 case _WKElementActionTypeOpen:
14815 return WKPreviewActionItemIdentifierOpen;
14816 case _WKElementActionTypeCopy:
14817 return WKPreviewActionItemIdentifierCopy;
14818#if !defined(TARGET_OS_IOS1) || TARGET_OS_IOS1
14819 case _WKElementActionTypeAddToReadingList:
14820 return WKPreviewActionItemIdentifierAddToReadingList;
14821#endif
14822 case _WKElementActionTypeShare:
14823 return WKPreviewActionItemIdentifierShare;
14824 default:
14825 return nilnullptr;
14826 }
14827ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
14828 ASSERT_NOT_REACHED()((void)0);
14829 return nilnullptr;
14830}
14831
14832@implementation WKContentView (WKInteractionPreview)
14833
14834#if USE(UICONTEXTMENU)(defined 1 && 1)
14835- (UIContextMenuInteraction *)contextMenuInteraction
14836{
14837 return [_textInteractionWrapper contextMenuInteraction];
14838}
14839#endif // USE(UICONTEXTMENU)
14840
14841- (void)_registerPreview
14842{
14843 if (!self.webView.allowsLinkPreview)
14844 return;
14845
14846#if USE(UICONTEXTMENU)(defined 1 && 1)
14847 if (self._shouldUseContextMenus) {
14848 _contextMenuHasRequestedLegacyData = NO__objc_no;
14849 [_textInteractionWrapper setExternalContextMenuInteractionDelegate:self];
14850
14851 if (id<_UIClickInteractionDriving> driver = self.webView.configuration._clickInteractionDriverForTesting)
14852 [self.contextMenuInteraction presentationInteraction].overrideDrivers = @[driver];
14853 return;
14854 }
14855#endif // USE(UICONTEXTMENU)
14856
14857 _previewItemController = adoptNS([[UIPreviewItemController alloc] initWithView:self]);
14858 [_previewItemController setDelegate:self];
14859 _previewGestureRecognizer = _previewItemController.get().presentationGestureRecognizer;
14860 if ([_previewItemController respondsToSelector:@selector(presentationSecondaryGestureRecognizer)])
14861 _previewSecondaryGestureRecognizer = _previewItemController.get().presentationSecondaryGestureRecognizer;
14862}
14863
14864- (void)_unregisterPreview
14865{
14866#if USE(UICONTEXTMENU)(defined 1 && 1)
14867 if (self._shouldUseContextMenus)
14868 return;
14869#endif
14870
14871 [_previewItemController setDelegate:nilnullptr];
14872 _previewGestureRecognizer = nilnullptr;
14873 _previewSecondaryGestureRecognizer = nilnullptr;
14874 _previewItemController = nilnullptr;
14875}
14876
14877#if USE(UICONTEXTMENU)(defined 1 && 1)
14878
14879static bool needsDeprecatedPreviewAPI(id<WKUIDelegate> delegate)
14880{
14881 // FIXME: Replace these with booleans in UIDelegate.h.
14882 // Note that we explicitly do not test for @selector(_webView:contextMenuDidEndForElement:)
14883 // and @selector(webView:contextMenuWillPresentForElement) since the methods are used by MobileSafari
14884 // to manage state despite the app not moving to the new API.
14885
14886 return delegate
14887 && ![delegate respondsToSelector:@selector(_webView:contextMenuConfigurationForElement:completionHandler:)]
14888 && ![delegate respondsToSelector:@selector(webView:contextMenuConfigurationForElement:completionHandler:)]
14889 && ![delegate respondsToSelector:@selector(_webView:contextMenuForElement:willCommitWithAnimator:)]
14890 && ![delegate respondsToSelector:@selector(webView:contextMenuForElement:willCommitWithAnimator:)]
14891 && ![delegate respondsToSelector:@selector(_webView:contextMenuWillPresentForElement:)]
14892 && ![delegate respondsToSelector:@selector(webView:contextMenuDidEndForElement:)]
14893 && ([delegate respondsToSelector:@selector(webView:shouldPreviewElement:)]
14894 || [delegate respondsToSelector:@selector(webView:previewingViewControllerForElement:defaultActions:)]
14895 || [delegate respondsToSelector:@selector(webView:commitPreviewingViewController:)]
14896 || [delegate respondsToSelector:@selector(_webView:previewViewControllerForURL:defaultActions:elementInfo:)]
14897 || [delegate respondsToSelector:@selector(_webView:previewViewControllerForURL:)]
14898 || [delegate respondsToSelector:@selector(_webView:previewViewControllerForImage:alternateURL:defaultActions:elementInfo:)]);
14899}
14900
14901ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
14902static NSArray<WKPreviewAction *> *wkLegacyPreviewActionsFromElementActions(NSArray<_WKElementAction *> *elementActions, _WKActivatedElementInfo *elementInfo)
14903{
14904 NSMutableArray<WKPreviewAction *> *previewActions = [NSMutableArray arrayWithCapacity:[elementActions count]];
14905 for (_WKElementAction *elementAction in elementActions) {
14906 RetainPtr previewAction = [WKPreviewAction actionWithIdentifier:protect(previewIdentifierForElementAction(elementAction)).get() title:elementAction.title style:UIPreviewActionStyleDefault handler:^(UIPreviewAction *, UIViewController *) {
14907 [elementAction runActionWithElementInfo:elementInfo];
14908 }];
14909 previewAction.get().image = [_WKElementAction imageForElementActionType:elementAction.type];
14910 [previewActions addObject:previewAction.get()];
14911 }
14912 return previewActions;
14913}
14914
14915static UIAction *uiActionForLegacyPreviewAction(UIPreviewAction *previewAction, UIViewController *previewViewController)
14916{
14917 // UIPreviewActionItem.image is SPI, so no external clients will be able
14918 // to provide glyphs for actions <rdar://problem/50151855>.
14919 // However, they should migrate to the new API.
14920
14921 return [UIAction actionWithTitle:previewAction.title image:previewAction.image identifier:nilnullptr handler:^(UIAction *action) {
14922 previewAction.handler(previewAction, previewViewController);
14923 }];
14924}
14925ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
14926
14927static NSArray<UIMenuElement *> *menuElementsFromLegacyPreview(UIViewController *previewViewController)
14928{
14929 if (!previewViewController)
14930 return nilnullptr;
14931
14932ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
14933 NSArray<id<UIPreviewActionItem>> *previewActions = previewViewController.previewActionItems;
14934 if (!previewActions || ![previewActions count])
14935 return nilnullptr;
14936
14937 auto actions = [NSMutableArray arrayWithCapacity:previewActions.count];
14938
14939 for (UIPreviewAction *previewAction in previewActions)
14940 [actions addObject:protect(uiActionForLegacyPreviewAction(previewAction, previewViewController)).get()];
14941ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
14942
14943 return actions;
14944}
14945
14946static NSMutableArray<UIMenuElement *> *menuElementsFromDefaultActions(const RetainPtr<NSArray>& defaultElementActions, RetainPtr<_WKActivatedElementInfo> elementInfo)
14947{
14948 if (!defaultElementActions || !defaultElementActions.get().count)
14949 return nilnullptr;
14950
14951 auto actions = [NSMutableArray arrayWithCapacity:defaultElementActions.get().count];
14952
14953 for (_WKElementAction *elementAction in defaultElementActions.get())
14954 [actions addObject:[elementAction uiActionForElementInfo:elementInfo.get()]];
14955
14956 return actions;
14957}
14958
14959static UIMenu *menuFromLegacyPreviewOrDefaultActions(UIViewController *previewViewController, const RetainPtr<NSArray>& defaultElementActions, RetainPtr<_WKActivatedElementInfo> elementInfo, NSString *title = nilnullptr)
14960{
14961 RetainPtr actions = menuElementsFromLegacyPreview(previewViewController);
14962 if (!actions)
14963 actions = menuElementsFromDefaultActions(defaultElementActions, elementInfo);
14964
14965 return [UIMenu menuWithTitle:title children:actions.get()];
14966}
14967
14968- (void)assignLegacyDataForContextMenuInteraction
14969{
14970 ASSERT(!_contextMenuHasRequestedLegacyData)((void)0);
14971 if (_contextMenuHasRequestedLegacyData)
14972 return;
14973 _contextMenuHasRequestedLegacyData = YES__objc_yes;
14974
14975 if (!_webView)
14976 return;
14977 auto uiDelegate = static_cast<id<WKUIDelegatePrivate>>(self.webView.UIDelegate);
14978 if (!uiDelegate)
14979 return;
14980
14981 const auto& url = _positionInformation.url;
14982
14983 protect(_page)->startInteractionWithPositionInformation(_positionInformation);
14984
14985 RetainPtr<UIViewController> previewViewController;
14986
14987 auto elementInfo = adoptNS([[_WKActivatedElementInfo alloc] _initWithInteractionInformationAtPosition:_positionInformation isUsingAlternateURLForImage:NO__objc_no userInfo:nilnullptr]);
14988
14989 ASSERT_IMPLIES(_positionInformation.isImage, _positionInformation.image)((void)0);
14990 if (_positionInformation.isLink) {
14991 _longPressCanClick = NO__objc_no;
14992
14993 RetainPtr<NSArray<_WKElementAction *>> defaultActionsFromAssistant = [protect(_actionSheetAssistant) defaultActionsForLinkSheet:elementInfo.get()];
14994
14995 // FIXME: Animated images go here.
14996
14997ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
14998 if ([uiDelegate respondsToSelector:@selector(webView:previewingViewControllerForElement:defaultActions:)]) {
14999 RetainPtr defaultActions = wkLegacyPreviewActionsFromElementActions(defaultActionsFromAssistant.get(), elementInfo.get());
15000 auto previewElementInfo = adoptNS([[WKPreviewElementInfo alloc] _initWithLinkURL:url.createNSURL().get()]);
15001 // FIXME: Clients using this legacy API will always show their previewViewController and ignore _showLinkPreviews.
15002 previewViewController = [uiDelegate webView:self.webView previewingViewControllerForElement:previewElementInfo.get() defaultActions:defaultActions.get()];
15003 } else if ([uiDelegate respondsToSelector:@selector(_webView:previewViewControllerForURL:defaultActions:elementInfo:)])
15004 previewViewController = [uiDelegate _webView:self.webView previewViewControllerForURL:url.createNSURL().get() defaultActions:defaultActionsFromAssistant.get() elementInfo:elementInfo.get()];
15005 else if ([uiDelegate respondsToSelector:@selector(_webView:previewViewControllerForURL:)])
15006 previewViewController = [uiDelegate _webView:self.webView previewViewControllerForURL:url.createNSURL().get()];
15007ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15008
15009 // Previously, UIPreviewItemController would detect the case where there was no previewViewController
15010 // and create one. We need to replicate this code for the new API.
15011 if (!previewViewController || [url.createNSURL() iTunesStoreURL]) {
15012 auto ddContextMenuActionClass = PAL::getDDContextMenuActionClassSingleton();
15013 BEGIN_BLOCK_OBJC_EXCEPTIONS@try {
15014 NSDictionary *context = [self dataDetectionContextForPositionInformation:_positionInformation];
15015 RetainPtr<UIContextMenuConfiguration> dataDetectorsResult = [ddContextMenuActionClass contextMenuConfigurationForURL:url.createNSURL().get() identifier:_positionInformation.dataDetectorIdentifier.createNSString().get() selectedText:self.selectedText results:_positionInformation.dataDetectorResults.get() inView:self context:context menuIdentifier:nilnullptr];
15016 if (_showLinkPreviews && dataDetectorsResult && dataDetectorsResult.get().previewProvider)
15017 _contextMenuLegacyPreviewController = dataDetectorsResult.get().previewProvider();
15018 if (dataDetectorsResult && dataDetectorsResult.get().actionProvider) {
15019 RetainPtr menuElements = menuElementsFromDefaultActions(defaultActionsFromAssistant, elementInfo);
15020 _contextMenuLegacyMenu = dataDetectorsResult.get().actionProvider(menuElements.get());
15021 }
15022 END_BLOCK_OBJC_EXCEPTIONS} @catch(NSException *localException) { ReportBlockedObjCException
(localException); }
15023 return;
15024 }
15025
15026 _contextMenuLegacyMenu = menuFromLegacyPreviewOrDefaultActions(previewViewController.get(), defaultActionsFromAssistant, elementInfo);
15027
15028 } else if (_positionInformation.isImage && _positionInformation.image) {
15029 RetainPtr nsURL = url.createNSURL();
15030 RetainPtr<NSDictionary> imageInfo;
15031 RetainPtr cgImage = protect(_positionInformation.image)->createPlatformImage();
15032 auto uiImage = adoptNS([[UIImage alloc] initWithCGImage:cgImage.get()]);
15033
15034 if ([uiDelegate respondsToSelector:@selector(_webView:alternateURLFromImage:userInfo:)]) {
15035 NSDictionary *userInfo;
15036 nsURL = [uiDelegate _webView:self.webView alternateURLFromImage:uiImage.get() userInfo:&userInfo];
15037 imageInfo = userInfo;
15038 }
15039
15040ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
15041 if ([uiDelegate respondsToSelector:@selector(_webView:willPreviewImageWithURL:)])
15042 [uiDelegate _webView:self.webView willPreviewImageWithURL:_positionInformation.imageURL.createNSURL().get()];
15043
15044 RetainPtr<NSArray<_WKElementAction *>> defaultActionsFromAssistant = [protect(_actionSheetAssistant) defaultActionsForImageSheet:elementInfo.get()];
15045
15046 if (imageInfo && [uiDelegate respondsToSelector:@selector(_webView:previewViewControllerForImage:alternateURL:defaultActions:elementInfo:)])
15047 previewViewController = [uiDelegate _webView:self.webView previewViewControllerForImage:uiImage.get() alternateURL:nsURL.get() defaultActions:defaultActionsFromAssistant.get() elementInfo:elementInfo.get()];
15048 else
15049 previewViewController = adoptNS([[WKImagePreviewViewController alloc] initWithCGImage:cgImage defaultActions:defaultActionsFromAssistant.get() elementInfo:elementInfo.get() presentingView:self]);
15050ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15051
15052 _contextMenuLegacyMenu = menuFromLegacyPreviewOrDefaultActions(previewViewController.get(), defaultActionsFromAssistant, elementInfo, _positionInformation.title.createNSString().get());
15053 }
15054
15055 _contextMenuLegacyPreviewController = WTF::move(previewViewController);
15056}
15057
15058- (UIContextMenuConfiguration *)contextMenuInteraction:(UIContextMenuInteraction *)interaction configurationForMenuAtLocation:(CGPoint)location
15059{
15060 RetainPtr<UIContextMenuConfiguration> configuration;
15061#if USE(BROWSERENGINEKIT)(defined 1 && 1)
15062 if (self._shouldUseUIContextMenuAsyncConfiguration) {
15063 auto asyncConfiguration = adoptNS([[BEContextMenuConfiguration alloc] init]);
15064 [self _internalContextMenuInteraction:interaction configurationForMenuAtLocation:location completion:[asyncConfiguration](UIContextMenuConfiguration *finalConfiguration) {
15065 [asyncConfiguration fulfillUsingConfiguration:finalConfiguration];
15066 }];
15067 configuration = asyncConfiguration.get();
15068 }
15069#endif // USE(BROWSERENGINEKIT)
15070 return configuration.autorelease();
15071}
15072
15073- (void)_internalContextMenuInteraction:(UIContextMenuInteraction *)interaction configurationForMenuAtLocation:(CGPoint)location completion:(void(^)(UIContextMenuConfiguration *))completion
15074{
15075 _useContextMenuInteractionDismissalPreview = YES__objc_yes;
15076
15077 if (!_webView)
15078 return completion(nilnullptr);
15079
15080 if (!self.webView.configuration._longPressActionsEnabled)
15081 return completion(nilnullptr);
15082
15083 auto getConfigurationAndContinue = [weakSelf = WeakObjCPtr<WKContentView>(self), interaction = retainPtr(interaction), completion = makeBlockPtr(completion)] (WebKit::ProceedWithTextSelectionInImage proceedWithTextSelectionInImage) {
15084 auto strongSelf = weakSelf.get();
15085 if (!strongSelf || proceedWithTextSelectionInImage == WebKit::ProceedWithTextSelectionInImage::Yes) {
15086 completion(nilnullptr);
15087 return;
15088 }
15089
15090 strongSelf->_showLinkPreviews = true;
15091 if (NSNumber *value = [[NSUserDefaults standardUserDefaults] objectForKey:webkitShowLinkPreviewsPreferenceKey])
15092 strongSelf->_showLinkPreviews = value.boolValue;
15093
15094 WebKit::InteractionInformationRequest request { WebCore::roundedIntPoint([interaction locationInView:strongSelf.get()]) };
15095 request.includeSnapshot = true;
15096 request.includeLinkIndicator = true;
15097 request.linkIndicatorShouldHaveLegacyMargins = ![strongSelf _shouldUseContextMenus];
15098 request.gatherAnimations = [strongSelf->_webView.get() _allowAnimationControls];
15099
15100 [strongSelf doAfterPositionInformationUpdate:[weakSelf = WeakObjCPtr<WKContentView>(strongSelf.get()), interaction, completion] (WebKit::InteractionInformationAtPosition) {
15101 if (auto strongSelf = weakSelf.get())
15102 [strongSelf continueContextMenuInteraction:interaction completion:completion.get()];
15103 else
15104 completion(nilnullptr);
15105 } forRequest:request];
15106 };
15107
15108#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
15109 [self _doAfterPendingImageAnalysis:getConfigurationAndContinue];
15110#else
15111 getConfigurationAndContinue(WebKit::ProceedWithTextSelectionInImage::No);
15112#endif
15113}
15114
15115- (UIAction *)placeholderForDynamicallyInsertedImageAnalysisActions
15116{
15117#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
15118 switch (_dynamicImageAnalysisContextMenuState) {
15119 case WebKit::DynamicImageAnalysisContextMenuState::NotWaiting:
15120 return nilnullptr;
15121 case WebKit::DynamicImageAnalysisContextMenuState::WaitingForImageAnalysis:
15122 case WebKit::DynamicImageAnalysisContextMenuState::WaitingForVisibleMenu: {
15123 // FIXME: This placeholder item warrants its own unique item identifier; however, to ensure that internal clients
15124 // that already allow image analysis items (e.g. Mail) continue to allow this placeholder item, we reuse an existing
15125 // image analysis identifier.
15126 RetainPtr placeholder = [UIAction actionWithTitle:@"" image:nilnullptr identifier:protect(elementActionTypeToUIActionIdentifier(_WKElementActionTypeRevealImage)).get() handler:^(UIAction *) { }];
15127 [placeholder setAttributes:UIMenuElementAttributesHidden];
15128 return placeholder.autorelease();
15129 }
15130 }
15131#endif // ENABLE(IMAGE_ANALYSIS)
15132 return nilnullptr;
15133}
15134
15135- (void)continueContextMenuInteraction:(UIContextMenuInteraction *)interaction completion:(void(^)(UIContextMenuConfiguration *))continueWithContextMenuConfiguration
15136{
15137 if (!self.window)
15138 return continueWithContextMenuConfiguration(nilnullptr);
15139
15140 if (!_positionInformation.touchCalloutEnabled)
15141 return continueWithContextMenuConfiguration(nilnullptr);
15142
15143 if (!_positionInformation.isLink && !_positionInformation.isImage && !_positionInformation.isAttachment && !_positionInformation.isInPlugin && !self.positionInformationHasImageOverlayDataDetector)
15144 return continueWithContextMenuConfiguration(nilnullptr);
15145
15146 URL linkURL = _positionInformation.url;
15147
15148 if (_positionInformation.isLink && linkURL.isEmpty())
15149 return continueWithContextMenuConfiguration(nilnullptr);
15150
15151 auto uiDelegate = static_cast<id<WKUIDelegatePrivate>>(self.webView.UIDelegate);
15152
15153 if (needsDeprecatedPreviewAPI(uiDelegate)) {
15154 if (_positionInformation.isLink) {
15155ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
15156 if ([uiDelegate respondsToSelector:@selector(webView:shouldPreviewElement:)]) {
15157 auto previewElementInfo = adoptNS([[WKPreviewElementInfo alloc] _initWithLinkURL:linkURL.createNSURL().get()]);
15158 if (![uiDelegate webView:self.webView shouldPreviewElement:previewElementInfo.get()])
15159 return continueWithContextMenuConfiguration(nilnullptr);
15160 }
15161ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15162
15163 // FIXME: Support JavaScript urls here. But make sure they don't show a preview.
15164 // <rdar://problem/50572283>
15165 if (!linkURL.protocolIsInHTTPFamily()) {
15166#if ENABLE(DATA_DETECTION)(defined 1 && 1)
15167 if (!WebCore::DataDetection::canBePresentedByDataDetectors(linkURL))
15168 return continueWithContextMenuConfiguration(nilnullptr);
15169#endif
15170 }
15171 }
15172
15173 _contextMenuLegacyPreviewController = nullptr;
15174 _contextMenuLegacyMenu = nullptr;
15175 _contextMenuHasRequestedLegacyData = NO__objc_no;
15176 _contextMenuActionProviderDelegateNeedsOverride = NO__objc_no;
15177 _contextMenuIsUsingAlternateURLForImage = NO__objc_no;
15178
15179 UIContextMenuActionProvider actionMenuProvider = [weakSelf = WeakObjCPtr<WKContentView>(self)] (NSArray<UIMenuElement *> *) -> UIMenu * {
15180 auto strongSelf = weakSelf.get();
15181 if (!strongSelf)
15182 return nilnullptr;
15183 if (!strongSelf->_contextMenuHasRequestedLegacyData)
15184 [strongSelf assignLegacyDataForContextMenuInteraction];
15185
15186 return strongSelf->_contextMenuLegacyMenu.get();
15187 };
15188
15189 UIContextMenuContentPreviewProvider contentPreviewProvider = [weakSelf = WeakObjCPtr<WKContentView>(self)] () -> UIViewController * {
15190 auto strongSelf = weakSelf.get();
15191 if (!strongSelf)
15192 return nilnullptr;
15193 if (!strongSelf->_contextMenuHasRequestedLegacyData)
15194 [strongSelf assignLegacyDataForContextMenuInteraction];
15195
15196 return strongSelf->_contextMenuLegacyPreviewController.get();
15197 };
15198
15199 protect(_page)->startInteractionWithPositionInformation(_positionInformation);
15200
15201 continueWithContextMenuConfiguration([UIContextMenuConfiguration configurationWithIdentifier:nilnullptr previewProvider:contentPreviewProvider actionProvider:actionMenuProvider]);
15202 return;
15203 }
15204
15205#if ENABLE(DATA_DETECTION)(defined 1 && 1)
15206 if ([linkURL.createNSURL() iTunesStoreURL]) {
15207 [self continueContextMenuInteractionWithDataDetectors:continueWithContextMenuConfiguration];
15208 return;
15209 }
15210#endif
15211
15212 auto completionBlock = makeBlockPtr([interaction = retainPtr(interaction), continueWithContextMenuConfiguration = makeBlockPtr(continueWithContextMenuConfiguration), linkURL = WTF::move(linkURL), weakSelf = WeakObjCPtr<WKContentView>(self)] (UIContextMenuConfiguration *configurationFromWKUIDelegate) mutable {
15213 auto strongSelf = weakSelf.get();
15214 if (!strongSelf) {
15215 continueWithContextMenuConfiguration(nilnullptr);
15216 return;
15217 }
15218
15219 if (configurationFromWKUIDelegate) {
15220 protect(strongSelf->_page)->startInteractionWithPositionInformation(strongSelf->_positionInformation);
15221 strongSelf->_contextMenuActionProviderDelegateNeedsOverride = YES__objc_yes;
15222 continueWithContextMenuConfiguration(configurationFromWKUIDelegate);
15223 return;
15224 }
15225
15226 bool canShowHTTPLinkOrDataDetectorPreview = ([&] {
15227 if (linkURL.protocolIsInHTTPFamily())
15228 return true;
15229
15230 if (WebCore::DataDetection::canBePresentedByDataDetectors(linkURL))
15231 return true;
15232
15233 if ([strongSelf positionInformationHasImageOverlayDataDetector])
15234 return true;
15235
15236 return false;
15237 })();
15238
15239 ASSERT_IMPLIES(strongSelf->_positionInformation.isImage, strongSelf->_positionInformation.image)((void)0);
15240 if (strongSelf->_positionInformation.isImage && strongSelf->_positionInformation.image && !canShowHTTPLinkOrDataDetectorPreview) {
15241 RetainPtr cgImage = protect(strongSelf->_positionInformation.image)->createPlatformImage();
15242
15243 strongSelf->_contextMenuActionProviderDelegateNeedsOverride = NO__objc_no;
15244
15245 auto elementInfo = adoptNS([[_WKActivatedElementInfo alloc] _initWithInteractionInformationAtPosition:strongSelf->_positionInformation isUsingAlternateURLForImage:strongSelf->_contextMenuIsUsingAlternateURLForImage userInfo:nilnullptr]);
15246
15247 UIContextMenuActionProvider actionMenuProvider = [weakSelf, elementInfo] (NSArray<UIMenuElement *> *) -> UIMenu * {
15248 auto strongSelf = weakSelf.get();
15249 if (!strongSelf)
15250 return nilnullptr;
15251
15252 RetainPtr<NSArray<_WKElementAction *>> defaultActionsFromAssistant = [strongSelf->_actionSheetAssistant defaultActionsForImageSheet:elementInfo.get()];
15253 RetainPtr actions = menuElementsFromDefaultActions(defaultActionsFromAssistant, elementInfo);
15254#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
15255 if (auto *placeholder = [strongSelf placeholderForDynamicallyInsertedImageAnalysisActions])
15256 [actions addObject:placeholder];
15257 else if (UIMenu *menu = [strongSelf machineReadableCodeSubMenuForImageContextMenu])
15258 [actions addObject:menu];
15259#endif // ENABLE(IMAGE_ANALYSIS)
15260 return [UIMenu menuWithTitle:strongSelf->_positionInformation.title.createNSString().get() children:actions.get()];
15261 };
15262
15263 UIContextMenuContentPreviewProvider contentPreviewProvider = [weakSelf, cgImage, elementInfo] () -> UIViewController * {
15264 auto strongSelf = weakSelf.get();
15265 if (!strongSelf)
15266 return nilnullptr;
15267
15268 auto uiDelegate = static_cast<id<WKUIDelegatePrivate>>([strongSelf webViewUIDelegate]);
15269 if ([uiDelegate respondsToSelector:@selector(_webView:contextMenuContentPreviewForElement:)]) {
15270 if (UIViewController *previewViewController = [uiDelegate _webView:[strongSelf webView] contextMenuContentPreviewForElement:strongSelf->_contextMenuElementInfo.get()])
15271 return previewViewController;
15272 }
15273
15274 return adoptNS([[WKImagePreviewViewController alloc] initWithCGImage:cgImage defaultActions:nilnullptr elementInfo:elementInfo.get() presentingView:strongSelf.get()]).autorelease();
15275 };
15276
15277 continueWithContextMenuConfiguration([UIContextMenuConfiguration configurationWithIdentifier:nilnullptr previewProvider:contentPreviewProvider actionProvider:actionMenuProvider]);
15278 return;
15279 }
15280
15281 // At this point we have an object we might want to show a context menu for, but the
15282 // client was unable to handle it. Before giving up, we ask DataDetectors.
15283
15284 strongSelf->_contextMenuElementInfo = nilnullptr;
15285
15286#if ENABLE(DATA_DETECTION)(defined 1 && 1)
15287 // FIXME: Support JavaScript urls here. But make sure they don't show a preview.
15288 // <rdar://problem/50572283>
15289 if (canShowHTTPLinkOrDataDetectorPreview) {
15290 [strongSelf continueContextMenuInteractionWithDataDetectors:continueWithContextMenuConfiguration.get()];
15291 return;
15292 }
15293#endif
15294
15295#if ENABLE(UNIFIED_PDF)(defined 1 && 1)
15296 if (strongSelf->_positionInformation.isInPlugin && [interaction menuAppearance] == UIContextMenuInteractionAppearanceCompact && [strongSelf shouldShowPDFDisplayOptions]) {
15297 [strongSelf continueContextMenuInteractionWithPDFDisplayOptions:continueWithContextMenuConfiguration.get()];;
15298 return;
15299 }
15300#endif
15301
15302 continueWithContextMenuConfiguration(nilnullptr);
15303 });
15304
15305 _contextMenuActionProviderDelegateNeedsOverride = NO__objc_no;
15306 _contextMenuIsUsingAlternateURLForImage = NO__objc_no;
15307 _contextMenuElementInfo = wrapper(API::ContextMenuElementInfo::create(_positionInformation, nilnullptr));
15308
15309 if (_positionInformation.isImage && _positionInformation.url.isNull() && [uiDelegate respondsToSelector:@selector(_webView:alternateURLFromImage:userInfo:)]) {
15310 UIImage *uiImage = [[_contextMenuElementInfo _activatedElementInfo] image];
15311 NSDictionary *userInfo = nilnullptr;
15312 NSURL *nsURL = [uiDelegate _webView:self.webView alternateURLFromImage:uiImage userInfo:&userInfo];
15313 _positionInformation.url = nsURL;
15314 if (nsURL)
15315 _contextMenuIsUsingAlternateURLForImage = YES__objc_yes;
15316 _contextMenuElementInfo = wrapper(API::ContextMenuElementInfo::create(_positionInformation, userInfo));
15317 }
15318
15319 if (_positionInformation.isLink && [uiDelegate respondsToSelector:@selector(webView:contextMenuConfigurationForElement:completionHandler:)]) {
15320 auto checker = WebKit::CompletionHandlerCallChecker::create(uiDelegate, @selector(webView:contextMenuConfigurationForElement:completionHandler:));
15321 [uiDelegate webView:self.webView contextMenuConfigurationForElement:_contextMenuElementInfo.get() completionHandler:makeBlockPtr([completionBlock = WTF::move(completionBlock), checker = WTF::move(checker)] (UIContextMenuConfiguration *configuration) {
15322 if (checker->completionHandlerHasBeenCalled())
15323 return;
15324 checker->didCallCompletionHandler();
15325 completionBlock(configuration);
15326 }).get()];
15327 } else if ([uiDelegate respondsToSelector:@selector(_webView:contextMenuConfigurationForElement:completionHandler:)]) {
15328 auto checker = WebKit::CompletionHandlerCallChecker::create(uiDelegate, @selector(_webView:contextMenuConfigurationForElement:completionHandler:));
15329 [uiDelegate _webView:self.webView contextMenuConfigurationForElement:_contextMenuElementInfo.get() completionHandler:makeBlockPtr([completionBlock = WTF::move(completionBlock), checker = WTF::move(checker)] (UIContextMenuConfiguration *configuration) {
15330 if (checker->completionHandlerHasBeenCalled())
15331 return;
15332 checker->didCallCompletionHandler();
15333 completionBlock(configuration);
15334 }).get()];
15335 } else
15336 completionBlock(nilnullptr);
15337}
15338
15339#if ENABLE(DATA_DETECTION)(defined 1 && 1)
15340
15341- (void)continueContextMenuInteractionWithDataDetectors:(void(^)(UIContextMenuConfiguration *))continueWithContextMenuConfiguration
15342{
15343 BEGIN_BLOCK_OBJC_EXCEPTIONS@try {
15344 auto ddContextMenuActionClass = PAL::getDDContextMenuActionClassSingleton();
15345 auto context = retainPtr([self dataDetectionContextForPositionInformation:_positionInformation]);
15346 RetainPtr<UIContextMenuConfiguration> configurationFromDataDetectors;
15347
15348 if (self.positionInformationHasImageOverlayDataDetector) {
15349 DDScannerResult *scannerResult = [_positionInformation.dataDetectorResults firstObject];
15350 configurationFromDataDetectors = [ddContextMenuActionClass contextMenuConfigurationWithResult:RetainPtr { scannerResult.coreResult }.get() inView:self context:context.get() menuIdentifier:nilnullptr];
15351 } else {
15352 configurationFromDataDetectors = [ddContextMenuActionClass contextMenuConfigurationForURL:_positionInformation.url.createNSURL().get() identifier:_positionInformation.dataDetectorIdentifier.createNSString().get() selectedText:[self selectedText] results:_positionInformation.dataDetectorResults.get() inView:self context:context.get() menuIdentifier:nilnullptr];
15353 protect(_page)->startInteractionWithPositionInformation(_positionInformation);
15354 }
15355
15356 _contextMenuActionProviderDelegateNeedsOverride = YES__objc_yes;
15357 continueWithContextMenuConfiguration(configurationFromDataDetectors.get());
15358 END_BLOCK_OBJC_EXCEPTIONS} @catch(NSException *localException) { ReportBlockedObjCException
(localException); }
15359}
15360
15361#endif // ENABLE(DATA_DETECTION)
15362
15363#if ENABLE(UNIFIED_PDF)(defined 1 && 1)
15364
15365- (BOOL)shouldShowPDFDisplayOptions
15366{
15367 return protect(_page->preferences())->twoUpPDFDisplayModeSupportEnabled() && self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular;
15368}
15369
15370- (void)continueContextMenuInteractionWithPDFDisplayOptions:(void(^)(UIContextMenuConfiguration *))continueWithContextMenuConfiguration
15371{
15372 static UIActionIdentifier const WKPDFActionSinglePageIdentifier = @"WKPDFActionSinglePageIdentifier";
15373 static UIActionIdentifier const WKPDFActionTwoPagesIdentifier = @"WKPDFActionPlayTwoPagesIdentifier";
15374
15375 RetainPtr configuration = [UIContextMenuConfiguration configurationWithIdentifier:nilnullptr previewProvider:nilnullptr actionProvider:[weakSelf = WeakObjCPtr<WKContentView>(self)](NSArray<UIMenuElement *> *) -> UIMenu * {
15376 RetainPtr strongSelf = weakSelf.get();
15377 if (!strongSelf)
15378 return nilnullptr;
15379
15380 UIActionHandler actionHandler = [weakSelf](UIAction *action) {
15381 RetainPtr strongSelf = weakSelf.get();
15382 if (!strongSelf)
15383 return;
15384
15385 RefPtr page = strongSelf->_page;
15386 if (!page)
15387 return;
15388
15389 BOOL isSinglePage = WebKit::isSinglePagePDFDisplayMode(page->pdfDisplayMode());
15390 BOOL isSinglePageAction = [action.identifier isEqualToString:WKPDFActionSinglePageIdentifier];
15391
15392 if (isSinglePage == isSinglePageAction)
15393 return;
15394
15395 page->requestPDFDisplayMode(isSinglePageAction ? WebKit::PDFDisplayMode::SinglePageContinuous : WebKit::PDFDisplayMode::TwoUpContinuous);
15396 };
15397
15398 RetainPtr singlePageAction = [UIAction actionWithTitle:WebCore::contextMenuItemPDFSinglePage().createNSString().get() image:nilnullptr identifier:WKPDFActionSinglePageIdentifier handler:actionHandler];
15399 RetainPtr twoPagesAction = [UIAction actionWithTitle:WebCore::contextMenuItemPDFTwoPages().createNSString().get() image:nilnullptr identifier:WKPDFActionTwoPagesIdentifier handler:actionHandler];
15400
15401 if (WebKit::isSinglePagePDFDisplayMode(protect(strongSelf->_page)->pdfDisplayMode()))
15402 [singlePageAction setState:UIMenuElementStateOn];
15403 else
15404 [twoPagesAction setState:UIMenuElementStateOn];
15405
15406 return [UIMenu menuWithTitle:@"" children:@[ singlePageAction.get(), twoPagesAction.get() ]];
15407 }];
15408
15409 continueWithContextMenuConfiguration(configuration.get());
15410}
15411
15412#endif
15413
15414- (NSArray<UIMenuElement *> *)_contextMenuInteraction:(UIContextMenuInteraction *)interaction overrideSuggestedActionsForConfiguration:(UIContextMenuConfiguration *)configuration
15415{
15416 // If we're here we're in the legacy path, which ignores the suggested actions anyway.
15417 if (!_contextMenuActionProviderDelegateNeedsOverride)
15418 return nilnullptr;
15419
15420 RetainPtr suggestedActions = [protect(_actionSheetAssistant) suggestedActionsForContextMenuWithPositionInformation:_positionInformation];
15421 if (auto *placeholder = self.placeholderForDynamicallyInsertedImageAnalysisActions)
15422 [suggestedActions addObject:placeholder];
15423 return suggestedActions.autorelease();
15424}
15425
15426- (UITargetedPreview *)contextMenuInteraction:(UIContextMenuInteraction *)interaction configuration:(UIContextMenuConfiguration *)configuration highlightPreviewForItemWithIdentifier:(id<NSCopying>)identifier
15427{
15428 [self _startSuppressingSelectionAssistantForReason:WebKit::InteractionIsHappening];
15429 [self _cancelTouchEventGestureRecognizer];
15430 _isPreparingToDisplayContextMenu = YES__objc_yes;
15431 return [self _createTargetedContextMenuHintPreviewIfPossible];
15432}
15433
15434- (void)contextMenuInteraction:(UIContextMenuInteraction *)interaction willDisplayMenuForConfiguration:(UIContextMenuConfiguration *)configuration animator:(id<UIContextMenuInteractionAnimating>)animator
15435{
15436 if (!_webView)
15437 return;
15438
15439 protect(_page)->willBeginContextMenuInteraction();
15440 _isPreparingToDisplayContextMenu = NO__objc_no;
15441 _isDisplayingContextMenuWithAnimation = YES__objc_yes;
15442 [animator addCompletion:[weakSelf = WeakObjCPtr<WKContentView>(self)] {
15443 if (auto strongSelf = weakSelf.get()) {
15444 ASSERT_IMPLIES(strongSelf->_isDisplayingContextMenuWithAnimation, [strongSelf->_contextMenuHintContainerView window])((void)0);
15445 strongSelf->_isDisplayingContextMenuWithAnimation = NO__objc_no;
15446 [strongSelf->_webView.get() _didShowContextMenu];
15447#if ENABLE(IMAGE_ANALYSIS)(defined 1 && 1)
15448 switch (strongSelf->_dynamicImageAnalysisContextMenuState) {
15449 case WebKit::DynamicImageAnalysisContextMenuState::NotWaiting:
15450 case WebKit::DynamicImageAnalysisContextMenuState::WaitingForImageAnalysis:
15451 break;
15452 case WebKit::DynamicImageAnalysisContextMenuState::WaitingForVisibleMenu:
15453 [strongSelf _insertDynamicImageAnalysisContextMenuItemsIfPossible];
15454 break;
15455 }
15456#endif // ENABLE(IMAGE_ANALYSIS)
15457 }
15458 }];
15459
15460 auto uiDelegate = static_cast<id<WKUIDelegatePrivate>>(self.webView.UIDelegate);
15461 if (!uiDelegate)
15462 return;
15463
15464 if ([uiDelegate respondsToSelector:@selector(webView:contextMenuWillPresentForElement:)])
15465 [uiDelegate webView:self.webView contextMenuWillPresentForElement:_contextMenuElementInfo.get()];
15466 else if ([uiDelegate respondsToSelector:@selector(_webView:contextMenuWillPresentForElement:)]) {
15467ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
15468 [uiDelegate _webView:self.webView contextMenuWillPresentForElement:_contextMenuElementInfo.get()];
15469ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15470 }
15471}
15472
15473- (UITargetedPreview *)contextMenuInteraction:(UIContextMenuInteraction *)interaction configuration:(UIContextMenuConfiguration *)configuration dismissalPreviewForItemWithIdentifier:(id<NSCopying>)identifier
15474{
15475 if (!_useContextMenuInteractionDismissalPreview) {
15476 _contextMenuInteractionTargetedPreview = nilnullptr;
15477 return nilnullptr;
15478 }
15479
15480 return std::exchange(_contextMenuInteractionTargetedPreview, nilnullptr).autorelease();
15481}
15482
15483- (void)contextMenuInteraction:(UIContextMenuInteraction *)interaction willPerformPreviewActionForMenuWithConfiguration:(UIContextMenuConfiguration *)configuration animator:(id<UIContextMenuInteractionCommitAnimating>)animator
15484{
15485 if (!_webView)
15486 return;
15487
15488 _useContextMenuInteractionDismissalPreview = NO__objc_no;
15489
15490 auto uiDelegate = static_cast<id<WKUIDelegatePrivate>>(self.webView.UIDelegate);
15491 if (!uiDelegate)
15492 return;
15493
15494 if (needsDeprecatedPreviewAPI(uiDelegate)) {
15495
15496 if (_positionInformation.isImage) {
15497 if ([uiDelegate respondsToSelector:@selector(_webView:commitPreviewedImageWithURL:)]) {
15498 const auto& imageURL = _positionInformation.imageURL;
15499 if (imageURL.isEmpty() || !(imageURL.protocolIsInHTTPFamily() || imageURL.protocolIs("data"_s)))
15500 return;
15501ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
15502 [uiDelegate _webView:self.webView commitPreviewedImageWithURL:imageURL.createNSURL().get()];
15503ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15504 }
15505 return;
15506 }
15507
15508 if ([uiDelegate respondsToSelector:@selector(webView:commitPreviewingViewController:)]) {
15509ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
15510 if (RetainPtr viewController = _contextMenuLegacyPreviewController.get())
15511 [uiDelegate webView:self.webView commitPreviewingViewController:viewController.get()];
15512ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15513 return;
15514 }
15515
15516 if ([uiDelegate respondsToSelector:@selector(_webView:commitPreviewedViewController:)]) {
15517ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
15518 if (RetainPtr viewController = _contextMenuLegacyPreviewController.get())
15519 [uiDelegate _webView:self.webView commitPreviewedViewController:viewController.get()];
15520ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15521 return;
15522 }
15523
15524 return;
15525 }
15526
15527 if ([uiDelegate respondsToSelector:@selector(webView:contextMenuForElement:willCommitWithAnimator:)])
15528 [uiDelegate webView:self.webView contextMenuForElement:_contextMenuElementInfo.get() willCommitWithAnimator:animator];
15529 else if ([uiDelegate respondsToSelector:@selector(_webView:contextMenuForElement:willCommitWithAnimator:)]) {
15530ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
15531 [uiDelegate _webView:self.webView contextMenuForElement:_contextMenuElementInfo.get() willCommitWithAnimator:animator];
15532ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15533 }
15534
15535#if defined(DD_CONTEXT_MENU_SPI_VERSION) && DD_CONTEXT_MENU_SPI_VERSION >= 2
15536 if ([configuration isKindOfClass:PAL::getDDContextMenuConfigurationClassSingleton()]) {
15537 DDContextMenuConfiguration *ddConfiguration = static_cast<DDContextMenuConfiguration *>(configuration);
15538
15539 BOOL shouldExpandPreview = NO__objc_no;
15540 RetainPtr<UIViewController> presentedViewController;
15541
15542#if defined(DD_CONTEXT_MENU_SPI_VERSION) && DD_CONTEXT_MENU_SPI_VERSION >= 3
15543 shouldExpandPreview = !!ddConfiguration.interactionViewControllerProvider;
15544 if (shouldExpandPreview)
15545 presentedViewController = ddConfiguration.interactionViewControllerProvider();
15546#else
15547 shouldExpandPreview = ddConfiguration.expandPreviewOnInteraction;
15548 presentedViewController = animator.previewViewController;
15549#endif
15550
15551 if (shouldExpandPreview) {
15552 animator.preferredCommitStyle = UIContextMenuInteractionCommitStylePop;
15553 _useContextMenuInteractionDismissalPreview = YES__objc_yes;
15554
15555 // We will re-present modally on the same VC that is currently presenting the preview in a context menu.
15556 RetainPtr<UIViewController> presentingViewController = animator.previewViewController.presentingViewController;
15557
15558 [animator addAnimations:^{
15559 [presentingViewController presentViewController:presentedViewController.get() animated:NO__objc_no completion:nilnullptr];
15560 }];
15561 return;
15562 }
15563
15564 if (NSURL *interactionURL = ddConfiguration.interactionURL) {
15565 animator.preferredCommitStyle = UIContextMenuInteractionCommitStylePop;
15566 _useContextMenuInteractionDismissalPreview = YES__objc_yes;
15567
15568 [animator addAnimations:^{
15569 [[UIApplication sharedApplication] openURL:interactionURL withCompletionHandler:nilnullptr];
15570 }];
15571 return;
15572 }
15573 }
15574#endif
15575}
15576
15577- (void)contextMenuInteraction:(UIContextMenuInteraction *)interaction willEndForConfiguration:(UIContextMenuConfiguration *)configuration animator:(id<UIContextMenuInteractionAnimating>)animator
15578{
15579 if (!_webView)
15580 return;
15581
15582 Ref page = *_page;
15583 page->didEndContextMenuInteraction();
15584 // FIXME: This delegate is being called more than once by UIKit. <rdar://problem/51550291>
15585 // This conditional avoids the WKUIDelegate being called twice too.
15586 if (_contextMenuElementInfo) {
15587 auto uiDelegate = static_cast<id<WKUIDelegatePrivate>>(self.webView.UIDelegate);
15588 if ([uiDelegate respondsToSelector:@selector(webView:contextMenuDidEndForElement:)])
15589 [uiDelegate webView:self.webView contextMenuDidEndForElement:_contextMenuElementInfo.get()];
15590 else if ([uiDelegate respondsToSelector:@selector(_webView:contextMenuDidEndForElement:)]) {
15591ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
15592 [uiDelegate _webView:self.webView contextMenuDidEndForElement:_contextMenuElementInfo.get()];
15593ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15594 }
15595 }
15596
15597 page->stopInteraction();
15598
15599 _contextMenuLegacyPreviewController = nullptr;
15600 _contextMenuLegacyMenu = nullptr;
15601 _contextMenuHasRequestedLegacyData = NO__objc_no;
15602 _contextMenuElementInfo = nullptr;
15603
15604 auto contextFinalizer = [weakSelf = WeakObjCPtr<WKContentView>(self)] () {
15605 auto strongSelf = weakSelf.get();
15606 if (!strongSelf)
15607 return;
15608
15609 strongSelf->_isDisplayingContextMenuWithAnimation = NO__objc_no;
15610 [strongSelf _removeContextMenuHintContainerIfPossible];
15611 [strongSelf->_webView.get() _didDismissContextMenu];
15612
15613 [strongSelf _stopSuppressingSelectionAssistantForReason:WebKit::InteractionIsHappening];
15614 };
15615
15616 if (animator)
15617 [animator addCompletion:contextFinalizer];
15618 else
15619 contextFinalizer();
15620}
15621
15622#endif // USE(UICONTEXTMENU)
15623
15624- (BOOL)_interactionShouldBeginFromPreviewItemController:(UIPreviewItemController *)controller forPosition:(CGPoint)position
15625{
15626 if (!_longPressCanClick)
15627 return NO__objc_no;
15628
15629 WebKit::InteractionInformationRequest request(WebCore::roundedIntPoint(position));
15630 request.includeSnapshot = true;
15631 request.includeLinkIndicator = true;
15632 request.linkIndicatorShouldHaveLegacyMargins = !self._shouldUseContextMenus;
15633 request.gatherAnimations = [self.webView _allowAnimationControls];
15634 if (![self ensurePositionInformationIsUpToDate:request])
15635 return NO__objc_no;
15636 if (!_positionInformation.isLink && !_positionInformation.isImage && !_positionInformation.isAttachment)
15637 return NO__objc_no;
15638
15639 const URL& linkURL = _positionInformation.url;
15640 if (_positionInformation.isLink) {
15641 RetainPtr uiDelegate = static_cast<id <WKUIDelegatePrivate>>([_webView.get() UIDelegate]);
15642ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
15643 if ([uiDelegate respondsToSelector:@selector(webView:shouldPreviewElement:)]) {
15644 auto previewElementInfo = adoptNS([[WKPreviewElementInfo alloc] _initWithLinkURL:linkURL.createNSURL().get()]);
15645 return [uiDelegate webView:self.webView shouldPreviewElement:previewElementInfo.get()];
15646 }
15647ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15648 if (linkURL.isEmpty())
15649 return NO__objc_no;
15650 if (linkURL.protocolIsInHTTPFamily())
15651 return YES__objc_yes;
15652#if ENABLE(DATA_DETECTION)(defined 1 && 1)
15653 if (WebCore::DataDetection::canBePresentedByDataDetectors(linkURL))
15654 return YES__objc_yes;
15655#endif
15656 return NO__objc_no;
15657 }
15658 return YES__objc_yes;
15659}
15660
15661- (NSDictionary *)_dataForPreviewItemController:(UIPreviewItemController *)controller atPosition:(CGPoint)position type:(UIPreviewItemType *)type
15662{
15663 *type = UIPreviewItemTypeNone;
15664
15665 RetainPtr uiDelegate = static_cast<id <WKUIDelegatePrivate>>([_webView.get() UIDelegate]);
15666 BOOL supportsImagePreview = [uiDelegate respondsToSelector:@selector(_webView:commitPreviewedImageWithURL:)];
15667 BOOL canShowImagePreview = _positionInformation.isImage && supportsImagePreview;
15668 BOOL canShowLinkPreview = _positionInformation.isLink || canShowImagePreview;
15669 BOOL useImageURLForLink = NO__objc_no;
15670 BOOL respondsToAttachmentListForWebViewSourceIsManaged = [uiDelegate respondsToSelector:@selector(_attachmentListForWebView:sourceIsManaged:)];
15671 BOOL supportsAttachmentPreview = ([uiDelegate respondsToSelector:@selector(_attachmentListForWebView:)] || respondsToAttachmentListForWebViewSourceIsManaged)
15672 && [uiDelegate respondsToSelector:@selector(_webView:indexIntoAttachmentListForElement:)];
15673 BOOL canShowAttachmentPreview = (_positionInformation.isAttachment || _positionInformation.isImage) && supportsAttachmentPreview;
15674 BOOL isDataDetectorLink = NO__objc_no;
15675#if ENABLE(DATA_DETECTION)(defined 1 && 1)
15676 isDataDetectorLink = _positionInformation.isDataDetectorLink;
15677#endif
15678
15679 if (canShowImagePreview && _positionInformation.isAnimatedImage) {
15680 canShowImagePreview = NO__objc_no;
15681 canShowLinkPreview = YES__objc_yes;
15682 useImageURLForLink = YES__objc_yes;
15683 }
15684
15685 if (!canShowLinkPreview && !canShowImagePreview && !canShowAttachmentPreview)
15686 return nilnullptr;
15687
15688 const URL& linkURL = _positionInformation.url;
15689 if (!useImageURLForLink && (linkURL.isEmpty() || (!linkURL.protocolIsInHTTPFamily() && !isDataDetectorLink))) {
15690 if (canShowLinkPreview && !canShowImagePreview)
15691 return nilnullptr;
15692 canShowLinkPreview = NO__objc_no;
15693 }
15694
15695 auto dataForPreview = adoptNS([[NSMutableDictionary alloc] init]);
15696 if (canShowLinkPreview) {
15697 *type = UIPreviewItemTypeLink;
15698 if (useImageURLForLink)
15699 dataForPreview.get()[UIPreviewDataLink] = _positionInformation.imageURL.createNSURL().get();
15700 else
15701 dataForPreview.get()[UIPreviewDataLink] = linkURL.createNSURL().get();
15702#if ENABLE(DATA_DETECTION)(defined 1 && 1)
15703 if (isDataDetectorLink) {
15704 RetainPtr<NSDictionary> context;
15705 if ([uiDelegate respondsToSelector:@selector(_dataDetectionContextForWebView:)])
15706 context = [uiDelegate _dataDetectionContextForWebView:self.webView];
15707
15708 DDDetectionController *controller = [PAL::getDDDetectionControllerClassSingleton() sharedController];
15709 // We cannot use a RetainPtr since this is an out-parameter for [DDDetectionController resultForURL:].
15710 SUPPRESS_UNRETAINED_LOCAL[[clang::suppress]] NSDictionary *rawNewContext = nilnullptr;
15711 RetainPtr<NSMutableDictionary> extendedContext;
15712 RetainPtr ddResult = [controller resultForURL:dataForPreview.get()[UIPreviewDataLink] identifier:_positionInformation.dataDetectorIdentifier.createNSString().get() selectedText:[self selectedText] results:_positionInformation.dataDetectorResults.get() context:context extendedContext:&rawNewContext];
15713 RetainPtr newContext = rawNewContext;
15714 if (ddResult)
15715 dataForPreview.get()[UIPreviewDataDDResult] = (__bridge id)ddResult.get();
15716 if (!_positionInformation.textBefore.isEmpty() || !_positionInformation.textAfter.isEmpty()) {
15717 extendedContext = adoptNS([@{
15718 PAL::get_DataDetectorsUI_kDataDetectorsLeadingTextSingleton() : _positionInformation.textBefore.createNSString().get(),
15719 PAL::get_DataDetectorsUI_kDataDetectorsTrailingTextSingleton() : _positionInformation.textAfter.createNSString().get(),
15720 } mutableCopy]);
15721
15722 if (newContext)
15723 [extendedContext addEntriesFromDictionary:newContext];
15724 newContext = extendedContext.get();
15725 }
15726 if (newContext)
15727 dataForPreview.get()[UIPreviewDataDDContext] = newContext.get();
15728 }
15729#endif // ENABLE(DATA_DETECTION)
15730 } else if (canShowImagePreview) {
15731 *type = UIPreviewItemTypeImage;
15732 dataForPreview.get()[UIPreviewDataLink] = _positionInformation.imageURL.createNSURL().get();
15733 } else if (canShowAttachmentPreview) {
15734 *type = UIPreviewItemTypeAttachment;
15735 auto element = adoptNS([[_WKActivatedElementInfo alloc] _initWithType:_WKActivatedElementTypeAttachment URL:linkURL.createNSURL().get() image:nilnullptr information:_positionInformation]);
15736 NSUInteger index = [uiDelegate _webView:self.webView indexIntoAttachmentListForElement:element.get()];
15737 if (index != NSNotFound) {
15738 BOOL sourceIsManaged = NO__objc_no;
15739 if (respondsToAttachmentListForWebViewSourceIsManaged)
15740 dataForPreview.get()[UIPreviewDataAttachmentList] = [uiDelegate _attachmentListForWebView:self.webView sourceIsManaged:&sourceIsManaged];
15741 else
15742 dataForPreview.get()[UIPreviewDataAttachmentList] = [uiDelegate _attachmentListForWebView:self.webView];
15743 dataForPreview.get()[UIPreviewDataAttachmentIndex] = [NSNumber numberWithUnsignedInteger:index];
15744 dataForPreview.get()[UIPreviewDataAttachmentListIsContentManaged] = [NSNumber numberWithBool:sourceIsManaged];
15745 }
15746 }
15747
15748 return dataForPreview.autorelease();
15749}
15750
15751- (CGRect)_presentationRectForPreviewItemController:(UIPreviewItemController *)controller
15752{
15753 return _positionInformation.bounds;
15754}
15755
15756- (UIViewController *)_presentedViewControllerForPreviewItemController:(UIPreviewItemController *)controller
15757{
15758 RetainPtr uiDelegate = static_cast<id <WKUIDelegatePrivate>>([_webView.get() UIDelegate]);
15759
15760 [_webView.get() _didShowContextMenu];
15761
15762 NSURL *targetURL = controller.previewData[UIPreviewDataLink];
15763 URL coreTargetURL = targetURL;
15764 bool isValidURLForImagePreview = !coreTargetURL.isEmpty() && (coreTargetURL.protocolIsInHTTPFamily() || coreTargetURL.protocolIs("data"_s));
15765
15766 if ([_previewItemController type] == UIPreviewItemTypeLink) {
15767 _longPressCanClick = NO__objc_no;
15768 protect(_page)->startInteractionWithPositionInformation(_positionInformation);
15769
15770 // Treat animated images like a link preview
15771 if (isValidURLForImagePreview && _positionInformation.isAnimatedImage) {
15772 auto animatedImageElementInfo = adoptNS([[_WKActivatedElementInfo alloc] _initWithType:_WKActivatedElementTypeImage URL:targetURL imageURL:nilnullptr information:_positionInformation]);
15773
15774 if ([uiDelegate respondsToSelector:@selector(_webView:previewViewControllerForAnimatedImageAtURL:defaultActions:elementInfo:imageSize:)]) {
15775 RetainPtr<NSArray> actions = [protect(_actionSheetAssistant) defaultActionsForImageSheet:animatedImageElementInfo.get()];
15776ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
15777 return [uiDelegate _webView:self.webView previewViewControllerForAnimatedImageAtURL:targetURL defaultActions:actions.get() elementInfo:animatedImageElementInfo.get() imageSize:_positionInformation.image->size()];
15778ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15779 }
15780 }
15781
15782 auto elementInfo = adoptNS([[_WKActivatedElementInfo alloc] _initWithType:_WKActivatedElementTypeLink URL:targetURL imageURL:nilnullptr information:_positionInformation]);
15783
15784 auto actions = [protect(_actionSheetAssistant) defaultActionsForLinkSheet:elementInfo.get()];
15785 if ([uiDelegate respondsToSelector:@selector(webView:previewingViewControllerForElement:defaultActions:)]) {
15786 auto previewActions = adoptNS([[NSMutableArray alloc] init]);
15787 for (_WKElementAction *elementAction in actions.get()) {
15788ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
15789 RetainPtr previewAction = [WKPreviewAction actionWithIdentifier:protect(previewIdentifierForElementAction(elementAction)).get() title:[elementAction title] style:UIPreviewActionStyleDefault handler:^(UIPreviewAction *, UIViewController *) {
15790 [elementAction runActionWithElementInfo:elementInfo.get()];
15791 }];
15792ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15793 [previewActions addObject:previewAction.get()];
15794 }
15795ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
15796 auto previewElementInfo = adoptNS([[WKPreviewElementInfo alloc] _initWithLinkURL:targetURL]);
15797 if (UIViewController *controller = [uiDelegate webView:self.webView previewingViewControllerForElement:previewElementInfo.get() defaultActions:previewActions.get()])
15798 return controller;
15799ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15800 }
15801
15802ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
15803 if ([uiDelegate respondsToSelector:@selector(_webView:previewViewControllerForURL:defaultActions:elementInfo:)])
15804 return [uiDelegate _webView:self.webView previewViewControllerForURL:targetURL defaultActions:actions.get() elementInfo:elementInfo.get()];
15805
15806 if ([uiDelegate respondsToSelector:@selector(_webView:previewViewControllerForURL:)])
15807 return [uiDelegate _webView:self.webView previewViewControllerForURL:targetURL];
15808ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15809
15810 return nilnullptr;
15811 }
15812
15813 if ([_previewItemController type] == UIPreviewItemTypeImage) {
15814 if (!isValidURLForImagePreview)
15815 return nilnullptr;
15816
15817 RetainPtr<NSURL> alternateURL = targetURL;
15818 RetainPtr<NSDictionary> imageInfo;
15819 RetainPtr<CGImageRef> cgImage = protect(_positionInformation.image)->createPlatformImage();
15820 RetainPtr<UIImage> uiImage = adoptNS([[UIImage alloc] initWithCGImage:cgImage.get()]);
15821 if ([uiDelegate respondsToSelector:@selector(_webView:alternateURLFromImage:userInfo:)]) {
15822 NSDictionary *userInfo;
15823 alternateURL = [uiDelegate _webView:self.webView alternateURLFromImage:uiImage.get() userInfo:&userInfo];
15824 imageInfo = userInfo;
15825 }
15826
15827 auto elementInfo = adoptNS([[_WKActivatedElementInfo alloc] _initWithType:_WKActivatedElementTypeImage URL:alternateURL.get() imageURL:nilnullptr userInfo:imageInfo.get() information:_positionInformation]);
15828 protect(_page)->startInteractionWithPositionInformation(_positionInformation);
15829
15830ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
15831 if ([uiDelegate respondsToSelector:@selector(_webView:willPreviewImageWithURL:)])
15832 [uiDelegate _webView:self.webView willPreviewImageWithURL:targetURL];
15833ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15834
15835 auto defaultActions = [protect(_actionSheetAssistant) defaultActionsForImageSheet:elementInfo.get()];
15836 if (imageInfo && [uiDelegate respondsToSelector:@selector(_webView:previewViewControllerForImage:alternateURL:defaultActions:elementInfo:)]) {
15837ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
15838 UIViewController *previewViewController = [uiDelegate _webView:self.webView previewViewControllerForImage:uiImage.get() alternateURL:alternateURL.get() defaultActions:defaultActions.get() elementInfo:elementInfo.get()];
15839ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15840 if (previewViewController)
15841 return previewViewController;
15842 }
15843
15844 return adoptNS([[WKImagePreviewViewController alloc] initWithCGImage:cgImage defaultActions:defaultActions elementInfo:elementInfo presentingView:self]).autorelease();
15845 }
15846
15847 return nilnullptr;
15848}
15849
15850- (void)_previewItemController:(UIPreviewItemController *)controller commitPreview:(UIViewController *)viewController
15851{
15852 RetainPtr uiDelegate = static_cast<id <WKUIDelegatePrivate>>([_webView.get() UIDelegate]);
15853 if ([_previewItemController type] == UIPreviewItemTypeImage) {
15854 if ([uiDelegate respondsToSelector:@selector(_webView:commitPreviewedImageWithURL:)]) {
15855 const URL& imageURL = _positionInformation.imageURL;
15856 if (imageURL.isEmpty() || !(imageURL.protocolIsInHTTPFamily() || imageURL.protocolIs("data"_s)))
15857 return;
15858ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
15859 [uiDelegate _webView:self.webView commitPreviewedImageWithURL:imageURL.createNSURL().get()];
15860ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15861 return;
15862 }
15863 return;
15864 }
15865
15866 if ([uiDelegate respondsToSelector:@selector(webView:commitPreviewingViewController:)]) {
15867ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
15868 [uiDelegate webView:self.webView commitPreviewingViewController:viewController];
15869ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15870 return;
15871 }
15872
15873 if ([uiDelegate respondsToSelector:@selector(_webView:commitPreviewedViewController:)]) {
15874ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
15875 [uiDelegate _webView:self.webView commitPreviewedViewController:viewController];
15876ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15877 return;
15878 }
15879
15880}
15881
15882- (void)_interactionStartedFromPreviewItemController:(UIPreviewItemController *)controller
15883{
15884 [self _removeDefaultGestureRecognizers];
15885
15886 [self _cancelInteraction];
15887}
15888
15889- (void)_interactionStoppedFromPreviewItemController:(UIPreviewItemController *)controller
15890{
15891 [self _addDefaultGestureRecognizers];
15892
15893 if (![protect(_actionSheetAssistant) isShowingSheet])
15894 protect(_page)->stopInteraction();
15895}
15896
15897- (void)_previewItemController:(UIPreviewItemController *)controller didDismissPreview:(UIViewController *)viewController committing:(BOOL)committing
15898{
15899 RetainPtr uiDelegate = static_cast<id <WKUIDelegatePrivate>>([_webView.get() UIDelegate]);
15900ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
15901 if ([uiDelegate respondsToSelector:@selector(_webView:didDismissPreviewViewController:committing:)])
15902 [uiDelegate _webView:self.webView didDismissPreviewViewController:viewController committing:committing];
15903 else if ([uiDelegate respondsToSelector:@selector(_webView:didDismissPreviewViewController:)])
15904 [uiDelegate _webView:self.webView didDismissPreviewViewController:viewController];
15905ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
15906
15907 [_webView.get() _didDismissContextMenu];
15908}
15909
15910- (UIImage *)_presentationSnapshotForPreviewItemController:(UIPreviewItemController *)controller
15911{
15912 if (!_positionInformation.textIndicator->contentImage())
15913 return nullptr;
15914
15915 auto nativeImage = protect(_positionInformation.textIndicator->contentImage())->nativeImage();
15916 if (!nativeImage)
15917 return nullptr;
15918
15919 return adoptNS([[UIImage alloc] initWithCGImage:nativeImage->platformImage().get()]).autorelease();
15920}
15921
15922- (NSArray *)_presentationRectsForPreviewItemController:(UIPreviewItemController *)controller
15923{
15924 if (_positionInformation.textIndicator->contentImage()) {
15925 auto origin = _positionInformation.textIndicator->textBoundingRectInRootViewCoordinates().location();
15926 return createNSArray(_positionInformation.textIndicator->textRectsInBoundingRectCoordinates(), [&] (CGRect rect) {
15927 return [NSValue valueWithCGRect:CGRectOffset(rect, origin.x(), origin.y())];
15928 }).autorelease();
15929 } else {
15930 float marginInPx = 4 * protect(_page)->deviceScaleFactor();
15931 return @[[NSValue valueWithCGRect:CGRectInset(_positionInformation.bounds, -marginInPx, -marginInPx)]];
15932 }
15933}
15934
15935- (void)_previewItemControllerDidCancelPreview:(UIPreviewItemController *)controller
15936{
15937 _longPressCanClick = NO__objc_no;
15938
15939 [_webView.get() _didDismissContextMenu];
15940}
15941
15942@end
15943
15944#endif // HAVE(LINK_PREVIEW)
15945
15946// UITextRange and UITextPosition implementations for WK2
15947// FIXME: Move these out into separate files.
15948
15949@implementation WKTextRange (UITextInputAdditions)
15950
15951- (BOOL)_isCaret
15952{
15953 return self.empty;
15954}
15955
15956- (BOOL)_isRanged
15957{
15958 return !self.empty;
15959}
15960
15961@end
15962
15963@implementation WKTextRange
15964
15965+ (WKTextRange *)textRangeWithState:(BOOL)isNone isRange:(BOOL)isRange isEditable:(BOOL)isEditable startRect:(CGRect)startRect endRect:(CGRect)endRect selectionRects:(NSArray *)selectionRects selectedTextLength:(NSUInteger)selectedTextLength
15966{
15967 auto range = adoptNS([[WKTextRange alloc] init]);
15968 [range setIsNone:isNone];
15969 [range setIsRange:isRange];
15970 [range setIsEditable:isEditable];
15971 [range setStartRect:startRect];
15972 [range setEndRect:endRect];
15973 [range setSelectedTextLength:selectedTextLength];
15974 [range setSelectionRects:selectionRects];
15975 return range.autorelease();
15976}
15977
15978- (void)dealloc
15979{
15980 [super dealloc];
15981}
15982
15983- (NSArray<WKTextSelectionRect *> *)selectionRects
15984{
15985 return _selectionRects.get();
15986}
15987
15988- (void)setSelectionRects:(NSArray<WKTextSelectionRect *> *)selectionRects
15989{
15990 _selectionRects = adoptNS([selectionRects copy]);
15991}
15992
15993- (NSString *)description
15994{
15995 return [NSString stringWithFormat:@"%@(%p) - start:%@, end:%@", [self class], self, protect(NSStringFromCGRect(self.startRect)).get(), protect(NSStringFromCGRect(self.endRect)).get()];
15996}
15997
15998- (WKTextPosition *)start
15999{
16000 WKTextPosition *position = [WKTextPosition textPositionWithRect:self.startRect];
16001 OptionSet anchors { WebKit::TextPositionAnchor::Start };
16002 if (self.isEmpty)
16003 anchors.add(WebKit::TextPositionAnchor::End);
16004 position.anchors = anchors;
16005 return position;
16006}
16007
16008- (WKTextPosition *)end
16009{
16010 WKTextPosition *position = [WKTextPosition textPositionWithRect:self.endRect];
16011 OptionSet anchors { WebKit::TextPositionAnchor::End };
16012 if (self.isEmpty)
16013 anchors.add(WebKit::TextPositionAnchor::Start);
16014 position.anchors = anchors;
16015 return position;
16016}
16017
16018- (BOOL)isEmpty
16019{
16020 return !self.isRange;
16021}
16022
16023// FIXME: Overriding isEqual: without overriding hash will cause trouble if this ever goes into an NSSet or is the key in an NSDictionary,
16024// since two equal items could have different hashes.
16025- (BOOL)isEqual:(id)other
16026{
16027 if (![other isKindOfClass:[WKTextRange class]])
16028 return NO__objc_no;
16029
16030 WKTextRange *otherRange = (WKTextRange *)other;
16031
16032 if (self == other)
16033 return YES__objc_yes;
16034
16035 // FIXME: Probably incorrect for equality to ignore so much of the object state.
16036 // It ignores isNone, isEditable, selectedTextLength, and selectionRects.
16037
16038 if (self.isRange) {
16039 if (!otherRange.isRange)
16040 return NO__objc_no;
16041 return CGRectEqualToRect(self.startRect, otherRange.startRect) && CGRectEqualToRect(self.endRect, otherRange.endRect);
16042 } else {
16043 if (otherRange.isRange)
16044 return NO__objc_no;
16045 // FIXME: Do we need to check isNone here?
16046 return CGRectEqualToRect(self.startRect, otherRange.startRect);
16047 }
16048}
16049
16050@end
16051
16052@implementation WKTextPosition
16053
16054@synthesize positionRect = _positionRect;
16055
16056+ (WKTextPosition *)textPositionWithRect:(CGRect)positionRect
16057{
16058 auto pos = adoptNS([[WKTextPosition alloc] init]);
16059 [pos setPositionRect:positionRect];
16060 return pos.autorelease();
16061}
16062
16063// FIXME: Overriding isEqual: without overriding hash will cause trouble if this ever goes into a NSSet or is the key in an NSDictionary,
16064// since two equal items could have different hashes.
16065- (BOOL)isEqual:(id)other
16066{
16067 if (![other isKindOfClass:[WKTextPosition class]])
16068 return NO__objc_no;
16069
16070 return CGRectEqualToRect(self.positionRect, ((WKTextPosition *)other).positionRect);
16071}
16072
16073- (NSString *)description
16074{
16075 return [NSString stringWithFormat:@"<WKTextPosition: %p, {%@}>", self, protect(NSStringFromCGRect(self.positionRect)).get()];
16076}
16077
16078@end
16079
16080#if HAVE(UIFINDINTERACTION)(defined 1 && 1)
16081
16082@implementation WKFoundTextRange
16083
16084+ (WKFoundTextRange *)foundTextRangeWithWebFoundTextRange:(WebKit::WebFoundTextRange)webRange
16085{
16086 RetainPtr range = WTF::switchOn(webRange.data,
16087 [] (const WebKit::WebFoundTextRange::DOMData& domData) -> RetainPtr<WKFoundTextRange> {
16088 RetainPtr foundDOMTextRange = adoptNS([[WKFoundDOMTextRange alloc] init]);
16089 [foundDOMTextRange setLocation:domData.location];
16090 [foundDOMTextRange setLength:domData.length];
16091 return foundDOMTextRange;
16092 },
16093 [] (const WebKit::WebFoundTextRange::PDFData& pdfData) -> RetainPtr<WKFoundTextRange> {
16094 RetainPtr foundPDFTextRange = adoptNS([[WKFoundPDFTextRange alloc] init]);
16095 [foundPDFTextRange setStartPage:pdfData.startPage];
16096 [foundPDFTextRange setStartPageOffset:pdfData.startOffset];
16097 [foundPDFTextRange setEndPage:pdfData.endPage];
16098 [foundPDFTextRange setEndPageOffset:pdfData.endOffset];
16099 return foundPDFTextRange;
16100 }
16101 );
16102
16103 [range setPathToFrame:createNSArray(webRange.pathToFrame, [](uint64_t index) {
16104 return @(index);
16105 }).get()];
16106 [range setOrder:webRange.order];
16107 return range.autorelease();
16108}
16109
16110- (void)dealloc
16111{
16112 [super dealloc];
16113}
16114
16115- (BOOL)isEmpty
16116{
16117 return NO__objc_no;
16118}
16119
16120- (WebKit::WebFoundTextRange)webFoundTextRange
16121{
16122 return { };
16123}
16124
16125@end
16126
16127@implementation WKFoundTextPosition
16128@end
16129
16130@implementation WKFoundDOMTextRange
16131
16132- (WKFoundDOMTextPosition *)start
16133{
16134 WKFoundDOMTextPosition *position = [WKFoundDOMTextPosition textPositionWithOffset:self.location order:self.order];
16135 return position;
16136}
16137
16138- (WKFoundDOMTextPosition *)end
16139{
16140 WKFoundDOMTextPosition *position = [WKFoundDOMTextPosition textPositionWithOffset:(self.location + self.length) order:self.order];
16141 return position;
16142}
16143
16144- (WebKit::WebFoundTextRange)webFoundTextRange
16145{
16146 WebKit::WebFoundTextRange::DOMData data { self.location, self.length };
16147 auto pathToFrameVector = makeVector(self.pathToFrame, [](id number) -> std::optional<uint64_t> {
16148 return [number unsignedLongValue];
16149 });
16150 return { data, WTF::move(pathToFrameVector), self.order };
16151}
16152
16153@end
16154
16155@implementation WKFoundDOMTextPosition
16156
16157+ (WKFoundDOMTextPosition *)textPositionWithOffset:(NSUInteger)offset order:(NSUInteger)order
16158{
16159 RetainPtr pos = adoptNS([[WKFoundDOMTextPosition alloc] init]);
16160 [pos setOffset:offset];
16161 [pos setOrder:order];
16162 return pos.autorelease();
16163}
16164
16165@end
16166
16167@implementation WKFoundPDFTextRange
16168
16169- (WKFoundPDFTextPosition *)start
16170{
16171 WKFoundPDFTextPosition *position = [WKFoundPDFTextPosition textPositionWithPage:self.startPage offset:self.startPageOffset];
16172 return position;
16173}
16174
16175- (WKFoundPDFTextPosition *)end
16176{
16177 WKFoundPDFTextPosition *position = [WKFoundPDFTextPosition textPositionWithPage:self.endPage offset:self.endPageOffset];
16178 return position;
16179}
16180
16181- (WebKit::WebFoundTextRange)webFoundTextRange
16182{
16183 WebKit::WebFoundTextRange::PDFData data { self.startPage, self.startPageOffset, self.endPage, self.endPageOffset };
16184 auto pathToFrameVector = makeVector(self.pathToFrame, [](id number) -> std::optional<uint64_t> {
16185 return [number unsignedLongValue];
16186 });
16187 return { data, WTF::move(pathToFrameVector), self.order };
16188}
16189
16190@end
16191
16192@implementation WKFoundPDFTextPosition
16193
16194+ (WKFoundPDFTextPosition *)textPositionWithPage:(NSUInteger)page offset:(NSUInteger)offset
16195{
16196 RetainPtr pos = adoptNS([[WKFoundPDFTextPosition alloc] init]);
16197 [pos setPage:page];
16198 [pos setOffset:offset];
16199 return pos.autorelease();
16200}
16201
16202@end
16203
16204#endif
16205
16206@implementation WKAutocorrectionRects
16207
16208+ (WKAutocorrectionRects *)autocorrectionRectsWithFirstCGRect:(CGRect)firstRect lastCGRect:(CGRect)lastRect
16209{
16210 auto rects = adoptNS([[WKAutocorrectionRects alloc] init]);
16211 [rects setFirstRect:firstRect];
16212 [rects setLastRect:lastRect];
16213 return rects.autorelease();
16214}
16215
16216@end
16217
16218@implementation WKAutocorrectionContext
16219
16220+ (WKAutocorrectionContext *)emptyAutocorrectionContext
16221{
16222 return [self autocorrectionContextWithWebContext:WebKit::WebAutocorrectionContext { }];
16223}
16224
16225+ (WKAutocorrectionContext *)autocorrectionContextWithWebContext:(const WebKit::WebAutocorrectionContext&)webCorrection
16226{
16227 auto correction = adoptNS([[WKAutocorrectionContext alloc] init]);
16228 [correction setContextBeforeSelection:nsStringNilIfEmpty(webCorrection.contextBefore).get()];
16229 [correction setSelectedText:nsStringNilIfEmpty(webCorrection.selectedText).get()];
16230 [correction setMarkedText:nsStringNilIfEmpty(webCorrection.markedText).get()];
16231 [correction setContextAfterSelection:nsStringNilIfEmpty(webCorrection.contextAfter).get()];
16232 [correction setRangeInMarkedText:webCorrection.selectedRangeInMarkedText];
16233 return correction.autorelease();
16234}
16235
16236@end
16237
16238#endif // PLATFORM(IOS_FAMILY)