Bug Summary

File:Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm
Warning:line 391, column 19
Local variable 'object' is uncounted and unsafe

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple arm64-apple-macosx15.5.0 -O2 -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name WebAccessibilityObjectWrapperMac.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=15.5 -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/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore -target-linker-version 1167.5 -fcoverage-compilation-dir=/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore -resource-dir /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/llvm-project/build/lib/clang/21 -dependency-file /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/WebAccessibilityObjectWrapperMac.d -skip-unused-modulemap-deps -MT dependencies -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk -iquote /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-generated-files.hmap -iquote /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-project-headers.hmap -isystem /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore/PAL/ThirdParty/dav1d/include -iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/PrivateFrameworks -iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/Frameworks -include-pch /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/PrecompiledHeaders/SharedPrecompiledHeaders/9111972217778337189/WebCorePrefix.h.gch -D _LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE -D CLANG_WEBKIT_BRANCH=1 -D NDEBUG -D BUILDING_WEBKIT -D GL_SILENCE_DEPRECATION=1 -D GLES_SILENCE_DEPRECATION=1 -D OBJC_OLD_DISPATCH_PROTOTYPES=0 -D __clang_analyzer__ -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-own-target-headers.hmap -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/WebCore-all-target-headers.hmap -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/include -I PAL -I ForwardingHeaders -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/include/libxslt -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/include/libxml2 -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/DerivedSources/WebCore -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include/WebKitAdditions -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include/WebKitAdditions -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitLibraries/SDKs/macosx15.0-additions.sdk/usr/local/include -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include/webrtc -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include/webrtc -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release/usr/local/include/webm -I /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include/webm -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/PAL.build/PAL.build/DerivedSources -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/PAL.build/Release/PAL.build/DerivedSources -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/DerivedSources-normal/arm64 -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/DerivedSources/arm64 -I /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/WebCore.build/Release/WebCore.build/DerivedSources -F/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/WebKitBuild/Release -I/usr/local/include -stdlib=libc++ -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/include/c++/v1 -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/local/include -internal-isystem /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/llvm-project/build/lib/clang/21/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/usr/include -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/Frameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.sdk/System/Library/SubFrameworks -internal-iframework /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.5.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 -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 -Wno-unknown-warning-option -Wliteral-conversion -Wthread-safety -Wno-profile-instr-out-of-date -Wno-profile-instr-unprofiled -Wunsafe-buffer-usage -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=macosx-15.5.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/macOS-Safer-CPP-Checks-EWS/build/scan-build-output/StaticAnalyzer/WebCore/WebCore/normal/arm64/WebAccessibilityObjectWrapperMac.plist -x objective-c++ /Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm
1/*
2 * Copyright (C) 2008-2025 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 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#import "config.h"
30#import "WebAccessibilityObjectWrapperMac.h"
31
32#import "AXIsolatedTree.h"
33#import "AXObjectCacheInlines.h"
34
35#if PLATFORM(MAC)(defined 1 && 1)
36
37#import "AXCrossProcessSearch.h"
38#import "AXIsolatedObject.h"
39#import "AXLogger.h"
40#import "AXRemoteFrame.h"
41#import "AXSearchManager.h"
42#import "AXTextMarker.h"
43#import "AXTreeStore.h"
44#import "AXTreeStoreInlines.h"
45#import "AccessibilityObjectInlines.h"
46#import "AccessibilityProgressIndicator.h"
47#import "AccessibilityRenderObject.h"
48#import "AccessibilityScrollView.h"
49#import "AccessibilitySpinButton.h"
50#import "AccessibilityTableColumn.h"
51#import "CGUtilities.h"
52#import "Chrome.h"
53#import "ChromeClient.h"
54#import "ContextMenuController.h"
55#import "DateComponents.h"
56#import "DocumentView.h"
57#import "ElementInlines.h"
58#import "Font.h"
59#import "FontCascade.h"
60#import "FrameSelection.h"
61#import "HTMLAnchorElement.h"
62#import "HTMLAreaElement.h"
63#import "HTMLFrameOwnerElement.h"
64#import "HTMLImageElement.h"
65#import "HTMLInputElement.h"
66#import "HTMLNames.h"
67#import "IntRect.h"
68#import "LocalFrame.h"
69#import "LocalFrameLoaderClient.h"
70#import "LocalizedStrings.h"
71#import "Page.h"
72#import "PluginDocument.h"
73#import "PluginViewBase.h"
74#import "Range.h"
75#import "RenderInline.h"
76#import "RenderObjectInlines.h"
77#import "RenderTextControl.h"
78#import "RenderView.h"
79#import "RenderWidget.h"
80#import "ScrollView.h"
81#import "Settings.h"
82#import "TextIterator.h"
83#import "VisibleUnits.h"
84#import "WebCoreFrameView.h"
85#import <AppKit/NSAccessibilityConstants.h>
86#import <pal/spi/cocoa/NSAccessibilitySPI.h>
87#import <wtf/ObjCRuntimeExtras.h>
88#import <wtf/RuntimeApplicationChecks.h>
89#import <wtf/cocoa/TypeCastsCocoa.h>
90#import <wtf/cocoa/VectorCocoa.h>
91#import <wtf/text/MakeString.h>
92#import <wtf/text/WTFString.h>
93
94#if ENABLE(MODEL_ELEMENT_ACCESSIBILITY)(defined 1 && 1)
95#import "ModelPlayerAccessibilityChildren.h"
96#endif
97
98using namespace WebCore;
99
100static id attributeValueForTesting(const RefPtr<AXCoreObject>&, NSString *);
101
102// Static C helper functions.
103
104// The CFAttributedStringType representation of the text associated with this accessibility
105// object that is specified by the given range.
106static NSAttributedString *attributedStringForNSRange(const AXCoreObject& backingObject, NSRange range)
107{
108 if (!range.length)
109 return nilnullptr;
110
111 auto markerRange = backingObject.textMarkerRangeForNSRange(range);
112 if (!markerRange)
113 return nilnullptr;
114
115 auto attributedString = backingObject.attributedStringForTextMarkerRange(WTF::move(markerRange), AXCoreObject::SpellCheck::Yes);
116 return [attributedString length] ? attributedString.autorelease() : nilnullptr;
117}
118
119// The RTF representation of the text associated with this accessibility object that is
120// specified by the given range.
121static NSData *rtfForNSRange(const AXCoreObject& backingObject, NSRange range)
122{
123 RetainPtr<NSAttributedString> attributedString = attributedStringForNSRange(backingObject, range);
124 return [attributedString RTFFromRange:NSMakeRange(0, [attributedString length]) documentAttributes:@{ }];
125}
126
127// Date time helpers.
128
129// VO requests a bit-wise combination of these constants via the API
130// AXDateTimeComponents to determine which fields of a datetime value are presented to the user.
131typedef NS_OPTIONS(NSUInteger, AXFDateTimeComponent)__attribute__((availability(swift,unavailable))) NSUInteger AXFDateTimeComponent
; enum __attribute__((flag_enum,enum_extensibility(open))) : AXFDateTimeComponent
{
132 AXFDateTimeComponentSeconds = 0x0002,
133 AXFDateTimeComponentMinutes = 0x0004,
134 AXFDateTimeComponentHours = 0x0008,
135 AXFDateTimeComponentDays = 0x0020,
136 AXFDateTimeComponentMonths = 0x0040,
137 AXFDateTimeComponentYears = 0x0080,
138 AXFDateTimeComponentEras = 0x0100
139};
140
141static inline unsigned convertToAXFDateTimeComponents(DateComponentsType type)
142{
143 switch (type) {
144 case DateComponentsType::Invalid:
145 return 0;
146 case DateComponentsType::Date:
147 return AXFDateTimeComponentDays | AXFDateTimeComponentMonths | AXFDateTimeComponentYears;
148 case DateComponentsType::DateTimeLocal:
149 return AXFDateTimeComponentSeconds | AXFDateTimeComponentMinutes | AXFDateTimeComponentHours
150 | AXFDateTimeComponentDays | AXFDateTimeComponentMonths | AXFDateTimeComponentYears;
151 case DateComponentsType::Month:
152 return AXFDateTimeComponentMonths | AXFDateTimeComponentYears;
153 case DateComponentsType::Time:
154 return AXFDateTimeComponentSeconds | AXFDateTimeComponentMinutes | AXFDateTimeComponentHours;
155 case DateComponentsType::Week:
156 return 0;
157 };
158}
159
160// VoiceOver expects the datetime value in the local time zone. Since we store it in GMT, we need to convert it to local before returning it to VoiceOver.
161// This helper funtion computes the offset to go from local to GMT and returns its opposite.
162static inline NSInteger gmtToLocalTimeOffset(DateComponentsType type)
163{
164 NSTimeZone *timeZone = [NSTimeZone localTimeZone];
165 NSDate *now = [NSDate date];
166 NSInteger offset = -1 * [timeZone secondsFromGMTForDate:now];
167 if (type != DateComponentsType::DateTimeLocal && [timeZone isDaylightSavingTimeForDate:now])
168 return offset + 3600; // + number of seconds in an hour.
169 return offset;
170}
171
172@implementation WebAccessibilityObjectWrapper
173
174- (void)detach
175{
176 AX_ASSERT(isMainThread())((void)0);
177
178 // If the IsolatedObject is initialized, do not UnregisterUniqueIdForUIElement here because the wrapper may be in the middle of serving a request on the AX thread.
179 // The IsolatedObject is capable to tend to some requests after the live object is gone.
180 // In regular mode, UnregisterUniqueIdForUIElement immediately.
181#if ENABLE(ACCESSIBILITY_ISOLATED_TREE)(defined 1 && 1)
182 if (!m_isolatedObjectInitialized)
183#endif
184 NSAccessibilityUnregisterUniqueIdForUIElement(self);
185
186 [super detach];
187}
188
189#if ENABLE(ACCESSIBILITY_ISOLATED_TREE)(defined 1 && 1)
190- (void)detachIsolatedObject:(AccessibilityDetachmentType)detachmentType
191{
192 // Only unregister this wrapper if the underlying object or cache is being destroyed. Unregistering it in other cases (like `ElementChanged`)
193 // would cause AX clients to get a notification that this wrapper was destroyed, which wouldn't be true.
194 if (detachmentType == AccessibilityDetachmentType::ElementDestroyed || detachmentType == AccessibilityDetachmentType::CacheDestroyed)
195 NSAccessibilityUnregisterUniqueIdForUIElement(self);
196 [super detachIsolatedObject:detachmentType];
197}
198#endif
199
200- (id)attachmentView
201{
202 return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
203 RefPtr<AXCoreObject> backingObject = protectedSelf.get().axBackingObject;
204 if (!backingObject)
205 return nilnullptr;
206
207 RefPtr widget = backingObject->widgetForAttachmentView();
208 return widget ? NSAccessibilityUnignoredDescendant(widget->platformWidget()) : nilnullptr;
209 });
210}
211
212#pragma mark SystemInterface wrappers
213
214static inline BOOL AXObjectIsTextMarker(id object)
215{
216 return object && CFGetTypeID((__bridge CFTypeRef)object) == AXTextMarkerGetTypeID();
217}
218
219static inline BOOL AXObjectIsTextMarkerRange(id object)
220{
221 return object && CFGetTypeID((__bridge CFTypeRef)object) == AXTextMarkerRangeGetTypeID();
222}
223
224#pragma mark Other helpers
225
226static IntRect screenToContents(AXCoreObject& axObject, IntRect&& rect)
227{
228 AX_ASSERT(isMainThread())((void)0);
229
230 RefPtr document = axObject.document();
231 RefPtr frameView = document ? document->view() : nullptr;
232 if (!frameView)
233 return { };
234
235 IntPoint startPoint = frameView->screenToContents(rect.minXMaxYCorner());
236 IntPoint endPoint = frameView->screenToContents(rect.maxXMinYCorner());
237 return IntRect(startPoint.x(), startPoint.y(), endPoint.x() - startPoint.x(), endPoint.y() - startPoint.y());
238}
239
240#pragma mark Select text helpers
241
242// To be deprecated.
243static std::pair<AccessibilitySearchTextCriteria, AccessibilityTextOperation> accessibilityTextCriteriaForParameterizedAttribute(const NSDictionary *parameterizedAttribute)
244{
245 AccessibilitySearchTextCriteria criteria;
246 AccessibilityTextOperation operation;
247
248 RetainPtr<NSString> activityParameter = [parameterizedAttribute objectForKey:NSAccessibilitySelectTextActivity@"AXSelectTextActivity"];
249 RetainPtr<NSString> ambiguityResolutionParameter = [parameterizedAttribute objectForKey:NSAccessibilitySelectTextAmbiguityResolution@"AXSelectTextAmbiguityResolution"];
250 RetainPtr<NSString> replacementStringParameter = [parameterizedAttribute objectForKey:NSAccessibilitySelectTextReplacementString@"AXSelectTextReplacementString"];
251 RetainPtr<NSArray> searchStringsParameter = [parameterizedAttribute objectForKey:NSAccessibilitySelectTextSearchStrings@"AXSelectTextSearchStrings"];
252
253 if ([activityParameter isKindOfClass:[NSString class]]) {
254 if ([activityParameter isEqualToString:NSAccessibilitySelectTextActivityFindAndReplace@"AXSelectTextActivityFindAndReplace"])
255 operation.type = AccessibilityTextOperationType::Replace;
256 else if ([activityParameter isEqualToString:NSAccessibilitySelectTextActivityFindAndCapitalize@"AXSelectTextActivityFindAndCapitalize"])
257 operation.type = AccessibilityTextOperationType::Capitalize;
258 else if ([activityParameter isEqualToString:NSAccessibilitySelectTextActivityFindAndLowercase@"AXSelectTextActivityFindAndLowercase"])
259 operation.type = AccessibilityTextOperationType::Lowercase;
260 else if ([activityParameter isEqualToString:NSAccessibilitySelectTextActivityFindAndUppercase@"AXSelectTextActivityFindAndUppercase"])
261 operation.type = AccessibilityTextOperationType::Uppercase;
262 }
263
264 criteria.direction = AccessibilitySearchTextDirection::Closest;
265 if ([ambiguityResolutionParameter isKindOfClass:[NSString class]]) {
266 if ([ambiguityResolutionParameter isEqualToString:NSAccessibilitySelectTextAmbiguityResolutionClosestAfterSelection@"AXSelectTextAmbiguityResolutionClosestAfterSelection"])
267 criteria.direction = AccessibilitySearchTextDirection::Forward;
268 else if ([ambiguityResolutionParameter isEqualToString:NSAccessibilitySelectTextAmbiguityResolutionClosestBeforeSelection@"AXSelectTextAmbiguityResolutionClosestBeforeSelection"])
269 criteria.direction = AccessibilitySearchTextDirection::Backward;
270 }
271
272 if ([replacementStringParameter isKindOfClass:[NSString class]])
273 operation.replacementStrings = { String(replacementStringParameter.get()) };
274
275 if ([searchStringsParameter isKindOfClass:[NSArray class]])
276 criteria.searchStrings = makeVector<String>(searchStringsParameter.get());
277
278 return std::make_pair(criteria, operation);
279}
280
281static AccessibilitySearchTextCriteria accessibilitySearchTextCriteriaForParameterizedAttribute(const NSDictionary *params)
282{
283 AccessibilitySearchTextCriteria criteria;
284
285 RetainPtr<NSArray> searchStrings = [params objectForKey:NSAccessibilitySearchTextSearchStrings@"AXSearchTextSearchStrings"];
286 RetainPtr<NSString> start = [params objectForKey:NSAccessibilitySearchTextStartFrom@"AXSearchTextStartFrom"];
287 RetainPtr<NSString> direction = [params objectForKey:NSAccessibilitySearchTextDirection@"AXSearchTextDirection"];
288
289 if ([searchStrings isKindOfClass:[NSArray class]])
290 criteria.searchStrings = makeVector<String>(searchStrings.get());
291
292 if ([start isKindOfClass:[NSString class]]) {
293 if ([start isEqualToString:NSAccessibilitySearchTextStartFromBegin@"AXSearchTextStartFromBegin"])
294 criteria.start = AccessibilitySearchTextStartFrom::Begin;
295 else if ([start isEqualToString:NSAccessibilitySearchTextStartFromEnd@"AXSearchTextStartFromEnd"])
296 criteria.start = AccessibilitySearchTextStartFrom::End;
297 }
298
299 if ([direction isKindOfClass:[NSString class]]) {
300 if ([direction isEqualToString:NSAccessibilitySearchTextDirectionBackward@"AXSearchTextDirectionBackward"])
301 criteria.direction = AccessibilitySearchTextDirection::Backward;
302 else if ([direction isEqualToString:NSAccessibilitySearchTextDirectionClosest@"AXSearchTextDirectionClosest"])
303 criteria.direction = AccessibilitySearchTextDirection::Closest;
304 else if ([direction isEqualToString:NSAccessibilitySearchTextDirectionAll@"AXSearchTextDirectionAll"])
305 criteria.direction = AccessibilitySearchTextDirection::All;
306 }
307
308 return criteria;
309}
310
311static AccessibilityTextOperation accessibilityTextOperationForParameterizedAttribute(AXObjectCache* axObjectCache, const NSDictionary *parameterizedAttribute)
312{
313 AccessibilityTextOperation operation;
314
315 RetainPtr<NSArray> markerRanges = [parameterizedAttribute objectForKey:NSAccessibilityTextOperationMarkerRanges@"AXTextOperationMarkerRanges"];
316 RetainPtr<NSString> operationType = [parameterizedAttribute objectForKey:NSAccessibilityTextOperationType@"AXTextOperationType"];
317 RetainPtr<NSArray> individualReplacementStrings = [parameterizedAttribute objectForKey:NSAccessibilityTextOperationIndividualReplacementStrings@"AXTextOperationIndividualReplacementStrings"];
318 RetainPtr<NSString> replacementString = [parameterizedAttribute objectForKey:NSAccessibilityTextOperationReplacementString@"AXTextOperationReplacementString"];
319 RetainPtr<NSNumber> smartReplace = [parameterizedAttribute objectForKey:NSAccessibilityTextOperationSmartReplace@"AXTextOperationSmartReplace"];
320
321 if ([markerRanges isKindOfClass:[NSArray class]]) {
322 operation.textRanges = makeVector(markerRanges.get(), [&axObjectCache] (id markerRange) {
323 AX_ASSERT(AXObjectIsTextMarkerRange(markerRange))((void)0);
324 return rangeForTextMarkerRange(axObjectCache, (AXTextMarkerRangeRef)markerRange);
325 });
326 }
327
328 if ([operationType isKindOfClass:[NSString class]]) {
329 if ([operationType isEqualToString:NSAccessibilityTextOperationReplace@"TextOperationReplace"])
330 operation.type = AccessibilityTextOperationType::Replace;
331 else if ([operationType isEqualToString:NSAccessibilityTextOperationReplacePreserveCase@"TextOperationReplacePreserveCase"])
332 operation.type = AccessibilityTextOperationType::ReplacePreserveCase;
333 else if ([operationType isEqualToString:NSAccessibilityTextOperationCapitalize@"Capitalize"])
334 operation.type = AccessibilityTextOperationType::Capitalize;
335 else if ([operationType isEqualToString:NSAccessibilityTextOperationLowercase@"Lowercase"])
336 operation.type = AccessibilityTextOperationType::Lowercase;
337 else if ([operationType isEqualToString:NSAccessibilityTextOperationUppercase@"Uppercase"])
338 operation.type = AccessibilityTextOperationType::Uppercase;
339 }
340
341 if ([individualReplacementStrings isKindOfClass:[NSArray class]]) {
342 operation.replacementStrings = makeVector<String>(individualReplacementStrings.get());
343 } else if ([replacementString isKindOfClass:[NSString class]])
344 operation.replacementStrings = { String(replacementString.get()) };
345
346 if ([smartReplace isKindOfClass:[NSNumber class]])
347 operation.smartReplace = [smartReplace boolValue] ? AccessibilityTextOperationSmartReplace::Yes : AccessibilityTextOperationSmartReplace::No;
348
349 return operation;
350}
351
352static std::pair<AXTextMarkerRange, AccessibilitySearchDirection> misspellingSearchCriteriaForParameterizedAttribute(const NSDictionary *params)
353{
354 RetainPtr<id> markerRangeRef = [params objectForKey:NSAccessibilityStartTextMarkerRangeParam@"AXStartTextMarkerRange"];
355 if (!AXObjectIsTextMarkerRange(markerRangeRef.get()))
356 return { };
357
358 std::pair<AXTextMarkerRange, AccessibilitySearchDirection> criteria;
359 criteria.first = AXTextMarkerRange { (AXTextMarkerRangeRef)markerRangeRef.get() };
360
361 RetainPtr<NSNumber> forward = [params objectForKey:NSAccessibilitySearchTextDirection@"AXSearchTextDirection"];
362 if ([forward isKindOfClass:[NSNumber class]])
363 criteria.second = [forward boolValue] ? AccessibilitySearchDirection::Next : AccessibilitySearchDirection::Previous;
364 else
365 criteria.second = AccessibilitySearchDirection::Next;
366
367 return criteria;
368}
369
370#pragma mark Cross-process search helpers
371
372// Creates an NSAccessibilityRemoteUIElement from an AccessibilityRemoteToken.
373// Returns nil if the token is empty or element creation fails.
374static RetainPtr<id> remoteElementFromToken(const AccessibilityRemoteToken& token)
375{
376 if (token.bytes.isEmpty())
377 return nilnullptr;
378 RetainPtr<NSData> tokenData = adoptNS([[NSData alloc] initWithBytes:token.bytes.span().data() length:token.bytes.size()]);
379 return adoptNS([[NSAccessibilityRemoteUIElement alloc] initWithRemoteToken:tokenData.get()]);
380}
381
382// Converts AccessibilitySearchResults to NSArray, creating platform elements for both
383// local objects and remote tokens.
384static RetainPtr<NSArray> searchResultsToNSArray(const AccessibilitySearchResults& searchResults, unsigned limit)
385{
386 RetainPtr<NSMutableArray> result = adoptNS([[NSMutableArray alloc] init]);
387 for (const auto& searchResult : searchResults) {
388 if ([result count] >= limit)
389 break;
390
391 if (auto* object = searchResult.objectIfLocalResult()) {
Local variable 'object' is uncounted and unsafe
392 if (RetainPtr wrapper = object->wrapper())
393 [result addObject:wrapper.get()];
394 } else if (searchResult.isRemote()) {
395 if (RetainPtr remoteElement = remoteElementFromToken(*searchResult.remoteToken()))
396 [result addObject:remoteElement.get()];
397 }
398 }
399 return result;
400}
401
402// Performs a search that may span multiple web content processes.
403// For remote frames encountered during the search, sends IPC to query them and merges results.
404// If we're in a child frame, eagerly dispatches parent search in parallel with local search.
405static RetainPtr<NSArray> performSearchWithRemoteFrames(AXCoreObject& backingObject, AccessibilitySearchCriteria&& criteria)
406{
407 unsigned originalLimit = criteria.resultsLimit;
408 auto searchResults = performSearchWithParentCoordination(backingObject, WTF::move(criteria));
409 return searchResultsToNSArray(searchResults, originalLimit);
410}
411
412#pragma mark Text Marker helpers
413
414static RetainPtr<AXTextMarkerRef> nextTextMarker(AXObjectCache* cache, const AXTextMarker& marker)
415{
416 if (!cache)
417 return nilnullptr;
418
419 auto nextMarker = cache->nextTextMarker(marker);
420 return nextMarker ? nextMarker.platformData() : nilnullptr;
421}
422
423static RetainPtr<AXTextMarkerRef> previousTextMarker(AXObjectCache* cache, const AXTextMarker& marker)
424{
425 if (!cache)
426 return nilnullptr;
427
428 auto previousMarker = cache->previousTextMarker(marker);
429 return previousMarker ? previousMarker.platformData() : nilnullptr;
430}
431
432static NSAttributedString *attributedStringForTextMarkerRange(const AXCoreObject& object, AXTextMarkerRangeRef textMarkerRangeRef, AXCoreObject::SpellCheck spellCheck)
433{
434 if (!textMarkerRangeRef)
435 return nilnullptr;
436
437 return object.attributedStringForTextMarkerRange({ textMarkerRangeRef }, spellCheck).autorelease();
438}
439
440ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-implementations"
441- (NSArray*)accessibilityActionNames
442{
443 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
444 if (!backingObject)
445 return nilnullptr;
446
447 // All elements should get ShowMenu and ScrollToVisible.
448 // But certain earlier VoiceOver versions do not support scroll to visible, and it confuses them to see it in the list.
449 static NeverDestroyed<RetainPtr<NSArray>> defaultElementActions = @[NSAccessibilityShowMenuAction, NSAccessibilityScrollToVisibleAction@"AXScrollToVisible"];
450
451 // Action elements allow Press.
452 // The order is important to VoiceOver, which expects the 'default' action to be the first action. In this case the default action should be press.
453 static NeverDestroyed<RetainPtr<NSArray>> actionElementActions = @[NSAccessibilityPressAction, NSAccessibilityShowMenuAction, NSAccessibilityScrollToVisibleAction@"AXScrollToVisible"];
454
455 // Menu elements allow Press and Cancel.
456 static NeverDestroyed<RetainPtr<NSArray>> menuElementActions = [actionElementActions.get() arrayByAddingObject:NSAccessibilityCancelAction];
457
458 static NeverDestroyed<RetainPtr<NSArray>> incrementorActions = [defaultElementActions.get() arrayByAddingObjectsFromArray:@[NSAccessibilityIncrementAction, NSAccessibilityDecrementAction]];
459
460 if (backingObject->isSlider() || (backingObject->isSpinButton() && backingObject->spinButtonType() == SpinButtonType::Standalone)) {
461 // Non-standalone spinbuttons should not advertise the increment and decrement actions because they have separate increment and decrement controls.
462 return incrementorActions.get().get();
463 }
464
465 if (backingObject->isMenuRelated())
466 return menuElementActions.get().get();
467 if (backingObject->isAttachment())
468 return [[self attachmentView] accessibilityActionNames];
469 if (backingObject->supportsPressAction())
470 return actionElementActions.get().get();
471
472 return defaultElementActions.get().get();
473}
474ALLOW_DEPRECATED_IMPLEMENTATIONS_ENDGCC diagnostic pop
475
476- (NSArray *)_additionalAccessibilityAttributeNames:(const RefPtr<AXCoreObject>&)backingObject
477{
478 NSMutableArray *additional = [NSMutableArray array];
479 if (backingObject->supportsActiveDescendant())
480 [additional addObject:NSAccessibilityActiveElementAttribute@"AXActiveElement"];
481
482 if (backingObject->supportsARIAOwns())
483 [additional addObject:NSAccessibilityOwnsAttribute@"AXOwns"];
484
485 if (backingObject->supportsExpanded() || backingObject->isSummary())
486 [additional addObject:NSAccessibilityExpandedAttribute];
487
488 if (backingObject->isScrollbar()
489 || backingObject->isRadioGroup()
490 || backingObject->isSplitter()
491 || backingObject->isToolbar()
492 || backingObject->role() == AccessibilityRole::HorizontalRule)
493 [additional addObject:NSAccessibilityOrientationAttribute];
494
495 if (backingObject->supportsDragging())
496 [additional addObject:NSAccessibilityGrabbedAttribute@"AXGrabbed"];
497
498 if (backingObject->supportsDropping())
499 [additional addObject:NSAccessibilityDropEffectsAttribute@"AXDropEffects"];
500
501 if (backingObject->isExposableTable() && backingObject->supportsSelectedRows())
502 [additional addObject:NSAccessibilitySelectedRowsAttribute];
503
504 if (backingObject->isTreeGrid() && backingObject->isExposableTable())
505 [additional addObject:NSAccessibilityOrientationAttribute];
506
507 if (backingObject->supportsSetSize())
508 [additional addObject:NSAccessibilityARIASetSizeAttribute@"AXARIASetSize"];
509
510 if (backingObject->supportsPosInSet())
511 [additional addObject:NSAccessibilityARIAPosInSetAttribute@"AXARIAPosInSet"];
512
513 if (backingObject->supportsKeyShortcuts())
514 [additional addObject:NSAccessibilityKeyShortcutsAttribute@"AXKeyShortcutsValue"];
515
516 if (backingObject->supportsLiveRegion()) {
517 [additional addObject:NSAccessibilityARIALiveAttribute@"AXARIALive"];
518 [additional addObject:NSAccessibilityARIARelevantAttribute@"AXARIARelevant"];
519 }
520
521 bool addedHasPopup = false;
522 if (backingObject->hasPopup()) {
523 addedHasPopup = true;
524 [additional addObject:NSAccessibilityHasPopupAttribute@"AXHasPopup"];
525 }
526 bool addedAriaAtomic = false;
527 bool addedSortDirection = false;
528 for (RefPtr ancestor = backingObject; ancestor; ancestor = ancestor->parentObject()) {
529 if (!addedHasPopup && ancestor->isLink() && ancestor->hasPopup()) {
530 // Require ancestor to be a link, matching AXCoreObject::selfOrAncestorLinkHasPopup.
531 addedHasPopup = true;
532 [additional addObject:NSAccessibilityHasPopupAttribute@"AXHasPopup"];
533 }
534
535 if (!addedAriaAtomic && ancestor->supportsLiveRegion()) {
536 addedAriaAtomic = true;
537 [additional addObject:NSAccessibilityARIAAtomicAttribute@"AXARIAAtomic"];
538 }
539
540 if (!addedSortDirection) {
541 auto sortDirection = ancestor->sortDirection();
542 if (sortDirection != AccessibilitySortDirection::None && sortDirection != AccessibilitySortDirection::Invalid) {
543 addedSortDirection = true;
544 [additional addObject:NSAccessibilitySortDirectionAttribute];
545 }
546 }
547 }
548
549 if (backingObject->supportsDatetimeAttribute())
550 [additional addObject:NSAccessibilityDatetimeValueAttribute@"AXDateTimeValue"];
551
552 if (backingObject->supportsRequiredAttribute())
553 [additional addObject:NSAccessibilityRequiredAttribute];
554
555 if (backingObject->isMathRoot()) {
556 // The index of a square root is always known, so there's no object associated with it.
557 if (!backingObject->isMathSquareRoot())
558 [additional addObject:NSAccessibilityMathRootIndexAttribute@"AXMathRootIndex"];
559 [additional addObject:NSAccessibilityMathRootRadicandAttribute@"AXMathRootRadicand"];
560 } else if (backingObject->isMathFraction()) {
561 [additional addObject:NSAccessibilityMathFractionNumeratorAttribute@"AXMathFractionNumerator"];
562 [additional addObject:NSAccessibilityMathFractionDenominatorAttribute@"AXMathFractionDenominator"];
563 [additional addObject:NSAccessibilityMathLineThicknessAttribute@"AXMathLineThickness"];
564 } else if (backingObject->isMathSubscriptSuperscript()) {
565 [additional addObject:NSAccessibilityMathBaseAttribute@"AXMathBase"];
566 [additional addObject:NSAccessibilityMathSubscriptAttribute@"AXMathSubscript"];
567 [additional addObject:NSAccessibilityMathSuperscriptAttribute@"AXMathSuperscript"];
568 } else if (backingObject->isMathUnderOver()) {
569 [additional addObject:NSAccessibilityMathBaseAttribute@"AXMathBase"];
570 [additional addObject:NSAccessibilityMathUnderAttribute@"AXMathUnder"];
571 [additional addObject:NSAccessibilityMathOverAttribute@"AXMathOver"];
572 } else if (backingObject->isMathFenced()) {
573 [additional addObject:NSAccessibilityMathFencedOpenAttribute@"AXMathFencedOpen"];
574 [additional addObject:NSAccessibilityMathFencedCloseAttribute@"AXMathFencedClose"];
575 } else if (backingObject->isMathMultiscript()) {
576 [additional addObject:NSAccessibilityMathBaseAttribute@"AXMathBase"];
577 [additional addObject:NSAccessibilityMathPrescriptsAttribute@"AXMathPrescripts"];
578 [additional addObject:NSAccessibilityMathPostscriptsAttribute@"AXMathPostscripts"];
579 }
580
581 // isStaticText() objects already note their support for path in `accessibilityAttributeNames`.
582 if (!backingObject->isStaticText() && backingObject->supportsPath())
583 [additional addObject:NSAccessibilityPathAttribute@"AXPath"];
584
585 if (backingObject->supportsExpandedTextValue())
586 [additional addObject:NSAccessibilityExpandedTextValueAttribute@"AXExpandedTextValue"];
587
588 if (!backingObject->brailleLabel().isEmpty())
589 [additional addObject:NSAccessibilityBrailleLabelAttribute@"AXBrailleLabel"];
590
591 if (!backingObject->brailleRoleDescription().isEmpty())
592 [additional addObject:NSAccessibilityBrailleRoleDescriptionAttribute@"AXBrailleRoleDescription"];
593
594 if (backingObject->detailedByObjects().size())
595 [additional addObject:NSAccessibilityDetailsElementsAttribute@"AXDetailsElements"];
596
597 if (backingObject->errorMessageObjects().size())
598 [additional addObject:NSAccessibilityErrorMessageElementsAttribute@"AXErrorMessageElements"];
599
600 if (!backingObject->keyShortcuts().isEmpty())
601 [additional addObject:NSAccessibilityKeyShortcutsAttribute@"AXKeyShortcutsValue"];
602
603 if (backingObject->titleUIElement())
604 [additional addObject:NSAccessibilityTitleUIElementAttribute];
605
606 if (backingObject->isColumnHeader() || backingObject->isRowHeader())
607 [additional addObject:NSAccessibilitySortDirectionAttribute];
608
609 // Only expose AXARIACurrent attribute when the element is set to be current item.
610 if (backingObject->currentState() != AccessibilityCurrentState::False)
611 [additional addObject:NSAccessibilityARIACurrentAttribute@"AXARIACurrent"];
612
613 if (backingObject->isTreeItem() && backingObject->supportsCheckedState()) {
614 // Tree items normally do not support value, but should if they are checkable.
615 [additional addObject:NSAccessibilityValueAttribute];
616 }
617
618 return additional;
619}
620
621ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-implementations"
622- (NSArray *)accessibilityAttributeNames
623{
624 AXTRACE("WebAccessibilityObjectWrapper accessibilityAttributeNames"_s)(void)0;
625
626 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
627 if (!backingObject)
628 return nilnullptr;
629
630 // TODO: we definitely don't want to return accessibilityAttributeNames for AccessibilityScrollViews,
631 // only for external attachments like PDFs. Figure out some more specific logic to do this only when needed.
632#if !ENABLE_ACCESSIBILITY_LOCAL_FRAME0
633 if (backingObject->isAttachment())
634 return [[self attachmentView] accessibilityAttributeNames];
635#endif // !ENABLE_ACCESSIBILITY_LOCAL_FRAME
636
637 static NeverDestroyed<RetainPtr<NSArray>> attributes = @[
638 NSAccessibilityRoleAttribute,
639 NSAccessibilitySubroleAttribute,
640 NSAccessibilityRoleDescriptionAttribute,
641 NSAccessibilityChildrenAttribute,
642 NSAccessibilityChildrenInNavigationOrderAttribute@"AXChildrenInNavigationOrder",
643 NSAccessibilityHelpAttribute,
644 NSAccessibilityParentAttribute,
645 NSAccessibilityPositionAttribute,
646 NSAccessibilitySizeAttribute,
647 NSAccessibilityTitleAttribute,
648 NSAccessibilityDescriptionAttribute,
649 NSAccessibilityValueAttribute,
650 NSAccessibilityFocusedAttribute,
651 NSAccessibilityEnabledAttribute,
652 NSAccessibilityWindowAttribute,
653 NSAccessibilitySelectedTextMarkerRangeAttribute@"AXSelectedTextMarkerRange",
654 NSAccessibilityStartTextMarkerAttribute@"AXStartTextMarker",
655 NSAccessibilityEndTextMarkerAttribute@"AXEndTextMarker",
656 NSAccessibilityVisitedAttribute@"AXVisited",
657 NSAccessibilityLinkedUIElementsAttribute,
658 NSAccessibilitySelectedAttribute,
659 NSAccessibilityBlockQuoteLevelAttribute@"AXBlockQuoteLevel",
660 NSAccessibilityTopLevelUIElementAttribute,
661 NSAccessibilityLanguageAttribute@"AXLanguage",
662 NSAccessibilityDOMIdentifierAttribute@"AXDOMIdentifier",
663 NSAccessibilityDOMClassListAttribute@"AXDOMClassList",
664 NSAccessibilityFocusableAncestorAttribute@"AXFocusableAncestor",
665 NSAccessibilityEditableAncestorAttribute@"AXEditableAncestor",
666 NSAccessibilityHighestEditableAncestorAttribute@"AXHighestEditableAncestor",
667 NSAccessibilityTextInputMarkedRangeAttribute@"AXTextInputMarkedRange",
668 NSAccessibilityTextInputMarkedTextMarkerRangeAttribute@"AXTextInputMarkedTextMarkerRange",
669 NSAccessibilityVisibleCharacterRangeAttribute,
670 NSAccessibilityRelativeFrameAttribute@"AXRelativeFrame",
671 // AppKit needs to know the screen height in order to do the coordinate conversion.
672 NSAccessibilityPrimaryScreenHeightAttribute@"_AXPrimaryScreenHeight",
673 // All objects should expose the ARIA busy attribute (ARIA 1.1 with ISSUE-538).
674 NSAccessibilityElementBusyAttribute@"AXElementBusy",
675 // This exists to tell assistive technologies that WebKit stitches adjacent text
676 // elements together in the accessibility tree — thus, assistive technologies know
677 // they don't need to.
678 @"AXPerformsOwnTextStitching",
679 // This indicates to assistive technologies whether WebKit will handle posting
680 // announcements for live region updates, or whether the AT is responsible.
681 @"AXPostsOwnLiveRegionAnnouncements"
682 ];
683 static NeverDestroyed spinButtonCommonAttributes = [] {
684 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
685 [tempArray addObject:NSAccessibilityValueDescriptionAttribute];
686 [tempArray addObject:NSAccessibilityMinValueAttribute];
687 [tempArray addObject:NSAccessibilityMaxValueAttribute];
688 return tempArray;
689 }();
690 static NeverDestroyed compositeSpinButtonAttributes = [] {
691 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:spinButtonCommonAttributes.get().get()]);
692 [tempArray addObject:NSAccessibilityIncrementButtonAttribute];
693 [tempArray addObject:NSAccessibilityDecrementButtonAttribute];
694 return tempArray;
695 }();
696 static NeverDestroyed anchorAttrs = [] {
697 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
698 [tempArray addObject:NSAccessibilityURLAttribute];
699 [tempArray addObject:NSAccessibilityAccessKeyAttribute@"AXAccessKey"];
700 [tempArray addObject:NSAccessibilityLinkRelationshipTypeAttribute@"AXLinkRelationshipType"];
701 return tempArray;
702 }();
703 static NeverDestroyed webAreaAttrs = [] {
704 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
705 // WebAreas should not expose AXSubrole.
706 [tempArray removeObject:NSAccessibilitySubroleAttribute];
707 // WebAreas should not expose ancestor attributes
708 [tempArray removeObject:NSAccessibilityFocusableAncestorAttribute@"AXFocusableAncestor"];
709 [tempArray removeObject:NSAccessibilityEditableAncestorAttribute@"AXEditableAncestor"];
710 [tempArray removeObject:NSAccessibilityHighestEditableAncestorAttribute@"AXHighestEditableAncestor"];
711 [tempArray addObject:NSAccessibilityLinkUIElementsAttribute@"AXLinkUIElements"];
712 [tempArray addObject:NSAccessibilityLoadedAttribute@"AXLoaded"];
713 [tempArray addObject:NSAccessibilityLayoutCountAttribute@"AXLayoutCount"];
714 [tempArray addObject:NSAccessibilityLoadingProgressAttribute@"AXLoadingProgress"];
715 [tempArray addObject:NSAccessibilityURLAttribute];
716 [tempArray addObject:NSAccessibilityCaretBrowsingEnabledAttribute@"AXCaretBrowsingEnabled"];
717 [tempArray addObject:NSAccessibilityPreventKeyboardDOMEventDispatchAttribute@"AXPreventKeyboardDOMEventDispatch"];
718 return tempArray;
719 }();
720 static NeverDestroyed textAttrs = [] {
721 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
722 [tempArray addObject:NSAccessibilityNumberOfCharactersAttribute];
723 [tempArray addObject:NSAccessibilitySelectedTextAttribute];
724 [tempArray addObject:NSAccessibilitySelectedTextRangeAttribute];
725 [tempArray addObject:NSAccessibilityInsertionPointLineNumberAttribute];
726 [tempArray addObject:NSAccessibilityAccessKeyAttribute@"AXAccessKey"];
727 [tempArray addObject:NSAccessibilityRequiredAttribute];
728 [tempArray addObject:NSAccessibilityInvalidAttribute@"AXInvalid"];
729 [tempArray addObject:NSAccessibilityPlaceholderValueAttribute];
730 [tempArray addObject:NSAccessibilityValueAutofillAvailableAttribute@"AXValueAutofillAvailable"];
731 return tempArray;
732 }();
733 static NeverDestroyed listAttrs = [] {
734 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
735 [tempArray addObject:NSAccessibilityActiveElementAttribute@"AXActiveElement"];
736 [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
737 [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
738 [tempArray addObject:NSAccessibilityOrientationAttribute];
739 return tempArray;
740 }();
741 static NeverDestroyed listBoxAttrs = [] {
742 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:listAttrs.get().get()]);
743 [tempArray addObject:NSAccessibilityAccessKeyAttribute@"AXAccessKey"];
744 [tempArray addObject:NSAccessibilityRequiredAttribute];
745 [tempArray addObject:NSAccessibilityInvalidAttribute@"AXInvalid"];
746 [tempArray addObject:NSAccessibilityOrientationAttribute];
747 return tempArray;
748 }();
749 static NeverDestroyed rangeAttrs = [] {
750 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
751 [tempArray addObject:NSAccessibilityMinValueAttribute];
752 [tempArray addObject:NSAccessibilityMaxValueAttribute];
753 [tempArray addObject:NSAccessibilityOrientationAttribute];
754 [tempArray addObject:NSAccessibilityValueDescriptionAttribute];
755 return tempArray;
756 }();
757 static NeverDestroyed menuBarAttrs = [] {
758 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
759 [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
760 [tempArray addObject:NSAccessibilityOrientationAttribute];
761 return tempArray;
762 }();
763 static NeverDestroyed menuAttrs = [] {
764 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
765 [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
766 [tempArray addObject:NSAccessibilityOrientationAttribute];
767 return tempArray;
768 }();
769 static NeverDestroyed menuItemAttrs = [] {
770 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
771 [tempArray addObject:NSAccessibilityTitleAttribute];
772 [tempArray addObject:NSAccessibilityDescriptionAttribute];
773 [tempArray addObject:NSAccessibilityHelpAttribute];
774 [tempArray addObject:NSAccessibilitySelectedAttribute];
775 [tempArray addObject:(NSString*)kAXMenuItemCmdCharAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXMenuItemCmdChar"
""))
];
776 [tempArray addObject:(NSString*)kAXMenuItemCmdVirtualKeyAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXMenuItemCmdVirtualKey"
""))
];
777 [tempArray addObject:(NSString*)kAXMenuItemCmdGlyphAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXMenuItemCmdGlyph"
""))
];
778 [tempArray addObject:(NSString*)kAXMenuItemCmdModifiersAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXMenuItemCmdModifiers"
""))
];
779 [tempArray addObject:(NSString*)kAXMenuItemMarkCharAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXMenuItemMarkChar"
""))
];
780 [tempArray addObject:(NSString*)kAXMenuItemPrimaryUIElementAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXMenuItemPrimaryUIElement"
""))
];
781 [tempArray addObject:NSAccessibilityServesAsTitleForUIElementsAttribute];
782 [tempArray addObject:NSAccessibilityFocusedAttribute];
783 return tempArray;
784 }();
785 static NeverDestroyed<RetainPtr<NSArray>> sharedControlAttrs = @[
786 NSAccessibilityAccessKeyAttribute@"AXAccessKey",
787 NSAccessibilityRequiredAttribute,
788 NSAccessibilityInvalidAttribute@"AXInvalid",
789 ];
790 static NeverDestroyed<RetainPtr<NSArray>> sharedComboBoxAttrs = @[
791 NSAccessibilitySelectedChildrenAttribute,
792 NSAccessibilityExpandedAttribute,
793 NSAccessibilityOrientationAttribute,
794 ];
795 static NeverDestroyed controlAttrs = [] {
796 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
797 [tempArray addObjectsFromArray:sharedControlAttrs.get().get()];
798 return tempArray;
799 }();
800 static NeverDestroyed buttonAttrs = [] {
801 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
802 // Buttons should not expose AXValue.
803 [tempArray removeObject:NSAccessibilityValueAttribute];
804 [tempArray addObject:NSAccessibilityAccessKeyAttribute@"AXAccessKey"];
805 [tempArray addObject:NSAccessibilityInvalidAttribute@"AXInvalid"];
806 return tempArray;
807 }();
808 static NeverDestroyed popupOrToggleButtonAttrs = [] {
809 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:buttonAttrs.get().get()]);
810 // Popup and toggle buttons do expose AXValue.
811 [tempArray addObject:NSAccessibilityValueAttribute];
812 return tempArray;
813 }();
814 static NeverDestroyed comboBoxAttrs = [] {
815 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:controlAttrs.get().get()]);
816 [tempArray addObjectsFromArray:sharedComboBoxAttrs.get().get()];
817 return tempArray;
818 }();
819 static NeverDestroyed textComboBoxAttrs = [] {
820 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:textAttrs.get().get()]);
821 [tempArray addObjectsFromArray:sharedControlAttrs.get().get()];
822 [tempArray addObjectsFromArray:sharedComboBoxAttrs.get().get()];
823 return tempArray;
824 }();
825 static NeverDestroyed tableAttrs = [] {
826 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
827 [tempArray addObject:NSAccessibilityRowsAttribute];
828 [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
829 [tempArray addObject:NSAccessibilityColumnsAttribute];
830 [tempArray addObject:NSAccessibilityVisibleColumnsAttribute];
831 [tempArray addObject:NSAccessibilityVisibleCellsAttribute];
832 [tempArray addObject:NSAccessibilityColumnHeaderUIElementsAttribute];
833 [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute];
834 [tempArray addObject:NSAccessibilityHeaderAttribute];
835 [tempArray addObject:NSAccessibilityColumnCountAttribute];
836 [tempArray addObject:NSAccessibilityRowCountAttribute];
837 [tempArray addObject:NSAccessibilityARIAColumnCountAttribute@"AXARIAColumnCount"];
838 [tempArray addObject:NSAccessibilityARIARowCountAttribute@"AXARIARowCount"];
839 [tempArray addObject:NSAccessibilitySelectedCellsAttribute];
840 [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
841 [tempArray addObject:NSAccessibilityTableLevelAttribute@"AXTableLevel"];
842 return tempArray;
843 }();
844 static NeverDestroyed tableRowAttrs = [] {
845 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
846 [tempArray addObject:NSAccessibilityIndexAttribute];
847 // FIXME: Consider exposing NSAccessibilityARIARowIndexAttribute and NSAccessibilityRowIndexDescriptionAttribute,
848 // i.e. aria-rowindex and aria-rowindextext, just like already done for cells
849 // https://bugs.webkit.org/show_bug.cgi?id=296857
850 return tempArray;
851 }();
852 static NeverDestroyed tableColAttrs = [] {
853 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
854 [tempArray addObject:NSAccessibilityIndexAttribute];
855 [tempArray addObject:NSAccessibilityHeaderAttribute];
856 [tempArray addObject:NSAccessibilityRowsAttribute];
857 [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
858 return tempArray;
859 }();
860 static NeverDestroyed tableCellAttrs = [] {
861 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
862 [tempArray addObject:NSAccessibilityRowIndexRangeAttribute];
863 [tempArray addObject:NSAccessibilityColumnIndexRangeAttribute];
864 [tempArray addObject:NSAccessibilityColumnHeaderUIElementsAttribute];
865 [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute];
866 [tempArray addObject:NSAccessibilityARIAColumnIndexAttribute@"AXARIAColumnIndex"];
867 [tempArray addObject:NSAccessibilityARIARowIndexAttribute@"AXARIARowIndex"];
868 [tempArray addObject:NSAccessibilityColumnIndexDescriptionAttribute@"AXColumnIndexDescription"];
869 [tempArray addObject:NSAccessibilityRowIndexDescriptionAttribute@"AXRowIndexDescription"];
870 return tempArray;
871 }();
872 static NeverDestroyed groupAttrs = [] {
873 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
874 [tempArray addObject:NSAccessibilityInlineTextAttribute@"AXInlineText"];
875 return tempArray;
876 }();
877 static NeverDestroyed inputImageAttrs = [] {
878 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:buttonAttrs.get().get()]);
879 [tempArray addObject:NSAccessibilityURLAttribute];
880 return tempArray;
881 }();
882 static NeverDestroyed secureFieldAttributes = [] {
883 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
884 [tempArray addObject:NSAccessibilityRequiredAttribute];
885 [tempArray addObject:NSAccessibilityInvalidAttribute@"AXInvalid"];
886 [tempArray addObject:NSAccessibilityPlaceholderValueAttribute];
887 [tempArray addObject:NSAccessibilitySelectedTextRangeAttribute];
888 return tempArray;
889 }();
890 static NeverDestroyed tabListAttrs = [] {
891 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
892 [tempArray addObject:NSAccessibilityTabsAttribute];
893 [tempArray addObject:NSAccessibilityContentsAttribute];
894 [tempArray addObject:NSAccessibilityOrientationAttribute];
895 [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
896 return tempArray;
897 }();
898 static NeverDestroyed outlineAttrs = [] {
899 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
900 [tempArray addObject:NSAccessibilityRequiredAttribute];
901 [tempArray addObject:NSAccessibilitySelectedRowsAttribute];
902 [tempArray addObject:NSAccessibilityRowsAttribute];
903 [tempArray addObject:NSAccessibilityColumnsAttribute];
904 [tempArray addObject:NSAccessibilityOrientationAttribute];
905 [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
906 return tempArray;
907 }();
908 static NeverDestroyed outlineRowAttrs = [] {
909 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:tableRowAttrs.get().get()]);
910 [tempArray addObject:NSAccessibilityDisclosingAttribute];
911 [tempArray addObject:NSAccessibilityDisclosedByRowAttribute];
912 [tempArray addObject:NSAccessibilityDisclosureLevelAttribute];
913 [tempArray addObject:NSAccessibilityDisclosedRowsAttribute];
914 [tempArray removeObject:NSAccessibilityValueAttribute];
915 return tempArray;
916 }();
917 static NeverDestroyed scrollViewAttrs = [] {
918 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
919 [tempArray addObject:NSAccessibilityContentsAttribute];
920 [tempArray addObject:NSAccessibilityHorizontalScrollBarAttribute];
921 [tempArray addObject:NSAccessibilityVerticalScrollBarAttribute];
922 return tempArray;
923 }();
924 static NeverDestroyed imageAttrs = [] {
925 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
926 [tempArray addObject:NSAccessibilityImageOverlayElementsAttribute@"AXImageOverlayElements"];
927 [tempArray addObject:NSAccessibilityEmbeddedImageDescriptionAttribute@"AXEmbeddedImageDescription"];
928 [tempArray addObject:NSAccessibilityURLAttribute];
929 return tempArray;
930 }();
931 static NeverDestroyed videoAttrs = [] {
932 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
933 // This should represent the URL of the video content, not the poster.
934 [tempArray addObject:NSAccessibilityURLAttribute];
935 return tempArray;
936 }();
937 static NeverDestroyed staticTextAttrs = [] {
938 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
939 [tempArray addObject:NSAccessibilityIntersectionWithSelectionRangeAttribute@"AXIntersectionWithSelectionRange"];
940 [tempArray addObject:NSAccessibilityPathAttribute@"AXPath"];
941 return tempArray;
942 }();
943
944 RetainPtr<NSArray> objectAttributes = nilnullptr;
945 if (backingObject->isSecureField())
946 objectAttributes = secureFieldAttributes.get().get();
947 else if (backingObject->isWebArea())
948 objectAttributes = webAreaAttrs.get().get();
949 else if (backingObject->isStaticText())
950 objectAttributes = staticTextAttrs.get().get();
951 else if (backingObject->isComboBox() && backingObject->isTextControl())
952 objectAttributes = textComboBoxAttrs.get().get();
953 else if (backingObject->isComboBox())
954 objectAttributes = comboBoxAttrs.get().get();
955 else if (backingObject->isTextControl())
956 objectAttributes = textAttrs.get().get();
957 else if (backingObject->isLink())
958 objectAttributes = anchorAttrs.get().get();
959 else if (backingObject->isImage())
960 objectAttributes = imageAttrs.get().get();
961 else if (backingObject->isTree())
962 objectAttributes = outlineAttrs.get().get();
963 else if (backingObject->isExposableTable())
964 objectAttributes = tableAttrs.get().get();
965 else if (backingObject->isTableColumn())
966 objectAttributes = tableColAttrs.get().get();
967 else if (backingObject->isExposedTableCell())
968 objectAttributes = tableCellAttrs.get().get();
969 else if (backingObject->isExposedTableRow()) {
970 // An ARIA table row can be collapsed and expanded, so it needs the extra attributes.
971 if (backingObject->isARIATreeGridRow())
972 objectAttributes = outlineRowAttrs.get().get();
973 else
974 objectAttributes = tableRowAttrs.get().get();
975 } else if (backingObject->isTreeItem())
976 objectAttributes = outlineRowAttrs.get().get();
977 else if (backingObject->isListBox())
978 objectAttributes = listBoxAttrs.get().get();
979 else if (backingObject->isList())
980 objectAttributes = listAttrs.get().get();
981 else if (backingObject->isProgressIndicator() || backingObject->isSlider() || backingObject->isSplitter())
982 objectAttributes = rangeAttrs.get().get();
983 // These are processed in order because an input image is a button, and a button is a control.
984 else if (backingObject->isInputImage())
985 objectAttributes = inputImageAttrs.get().get();
986 else if (backingObject->isPopUpButton() || backingObject->isToggleButton())
987 objectAttributes = popupOrToggleButtonAttrs.get().get();
988 else if (backingObject->isButton())
989 objectAttributes = buttonAttrs.get().get();
990 else if (backingObject->isControl())
991 objectAttributes = controlAttrs.get().get();
992
993 else if (backingObject->isGroup() || backingObject->isListItem() || backingObject->role() == AccessibilityRole::Figure)
994 objectAttributes = groupAttrs.get().get();
995 else if (backingObject->isTabList())
996 objectAttributes = tabListAttrs.get().get();
997 else if (backingObject->isScrollArea())
998 objectAttributes = scrollViewAttrs.get().get();
999 else if (backingObject->isSpinButton()) {
1000 if (backingObject->spinButtonType() == SpinButtonType::Composite)
1001 objectAttributes = compositeSpinButtonAttributes.get().get();
1002 else
1003 objectAttributes = spinButtonCommonAttributes.get().get();
1004 } else if (backingObject->isMenu())
1005 objectAttributes = menuAttrs.get().get();
1006 else if (backingObject->isMenuBar())
1007 objectAttributes = menuBarAttrs.get().get();
1008 else if (backingObject->isMenuItem())
1009 objectAttributes = menuItemAttrs.get().get();
1010 else if (backingObject->isVideo())
1011 objectAttributes = videoAttrs.get().get();
1012
1013 if (!objectAttributes)
1014 objectAttributes = attributes.get().get();
1015
1016 // Adding these additional attributes is separated so that we only call arrayByAddingObjectsFromArray
1017 // (which does a copy) if we have any uncommon attributes to add.
1018 RetainPtr<NSArray> additionalAttributes = [self _additionalAccessibilityAttributeNames:backingObject];
1019 if ([additionalAttributes count])
1020 objectAttributes = [objectAttributes arrayByAddingObjectsFromArray:additionalAttributes.get()];
1021
1022 return objectAttributes.unsafeGet();
1023}
1024ALLOW_DEPRECATED_IMPLEMENTATIONS_ENDGCC diagnostic pop
1025
1026- (id)remoteAccessibilityParentObject
1027{
1028 RefPtr<AXCoreObject> backingObject = self.axBackingObject;
1029 return backingObject ? backingObject->remoteParent().unsafeGet() : nilnullptr;
1030}
1031
1032static void convertToVector(NSArray* array, AccessibilityObject::AccessibilityChildrenVector& vector)
1033{
1034 unsigned length = [array count];
1035 vector.reserveInitialCapacity(length);
1036 for (unsigned i = 0; i < length; ++i) {
1037 if (RefPtr object = [[array objectAtIndex:i] axBackingObject])
1038 vector.append(object.releaseNonNull());
1039 }
1040}
1041
1042- (AXTextMarkerRangeRef)selectedTextMarkerRange
1043{
1044 RefPtr<AXCoreObject> backingObject = self.axBackingObject;
1045 if (!backingObject)
1046 return nilnullptr;
1047
1048 auto range = backingObject->selectedTextMarkerRange();
1049 if (!range.start().isValid() || !range.end().isValid())
1050 return nilnullptr;
1051
1052 return range;
1053}
1054
1055- (id)_associatedPluginParent
1056{
1057 RefPtr<AXCoreObject> backingObject = self.axBackingObject;
1058 return [self _associatedPluginParentWith:self.axBackingObject];
1059}
1060
1061- (id)_associatedPluginParentWith:(const RefPtr<AXCoreObject>&)backingObject
1062{
1063 if (!backingObject || !backingObject->hasApplePDFAnnotationAttribute())
1064 return nilnullptr;
1065
1066 return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
1067 RefPtr<AXCoreObject> backingObject = protectedSelf.get().axBackingObject;
1068 if (!backingObject || !backingObject->hasApplePDFAnnotationAttribute())
1069 return nilnullptr;
1070 RefPtr document = dynamicDowncast<PluginDocument>(backingObject->document());
1071 if (!document)
1072 return nilnullptr;
1073 RefPtr widget = document->pluginWidget();
1074 if (!widget)
1075 return nilnullptr;
1076 RefPtr element = backingObject->element();
1077 return widget->accessibilityAssociatedPluginParentForElement(element.get());
1078 });
1079}
1080
1081static void WebTransformCGPathToNSBezierPath(void* info, const CGPathElement *element)
1082{
1083 auto points = pointsSpan(element);
1084 NSBezierPath *bezierPath = (__bridge NSBezierPath *)info;
1085 switch (element->type) {
1086 case kCGPathElementMoveToPoint:
1087 [bezierPath moveToPoint:NSPointFromCGPoint(points[0])];
1088 break;
1089 case kCGPathElementAddLineToPoint:
1090 [bezierPath lineToPoint:NSPointFromCGPoint(points[0])];
1091 break;
1092 case kCGPathElementAddCurveToPoint: {
1093 [bezierPath curveToPoint:NSPointFromCGPoint(points[0]) controlPoint1:NSPointFromCGPoint(points[1]) controlPoint2:NSPointFromCGPoint(points[2])];
1094 break;
1095 }
1096 case kCGPathElementCloseSubpath:
1097 [bezierPath closePath];
1098 break;
1099 default:
1100 break;
1101 }
1102}
1103
1104- (NSBezierPath *)bezierPathFromPath:(CGPathRef)path
1105{
1106 NSBezierPath *bezierPath = [NSBezierPath bezierPath];
1107 CGPathApply(path, (__bridge void*)bezierPath, WebTransformCGPathToNSBezierPath);
1108 return bezierPath;
1109}
1110
1111- (NSBezierPath *)path
1112{
1113 RefPtr<AXCoreObject> backingObject = self.axBackingObject;
1114 if (!backingObject)
1115 return NULL__null;
1116
1117 Path path = backingObject->elementPath();
1118 if (path.isEmpty())
1119 return NULL__null;
1120
1121 RetainPtr<CGPathRef> transformedPath = [self convertPathToScreenSpace:path];
1122 return [self bezierPathFromPath:transformedPath.get()];
1123}
1124
1125// `unignoredChildren` must be the children of `backingObject`.
1126static NSArray *transformSpecialChildrenCases(AXCoreObject& backingObject, const Vector<Ref<AXCoreObject>>& unignoredChildren)
1127{
1128#if ENABLE(MODEL_ELEMENT_ACCESSIBILITY)(defined 1 && 1)
1129 if (backingObject.isModel()) {
1130 auto modelChildren = backingObject.modelElementChildren();
1131 if (modelChildren.children.size()) {
1132 return createNSArray(WTF::move(modelChildren.children), [](auto&& child) -> id {
1133 return child.get();
1134 }).autorelease();
1135 }
1136 }
1137#endif
1138
1139 if (!unignoredChildren.size()) {
1140 if (RetainPtr widgetChildren = renderWidgetChildren(backingObject))
1141 return widgetChildren.unsafeGet();
1142 }
1143 return nilnullptr;
1144}
1145
1146static NSArray *children(AXCoreObject& backingObject)
1147{
1148 const auto& unignoredChildren = backingObject.crossFrameUnignoredChildren();
1149 RetainPtr<NSArray> specialChildren = transformSpecialChildrenCases(backingObject, unignoredChildren);
1150 if ([specialChildren count])
1151 return specialChildren.unsafeGet();
1152
1153 // The tree's (AXOutline) children are supposed to be its rows and columns.
1154 // The ARIA spec doesn't have columns, so we just need rows.
1155 if (backingObject.isTree())
1156 return makeNSArray(backingObject.ariaTreeRows());
1157
1158 // A tree item should only expose its content as its children (not its rows)
1159 if (backingObject.isTreeItem())
1160 return makeNSArray(backingObject.ariaTreeItemContent());
1161
1162 return makeNSArray(unignoredChildren);
1163}
1164
1165static RetainPtr<NSString> roleString(AXCoreObject& backingObject)
1166{
1167 String roleString = backingObject.rolePlatformString();
1168 if (!roleString.isEmpty())
1169 return roleString.createNSString();
1170 return NSAccessibilityUnknownRole;
1171}
1172
1173static RetainPtr<NSString> subroleString(AXCoreObject& backingObject)
1174{
1175 if (backingObject.isEmptyGroup())
1176 return NSAccessibilityEmptyGroupSubrole@"AXEmptyGroup";
1177
1178 String subrole = backingObject.subrolePlatformString();
1179 if (!subrole.isEmpty())
1180 return subrole.createNSString();
1181 return nilnullptr;
1182}
1183
1184static RetainPtr<NSString> roleDescription(AXCoreObject& backingObject)
1185{
1186 String roleDescription = backingObject.roleDescription();
1187 if (!roleDescription.isEmpty())
1188 return roleDescription.createNSString();
1189
1190 RetainPtr axRole = roleString(backingObject);
1191 RetainPtr subrole = subroleString(backingObject);
1192 // Fallback to the system role description.
1193 // If we get the same string back, then as a last resort, return unknown.
1194 RetainPtr<NSString> systemRoleDescription = NSAccessibilityRoleDescription(axRole.get(), subrole.get());
1195 if (![systemRoleDescription isEqualToString:axRole.get()])
1196 return systemRoleDescription;
1197 return NSAccessibilityRoleDescription(NSAccessibilityUnknownRole, nilnullptr);
1198}
1199
1200static id scrollViewParent(AXCoreObject& axObject)
1201{
1202 if (!axObject.isScrollArea())
1203 return nilnullptr;
1204
1205#if ENABLE_ACCESSIBILITY_LOCAL_FRAME0
1206 if (RefPtr crossFrameParent = axObject.crossFrameParentObject())
1207 return crossFrameParent->wrapper();
1208#endif
1209
1210 // If this scroll view provides it's parent object (because it's a sub-frame), then
1211 // we should not find the remoteAccessibilityParent.
1212 if (axObject.parentObject())
1213 return nilnullptr;
1214
1215 if (RetainPtr platformWidget = axObject.platformWidget())
1216 return NSAccessibilityUnignoredAncestor(platformWidget.get());
1217
1218 return axObject.remoteParent().unsafeGet();
1219}
1220
1221- (id)windowElement:(NSString *)attributeName
1222{
1223 if (RetainPtr<id> remoteParent = self.remoteAccessibilityParentObject) {
1224 ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
1225 return [remoteParent accessibilityAttributeValue:attributeName];
1226 ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
1227 }
1228
1229 RefPtr<AXCoreObject> backingObject = self.axBackingObject;
1230 RefPtr axScrollView = backingObject ? backingObject->axScrollView() : nullptr;
1231 return axScrollView ? [protect(axScrollView->platformWidget()) window] : nilnullptr;
1232}
1233
1234// FIXME: split up this function in a better way.
1235// suggestions: Use a hash table that maps attribute names to function calls,
1236// or maybe pointers to member functions
1237ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-implementations"
1238- (id)accessibilityAttributeValue:(NSString *)attributeName
1239{
1240 AXTRACE(makeString("WebAccessibilityObjectWrapper accessibilityAttributeValue:"_s, String(attributeName)))(void)0;
1241
1242 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
1243 if (!backingObject) {
1244 AXLOG(makeString("No backingObject for wrapper "_s, hex(reinterpret_cast<uintptr_t>(self))))(void)0;
1245 return nilnullptr;
1246 }
1247
1248 if ([attributeName isEqualToString:NSAccessibilityRoleAttribute])
1249 return roleString(*backingObject).autorelease();
1250
1251 if ([attributeName isEqualToString: NSAccessibilitySubroleAttribute])
1252 return subroleString(*backingObject).autorelease();
1253
1254 if ([attributeName isEqualToString:NSAccessibilityRoleDescriptionAttribute])
1255 return roleDescription(*backingObject).autorelease();
1256
1257 if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) {
1258 // This will return the parent of the AXScrollArea, if this is a AccessibilityScrollView.
1259 if (RetainPtr scrollView = scrollViewParent(*backingObject))
1260 return scrollView.unsafeGet();
1261
1262 // Tree item (changed to AXRows) can only report the tree (AXOutline) as its parent.
1263 if (backingObject->isTreeItem()) {
1264 RefPtr parent = backingObject->parentObjectUnignored();
1265 while (parent) {
1266 if (parent->isTree())
1267 return parent->wrapper();
1268 parent = parent->parentObjectUnignored();
1269 }
1270 }
1271
1272 RefPtr parent = backingObject->parentObjectUnignored();
1273 if (!parent)
1274 return nilnullptr;
1275
1276#if !ENABLE_ACCESSIBILITY_LOCAL_FRAME0
1277 // In WebKit1, the scroll view is provided by the system (the attachment view), so the parent
1278 // should be reported directly as such.
1279 if (backingObject->isWebArea() && parent->isAttachment())
1280 return [protect(parent->wrapper()) attachmentView];
1281#endif // !ENABLE_ACCESSIBILITY_LOCAL_FRAME
1282
1283 return parent->wrapper();
1284 }
1285
1286 if ([attributeName isEqualToString:NSAccessibilityChildrenAttribute] || [attributeName isEqualToString:NSAccessibilityChildrenInNavigationOrderAttribute@"AXChildrenInNavigationOrder"])
1287 return children(*backingObject);
1288
1289 if ([attributeName isEqualToString:NSAccessibilitySelectedChildrenAttribute]) {
1290 auto selectedChildren = backingObject->selectedChildren();
1291 return selectedChildren.size() ? makeNSArray(WTF::move(selectedChildren)) : nilnullptr;
1292 }
1293
1294 if ([attributeName isEqualToString:NSAccessibilityActiveElementAttribute@"AXActiveElement"]) {
1295 RefPtr activeDescendant = backingObject->activeDescendant();
1296 return activeDescendant ? activeDescendant->wrapper() : nilnullptr;
1297 }
1298
1299 if ([attributeName isEqualToString:NSAccessibilityVisibleChildrenAttribute]) {
1300 if (backingObject->isListBox())
1301 return makeNSArray(backingObject->visibleChildren());
1302 if (backingObject->isList())
1303 return children(*backingObject);
1304 return nilnullptr;
1305 }
1306
1307 if (backingObject->isWebArea()) {
1308 if ([attributeName isEqualToString:NSAccessibilityLinkUIElementsAttribute@"AXLinkUIElements"])
1309 return makeNSArray(backingObject->documentLinks());
1310
1311 if ([attributeName isEqualToString:NSAccessibilityLoadedAttribute@"AXLoaded"])
1312 return [NSNumber numberWithBool:backingObject->isLoaded()];
1313 if ([attributeName isEqualToString:NSAccessibilityLayoutCountAttribute@"AXLayoutCount"])
1314 return @(backingObject->layoutCount());
1315 if ([attributeName isEqualToString:NSAccessibilityLoadingProgressAttribute@"AXLoadingProgress"])
1316 return @(backingObject->loadingProgress());
1317 if ([attributeName isEqualToString:NSAccessibilityPreventKeyboardDOMEventDispatchAttribute@"AXPreventKeyboardDOMEventDispatch"])
1318 return [NSNumber numberWithBool:backingObject->preventKeyboardDOMEventDispatch()];
1319 if ([attributeName isEqualToString:NSAccessibilityCaretBrowsingEnabledAttribute@"AXCaretBrowsingEnabled"])
1320 return [NSNumber numberWithBool:backingObject->caretBrowsingEnabled()];
1321 }
1322
1323 if (backingObject->isTextControl()) {
1324 if ([attributeName isEqualToString:NSAccessibilityNumberOfCharactersAttribute])
1325 return @(backingObject->textLength());
1326
1327 if ([attributeName isEqualToString:NSAccessibilitySelectedTextAttribute]) {
1328 String selectedText = backingObject->selectedText();
1329 if (selectedText.isNull())
1330 return nilnullptr;
1331 return selectedText.createNSString().autorelease();
1332 }
1333
1334 if ([attributeName isEqualToString:NSAccessibilitySelectedTextRangeAttribute])
1335 return [NSValue valueWithRange:backingObject->selectedTextRange()];
1336
1337 if ([attributeName isEqualToString:NSAccessibilityInsertionPointLineNumberAttribute]) {
1338 int lineNumber = backingObject->insertionPointLineNumber();
1339 return lineNumber >= 0 ? @(lineNumber) : nilnullptr;
1340 }
1341 }
1342
1343 if (backingObject->isStaticText()) {
1344 if ([attributeName isEqualToString:NSAccessibilityIntersectionWithSelectionRangeAttribute@"AXIntersectionWithSelectionRange"])
1345 return [self intersectionWithSelectionRange];
1346 }
1347
1348 if ([attributeName isEqualToString:NSAccessibilityVisibleCharacterRangeAttribute]) {
1349 if (backingObject->isSecureField())
1350 return nilnullptr;
1351 // FIXME: Get actual visible range. <rdar://problem/4712101>
1352 if (backingObject->isTextControl())
1353 return [NSValue valueWithRange:NSMakeRange(0, backingObject->textLength())];
1354 return [NSValue valueWithRange:[self accessibilityVisibleCharacterRange]];
1355 }
1356
1357 if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) {
1358 URL url = backingObject->url();
1359 if (url.isNull())
1360 return nilnullptr;
1361 return url.createNSURL().autorelease();
1362 }
1363
1364 if ([attributeName isEqualToString:NSAccessibilityIncrementButtonAttribute]) {
1365 RefPtr incrementButton = backingObject->incrementButton();
1366 return incrementButton ? incrementButton->wrapper() : nilnullptr;
1367 }
1368
1369 if ([attributeName isEqualToString:NSAccessibilityDecrementButtonAttribute]) {
1370 RefPtr decrementButton = backingObject->decrementButton();
1371 return decrementButton ? decrementButton->wrapper() : nilnullptr;
1372 }
1373
1374 if ([attributeName isEqualToString: NSAccessibilityVisitedAttribute@"AXVisited"])
1375 return [NSNumber numberWithBool: backingObject->isVisitedLink()];
1376
1377 if ([attributeName isEqualToString: NSAccessibilityTitleAttribute]) {
1378 if (backingObject->isAttachment()) {
1379 RetainPtr<id> attachmentView = [self attachmentView];
1380 if ([[attachmentView accessibilityAttributeNames] containsObject:NSAccessibilityTitleAttribute])
1381 return [attachmentView accessibilityAttributeValue:NSAccessibilityTitleAttribute];
1382 }
1383
1384 return backingObject->title().createNSString().autorelease();
1385 }
1386
1387 if ([attributeName isEqualToString:NSAccessibilityDescriptionAttribute]) {
1388 if (backingObject->isAttachment()) {
1389 id attachmentView = [self attachmentView];
1390 if ([[attachmentView accessibilityAttributeNames] containsObject:NSAccessibilityDescriptionAttribute])
1391 return [attachmentView accessibilityAttributeValue:NSAccessibilityDescriptionAttribute];
1392 }
1393 return backingObject->descriptionAttributeValue().createNSString().autorelease();
1394 }
1395
1396 if ([attributeName isEqualToString:NSAccessibilityValueAttribute]) {
1397 if (backingObject->isAttachment()) {
1398 id attachmentView = [self attachmentView];
1399 if ([[attachmentView accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute])
1400 return [attachmentView accessibilityAttributeValue:NSAccessibilityValueAttribute];
1401 }
1402
1403 auto value = backingObject->value();
1404 return WTF::switchOn(value,
1405 [] (bool& typedValue) -> id { return @(typedValue); },
1406 [] (unsigned& typedValue) -> id { return @(typedValue); },
1407 [] (float& typedValue) -> id { return @(typedValue); },
1408 [] (String& typedValue) -> id { return typedValue.createNSString().autorelease(); },
1409 [&backingObject] (WallTime& typedValue) -> id {
1410 NSInteger offset = gmtToLocalTimeOffset(backingObject->dateTimeComponentsType());
1411 auto time = typedValue.secondsSinceEpoch().value();
1412 NSDate *gmtDate = [NSDate dateWithTimeIntervalSince1970:time];
1413 return [NSDate dateWithTimeInterval:offset sinceDate:gmtDate];
1414 },
1415 [] (AccessibilityButtonState& typedValue) -> id { return @((unsigned)typedValue); },
1416 [] (AXCoreObject*& typedValue) { return typedValue ? (id)typedValue->wrapper() : nilnullptr; },
1417 [] (auto&) { return nilnullptr; }
1418 );
1419 }
1420
1421 if ([attributeName isEqualToString:NSAccessibilityDateTimeComponentsAttribute@"AXDateTimeComponents"])
1422 return @(convertToAXFDateTimeComponents(backingObject->dateTimeComponentsType()));
1423
1424 if ([attributeName isEqualToString:bridge_cast(kAXMenuItemMarkCharAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXMenuItemMarkChar"
""))
)]) {
1425 const unichar ch = 0x2713; // ✓ used on Mac for selected menu items.
1426 return (backingObject->isChecked()) ? [NSString stringWithCharacters:&ch length:1] : nilnullptr;
1427 }
1428
1429 if ([attributeName isEqualToString: NSAccessibilityMinValueAttribute]) {
1430 // Indeterminate progress indicator should return 0.
1431 if (backingObject->isIndeterminate())
1432 return @0;
1433 return [NSNumber numberWithFloat:backingObject->minValueForRange()];
1434 }
1435
1436 if ([attributeName isEqualToString: NSAccessibilityMaxValueAttribute]) {
1437 // Indeterminate progress indicator should return 0.
1438 if (backingObject->isIndeterminate())
1439 return @0;
1440 return [NSNumber numberWithFloat:backingObject->maxValueForRange()];
1441 }
1442
1443 if ([attributeName isEqualToString: NSAccessibilityHelpAttribute])
1444 return [self baseAccessibilityHelpText];
1445
1446 if ([attributeName isEqualToString:NSAccessibilityFocusedAttribute])
1447 return @(backingObject->isFocused());
1448
1449 if ([attributeName isEqualToString: NSAccessibilityEnabledAttribute])
1450 return [NSNumber numberWithBool: backingObject->isEnabled()];
1451
1452 if ([attributeName isEqualToString:NSAccessibilitySizeAttribute]) {
1453 auto size = backingObject->size();
1454 if (backingObject->isControl())
1455 Accessibility::adjustControlSize(size);
1456 return [NSValue valueWithSize:(CGSize)size];
1457 }
1458
1459 if ([attributeName isEqualToString:NSAccessibilityPrimaryScreenHeightAttribute@"_AXPrimaryScreenHeight"])
1460 return @(backingObject->primaryScreenRect().height());
1461
1462 if ([attributeName isEqualToString:NSAccessibilityPositionAttribute])
1463 return [NSValue valueWithPoint:(CGPoint)backingObject->screenRelativePosition()];
1464
1465 if ([attributeName isEqualToString:NSAccessibilityPathAttribute@"AXPath"])
1466 return [self path];
1467
1468 if ([attributeName isEqualToString:NSAccessibilityLineRectsAndTextAttribute@"AXLineRectsAndText"]) {
1469 return Accessibility::retrieveAutoreleasedValueFromMainThread<NSArray *>([protectedSelf = retainPtr(self)] () -> RetainPtr<NSArray> {
1470 return protectedSelf.get().lineRectsAndText;
1471 });
1472 }
1473
1474 if ([attributeName isEqualToString:NSAccessibilityImageOverlayElementsAttribute@"AXImageOverlayElements"]) {
1475 auto imageOverlayElements = backingObject->imageOverlayElements();
1476 return imageOverlayElements ? makeNSArray(*imageOverlayElements) : nilnullptr;
1477 }
1478
1479 if ([attributeName isEqualToString:NSAccessibilityEmbeddedImageDescriptionAttribute@"AXEmbeddedImageDescription"])
1480 return backingObject->embeddedImageDescription().createNSString().autorelease();
1481
1482 if ([attributeName isEqualToString:NSAccessibilityWindowAttribute]
1483 || [attributeName isEqualToString:NSAccessibilityTopLevelUIElementAttribute])
1484 return [self windowElement:attributeName];
1485
1486 if ([attributeName isEqualToString:NSAccessibilityAccessKeyAttribute@"AXAccessKey"]) {
1487 auto accessKey = backingObject->accessKey();
1488 if (accessKey.isNull())
1489 return nilnullptr;
1490 return accessKey.createNSString().autorelease();
1491 }
1492
1493 if ([attributeName isEqualToString:NSAccessibilityLinkRelationshipTypeAttribute@"AXLinkRelationshipType"])
1494 return backingObject->linkRelValue().createNSString().autorelease();
1495
1496 if ([attributeName isEqualToString:NSAccessibilityTabsAttribute] && backingObject->isTabList())
1497 return makeNSArray(backingObject->tabChildren());
1498
1499 if ([attributeName isEqualToString:NSAccessibilityContentsAttribute])
1500 return makeNSArray(backingObject->contents());
1501
1502 if (backingObject->isExposableTable()) {
1503 if ([attributeName isEqualToString:NSAccessibilityRowsAttribute])
1504 return makeNSArray(backingObject->rows());
1505
1506 if ([attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute])
1507 return makeNSArray(backingObject->visibleRows());
1508
1509 // TODO: distinguish between visible and non-visible columns
1510 if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute]
1511 || [attributeName isEqualToString:NSAccessibilityVisibleColumnsAttribute])
1512 return makeNSArray(backingObject->columns());
1513
1514 if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
1515 auto selectedChildren = backingObject->selectedChildren();
1516 return selectedChildren.size() ? makeNSArray(WTF::move(selectedChildren)) : nilnullptr;
1517 }
1518
1519 // HTML tables don't support this attribute yet.
1520 if ([attributeName isEqualToString:NSAccessibilitySelectedColumnsAttribute])
1521 return nilnullptr;
1522
1523 if ([attributeName isEqualToString:NSAccessibilitySelectedCellsAttribute])
1524 return makeNSArray(backingObject->selectedCells());
1525
1526 if ([attributeName isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute])
1527 return makeNSArray(backingObject->columnHeaders());
1528
1529 if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
1530 RefPtr headerContainer = backingObject->tableHeaderContainer();
1531 return headerContainer ? headerContainer->wrapper() : nilnullptr;
1532 }
1533
1534 if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute])
1535 return makeNSArray(backingObject->rowHeaders());
1536
1537 if ([attributeName isEqualToString:NSAccessibilityVisibleCellsAttribute])
1538 return makeNSArray(backingObject->cells());
1539
1540 if ([attributeName isEqualToString:NSAccessibilityColumnCountAttribute])
1541 return @(backingObject->columnCount());
1542
1543 if ([attributeName isEqualToString:NSAccessibilityRowCountAttribute])
1544 return @(backingObject->rowCount());
1545
1546 if ([attributeName isEqualToString:NSAccessibilityARIAColumnCountAttribute@"AXARIAColumnCount"])
1547 return @(backingObject->axColumnCount());
1548
1549 if ([attributeName isEqualToString:NSAccessibilityARIARowCountAttribute@"AXARIARowCount"])
1550 return @(backingObject->axRowCount());
1551 }
1552
1553 if (backingObject->isTableColumn()) {
1554 if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
1555 return @(backingObject->columnIndex());
1556
1557 // rows attribute for a column is the list of all the elements in that column at each row
1558 if ([attributeName isEqualToString:NSAccessibilityRowsAttribute]
1559 || [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute])
1560 return makeNSArray(backingObject->unignoredChildren());
1561
1562 if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
1563 RefPtr header = backingObject->columnHeader();
1564 return header ? header->wrapper() : nilnullptr;
1565 }
1566 }
1567
1568 if (backingObject->isExposedTableCell()) {
1569 if ([attributeName isEqualToString:NSAccessibilityRowIndexRangeAttribute]) {
1570 auto rowRange = backingObject->rowIndexRange();
1571 return [NSValue valueWithRange:NSMakeRange(rowRange.first, rowRange.second)];
1572 }
1573
1574 if ([attributeName isEqualToString:NSAccessibilityColumnIndexRangeAttribute]) {
1575 auto columnRange = backingObject->columnIndexRange();
1576 return [NSValue valueWithRange:NSMakeRange(columnRange.first, columnRange.second)];
1577 }
1578
1579 if ([attributeName isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute])
1580 return makeNSArray(backingObject->columnHeaders());
1581
1582 if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute])
1583 return makeNSArray(backingObject->rowHeaders());
1584
1585 if ([attributeName isEqualToString:NSAccessibilityARIAColumnIndexAttribute@"AXARIAColumnIndex"]) {
1586 if (std::optional columnIndex = backingObject->axColumnIndex())
1587 return @(*columnIndex);
1588 return @(-1);
1589 }
1590
1591 if ([attributeName isEqualToString:NSAccessibilityARIARowIndexAttribute@"AXARIARowIndex"]) {
1592 if (std::optional rowIndex = backingObject->axRowIndex())
1593 return @(*rowIndex);
1594 return @(-1);
1595 }
1596
1597 if ([attributeName isEqualToString:NSAccessibilityColumnIndexDescriptionAttribute@"AXColumnIndexDescription"]) {
1598 String columnIndexText = backingObject->axColumnIndexText();
1599 return !columnIndexText.isNull() ? columnIndexText.createNSString().autorelease() : nilnullptr;
1600 }
1601
1602 if ([attributeName isEqualToString:NSAccessibilityRowIndexDescriptionAttribute@"AXRowIndexDescription"]) {
1603 String rowIndexText = backingObject->axRowIndexText();
1604 return !rowIndexText.isNull() ? rowIndexText.createNSString().autorelease() : nilnullptr;
1605 }
1606 }
1607
1608 if (backingObject->isTree()) {
1609 if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
1610 auto selectedChildren = backingObject->selectedChildren();
1611 return selectedChildren.size() ? makeNSArray(WTF::move(selectedChildren)) : nilnullptr;
1612 }
1613
1614 if ([attributeName isEqualToString:NSAccessibilityRowsAttribute])
1615 return makeNSArray(backingObject->ariaTreeRows());
1616
1617 // TreeRoles do not support columns, but Mac AX expects to be able to ask about columns at the least.
1618 if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute])
1619 return @[];
1620 }
1621
1622 if ([attributeName isEqualToString:NSAccessibilityIndexAttribute]) {
1623 if (backingObject->isTreeItem()) {
1624 RefPtr parent = backingObject->parentObject();
1625 for (; parent && !parent->isTree(); parent = parent->parentObject())
1626 { }
1627
1628 if (!parent)
1629 return nilnullptr;
1630
1631 // Find the index of this item by iterating the parents.
1632 auto rowsCopy = parent->ariaTreeRows();
1633 size_t count = rowsCopy.size();
1634 for (size_t k = 0; k < count; ++k) {
1635 if (rowsCopy[k]->wrapper() == self)
1636 return @(k);
1637 }
1638
1639 return nilnullptr;
1640 }
1641
1642 if (backingObject->isExposedTableRow())
1643 return @(backingObject->rowIndex());
1644 }
1645
1646 // The rows that are considered inside this row.
1647 if ([attributeName isEqualToString:NSAccessibilityDisclosedRowsAttribute]) {
1648 if (backingObject->isTreeItem() || backingObject->isARIATreeGridRow())
1649 return makeNSArray(backingObject->disclosedRows());
1650 }
1651
1652 // The row that contains this row. It should be the same as the first parent that is a treeitem.
1653 if ([attributeName isEqualToString:NSAccessibilityDisclosedByRowAttribute]) {
1654 if (backingObject->isTreeItem()) {
1655 RefPtr<AXCoreObject> parent = backingObject->parentObject();
1656 while (parent) {
1657 if (parent->isTreeItem())
1658 return parent->wrapper();
1659 // If the parent is the tree itself, then this value == nil.
1660 if (parent->isTree())
1661 return nilnullptr;
1662 parent = parent->parentObject();
1663 }
1664 return nilnullptr;
1665 }
1666
1667 if (backingObject->isARIATreeGridRow()) {
1668 RefPtr row = backingObject->disclosedByRow();
1669 return row ? row->wrapper() : nilnullptr;
1670 }
1671 }
1672
1673 if ([attributeName isEqualToString:NSAccessibilityDisclosureLevelAttribute]) {
1674 // Convert from 1-based level (from aria-level spec) to 0-based level (Mac)
1675 int level = backingObject->hierarchicalLevel();
1676 if (level > 0)
1677 level -= 1;
1678 return @(level);
1679 }
1680 if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
1681 return [NSNumber numberWithBool:backingObject->isExpanded()];
1682
1683 if ([attributeName isEqualToString:NSAccessibilitySelectedTextMarkerRangeAttribute@"AXSelectedTextMarkerRange"])
1684 return (id)[self selectedTextMarkerRange];
1685
1686 if ([attributeName isEqualToString:NSAccessibilityStartTextMarkerAttribute@"AXStartTextMarker"]) {
1687 if (AXObjectCache::useAXThreadTextApis()) {
1688 if (RefPtr tree = std::get<RefPtr<AXIsolatedTree>>(axTreeForID(backingObject->treeID())))
1689 return tree->firstMarker().platformData().bridgingAutorelease();
1690 }
1691 return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
1692 RefPtr backingObject = downcast<AccessibilityObject>(protectedSelf.get().axBackingObject);
1693 if (!backingObject)
1694 return nilnullptr;
1695
1696 CheckedPtr cache = backingObject->axObjectCache();
1697 RefPtr document = backingObject->document();
1698 return (id)textMarkerForVisiblePosition(cache.get(), startOfDocument(document.get()));
1699 });
1700 }
1701
1702 if ([attributeName isEqualToString:NSAccessibilityEndTextMarkerAttribute@"AXEndTextMarker"]) {
1703 if (AXObjectCache::useAXThreadTextApis()) {
1704 if (RefPtr tree = std::get<RefPtr<AXIsolatedTree>>(axTreeForID(backingObject->treeID())))
1705 return tree->lastMarker().platformData().bridgingAutorelease();
1706 }
1707 return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
1708 RefPtr backingObject = downcast<AccessibilityObject>(protectedSelf.get().axBackingObject);
1709 if (!backingObject)
1710 return nilnullptr;
1711
1712 CheckedPtr cache = backingObject->axObjectCache();
1713 RefPtr document = backingObject->document();
1714 return (id)textMarkerForVisiblePosition(cache.get(), endOfDocument(document.get()));
1715 });
1716 }
1717
1718 if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute@"AXBlockQuoteLevel"])
1719 return @(backingObject->blockquoteLevel());
1720 if ([attributeName isEqualToString:NSAccessibilityTableLevelAttribute@"AXTableLevel"])
1721 return @(backingObject->tableLevel());
1722
1723 if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute])
1724 return makeNSArray(backingObject->linkedObjects());
1725
1726 if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
1727 return [NSNumber numberWithBool:backingObject->isSelected()];
1728
1729 if ([attributeName isEqualToString: NSAccessibilityARIACurrentAttribute@"AXARIACurrent"])
1730 return backingObject->currentValue().createNSString().autorelease();
1731
1732 if ([attributeName isEqualToString:NSAccessibilityTitleUIElementAttribute]) {
1733 // FIXME: change to return an array instead of a single object.
1734 RefPtr object = backingObject->titleUIElement();
1735 return object ? object->wrapper() : nilnullptr;
1736 }
1737
1738 if ([attributeName isEqualToString:NSAccessibilityValueDescriptionAttribute])
1739 return backingObject->valueDescription().createNSString().autorelease();
1740
1741 if ([attributeName isEqualToString:NSAccessibilityOrientationAttribute]) {
1742 AccessibilityOrientation elementOrientation = backingObject->orientation();
1743 if (elementOrientation == AccessibilityOrientation::Vertical)
1744 return NSAccessibilityVerticalOrientationValue;
1745 if (elementOrientation == AccessibilityOrientation::Horizontal)
1746 return NSAccessibilityHorizontalOrientationValue;
1747 if (elementOrientation == AccessibilityOrientation::Undefined)
1748 return NSAccessibilityUnknownOrientationValue;
1749 return nilnullptr;
1750 }
1751
1752 if ([attributeName isEqualToString:NSAccessibilityHorizontalScrollBarAttribute]) {
1753 RefPtr scrollBar = backingObject->scrollBar(AccessibilityOrientation::Horizontal);
1754 return scrollBar ? scrollBar->wrapper() : nilnullptr;
1755 }
1756
1757 if ([attributeName isEqualToString:NSAccessibilityVerticalScrollBarAttribute]) {
1758 RefPtr scrollBar = backingObject->scrollBar(AccessibilityOrientation::Vertical);
1759 return scrollBar ? scrollBar->wrapper() : nilnullptr;
1760 }
1761
1762 if ([attributeName isEqualToString:NSAccessibilitySortDirectionAttribute]) {
1763 switch (backingObject->sortDirectionIncludingAncestors()) {
1764 case AccessibilitySortDirection::Ascending:
1765 return NSAccessibilityAscendingSortDirectionValue;
1766 case AccessibilitySortDirection::Descending:
1767 return NSAccessibilityDescendingSortDirectionValue;
1768 default:
1769 return NSAccessibilityUnknownSortDirectionValue;
1770 }
1771 }
1772
1773 if ([attributeName isEqualToString:NSAccessibilityLanguageAttribute@"AXLanguage"])
1774 return backingObject->languageIncludingAncestors().createNSString().autorelease();
1775
1776 if ([attributeName isEqualToString:NSAccessibilityExpandedAttribute])
1777 return [NSNumber numberWithBool:backingObject->isExpanded()];
1778
1779 if ([attributeName isEqualToString:NSAccessibilityRequiredAttribute])
1780 return [NSNumber numberWithBool:backingObject->isRequired()];
1781
1782 if ([attributeName isEqualToString:NSAccessibilityInvalidAttribute@"AXInvalid"])
1783 return backingObject->invalidStatus().createNSString().autorelease();
1784
1785 if ([attributeName isEqualToString:NSAccessibilityOwnsAttribute@"AXOwns"])
1786 return makeNSArray(backingObject->ownedObjects());
1787
1788 if ([attributeName isEqualToString:NSAccessibilityARIAPosInSetAttribute@"AXARIAPosInSet"])
1789 return @(backingObject->posInSet());
1790 if ([attributeName isEqualToString:NSAccessibilityARIASetSizeAttribute@"AXARIASetSize"])
1791 return @(backingObject->setSize());
1792
1793 if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute@"AXGrabbed"])
1794 return [NSNumber numberWithBool:backingObject->isGrabbed()];
1795
1796 if ([attributeName isEqualToString:NSAccessibilityDropEffectsAttribute@"AXDropEffects"])
1797 return createNSArray(backingObject->determineDropEffects()).autorelease();
1798
1799 if ([attributeName isEqualToString:NSAccessibilityPlaceholderValueAttribute])
1800 return backingObject->placeholderValue().createNSString().autorelease();
1801
1802 if ([attributeName isEqualToString:NSAccessibilityValueAutofillAvailableAttribute@"AXValueAutofillAvailable"])
1803 return @(backingObject->isValueAutofillAvailable());
1804
1805 if ([attributeName isEqualToString:NSAccessibilityValueAutofillTypeAttribute@"AXValueAutofillType"]) {
1806 switch (backingObject->valueAutofillButtonType()) {
1807 case AutoFillButtonType::None:
1808 return @"none";
1809 case AutoFillButtonType::Credentials:
1810 return @"credentials";
1811 case AutoFillButtonType::Contacts:
1812 return @"contacts";
1813 case AutoFillButtonType::StrongPassword:
1814 return @"strong password";
1815 case AutoFillButtonType::CreditCard:
1816 return @"credit card";
1817 case AutoFillButtonType::Loading:
1818 return @"loading";
1819 }
1820 }
1821
1822 if ([attributeName isEqualToString:NSAccessibilityHasPopupAttribute@"AXHasPopup"])
1823 return [NSNumber numberWithBool:backingObject->selfOrAncestorLinkHasPopup()];
1824
1825 if ([attributeName isEqualToString:NSAccessibilityDatetimeValueAttribute@"AXDateTimeValue"])
1826 return backingObject->datetimeAttributeValue().createNSString().autorelease();
1827
1828 if ([attributeName isEqualToString:NSAccessibilityInlineTextAttribute@"AXInlineText"]) {
1829 // FIXME: After the AccessibilityStitchedText feature ships, we can probably remove this
1830 // and all related code (making sure not to break backported versions of WebKit which won't
1831 // have the corresponding VoiceOver changes).
1832 return @(backingObject->isInlineText());
1833 }
1834
1835 // ARIA Live region attributes.
1836 if ([attributeName isEqualToString:NSAccessibilityARIALiveAttribute@"AXARIALive"])
1837 return backingObject->liveRegionStatus().createNSString().autorelease();
1838 if ([attributeName isEqualToString:NSAccessibilityARIARelevantAttribute@"AXARIARelevant"])
1839 return backingObject->liveRegionRelevant().createNSString().autorelease();
1840 if ([attributeName isEqualToString:NSAccessibilityARIAAtomicAttribute@"AXARIAAtomic"])
1841 return [NSNumber numberWithBool:backingObject->liveRegionAtomic()];
1842 if ([attributeName isEqualToString:NSAccessibilityElementBusyAttribute@"AXElementBusy"])
1843 return [NSNumber numberWithBool:backingObject->isBusy()];
1844
1845 // MathML Attributes.
1846 if (backingObject->isMathElement()) {
1847 if ([attributeName isEqualToString:NSAccessibilityMathRootIndexAttribute@"AXMathRootIndex"]) {
1848 RefPtr rootIndex = backingObject->mathRootIndexObject();
1849 return rootIndex ? rootIndex->wrapper() : nilnullptr;
1850 }
1851
1852 if ([attributeName isEqualToString:NSAccessibilityMathRootRadicandAttribute@"AXMathRootRadicand"]) {
1853 auto radicand = backingObject->mathRadicand();
1854 return radicand ? makeNSArray(*radicand) : nilnullptr;
1855 }
1856
1857 if ([attributeName isEqualToString:NSAccessibilityMathFractionNumeratorAttribute@"AXMathFractionNumerator"])
1858 return (backingObject->mathNumeratorObject()) ? backingObject->mathNumeratorObject()->wrapper() : 0;
1859 if ([attributeName isEqualToString:NSAccessibilityMathFractionDenominatorAttribute@"AXMathFractionDenominator"])
1860 return (backingObject->mathDenominatorObject()) ? backingObject->mathDenominatorObject()->wrapper() : 0;
1861 if ([attributeName isEqualToString:NSAccessibilityMathBaseAttribute@"AXMathBase"])
1862 return (backingObject->mathBaseObject()) ? backingObject->mathBaseObject()->wrapper() : 0;
1863 if ([attributeName isEqualToString:NSAccessibilityMathSubscriptAttribute@"AXMathSubscript"])
1864 return (backingObject->mathSubscriptObject()) ? backingObject->mathSubscriptObject()->wrapper() : 0;
1865 if ([attributeName isEqualToString:NSAccessibilityMathSuperscriptAttribute@"AXMathSuperscript"])
1866 return (backingObject->mathSuperscriptObject()) ? backingObject->mathSuperscriptObject()->wrapper() : 0;
1867 if ([attributeName isEqualToString:NSAccessibilityMathUnderAttribute@"AXMathUnder"])
1868 return (backingObject->mathUnderObject()) ? backingObject->mathUnderObject()->wrapper() : 0;
1869 if ([attributeName isEqualToString:NSAccessibilityMathOverAttribute@"AXMathOver"])
1870 return (backingObject->mathOverObject()) ? backingObject->mathOverObject()->wrapper() : 0;
1871 if ([attributeName isEqualToString:NSAccessibilityMathFencedOpenAttribute@"AXMathFencedOpen"])
1872 return backingObject->mathFencedOpenString().createNSString().autorelease();
1873 if ([attributeName isEqualToString:NSAccessibilityMathFencedCloseAttribute@"AXMathFencedClose"])
1874 return backingObject->mathFencedCloseString().createNSString().autorelease();
1875 if ([attributeName isEqualToString:NSAccessibilityMathLineThicknessAttribute@"AXMathLineThickness"])
1876 return [NSNumber numberWithInteger:backingObject->mathLineThickness()];
1877 if ([attributeName isEqualToString:NSAccessibilityMathPostscriptsAttribute@"AXMathPostscripts"])
1878 return [self accessibilityMathPostscriptPairs];
1879 if ([attributeName isEqualToString:NSAccessibilityMathPrescriptsAttribute@"AXMathPrescripts"])
1880 return [self accessibilityMathPrescriptPairs];
1881 }
1882
1883 if ([attributeName isEqualToString:NSAccessibilityExpandedTextValueAttribute@"AXExpandedTextValue"])
1884 return backingObject->expandedTextValue().createNSString().autorelease();
1885
1886 if ([attributeName isEqualToString:NSAccessibilityDOMIdentifierAttribute@"AXDOMIdentifier"])
1887 return backingObject->identifierAttribute().createNSString().autorelease();
1888 if ([attributeName isEqualToString:NSAccessibilityDOMClassListAttribute@"AXDOMClassList"])
1889 return createNSArray(backingObject->classList()).autorelease();
1890
1891 // This allows us to connect to a plugin that creates a shadow node for editing (like PDFs).
1892 if ([attributeName isEqualToString:NSAccessibilityAssociatedPluginParentAttribute@"_AXAssociatedPluginParent"])
1893 return [self _associatedPluginParentWith:backingObject];
1894
1895 // This used to be a testing-only attribute, but unfortunately some ATs do actually request it.
1896 if ([attributeName isEqualToString:NSAccessibilityDRTSpeechAttributeAttribute@"AXDRTSpeechAttribute"])
1897 return [self baseAccessibilitySpeechHint];
1898
1899 if ([attributeName isEqualToString:NSAccessibilityPopupValueAttribute@"AXPopupValue"])
1900 return backingObject->popupValue().createNSString().autorelease();
1901
1902 if ([attributeName isEqualToString:NSAccessibilityKeyShortcutsAttribute@"AXKeyShortcutsValue"])
1903 return backingObject->keyShortcuts().createNSString().autorelease();
1904
1905 if ([attributeName isEqualToString:NSAccessibilityIsInDescriptionListTermAttribute@"AXIsInDescriptionListTerm"])
1906 return [NSNumber numberWithBool:backingObject->isInDescriptionListTerm()];
1907
1908 if ([attributeName isEqualToString:NSAccessibilityDetailsElementsAttribute@"AXDetailsElements"])
1909 return makeNSArray(backingObject->detailedByObjects());
1910
1911 if ([attributeName isEqualToString:NSAccessibilityBrailleLabelAttribute@"AXBrailleLabel"])
1912 return backingObject->brailleLabel().createNSString().autorelease();
1913
1914 if ([attributeName isEqualToString:NSAccessibilityBrailleRoleDescriptionAttribute@"AXBrailleRoleDescription"])
1915 return backingObject->brailleRoleDescription().createNSString().autorelease();
1916
1917 if ([attributeName isEqualToString:NSAccessibilityRelativeFrameAttribute@"AXRelativeFrame"]) {
1918 auto frame = backingObject->relativeFrame();
1919 if (backingObject->isControl())
1920 Accessibility::adjustControlSize(frame);
1921 return [NSValue valueWithRect:(NSRect)frame];
1922 }
1923
1924 if ([attributeName isEqualToString:NSAccessibilityErrorMessageElementsAttribute@"AXErrorMessageElements"]) {
1925 // Only expose error messages for objects in an invalid state.
1926 // https://www.w3.org/TR/wai-aria-1.2/#aria-errormessage
1927 if (backingObject->invalidStatus() == "false"_s)
1928 return nilnullptr;
1929 return makeNSArray(backingObject->errorMessageObjects());
1930 }
1931
1932 if ([attributeName isEqualToString:NSAccessibilityFocusableAncestorAttribute@"AXFocusableAncestor"]) {
1933 RefPtr object = backingObject->focusableAncestor();
1934 return object ? object->wrapper() : nilnullptr;
1935 }
1936
1937 if ([attributeName isEqualToString:NSAccessibilityEditableAncestorAttribute@"AXEditableAncestor"]) {
1938 RefPtr object = backingObject->editableAncestor();
1939 return object ? object->wrapper() : nilnullptr;
1940 }
1941
1942 if ([attributeName isEqualToString:NSAccessibilityHighestEditableAncestorAttribute@"AXHighestEditableAncestor"]) {
1943 RefPtr object = backingObject->highestEditableAncestor();
1944 return object ? object->wrapper() : nilnullptr;
1945 }
1946
1947 if ([attributeName isEqualToString:NSAccessibilityTextInputMarkedRangeAttribute@"AXTextInputMarkedRange"]) {
1948 auto range = backingObject->textInputMarkedTextMarkerRange();
1949 auto nsRange = range.nsRange();
1950 return range && nsRange ? [NSValue valueWithRange:*nsRange] : nilnullptr;
1951 }
1952
1953 if ([attributeName isEqualToString:NSAccessibilityTextInputMarkedTextMarkerRangeAttribute@"AXTextInputMarkedTextMarkerRange"]) {
1954 auto range = backingObject->textInputMarkedTextMarkerRange();
1955 return range ? range.platformData().bridgingAutorelease() : nilnullptr;
1956 }
1957
1958 // VoiceOver property to ignore certain groups.
1959 if ([attributeName isEqualToString:NSAccessibilityAutoInteractableAttribute@"AXAutoInteractable"])
1960 return @(backingObject->isRemoteFrame());
1961
1962 if (AXObjectCache::clientIsInTestMode())
1963 return attributeValueForTesting(backingObject, attributeName);
1964 return nilnullptr;
1965}
1966ALLOW_DEPRECATED_IMPLEMENTATIONS_ENDGCC diagnostic pop
1967
1968id attributeValueForTesting(const RefPtr<AXCoreObject>& backingObject, NSString *attributeName)
1969{
1970 ASSERT_WITH_MESSAGE(AXObjectCache::clientIsInTestMode(), "Should be used for testing only, not for AT clients.")((void)0);
1971
1972 if ([attributeName isEqualToString:NSAccessibilityARIARoleAttribute@"AXARIARole"])
1973 return backingObject->computedRoleString().createNSString().autorelease();
1974
1975 if ([attributeName isEqualToString:NSAccessibilityStringValueAttribute@"AXStringValue"])
1976 return backingObject->stringValue().createNSString().autorelease();
1977
1978 if ([attributeName isEqualToString:NSAccessibilityDateTimeComponentsTypeAttribute@"AXDateTimeComponentsType"])
1979 return [NSNumber numberWithUnsignedShort:(uint8_t)backingObject->dateTimeComponentsType()];
1980
1981 if ([attributeName isEqualToString:NSAccessibilityControllersAttribute@"AXControllers"])
1982 return makeNSArray(backingObject->controllers());
1983
1984 if ([attributeName isEqualToString:NSAccessibilityActionTargetsAttribute@"_AXActionTargets"])
1985 return makeNSArray(backingObject->associatedActionElements());
1986
1987 if ([attributeName isEqualToString:NSAccessibilityControllerForAttribute@"AXControllerFor"])
1988 return makeNSArray(backingObject->controlledObjects());
1989
1990 if ([attributeName isEqualToString:NSAccessibilityDescribedByAttribute@"AXDescribedBy"])
1991 return makeNSArray(backingObject->describedByObjects());
1992
1993 if ([attributeName isEqualToString:NSAccessibilityDescriptionForAttribute@"AXDescriptionFor"])
1994 return makeNSArray(backingObject->descriptionForObjects());
1995
1996 if ([attributeName isEqualToString:NSAccessibilityDetailsForAttribute@"AXDetailsFor"])
1997 return makeNSArray(backingObject->detailsForObjects());
1998
1999 if ([attributeName isEqualToString:NSAccessibilityErrorMessageForAttribute@"AXErrorMessageFor"])
2000 return makeNSArray(backingObject->errorMessageForObjects());
2001
2002 if ([attributeName isEqualToString:NSAccessibilityFlowFromAttribute@"AXFlowFrom"])
2003 return makeNSArray(backingObject->flowFromObjects());
2004
2005 if ([attributeName isEqualToString:NSAccessibilityFlowToAttribute@"AXFlowTo"])
2006 return makeNSArray(backingObject->flowToObjects());
2007
2008 if ([attributeName isEqualToString:NSAccessibilityLabelledByAttribute@"AXLabelledBy"])
2009 return makeNSArray(backingObject->labeledByObjects());
2010
2011 if ([attributeName isEqualToString:NSAccessibilityLabelForAttribute@"AXLabelFor"])
2012 return makeNSArray(backingObject->labelForObjects());
2013
2014 if ([attributeName isEqualToString:NSAccessibilityOwnersAttribute@"AXOwners"])
2015 return makeNSArray(backingObject->owners());
2016
2017 if ([attributeName isEqualToString:NSAccessibilityARIAPressedIsPresentAttribute@"AXARIAPressedIsPresent"])
2018 return [NSNumber numberWithBool:backingObject->pressedIsPresent()];
2019
2020 if ([attributeName isEqualToString:NSAccessibilityAutocompleteValueAttribute@"AXAutocompleteValue"])
2021 return backingObject->autoCompleteValue().createNSString().autorelease();
2022
2023 if ([attributeName isEqualToString:NSAccessibilityClickPointAttribute@"AXClickPoint"])
2024 return [NSValue valueWithPoint:backingObject->clickPoint()];
2025
2026 if ([attributeName isEqualToString:NSAccessibilityIsIndeterminateAttribute@"AXIsIndeterminate"])
2027 return [NSNumber numberWithBool:backingObject->isIndeterminate()];
2028
2029 if ([attributeName isEqualToString:NSAccessibilityIsMultiSelectableAttribute@"AXIsMultiSelectable"])
2030 return [NSNumber numberWithBool:backingObject->isMultiSelectable()];
2031
2032 if ([attributeName isEqualToString:NSAccessibilityIsOnScreenAttribute@"AXIsOnScreen"])
2033 return [NSNumber numberWithBool:backingObject->isOnScreen()];
2034
2035 if ([attributeName isEqualToString:NSAccessibilityIsInTableAttribute@"_AXIsInTable"]) {
2036 RefPtr table = Accessibility::findAncestor(*backingObject, false, [&] (const auto& ancestor) {
2037 return ancestor.isTable();
2038 });
2039 return [NSNumber numberWithBool:!!table.get()];
2040 }
2041
2042 if ([attributeName isEqualToString:NSAccessibilityIsRemoteFrameAttribute@"AXIsRemoteFrame"])
2043 return [NSNumber numberWithBool:backingObject->isRemoteFrame()];
2044
2045 if ([attributeName isEqualToString:NSAccessibilityInfoStringForTestingAttribute@"AXInfoStringForTesting"])
2046 return backingObject->infoStringForTesting().createNSString().autorelease();
2047
2048 if ([attributeName isEqualToString:NSAccessibilityPageRelativePositionAttribute@"_AXPageRelativePosition"])
2049 return [NSValue valueWithPoint:(CGPoint)backingObject->relativeFrame().location()];
2050
2051 return nilnullptr;
2052}
2053
2054- (id)parameterizedAttributeValueForTesting:(NSString *)attribute parameter:(id)parameter backingObject:(const RefPtr<AXCoreObject>&)backingObject
2055{
2056 // This should've been null-checked already.
2057 RELEASE_ASSERT(parameter)do { if (__builtin_expect(!!(!(parameter)), 0)) do { WTF::isIntegralOrPointerType
(); compilerFenceForCrash(); WTFCrashWithInfo(2057, "/Volumes/Data/worker/macOS-Safer-CPP-Checks-EWS/build/Source/WebCore/accessibility/mac/WebAccessibilityObjectWrapperMac.mm"
, __PRETTY_FUNCTION__ ); } while (false); } while (0)
;
2058
2059 AXTextMarkerRef markerRef = nilnullptr;
2060 AXTextMarkerRangeRef markerRangeRef = nilnullptr;
2061 NSRange nsRange = { 0, 0 };
2062
2063 if (AXObjectIsTextMarker(parameter))
2064 markerRef = (AXTextMarkerRef)parameter;
2065 else if (AXObjectIsTextMarkerRange(parameter))
2066 markerRangeRef = (AXTextMarkerRangeRef)parameter;
2067 else if ([parameter isKindOfClass:[NSValue class]] && nsValueHasObjCType<NSRange>((NSValue *)parameter))
2068 nsRange = [(NSValue*)parameter rangeValue];
2069 else
2070 return nilnullptr;
2071
2072 if ([attribute isEqualToString:NSAccessibilityTextMarkerIsNullParameterizedAttribute@"AXTextMarkerIsNull"])
2073 return [NSNumber numberWithBool:AXTextMarker(markerRef).isNull()];
2074
2075 if ([attribute isEqualToString:NSAccessibilityTextMarkerRangeIsValidParameterizedAttribute@"AXTextMarkerRangeIsValid"]) {
2076 AXTextMarkerRange markerRange { markerRangeRef };
2077 return [NSNumber numberWithBool:markerRange.start().isValid() && markerRange.end().isValid()];
2078 }
2079
2080 if ([attribute isEqualToString:_AXStartTextMarkerForTextMarkerRangeAttribute@"_AXStartTextMarkerForTextMarkerRange"]) {
2081 AXTextMarkerRange markerRange { markerRangeRef };
2082 return markerRange.start().platformData().bridgingAutorelease();
2083 }
2084
2085 if ([attribute isEqualToString:_AXEndTextMarkerForTextMarkerRangeAttribute@"_AXEndTextMarkerForTextMarkerRange"]) {
2086 AXTextMarkerRange markerRange { markerRangeRef };
2087 return markerRange.end().platformData().bridgingAutorelease();
2088 }
2089
2090 if ([attribute isEqualToString:_AXTextMarkerRangeForNSRangeAttribute@"_AXTextMarkerRangeForNSRange"])
2091 return backingObject->textMarkerRangeForNSRange(nsRange).platformData().bridgingAutorelease();
2092
2093 if ([attribute isEqualToString:_AXPageBoundsForTextMarkerRangeAttribute@"_AXPageBoundsForTextMarkerRange"]) {
2094 NSRect rect = CGRectZero;
2095 if (backingObject)
2096 rect = [self computeTextBoundsForRange:nsRange backingObject:*backingObject];
2097
2098 return [NSValue valueWithRect:rect];
2099 }
2100
2101 return nilnullptr;
2102}
2103
2104- (NSValue *)intersectionWithSelectionRange
2105{
2106 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
2107 if (!backingObject)
2108 return nilnullptr;
2109
2110 auto objectRange = backingObject->textMarkerRange();
2111 auto selectionRange = backingObject->selectedTextMarkerRange();
2112
2113 auto intersection = selectionRange.intersectionWith(objectRange);
2114 if (intersection.has_value()) {
2115 auto intersectionCharacterRange = intersection->characterRange();
2116 if (intersectionCharacterRange.has_value())
2117 return [NSValue valueWithRange:intersectionCharacterRange.value()];
2118 }
2119
2120 return nilnullptr;
2121}
2122
2123- (NSString *)accessibilityPlatformMathSubscriptKey
2124{
2125 return NSAccessibilityMathSubscriptAttribute@"AXMathSubscript";
2126}
2127
2128- (NSString *)accessibilityPlatformMathSuperscriptKey
2129{
2130 return NSAccessibilityMathSuperscriptAttribute@"AXMathSuperscript";
2131}
2132
2133- (id)accessibilityFocusedUIElement
2134{
2135 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
2136 if (!backingObject)
2137 return nilnullptr;
2138
2139 RefPtr focusedObject = backingObject->focusedUIElementInAnyLocalFrame();
2140 return focusedObject ? focusedObject->platformElement().autorelease() : nilnullptr;
2141}
2142
2143- (id)accessibilityHitTest:(NSPoint)point
2144{
2145 return [self _accessibilityHitTest:point returnPlatformElements:YES__objc_yes];
2146}
2147
2148- (id)_accessibilityHitTest:(NSPoint)point returnPlatformElements:(BOOL)returnPlatformElements
2149{
2150 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
2151 if (!backingObject)
2152 return nilnullptr;
2153
2154 if (RefPtr axObject = dynamicDowncast<AccessibilityObject>(backingObject))
2155 axObject->updateChildrenIfNecessary();
2156 RefPtr axObject = backingObject->accessibilityHitTest(IntPoint(point));
2157
2158 RetainPtr<id> hit = nilnullptr;
2159 if (axObject) {
2160 if (axObject->isAttachment()) {
2161 RetainPtr wrapper = axObject->wrapper();
2162 if (RetainPtr<id> attachmentView = [wrapper.get() attachmentView])
2163 return attachmentView.autorelease();
2164 } else if (axObject->isRemoteFrame()) {
2165 if (returnPlatformElements)
2166 return axObject->remoteFramePlatformElement().autorelease();
2167 } else if (axObject->isWidget()) {
2168 // Only call out to the main-thread if this object has a backing widget to query.
2169 hit = Accessibility::retrieveAutoreleasedValueFromMainThread<id>([axObject, &point] () -> RetainPtr<id> {
2170 RefPtr widget = axObject->widget();
2171 if (is<PluginViewBase>(widget))
2172 return widget->accessibilityHitTest(IntPoint(point));
2173 return nilnullptr;
2174 });
2175 }
2176
2177 if (!hit)
2178 hit = axObject->wrapper();
2179 } else
2180 hit = self;
2181
2182 return NSAccessibilityUnignoredAncestor(hit.get());
2183}
2184
2185- (void)_accessibilityHitTestResolvingRemoteFrame:(NSPoint)point callback:(void(^)(NSString *))callback
2186{
2187 if (!AXObjectCache::clientIsInTestMode()) {
2188 callback(@"");
2189 return;
2190 }
2191
2192 RetainPtr<id> hitTestResult = [self accessibilityHitTest:point];
2193 if (!hitTestResult) {
2194 callback(@"");
2195 return;
2196 }
2197
2198 if ([hitTestResult isKindOfClass:[NSAccessibilityRemoteUIElement class]]) {
2199 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
2200 if (!backingObject)
2201 return callback(@"no backing object");
2202
2203 RefPtr axObject = backingObject->accessibilityHitTest(IntPoint(point));
2204 if (axObject && axObject->isRemoteFrame()) {
2205 RefPtr page = backingObject ? backingObject->page() : nullptr;
2206 RefPtr axRemoteFrame = dynamicDowncast<AXRemoteFrame>(axObject);
2207 if (page && axRemoteFrame) {
2208 auto clientCallback = [callback = makeBlockPtr(callback)] (String result) {
2209 callback(nsStringNilIfEmpty(result).get());
2210 };
2211
2212 page->chrome().client().resolveAccessibilityHitTestForTesting(*axRemoteFrame->remoteFrameID(), IntPoint(point), WTF::move(clientCallback));
2213 }
2214 }
2215 } else {
2216 ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
2217 callback([hitTestResult accessibilityAttributeValue:NSAccessibilityInfoStringForTestingAttribute@"AXInfoStringForTesting"]);
2218 ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
2219 }
2220}
2221
2222ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-implementations"
2223- (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName
2224{
2225 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
2226 if (!backingObject)
2227 return NO__objc_no;
2228
2229 if ([attributeName isEqualToString:NSAccessibilitySelectedTextMarkerRangeAttribute@"AXSelectedTextMarkerRange"])
2230 return YES__objc_yes;
2231
2232 if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
2233 return backingObject->canSetFocusAttribute();
2234
2235 if ([attributeName isEqualToString: NSAccessibilityValueAttribute])
2236 return backingObject->canSetValueAttribute();
2237
2238 if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
2239 return backingObject->canSetSelectedAttribute();
2240
2241 if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute])
2242 return backingObject->canSetSelectedChildren();
2243
2244 if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute]
2245 || [attributeName isEqualToString:NSAccessibilityExpandedAttribute])
2246 return backingObject->canSetExpandedAttribute();
2247
2248 if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute])
2249 return YES__objc_yes;
2250
2251 if ([attributeName isEqualToString:NSAccessibilitySelectedTextAttribute]
2252 || [attributeName isEqualToString:NSAccessibilitySelectedTextRangeAttribute])
2253 return backingObject->canSetTextRangeAttributes();
2254
2255 if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute@"AXGrabbed"])
2256 return YES__objc_yes;
2257
2258 if (backingObject->isWebArea()
2259 && ([attributeName isEqualToString:NSAccessibilityPreventKeyboardDOMEventDispatchAttribute@"AXPreventKeyboardDOMEventDispatch"]
2260 || [attributeName isEqualToString:NSAccessibilityCaretBrowsingEnabledAttribute@"AXCaretBrowsingEnabled"]))
2261 return YES__objc_yes;
2262
2263 return NO__objc_no;
2264}
2265ALLOW_DEPRECATED_IMPLEMENTATIONS_ENDGCC diagnostic pop
2266
2267ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-implementations"
2268- (BOOL)accessibilityIsIgnored
2269{
2270 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
2271 if (!backingObject)
2272 return YES__objc_yes;
2273
2274 if (backingObject->isAttachment())
2275 return [[self attachmentView] accessibilityIsIgnored];
2276 return backingObject->isIgnored();
2277}
2278ALLOW_DEPRECATED_IMPLEMENTATIONS_ENDGCC diagnostic pop
2279
2280ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-implementations"
2281- (NSArray *)accessibilityParameterizedAttributeNames
2282{
2283 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
2284 if (!backingObject)
2285 return nilnullptr;
2286
2287#if !ENABLE_ACCESSIBILITY_LOCAL_FRAME0
2288 if (backingObject->isAttachment())
2289 return nilnullptr;
2290#endif // !ENABLE_ACCESSIBILITY_LOCAL_FRAME
2291
2292 static NeverDestroyed<RetainPtr<NSArray>> paramAttrs = @[
2293 NSAccessibilityUIElementForTextMarkerAttribute@"AXUIElementForTextMarker",
2294 NSAccessibilityTextMarkerRangeForUIElementAttribute@"AXTextMarkerRangeForUIElement",
2295 NSAccessibilityLineForTextMarkerAttribute@"AXLineForTextMarker",
2296 NSAccessibilityTextMarkerRangeForLineAttribute@"AXTextMarkerRangeForLine",
2297 NSAccessibilityStringForTextMarkerRangeAttribute@"AXStringForTextMarkerRange",
2298 NSAccessibilityTextMarkerForPositionAttribute@"AXTextMarkerForPosition",
2299 NSAccessibilityBoundsForTextMarkerRangeAttribute@"AXBoundsForTextMarkerRange",
2300 NSAccessibilityAttributedStringForTextMarkerRangeAttribute@"AXAttributedStringForTextMarkerRange",
2301 NSAccessibilityAttributedStringForTextMarkerRangeWithOptionsAttribute@"AXAttributedStringForTextMarkerRangeWithOptions",
2302 NSAccessibilityTextMarkerRangeForTextMarkersAttribute@"AXTextMarkerRangeForTextMarkers",
2303 NSAccessibilityTextMarkerRangeForUnorderedTextMarkersAttribute@"AXTextMarkerRangeForUnorderedTextMarkers",
2304 NSAccessibilityNextTextMarkerForTextMarkerAttribute@"AXNextTextMarkerForTextMarker",
2305 NSAccessibilityPreviousTextMarkerForTextMarkerAttribute@"AXPreviousTextMarkerForTextMarker",
2306 NSAccessibilityLeftWordTextMarkerRangeForTextMarkerAttribute@"AXLeftWordTextMarkerRangeForTextMarker",
2307 NSAccessibilityRightWordTextMarkerRangeForTextMarkerAttribute@"AXRightWordTextMarkerRangeForTextMarker",
2308 NSAccessibilityLeftLineTextMarkerRangeForTextMarkerAttribute@"AXLeftLineTextMarkerRangeForTextMarker",
2309 NSAccessibilityRightLineTextMarkerRangeForTextMarkerAttribute@"AXRightLineTextMarkerRangeForTextMarker",
2310 NSAccessibilitySentenceTextMarkerRangeForTextMarkerAttribute@"AXSentenceTextMarkerRangeForTextMarker",
2311 NSAccessibilityParagraphTextMarkerRangeForTextMarkerAttribute@"AXParagraphTextMarkerRangeForTextMarker",
2312 NSAccessibilityNextWordEndTextMarkerForTextMarkerAttribute@"AXNextWordEndTextMarkerForTextMarker",
2313 NSAccessibilityPreviousWordStartTextMarkerForTextMarkerAttribute@"AXPreviousWordStartTextMarkerForTextMarker",
2314 NSAccessibilityNextLineEndTextMarkerForTextMarkerAttribute@"AXNextLineEndTextMarkerForTextMarker",
2315 NSAccessibilityPreviousLineStartTextMarkerForTextMarkerAttribute@"AXPreviousLineStartTextMarkerForTextMarker",
2316 NSAccessibilityNextSentenceEndTextMarkerForTextMarkerAttribute@"AXNextSentenceEndTextMarkerForTextMarker",
2317 NSAccessibilityPreviousSentenceStartTextMarkerForTextMarkerAttribute@"AXPreviousSentenceStartTextMarkerForTextMarker",
2318 NSAccessibilityNextParagraphEndTextMarkerForTextMarkerAttribute@"AXNextParagraphEndTextMarkerForTextMarker",
2319 NSAccessibilityPreviousParagraphStartTextMarkerForTextMarkerAttribute@"AXPreviousParagraphStartTextMarkerForTextMarker",
2320 NSAccessibilityStyleTextMarkerRangeForTextMarkerAttribute@"AXStyleTextMarkerRangeForTextMarker",
2321 NSAccessibilityLengthForTextMarkerRangeAttribute@"AXLengthForTextMarkerRange",
2322 NSAccessibilityBoundsForRangeParameterizedAttribute,
2323 NSAccessibilityStringForRangeParameterizedAttribute,
2324 NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute@"AXUIElementsForSearchPredicate",
2325 NSAccessibilityEndTextMarkerForBoundsAttribute@"AXEndTextMarkerForBounds",
2326 NSAccessibilityStartTextMarkerForBoundsAttribute@"AXStartTextMarkerForBounds",
2327 NSAccessibilityLineTextMarkerRangeForTextMarkerAttribute@"AXLineTextMarkerRangeForTextMarker",
2328 NSAccessibilitySelectTextWithCriteriaParameterizedAttribute@"AXSelectTextWithCriteria",
2329 NSAccessibilitySearchTextWithCriteriaParameterizedAttribute@"AXSearchTextWithCriteria",
2330 NSAccessibilityTextOperationParameterizedAttribute@"AXTextOperation"
2331 ];
2332
2333 static NeverDestroyed textParamAttrs = [] {
2334 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:paramAttrs.get().get()]);
2335 [tempArray addObject:(NSString*)kAXLineForIndexParameterizedAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXLineForIndex"
""))
];
2336 [tempArray addObject:(NSString*)kAXRangeForLineParameterizedAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXRangeForLine"
""))
];
2337 [tempArray addObject:(NSString*)kAXStringForRangeParameterizedAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXStringForRange"
""))
];
2338 [tempArray addObject:(NSString*)kAXRangeForPositionParameterizedAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXRangeForPosition"
""))
];
2339 [tempArray addObject:(NSString*)kAXRangeForIndexParameterizedAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXRangeForIndex"
""))
];
2340 [tempArray addObject:(NSString*)kAXBoundsForRangeParameterizedAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXBoundsForRange"
""))
];
2341 [tempArray addObject:(NSString*)kAXRTFForRangeParameterizedAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXRTFForRange"
""))
];
2342 [tempArray addObject:(NSString*)kAXAttributedStringForRangeParameterizedAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXAttributedStringForRange"
""))
];
2343 [tempArray addObject:(NSString*)kAXStyleRangeForIndexParameterizedAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXStyleRangeForIndex"
""))
];
2344 return tempArray;
2345 }();
2346 static NeverDestroyed tableParamAttrs = [] {
2347 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:paramAttrs.get().get()]);
2348 [tempArray addObject:NSAccessibilityCellForColumnAndRowParameterizedAttribute];
2349 return tempArray;
2350 }();
2351 static NeverDestroyed webAreaParamAttrs = [] {
2352 auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:paramAttrs.get().get()]);
2353 [tempArray addObject:NSAccessibilityTextMarkerForIndexAttribute@"AXTextMarkerForIndex"];
2354 [tempArray addObject:NSAccessibilityTextMarkerIsValidAttribute@"AXTextMarkerIsValid"];
2355 [tempArray addObject:NSAccessibilityIndexForTextMarkerAttribute@"AXIndexForTextMarker"];
2356 return tempArray;
2357 }();
2358 static NeverDestroyed secureFieldParamAttrs = [] {
2359 auto tempArray = adoptNS([[NSMutableArray alloc] init]);
2360 [tempArray addObject:NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute@"AXUIElementsForSearchPredicate"];
2361 return tempArray;
2362 }();
2363
2364 if (backingObject->isSecureField())
2365 return secureFieldParamAttrs.get().get();
2366
2367 if (backingObject->isTextControl())
2368 return textParamAttrs.get().get();
2369
2370 if (backingObject->isExposableTable())
2371 return tableParamAttrs.get().get();
2372
2373 if (backingObject->isWebArea())
2374 return webAreaParamAttrs.get().get();
2375
2376 // The object that serves up the remote frame also is the one that does the frame conversion.
2377 if (backingObject->hasRemoteFrameChild())
2378 return [paramAttrs.get().get() arrayByAddingObject:NSAccessibilityConvertRelativeFrameParameterizedAttribute@"AXConvertRelativeFrame"];
2379
2380 return paramAttrs.get().get();
2381}
2382ALLOW_DEPRECATED_IMPLEMENTATIONS_ENDGCC diagnostic pop
2383
2384ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
2385
2386- (NSString *)accessibilityIdentifier
2387{
2388 if (AXObjectCache::accessibilityDOMIdentifiersEnabled()) {
2389 if (RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore)
2390 return backingObject->identifierAttribute().createNSString().autorelease();
2391 }
2392
2393 return nilnullptr;
2394}
2395
2396- (void)accessibilityPerformPressAction
2397{
2398 // In case anything we do by performing the press action causes an alert or other modal
2399 // behaviors, we need to return now, so that VoiceOver doesn't hang indefinitely.
2400 RunLoop::mainSingleton().dispatch([protectedSelf = retainPtr(self)] {
2401 [protectedSelf _accessibilityPerformPressAction];
2402 });
2403}
2404
2405- (void)_accessibilityPerformPressAction
2406{
2407 AX_ASSERT(isMainThread())((void)0);
2408 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
2409 if (!backingObject)
2410 return;
2411
2412 if (backingObject->isAttachment())
2413 [[self attachmentView] accessibilityPerformAction:NSAccessibilityPressAction];
2414 else
2415 backingObject->press();
2416}
2417
2418- (void)accessibilityPerformIncrementAction
2419{
2420 RunLoop::mainSingleton().dispatch([protectedSelf = retainPtr(self)] {
2421 [protectedSelf _accessibilityPerformIncrementAction];
2422 });
2423}
2424
2425- (void)_accessibilityPerformIncrementAction
2426{
2427 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
2428 if (!backingObject)
2429 return;
2430
2431 if (backingObject->isAttachment())
2432 [[self attachmentView] accessibilityPerformAction:NSAccessibilityIncrementAction];
2433 else
2434 backingObject->increment();
2435}
2436
2437- (void)accessibilityPerformDecrementAction
2438{
2439 RunLoop::mainSingleton().dispatch([protectedSelf = retainPtr(self)] {
2440 [protectedSelf _accessibilityPerformDecrementAction];
2441 });
2442}
2443
2444- (void)_accessibilityPerformDecrementAction
2445{
2446 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
2447 if (!backingObject)
2448 return;
2449
2450 if (backingObject->isAttachment())
2451 [[self attachmentView] accessibilityPerformAction:NSAccessibilityDecrementAction];
2452 else
2453 backingObject->decrement();
2454}
2455
2456ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
2457
2458- (void)accessibilityPerformShowMenuAction
2459{
2460 AXTRACE("WebAccessibilityObjectWrapper accessibilityPerformShowMenuAction"_s)(void)0;
2461
2462 RefPtr<AXCoreObject> backingObject = self.axBackingObject;
2463 if (!backingObject) {
2464 AXLOG(makeString("No backingObject for wrapper "_s, hex(reinterpret_cast<uintptr_t>(self))))(void)0;
2465 return;
2466 }
2467
2468 if (backingObject->role() == AccessibilityRole::ComboBox) {
2469 backingObject->setIsExpanded(true);
2470 return;
2471 }
2472
2473 Accessibility::performFunctionOnMainThread([protectedSelf = retainPtr(self)] {
2474 // This needs to be performed in an iteration of the run loop that did not start from an AX call.
2475 // If it's the same run loop iteration, the menu open notification won't be sent.
2476 [protectedSelf performSelector:@selector(_accessibilityShowContextMenu) withObject:nilnullptr afterDelay:0.0];
2477 });
2478}
2479
2480- (void)_accessibilityShowContextMenu
2481{
2482 AXTRACE("WebAccessibilityObjectWrapper _accessibilityShowContextMenu"_s)(void)0;
2483 AX_ASSERT(isMainThread())((void)0);
2484
2485 RefPtr<AccessibilityObject> backingObject = dynamicDowncast<AccessibilityObject>(self.axBackingObject);
2486 if (!backingObject) {
2487 AXLOG(makeString("No backingObject for wrapper "_s, hex(reinterpret_cast<uintptr_t>(self))))(void)0;
2488 return;
2489 }
2490
2491 RefPtr page = backingObject->page();
2492 if (!page)
2493 return;
2494
2495 IntRect rect = snappedIntRect(backingObject->elementRect());
2496 // On WK2, we need to account for the scroll position with regards to root view.
2497 // On WK1, we need to convert rect to window space to match mouse clicking.
2498 RefPtr frameView = backingObject->documentFrameView();
2499 if (frameView) {
2500 // Find the appropriate scroll view to convert the coordinates to window space.
2501 RefPtr axScrollView = Accessibility::findAncestor(*backingObject, false, [] (const auto& ancestor) {
2502 return ancestor.isScrollArea() && ancestor.scrollView();
2503 });
2504
2505 if (RefPtr scrollView = axScrollView ? axScrollView->scrollView() : nullptr) {
2506 if (!frameView->platformWidget())
2507 rect = scrollView->contentsToRootView(rect);
2508 else
2509 rect = scrollView->contentsToWindow(rect);
2510 }
2511 }
2512
2513 if (RefPtr localMainFrame = page->localMainFrame())
2514 page->contextMenuController().showContextMenuAt(*localMainFrame, rect.center());
2515}
2516
2517- (void)accessibilityScrollToVisible
2518{
2519 if (RefPtr<AXCoreObject> backingObject = self.axBackingObject)
2520 backingObject->scrollToMakeVisible();
2521}
2522
2523- (void)_accessibilityScrollToMakeVisibleWithSubFocus:(NSRect)rect
2524{
2525 if (RefPtr<AXCoreObject> backingObject = self.axBackingObject)
2526 backingObject->scrollToMakeVisibleWithSubFocus(IntRect(rect));
2527}
2528
2529- (void)_accessibilityScrollToGlobalPoint:(NSPoint)point
2530{
2531 if (RefPtr<AXCoreObject> backingObject = self.axBackingObject)
2532 backingObject->scrollToGlobalPoint(IntPoint(point));
2533}
2534
2535ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-implementations"
2536- (void)accessibilityPerformAction:(NSString*)action
2537{
2538 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
2539 if (!backingObject)
2540 return;
2541
2542 if ([action isEqualToString:NSAccessibilityPressAction])
2543 [self accessibilityPerformPressAction];
2544 else if ([action isEqualToString:NSAccessibilitySyncPressAction@"AXSyncPressAction"]) {
2545 // Used in layout tests, so that we don't have to wait for the async press action.
2546 [self _accessibilityPerformPressAction];
2547 } else if ([action isEqualToString:NSAccessibilitySyncIncrementAction@"AXSyncIncrementAction"])
2548 [self _accessibilityPerformIncrementAction];
2549 else if ([action isEqualToString:NSAccessibilitySyncDecrementAction@"AXSyncDecrementAction"])
2550 [self _accessibilityPerformDecrementAction];
2551 else if ([action isEqualToString:NSAccessibilityShowMenuAction])
2552 [self accessibilityPerformShowMenuAction];
2553 else if ([action isEqualToString:NSAccessibilityIncrementAction])
2554 [self accessibilityPerformIncrementAction];
2555 else if ([action isEqualToString:NSAccessibilityDecrementAction])
2556 [self accessibilityPerformDecrementAction];
2557 else if ([action isEqualToString:NSAccessibilityScrollToVisibleAction@"AXScrollToVisible"])
2558 [self accessibilityScrollToVisible];
2559 else if ([action isEqualToString:NSAccessibilityDismissAction@"AXDismissAction"])
2560 backingObject->performDismissActionIgnoringResult();
2561 else if (AXObjectCache::clientIsInTestMode() && [action isEqualToString:@"AXLogTrees"])
2562 [self _accessibilityPrintTrees];
2563}
2564ALLOW_DEPRECATED_IMPLEMENTATIONS_ENDGCC diagnostic pop
2565
2566// Internal method to print the accessibility trees to standard error.
2567- (void)_accessibilityPrintTrees
2568{
2569 Accessibility::performFunctionOnMainThread([protectedSelf = retainPtr(self)] {
2570 RefPtr backingObject = downcast<AccessibilityObject>(protectedSelf.get().axBackingObject);
2571 if (!backingObject)
2572 return;
2573
2574 CheckedPtr cache = backingObject->axObjectCache();
2575 if (!cache)
2576 return;
2577
2578 AXTreeData data = cache->treeData({ { AXStreamOptions::IdentifierAttribute, AXStreamOptions::OuterHTML, AXStreamOptions::RendererOrNode } }); // Can specify AXStreamOptions here if needed (e.g., TextRuns)
2579
2580 data.dumpToStderr();
2581 });
2582}
2583
2584- (BOOL)accessibilityReplaceRange:(NSRange)range withText:(NSString *)string
2585{
2586 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
2587 return backingObject ? backingObject->replaceTextInRange(String(string), range) : NO__objc_no;
2588}
2589
2590- (BOOL)accessibilityInsertText:(NSString *)text
2591{
2592 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
2593 return backingObject ? backingObject->insertText(String(text)) : NO__objc_no;
2594}
2595
2596ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-implementations"
2597- (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName
2598{
2599#if PLATFORM(MAC)(defined 1 && 1)
2600
2601 RetainPtr retainedValue = value;
2602 if (AXObjectCache::useAXThreadTextApis()) {
2603 if (AXObjectIsTextMarkerRange(value))
2604 retainedValue = AXTextMarkerRange { (AXTextMarkerRangeRef)value }.convertToDomOffsetRange().platformData().bridgingAutorelease();
2605 }
2606
2607 // In case anything we do by changing values causes an alert or other modal
2608 // behaviors, we need to return now, so that VoiceOver doesn't hang indefinitely.
2609 callOnMainThread([retainedValue = WTF::move(retainedValue), attributeName = retainPtr(attributeName), protectedSelf = retainPtr(self)] {
2610 [protectedSelf _accessibilitySetValue:retainedValue.get() forAttribute:attributeName.get()];
2611 });
2612#else
2613 // dispatch_async on earlier versions can cause focus not to track.
2614 [self _accessibilitySetValue:value forAttribute:attributeName];
2615#endif // PLATFORM(MAC)
2616}
2617ALLOW_DEPRECATED_IMPLEMENTATIONS_ENDGCC diagnostic pop
2618
2619- (void)_accessibilitySetValue:(id)value forAttribute:(NSString *)attributeName
2620{
2621 AXTRACE(makeString("WebAccessibilityObjectWrapper _accessibilitySetValue: forAttribute:"_s, String(attributeName)))(void)0;
2622
2623 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
2624 if (!backingObject) {
2625 AXLOG(makeString("No backingObject for wrapper "_s, hex(reinterpret_cast<uintptr_t>(self))))(void)0;
2626 return;
2627 }
2628
2629 AXTextMarkerRangeRef textMarkerRange = nilnullptr;
2630 NSNumber* number = nilnullptr;
2631 NSString* string = nilnullptr;
2632 NSRange range = { 0, 0 };
2633 NSArray* array = nilnullptr;
2634
2635 // decode the parameter
2636 if (AXObjectIsTextMarkerRange(value))
2637 textMarkerRange = (AXTextMarkerRangeRef)value;
2638 else if ([value isKindOfClass:[NSNumber class]])
2639 number = value;
2640 else if ([value isKindOfClass:[NSString class]])
2641 string = value;
2642 else if ([value isKindOfClass:[NSValue class]])
2643 range = [value rangeValue];
2644 else if ([value isKindOfClass:[NSArray class]])
2645 array = value;
2646
2647 // handle the command
2648 if ([attributeName isEqualToString:NSAccessibilitySelectedTextMarkerRangeAttribute@"AXSelectedTextMarkerRange"]) {
2649 AX_ASSERT(textMarkerRange)((void)0);
2650 Accessibility::performFunctionOnMainThread([textMarkerRange = retainPtr(textMarkerRange), protectedSelf = retainPtr(self)] {
2651 if (RefPtr<AXCoreObject> backingObject = protectedSelf.get().axBackingObject)
2652 backingObject->setSelectedVisiblePositionRange(AXTextMarkerRange { textMarkerRange.get() });
2653 });
2654 } else if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) {
2655 backingObject->setFocused([number boolValue]);
2656 } else if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
2657 if (number && backingObject->canSetNumericValue())
2658 backingObject->setValueIgnoringResult([number floatValue]);
2659 else if (string)
2660 backingObject->setValueIgnoringResult(string);
2661 } else if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) {
2662 if (!number)
2663 return;
2664 backingObject->setSelected([number boolValue]);
2665 } else if ([attributeName isEqualToString:NSAccessibilitySelectedChildrenAttribute]) {
2666 if (!array || !backingObject->canSetSelectedChildren())
2667 return;
2668
2669 AXCoreObject::AccessibilityChildrenVector selectedChildren;
2670 convertToVector(array, selectedChildren);
2671 backingObject->setSelectedChildren(selectedChildren);
2672 } else if (backingObject->isTextControl()) {
2673 if ([attributeName isEqualToString:NSAccessibilitySelectedTextAttribute])
2674 backingObject->setSelectedText(string);
2675 else if ([attributeName isEqualToString:NSAccessibilitySelectedTextRangeAttribute])
2676 backingObject->setSelectedTextRange(range);
2677 } else if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute] || [attributeName isEqualToString:NSAccessibilityExpandedAttribute])
2678 backingObject->setIsExpanded([number boolValue]);
2679 else if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
2680 AccessibilityObject::AccessibilityChildrenVector selectedRows;
2681 convertToVector(array, selectedRows);
2682 if (backingObject->isTree() || backingObject->isExposableTable())
2683 backingObject->setSelectedRows(WTF::move(selectedRows));
2684 } else if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute@"AXGrabbed"])
2685 backingObject->setARIAGrabbed([number boolValue]);
2686 else if (backingObject->isWebArea() && [attributeName isEqualToString:NSAccessibilityPreventKeyboardDOMEventDispatchAttribute@"AXPreventKeyboardDOMEventDispatch"])
2687 backingObject->setPreventKeyboardDOMEventDispatch([number boolValue]);
2688 else if (backingObject->isWebArea() && [attributeName isEqualToString:NSAccessibilityCaretBrowsingEnabledAttribute@"AXCaretBrowsingEnabled"])
2689 backingObject->setCaretBrowsingEnabled([number boolValue]);
2690}
2691
2692static RenderObject* rendererForView(NSView* view)
2693{
2694 if (![view conformsToProtocol:@protocol(WebCoreFrameView)])
2695 return nullptr;
2696
2697 NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
2698 auto frame = [frameView _web_frame];
2699 if (!frame)
2700 return nullptr;
2701
2702 RefPtr<Node> node = protect(frame->document())->ownerElement();
2703 if (!node)
2704 return nullptr;
2705
2706 return node->renderer();
2707}
2708
2709- (id)_accessibilityParentForSubview:(NSView*)subview
2710{
2711 CheckedPtr renderer = rendererForView(subview);
2712 if (!renderer)
2713 return nilnullptr;
2714
2715 CheckedPtr cache = protect(renderer->document())->axObjectCache();
2716 RefPtr object = cache ? cache->getOrCreate(*renderer) : nilnullptr;
2717 RefPtr parent = object ? object->parentObjectUnignored() : nilnullptr;
2718 return parent ? parent->wrapper() : nilnullptr;
2719}
2720
2721ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-implementations"
2722- (NSString*)accessibilityActionDescription:(NSString*)action
2723{
2724 // we have no custom actions
2725 return NSAccessibilityActionDescription(action);
2726}
2727ALLOW_DEPRECATED_IMPLEMENTATIONS_ENDGCC diagnostic pop
2728
2729- (AXTextMarkerRef)_textMarkerForIndex:(NSInteger)textIndex
2730{
2731 return Accessibility::retrieveAutoreleasedValueFromMainThread<AXTextMarkerRef>([&textIndex, protectedSelf = retainPtr(self)] () -> RetainPtr<AXTextMarkerRef> {
2732 RefPtr backingObject = downcast<AccessibilityObject>(protectedSelf.get().axBackingObject);
2733 if (!backingObject)
2734 return nilnullptr;
2735
2736 CheckedPtr cache = backingObject->axObjectCache();
2737 if (!cache)
2738 return nilnullptr;
2739
2740 RefPtr document = backingObject->document();
2741 if (!document)
2742 return nilnullptr;
2743
2744 RefPtr documentElement = document->documentElement();
2745 if (!documentElement)
2746 return nilnullptr;
2747
2748 auto boundary = resolveCharacterLocation(makeRangeSelectingNodeContents(*documentElement), textIndex);
2749 auto characterOffset = cache->startOrEndCharacterOffsetForRange(makeSimpleRange(boundary), true);
2750
2751 return textMarkerForCharacterOffset(cache.get(), characterOffset);
2752 });
2753}
2754
2755#if ENABLE(TREE_DEBUGGING)(defined ENABLE_TREE_DEBUGGING && ENABLE_TREE_DEBUGGING
)
2756- (void)showNodeForTextMarker:(AXTextMarkerRef)textMarker
2757{
2758 CheckedPtr cache = downcast<AccessibilityObject>(self.axBackingObject)->axObjectCache();
2759 auto visiblePosition = visiblePositionForTextMarker(cache.get(), textMarker);
2760 RefPtr node = visiblePosition.deepEquivalent().deprecatedNode();
2761 if (!node)
2762 return;
2763 node->showNode();
2764 node->showNodePathForThis();
2765}
2766
2767- (void)showNodeTreeForTextMarker:(AXTextMarkerRef)textMarker
2768{
2769 CheckedPtr cache = downcast<AccessibilityObject>(self.axBackingObject)->axObjectCache();
2770 auto visiblePosition = visiblePositionForTextMarker(cache.get(), textMarker);
2771 RefPtr node = visiblePosition.deepEquivalent().deprecatedNode();
2772 if (!node)
2773 return;
2774 node->showTreeForThis();
2775}
2776#endif
2777
2778enum class TextUnit {
2779 LeftWord = 1,
2780 RightWord,
2781 NextWordEnd,
2782 PreviousWordStart,
2783 Sentence,
2784 NextSentenceEnd,
2785 PreviousSentenceStart,
2786 Paragraph,
2787 NextParagraphEnd,
2788 PreviousParagraphStart,
2789 Line,
2790 LeftLine,
2791 RightLine,
2792 NextLineEnd,
2793 PreviousLineStart,
2794};
2795
2796- (AXTextMarkerRangeRef)textMarkerRangeAtTextMarker:(AXTextMarkerRef)textMarker forUnit:(TextUnit)textUnit
2797{
2798 if (AXObjectCache::useAXThreadTextApis()) {
2799 AXTextMarker inputMarker { textMarker };
2800 switch (textUnit) {
2801 case TextUnit::LeftWord:
2802 return inputMarker.wordRange(WordRangeType::Left).platformData().autorelease();
2803 case TextUnit::RightWord:
2804 return inputMarker.wordRange(WordRangeType::Right).platformData().autorelease();
2805 case TextUnit::Sentence:
2806 return inputMarker.sentenceRange(SentenceRangeType::Current).platformData().autorelease();
2807 case TextUnit::Paragraph:
2808 return inputMarker.paragraphRange().platformData().autorelease();
2809 default:
2810 AX_ASSERT_NOT_REACHED()((void)0);
2811 return nilnullptr;
2812 }
2813 }
2814 return Accessibility::retrieveAutoreleasedValueFromMainThread<AXTextMarkerRangeRef>([textMarker = retainPtr(textMarker), &textUnit, protectedSelf = retainPtr(self)] () -> RetainPtr<AXTextMarkerRangeRef> {
2815 RefPtr backingObject = downcast<AccessibilityObject>(protectedSelf.get().axBackingObject);
2816 if (!backingObject)
2817 return nilnullptr;
2818
2819 CheckedPtr cache = backingObject->axObjectCache();
2820 if (!cache)
2821 return nilnullptr;
2822
2823 AXTextMarker marker { textMarker.get() };
2824 std::optional<SimpleRange> range;
2825 switch (textUnit) {
2826 case TextUnit::LeftWord:
2827 range = cache->leftWordRange(marker);
2828 break;
2829 case TextUnit::RightWord:
2830 range = cache->rightWordRange(marker);
2831 break;
2832 case TextUnit::Sentence:
2833 range = cache->sentenceForCharacterOffset(marker);
2834 break;
2835 case TextUnit::Paragraph:
2836 range = cache->paragraphForCharacterOffset(marker);
2837 break;
2838 default:
2839 AX_ASSERT_NOT_REACHED()((void)0);
2840 break;
2841 }
2842
2843 return textMarkerRangeFromRange(cache.get(), range);
2844 });
2845}
2846
2847- (id)lineTextMarkerRangeForTextMarker:(AXTextMarkerRef)textMarker forUnit:(TextUnit)textUnit
2848{
2849 if (AXObjectCache::useAXThreadTextApis()) {
2850 auto rangeType = LineRangeType::Current;
2851 switch (textUnit) {
2852 case TextUnit::Line:
2853 break;
2854 case TextUnit::LeftLine:
2855 rangeType = LineRangeType::Left;
2856 break;
2857 case TextUnit::RightLine:
2858 rangeType = LineRangeType::Right;
2859 break;
2860 default:
2861 AX_ASSERT_NOT_REACHED()((void)0);
2862 break;
2863 }
2864 return AXTextMarker { textMarker }.lineRange(rangeType).platformData().bridgingAutorelease();
2865 }
2866
2867 return (id)Accessibility::retrieveAutoreleasedValueFromMainThread<AXTextMarkerRangeRef>([textMarker = retainPtr(textMarker), &textUnit, protectedSelf = retainPtr(self)] () -> RetainPtr<AXTextMarkerRangeRef> {
2868 RefPtr<AXCoreObject> backingObject = protectedSelf.get().axBackingObject;
2869 if (!backingObject)
2870 return nilnullptr;
2871
2872 AXTextMarker marker { textMarker.get() };
2873 VisiblePositionRange visiblePositionRange;
2874 switch (textUnit) {
2875 case TextUnit::Line:
2876 visiblePositionRange = backingObject->lineRangeForPosition(marker);
2877 break;
2878 case TextUnit::LeftLine:
2879 visiblePositionRange = backingObject->leftLineVisiblePositionRange(marker);
2880 break;
2881 case TextUnit::RightLine:
2882 visiblePositionRange = backingObject->rightLineVisiblePositionRange(marker);
2883 break;
2884 default:
2885 AX_ASSERT_NOT_REACHED()((void)0);
2886 break;
2887 }
2888
2889 return AXTextMarkerRange(visiblePositionRange).platformData();
2890 });
2891}
2892
2893- (AXTextMarkerRef)textMarkerForTextMarker:(AXTextMarkerRef)textMarkerRef atUnit:(TextUnit)textUnit
2894{
2895 if (AXObjectCache::useAXThreadTextApis()) {
2896 AXTextMarker inputMarker { textMarkerRef };
2897 switch (textUnit) {
2898 case TextUnit::NextSentenceEnd:
2899 return inputMarker.nextSentenceEnd().platformData().autorelease();
2900 case TextUnit::PreviousSentenceStart:
2901 return inputMarker.previousSentenceStart().platformData().autorelease();
2902 case TextUnit::NextParagraphEnd:
2903 return inputMarker.nextParagraphEnd().platformData().autorelease();
2904 case TextUnit::PreviousParagraphStart:
2905 return inputMarker.previousParagraphStart().platformData().autorelease();
2906 case TextUnit::NextWordEnd:
2907 return inputMarker.nextWordEnd().platformData().autorelease();
2908 case TextUnit::PreviousWordStart:
2909 return inputMarker.previousWordStart().platformData().autorelease();
2910 default:
2911 // TODO: Not implemented!
2912 break;
2913 }
2914 }
2915 return Accessibility::retrieveAutoreleasedValueFromMainThread<AXTextMarkerRef>([textMarkerRef = retainPtr(textMarkerRef), &textUnit, protectedSelf = retainPtr(self)] () -> RetainPtr<AXTextMarkerRef> {
2916 RefPtr backingObject = downcast<AccessibilityObject>(protectedSelf.get().axBackingObject);
2917 if (!backingObject)
2918 return nilnullptr;
2919
2920 CheckedPtr cache = backingObject->axObjectCache();
2921 if (!cache)
2922 return nilnullptr;
2923
2924 AXTextMarker oldMarker { textMarkerRef.get() };
2925 AXTextMarker newMarker;
2926 switch (textUnit) {
2927 case TextUnit::NextWordEnd:
2928 newMarker = cache->nextWordEndCharacterOffset(oldMarker);
2929 break;
2930 case TextUnit::PreviousWordStart:
2931 newMarker = cache->previousWordStartCharacterOffset(oldMarker);
2932 break;
2933 case TextUnit::NextSentenceEnd:
2934 newMarker = cache->nextSentenceEndCharacterOffset(oldMarker);
2935 break;
2936 case TextUnit::PreviousSentenceStart:
2937 newMarker = cache->previousSentenceStartCharacterOffset(oldMarker);
2938 break;
2939 case TextUnit::NextParagraphEnd:
2940 newMarker = cache->nextParagraphEndCharacterOffset(oldMarker);
2941 break;
2942 case TextUnit::PreviousParagraphStart:
2943 newMarker = cache->previousParagraphStartCharacterOffset(oldMarker);
2944 break;
2945 case TextUnit::NextLineEnd:
2946 return textMarkerForVisiblePosition(cache.get(), backingObject->nextLineEndPosition(oldMarker));
2947 case TextUnit::PreviousLineStart:
2948 return textMarkerForVisiblePosition(cache.get(), backingObject->previousLineStartPosition(oldMarker));
2949 default:
2950 AX_ASSERT_NOT_REACHED()((void)0);
2951 break;
2952 }
2953
2954 return newMarker.platformData();
2955 });
2956}
2957
2958static bool isMatchingPlugin(AXCoreObject& axObject, const AccessibilitySearchCriteria& criteria)
2959{
2960 if (!axObject.isPlugin())
2961 return false;
2962
2963 return criteria.searchKeys.contains(AccessibilitySearchKey::AnyType)
2964 && (!criteria.visibleOnly || axObject.isVisible());
2965}
2966
2967- (NSRect)computeTextBoundsForRange:(NSRange)range backingObject:(const AXCoreObject&)backingObject
2968{
2969 if (!isMainThread()) {
2970 std::optional markerRange = Accessibility::markerRangeFrom(range, backingObject);
2971 return markerRange ? static_cast<CGRect>(markerRange->viewportRelativeFrame()) : CGRectZero;
2972 }
2973
2974 auto start = backingObject.visiblePositionForIndex(range.location);
2975 auto end = backingObject.visiblePositionForIndex(range.location + range.length);
2976 auto webRange = makeSimpleRange({ start, end });
2977 if (!webRange)
2978 return CGRectZero;
2979
2980 return FloatRect(backingObject.boundsForRange(*webRange));
2981}
2982
2983ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-implementations"
2984- (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter
2985{
2986 AXTRACE(makeString("WebAccessibilityObjectWrapper accessibilityAttributeValue:"_s, String(attribute)))(void)0;
2987 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
2988 if (!backingObject)
2989 return nilnullptr;
2990
2991 // Basic parameter validation.
2992 if (!attribute || !parameter)
2993 return nilnullptr;
2994
2995 AXTextMarkerRef textMarker = nilnullptr;
2996 AXTextMarkerRangeRef textMarkerRange = nilnullptr;
2997 NSNumber *number = nilnullptr;
2998 NSArray *array = nilnullptr;
2999 NSDictionary *dictionary = nilnullptr;
3000 RefPtr<AXCoreObject> uiElement;
3001 NSPoint point = NSZeroPoint;
3002 bool pointSet = false;
3003 NSRange range = { 0, 0 };
3004 bool rangeSet = false;
3005 NSRect rect = NSZeroRect;
3006
3007 // common parameter type check/casting. Nil checks in handlers catch wrong type case.
3008 // NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from
3009 // a parameter of the wrong type.
3010 if (AXObjectIsTextMarker(parameter))
3011 textMarker = (AXTextMarkerRef)parameter;
3012 else if (AXObjectIsTextMarkerRange(parameter))
3013 textMarkerRange = (AXTextMarkerRangeRef)parameter;
3014 else if ([parameter isKindOfClass:[WebAccessibilityObjectWrapper class]]) {
3015 uiElement = [(WebAccessibilityObjectWrapper*)parameter axBackingObject];
3016 // The parameter wrapper object has lost its AX object since being given to the client, so bail early.
3017 if (!uiElement)
3018 return nilnullptr;
3019 } else if ([parameter isKindOfClass:[NSNumber class]])
3020 number = parameter;
3021 else if ([parameter isKindOfClass:[NSArray class]])
3022 array = parameter;
3023 else if ([parameter isKindOfClass:[NSDictionary class]])
3024 dictionary = parameter;
3025 else if ([parameter isKindOfClass:[NSValue class]] && nsValueHasObjCType<NSPoint>((NSValue*)parameter)) {
3026 pointSet = true;
3027 point = [(NSValue*)parameter pointValue];
3028 } else if ([parameter isKindOfClass:[NSValue class]] && nsValueHasObjCType<NSRange>((NSValue*)parameter)) {
3029 rangeSet = true;
3030 range = [(NSValue*)parameter rangeValue];
3031 } else if ([parameter isKindOfClass:[NSValue class]] && nsValueHasObjCType<NSRect>((NSValue*)parameter))
3032 rect = [(NSValue*)parameter rectValue];
3033 else {
3034 // Attribute type is not supported. Allow super to handle.
3035 return [super accessibilityAttributeValue:attribute forParameter:parameter];
3036 }
3037
3038 // dispatch
3039 if ([attribute isEqualToString:NSAccessibilitySelectTextWithCriteriaParameterizedAttribute@"AXSelectTextWithCriteria"]) {
3040 // To be deprecated.
3041 auto result = Accessibility::retrieveValueFromMainThread<Vector<String>>([protectedDictionary = retainPtr(dictionary), protectedSelf = retainPtr(self)] () -> Vector<String> {
3042 RefPtr<AXCoreObject> backingObject = protectedSelf.get().axBackingObject;
3043 if (!backingObject)
3044 return Vector<String>();
3045
3046 auto criteria = accessibilityTextCriteriaForParameterizedAttribute(protectedDictionary.get());
3047 criteria.second.textRanges = backingObject->findTextRanges(criteria.first);
3048 AX_ASSERT(criteria.second.textRanges.size() <= 1)((void)0);
3049 return backingObject->performTextOperation(criteria.second);
3050 });
3051 AX_ASSERT(result.size() <= 1)((void)0);
3052 if (result.size() > 0)
3053 return result[0].createNSString().autorelease();
3054 return @"";
3055 }
3056
3057 if ([attribute isEqualToString:NSAccessibilitySearchTextWithCriteriaParameterizedAttribute@"AXSearchTextWithCriteria"]) {
3058 auto criteria = accessibilitySearchTextCriteriaForParameterizedAttribute(dictionary);
3059 return Accessibility::retrieveAutoreleasedValueFromMainThread<NSArray *>([&criteria, protectedSelf = retainPtr(self)] () -> RetainPtr<NSArray> {
3060 RefPtr backingObject = downcast<AccessibilityObject>(protectedSelf.get().axBackingObject);
3061 if (!backingObject)
3062 return nilnullptr;
3063 auto ranges = backingObject->findTextRanges(criteria);
3064 if (ranges.isEmpty())
3065 return nilnullptr;
3066 CheckedPtr cache = backingObject->axObjectCache();
3067 return createNSArray(WTF::move(ranges), [&] (SimpleRange&& range) {
3068 return (id)textMarkerRangeFromRange(cache.get(), WTF::move(range));
3069 }).autorelease();
3070 });
3071 }
3072
3073 if ([attribute isEqualToString:NSAccessibilityTextOperationParameterizedAttribute@"AXTextOperation"]) {
3074 auto operationResult = Accessibility::retrieveValueFromMainThread<Vector<String>>([protectedDictionary = retainPtr(dictionary), protectedSelf = retainPtr(self)] () -> Vector<String> {
3075 RefPtr backingObject = downcast<AccessibilityObject>(protectedSelf.get().axBackingObject);
3076 if (!backingObject)
3077 return Vector<String>();
3078
3079 CheckedPtr cache = backingObject->axObjectCache();
3080 auto textOperation = accessibilityTextOperationForParameterizedAttribute(cache.get(), protectedDictionary.get());
3081 return backingObject->performTextOperation(textOperation);
3082 });
3083 if (operationResult.isEmpty())
3084 return nilnullptr;
3085 return createNSArray(operationResult).autorelease();
3086 }
3087
3088 if ([attribute isEqualToString:NSAccessibilityRangesForSearchPredicateParameterizedAttribute@"AXRangesForSearchPredicate"]) {
3089 auto criteria = accessibilitySearchCriteriaForSearchPredicate(*backingObject, dictionary);
3090 if (criteria.searchKeys.size() == 1 && criteria.searchKeys[0] == AccessibilitySearchKey::MisspelledWord) {
3091 // Request for the next/previous misspelling.
3092 auto textMarkerRange = AXSearchManager().findMatchingRange(WTF::move(criteria));
3093 if (!textMarkerRange)
3094 return nilnullptr;
3095
3096 RefPtr object = textMarkerRange->start().object();
3097 if (!object)
3098 return nilnullptr;
3099
3100 RetainPtr result = adoptNS([[NSMutableDictionary alloc] initWithObjectsAndKeys:
3101 protect(object->wrapper()).get(), NSAccessibilitySearchResultElementKey@"AXSearchResultElement",
3102 textMarkerRange->platformData().bridgingAutorelease(), NSAccessibilitySearchResultRangeKey@"AXSearchResultRange",
3103 nilnullptr]);
3104 return [[[NSArray alloc] initWithObjects:result.get(), nilnullptr] autorelease];
3105 }
3106 }
3107
3108 if ([attribute isEqualToString:NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute@"AXUIElementsForSearchPredicate"]) {
3109 auto criteria = accessibilitySearchCriteriaForSearchPredicate(*backingObject, dictionary);
3110 RetainPtr<NSArray> widgetChildren;
3111 if (isMatchingPlugin(*backingObject, criteria)) {
3112 // FIXME: We should also be searching the tree(s) resulting from `renderWidgetChildren` for matches.
3113 // This is tracked by https://bugs.webkit.org/show_bug.cgi?id=230167.
3114 if (RetainPtr children = renderWidgetChildren(*backingObject)) {
3115 NSUInteger includedChildrenCount = std::min([children count], NSUInteger(criteria.resultsLimit));
3116 widgetChildren = [children subarrayWithRange:NSMakeRange(0, includedChildrenCount)];
3117 if ([widgetChildren count] >= criteria.resultsLimit)
3118 return widgetChildren.autorelease();
3119 criteria.resultsLimit -= [widgetChildren count];
3120 }
3121 } else if (backingObject->isRemoteFrame()
3122 && criteria.searchKeys.contains(AccessibilitySearchKey::AnyType)
3123 && (!criteria.visibleOnly || backingObject->isVisible())) {
3124 RetainPtr remoteFrameChildren = children(*backingObject);
3125 AX_ASSERT([remoteFrameChildren count] == 1)((void)0);
3126 if ([remoteFrameChildren count] == 1) {
3127 NSUInteger includedChildrenCount = std::min([remoteFrameChildren count], NSUInteger(criteria.resultsLimit));
3128 widgetChildren = [remoteFrameChildren subarrayWithRange:NSMakeRange(0, includedChildrenCount)];
3129 if ([widgetChildren count] >= criteria.resultsLimit)
3130 return remoteFrameChildren.autorelease();
3131 criteria.resultsLimit -= [widgetChildren count];
3132 }
3133 }
3134
3135 RetainPtr<NSArray> results = performSearchWithRemoteFrames(*backingObject, WTF::move(criteria));
3136 if (widgetChildren)
3137 return [widgetChildren arrayByAddingObjectsFromArray:results.get()];
3138 return results.autorelease();
3139 }
3140
3141 // TextMarker attributes.
3142
3143 if ([attribute isEqualToString:NSAccessibilityEndTextMarkerForBoundsAttribute@"AXEndTextMarkerForBounds"]) {
3144 return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([&rect, protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
3145 RefPtr backingObject = downcast<AccessibilityObject>(protectedSelf.get().axBackingObject);
3146 CheckedPtr cache = backingObject ? backingObject->axObjectCache() : nullptr;
3147 if (!cache)
3148 return nilnullptr;
3149
3150 IntRect webCoreRect = screenToContents(*backingObject, enclosingIntRect(rect));
3151 CharacterOffset characterOffset = cache->characterOffsetForBounds(webCoreRect, false);
3152
3153 return (id)textMarkerForCharacterOffset(cache.get(), characterOffset, TextMarkerOrigin::EndTextMarkerForBounds);
3154 });
3155 }
3156
3157 if ([attribute isEqualToString:NSAccessibilityStartTextMarkerForBoundsAttribute@"AXStartTextMarkerForBounds"]) {
3158 return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([&rect, protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
3159 RefPtr backingObject = downcast<AccessibilityObject>(protectedSelf.get().axBackingObject);
3160 CheckedPtr cache = backingObject ? backingObject->axObjectCache() : nullptr;
3161 if (!cache)
3162 return nilnullptr;
3163
3164 IntRect webCoreRect = screenToContents(*backingObject, enclosingIntRect(rect));
3165 CharacterOffset characterOffset = cache->characterOffsetForBounds(webCoreRect, true);
3166
3167 return (id)textMarkerForCharacterOffset(cache.get(), characterOffset, TextMarkerOrigin::StartTextMarkerForBounds);
3168 });
3169 }
3170
3171 // TextMarkerRange attributes.
3172 if ([attribute isEqualToString:NSAccessibilityLineTextMarkerRangeForTextMarkerAttribute@"AXLineTextMarkerRangeForTextMarker"])
3173 return [self lineTextMarkerRangeForTextMarker:textMarker forUnit:TextUnit::Line];
3174
3175 if ([attribute isEqualToString:NSAccessibilityMisspellingTextMarkerRangeAttribute@"AXMisspellingTextMarkerRange"]) {
3176 return (id)Accessibility::retrieveAutoreleasedValueFromMainThread<AXTextMarkerRangeRef>([protectedDictionary = retainPtr(dictionary), protectedSelf = retainPtr(self)] () -> RetainPtr<AXTextMarkerRangeRef> {
3177 RefPtr<AXCoreObject> backingObject = protectedSelf.get().axBackingObject;
3178 if (!backingObject)
3179 return nilnullptr;
3180
3181 auto criteria = misspellingSearchCriteriaForParameterizedAttribute(protectedDictionary.get());
3182 if (!criteria.first)
3183 return nilnullptr;
3184
3185 auto characterRange = criteria.first.characterRange();
3186 if (!characterRange)
3187 return nilnullptr;
3188
3189 RefPtr startObject = criteria.second == AccessibilitySearchDirection::Next ? criteria.first.end().object() : criteria.first.start().object();
3190 auto misspellingRange = AXSearchManager().findMatchingRange(AccessibilitySearchCriteria {
3191 backingObject.get(), startObject.get(), *characterRange,
3192 criteria.second,
3193 { AccessibilitySearchKey::MisspelledWord }, { }, 1
3194 });
3195 if (!misspellingRange)
3196 return nilnullptr;
3197 return misspellingRange->platformData();
3198 });
3199 }
3200
3201 if ([attribute isEqualToString:NSAccessibilityTextMarkerIsValidAttribute@"AXTextMarkerIsValid"])
3202 return [NSNumber numberWithBool:AXTextMarker(textMarker).isValid()];
3203
3204 if ([attribute isEqualToString:NSAccessibilityIndexForTextMarkerAttribute@"AXIndexForTextMarker"]) {
3205 auto marker = AXTextMarker { textMarker };
3206 if (!isMainThread())
3207 return [NSNumber numberWithUnsignedInt:marker.offsetFromRoot()];
3208 if (!marker.isValid())
3209 return @(NSNotFound);
3210 long markerLocation = makeNSRange(AXTextMarkerRange { marker, marker }.simpleRange()).location;
3211 return [NSNumber numberWithInteger:markerLocation];
3212 }
3213
3214 if ([attribute isEqualToString:NSAccessibilityTextMarkerForIndexAttribute@"AXTextMarkerForIndex"]) {
3215 if (AXObjectCache::useAXThreadTextApis()) {
3216 long index = [number longValue];
3217 if (index < 0)
3218 return nilnullptr;
3219
3220 RefPtr tree = std::get<RefPtr<AXIsolatedTree>>(axTreeForID(backingObject->treeID()));
3221 if (RefPtr root = tree ? tree->rootNode() : nullptr) {
3222 AXTextMarker rootMarker { root->treeID(), root->objectID(), 0 };
3223 return rootMarker.nextMarkerFromOffset(static_cast<unsigned>(index)).platformData().bridgingAutorelease();
3224 }
3225 return nilnullptr;
3226 }
3227 return (id)[self _textMarkerForIndex:[number integerValue]];
3228 }
3229
3230 if ([attribute isEqualToString:NSAccessibilityUIElementForTextMarkerAttribute@"AXUIElementForTextMarker"]) {
3231 AXTextMarker marker { textMarker };
3232 RefPtr object = marker.object();
3233 if (!object)
3234 return nilnullptr;
3235
3236 RetainPtr wrapper = object->wrapper();
3237 if (!wrapper)
3238 return nilnullptr;
3239
3240 if (object->isAttachment()) {
3241 if (RetainPtr<id> attachmentView = [wrapper attachmentView])
3242 return attachmentView.autorelease();
3243 }
3244 return wrapper.autorelease();
3245 }
3246
3247 if ([attribute isEqualToString:NSAccessibilityTextMarkerRangeForUIElementAttribute@"AXTextMarkerRangeForUIElement"]) {
3248 if (uiElement) {
3249 if (auto markerRange = uiElement->textMarkerRange())
3250 return markerRange.platformData().bridgingAutorelease();
3251 }
3252 return nilnullptr;
3253 }
3254
3255 if ([attribute isEqualToString:NSAccessibilityLineForTextMarkerAttribute@"AXLineForTextMarker"]) {
3256 if (!isMainThread())
3257 return @(AXTextMarker { textMarker }.lineIndex());
3258
3259 RefPtr<AXCoreObject> backingObject = self.axBackingObject;
3260 if (!backingObject)
3261 return @(-1);
3262 return @(backingObject->lineForPosition(AXTextMarker { textMarker }));
3263 }
3264
3265 if ([attribute isEqualToString:NSAccessibilityTextMarkerRangeForLineAttribute@"AXTextMarkerRangeForLine"]) {
3266 if (AXObjectCache::useAXThreadTextApis()) {
3267 // Unfortunately, the main-thread version of this function expects a 1-indexed line, so callers pass it that way.
3268 // The text marker code expects normal 0-based indices, so we need to subtract one from the given value.
3269 unsigned lineIndex = [number unsignedIntValue];
3270 if (!lineIndex) {
3271 // Match the main-thread implementation's behavior.
3272 return nilnullptr;
3273 }
3274 if (RefPtr tree = std::get<RefPtr<AXIsolatedTree>>(axTreeForID(backingObject->treeID())))
3275 return tree->firstMarker().markerRangeForLineIndex(lineIndex - 1).platformData().bridgingAutorelease();
3276 return nilnullptr;
3277 }
3278
3279 return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([protectedNumber = retainPtr(number), protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
3280 RefPtr backingObject = downcast<AccessibilityObject>(protectedSelf.get().axBackingObject);
3281 if (!backingObject)
3282 return nilnullptr;
3283
3284 VisiblePositionRange vpRange;
3285 if ([protectedNumber.get() unsignedIntegerValue] != NSNotFound)
3286 vpRange = backingObject->visiblePositionRangeForLine([protectedNumber.get() unsignedIntValue]);
3287
3288 CheckedPtr cache = backingObject->axObjectCache();
3289 return (id)textMarkerRangeFromVisiblePositions(cache.get(), vpRange.start, vpRange.end);
3290 });
3291 }
3292
3293 if ([attribute isEqualToString:NSAccessibilityStringForTextMarkerRangeAttribute@"AXStringForTextMarkerRange"])
3294 return AXTextMarkerRange { textMarkerRange }.toString().createNSString().autorelease();
3295
3296 if ([attribute isEqualToString:NSAccessibilityTextMarkerForPositionAttribute@"AXTextMarkerForPosition"]) {
3297 if (!pointSet)
3298 return nilnullptr;
3299 IntPoint webCorePoint = IntPoint(point);
3300
3301 return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([&webCorePoint, protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
3302 RefPtr<AXCoreObject> backingObject = protectedSelf.get().axBackingObject;
3303 if (!backingObject)
3304 return nilnullptr;
3305
3306 return AXTextMarker(backingObject->visiblePositionForPoint(webCorePoint), TextMarkerOrigin::Position).platformData().bridgingAutorelease();
3307 });
3308 }
3309
3310 if ([attribute isEqualToString:NSAccessibilityBoundsForTextMarkerRangeAttribute@"AXBoundsForTextMarkerRange"]) {
3311 if (!isMainThread()) {
3312 AXTextMarkerRange markerRange { textMarkerRange };
3313 if (!markerRange)
3314 return [NSValue valueWithRect:CGRectZero];
3315
3316 return [NSValue valueWithRect:[self convertRectToSpace:markerRange.viewportRelativeFrame() space:AccessibilityConversionSpace::Screen]];
3317 }
3318
3319 RefPtr<AXCoreObject> backingObject = self.axBackingObject;
3320 if (!backingObject)
3321 return [NSValue valueWithRect:CGRectZero];
3322
3323 AXTextMarkerRange markerRange { textMarkerRange };
3324 std::optional range = markerRange.simpleRange();
3325 if (!range)
3326 return [NSValue valueWithRect:CGRectZero];
3327
3328 auto bounds = FloatRect(backingObject->boundsForRange(*range));
3329 auto convertedRect = [self convertRectToSpace:bounds space:AccessibilityConversionSpace::Screen];
3330 return [NSValue valueWithRect:convertedRect];
3331 }
3332
3333 if ([attribute isEqualToString:NSAccessibilityBoundsForRangeParameterizedAttribute]) {
3334 NSRect rect = CGRectZero;
3335 if (backingObject)
3336 rect = [self computeTextBoundsForRange:range backingObject:*backingObject];
3337
3338 return [NSValue valueWithRect:[self convertRectToSpace:rect space:AccessibilityConversionSpace::Screen]];
3339 }
3340
3341 if ([attribute isEqualToString:NSAccessibilityStringForRangeParameterizedAttribute]) {
3342 if (backingObject->isTextControl())
3343 return backingObject->doAXStringForRange(range).createNSString().autorelease();
3344
3345 if (!isMainThread()) {
3346 std::optional markerRange = Accessibility::markerRangeFrom(range, *backingObject);
3347 return markerRange ? markerRange->toString().createNSString().autorelease() : @"";
3348 }
3349
3350 RefPtr mainThreadBackingObject = downcast<AccessibilityObject>(self.axBackingObject);
3351 if (!mainThreadBackingObject)
3352 return @"";
3353 CheckedPtr cache = mainThreadBackingObject->axObjectCache();
3354 if (!cache)
3355 return @"";
3356
3357 auto start = cache->characterOffsetForIndex(range.location, mainThreadBackingObject.get());
3358 auto end = cache->characterOffsetForIndex(range.location + range.length, mainThreadBackingObject.get());
3359 auto characterRange = cache->rangeForUnorderedCharacterOffsets(start, end);
3360 return AXTextMarkerRange { characterRange }.toString().createNSString().autorelease();
3361 }
3362
3363 if ([attribute isEqualToString:NSAccessibilityAttributedStringForTextMarkerRangeAttribute@"AXAttributedStringForTextMarkerRange"])
3364 return attributedStringForTextMarkerRange(*backingObject, textMarkerRange, AXCoreObject::SpellCheck::Yes);
3365
3366 if ([attribute isEqualToString:NSAccessibilityAttributedStringForTextMarkerRangeWithOptionsAttribute@"AXAttributedStringForTextMarkerRangeWithOptions"]) {
3367 if (textMarkerRange)
3368 return attributedStringForTextMarkerRange(*backingObject, textMarkerRange, AXCoreObject::SpellCheck::No);
3369
3370 if (dictionary) {
3371 RetainPtr<AXTextMarkerRangeRef> textMarkerRange = nilnullptr;
3372 RetainPtr<id> parameter = [dictionary objectForKey:NSAccessibilityTextMarkerRangeParam@"AXTextMarkerRange"];
3373 if (AXObjectIsTextMarkerRange(parameter.get()))
3374 textMarkerRange = (AXTextMarkerRangeRef)parameter.get();
3375
3376 auto spellCheck = AXCoreObject::SpellCheck::No;
3377 parameter = [dictionary objectForKey:NSAccessibilitySpellCheckParam@"AXSpellCheck"];
3378 if ([parameter isKindOfClass:[NSNumber class]] && [parameter boolValue])
3379 spellCheck = AXCoreObject::SpellCheck::Yes;
3380 return attributedStringForTextMarkerRange(*backingObject, textMarkerRange.get(), spellCheck);
3381 }
3382
3383 return nilnullptr;
3384 }
3385
3386 if ([attribute isEqualToString:NSAccessibilityTextMarkerRangeForTextMarkersAttribute@"AXTextMarkerRangeForTextMarkers"]
3387 || [attribute isEqualToString:NSAccessibilityTextMarkerRangeForUnorderedTextMarkersAttribute@"AXTextMarkerRangeForUnorderedTextMarkers"]) {
3388 if (array.count < 2
3389 || !AXObjectIsTextMarker([array objectAtIndex:0])
3390 || !AXObjectIsTextMarker([array objectAtIndex:1]))
3391 return nilnullptr;
3392
3393 return AXTextMarkerRange { { (AXTextMarkerRef)[array objectAtIndex:0] }, { (AXTextMarkerRef)[array objectAtIndex:1] } }.platformData().bridgingAutorelease();
3394 }
3395
3396 if ([attribute isEqualToString:NSAccessibilityNextTextMarkerForTextMarkerAttribute@"AXNextTextMarkerForTextMarker"]) {
3397 if (AXObjectCache::useAXThreadTextApis()) {
3398 AXTextMarker inputMarker { textMarker };
3399 return inputMarker.findMarker(AXDirection::Next).platformData().bridgingAutorelease();
3400 }
3401 return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([textMarker = retainPtr(textMarker), protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
3402 RefPtr backingObject = downcast<AccessibilityObject>(protectedSelf.get().axBackingObject);
3403 CheckedPtr cache = backingObject ? backingObject->axObjectCache() : nullptr;
3404
3405 return nextTextMarker(cache.get(), AXTextMarker { textMarker.get() }).bridgingAutorelease();
3406 });
3407 }
3408
3409 if ([attribute isEqualToString:NSAccessibilityPreviousTextMarkerForTextMarkerAttribute@"AXPreviousTextMarkerForTextMarker"]) {
3410 if (AXObjectCache::useAXThreadTextApis()) {
3411 AXTextMarker inputMarker { textMarker };
3412 return inputMarker.findMarker(AXDirection::Previous).platformData().bridgingAutorelease();
3413 }
3414 return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([textMarker = retainPtr(textMarker), protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
3415 RefPtr backingObject = downcast<AccessibilityObject>(protectedSelf.get().axBackingObject);
3416 CheckedPtr cache = backingObject ? backingObject->axObjectCache() : nullptr;
3417
3418 return previousTextMarker(cache.get(), AXTextMarker { textMarker.get() }).bridgingAutorelease();
3419 });
3420 }
3421
3422 if ([attribute isEqualToString:NSAccessibilityLeftWordTextMarkerRangeForTextMarkerAttribute@"AXLeftWordTextMarkerRangeForTextMarker"])
3423 return (id)[self textMarkerRangeAtTextMarker:textMarker forUnit:TextUnit::LeftWord];
3424
3425 if ([attribute isEqualToString:NSAccessibilityRightWordTextMarkerRangeForTextMarkerAttribute@"AXRightWordTextMarkerRangeForTextMarker"])
3426 return (id)[self textMarkerRangeAtTextMarker:textMarker forUnit:TextUnit::RightWord];
3427
3428 if ([attribute isEqualToString:NSAccessibilityLeftLineTextMarkerRangeForTextMarkerAttribute@"AXLeftLineTextMarkerRangeForTextMarker"])
3429 return [self lineTextMarkerRangeForTextMarker:textMarker forUnit:TextUnit::LeftLine];
3430
3431 if ([attribute isEqualToString:NSAccessibilityRightLineTextMarkerRangeForTextMarkerAttribute@"AXRightLineTextMarkerRangeForTextMarker"])
3432 return [self lineTextMarkerRangeForTextMarker:textMarker forUnit:TextUnit::RightLine];
3433
3434 if ([attribute isEqualToString:NSAccessibilitySentenceTextMarkerRangeForTextMarkerAttribute@"AXSentenceTextMarkerRangeForTextMarker"])
3435 return (id)[self textMarkerRangeAtTextMarker:textMarker forUnit:TextUnit::Sentence];
3436
3437 if ([attribute isEqualToString:NSAccessibilityParagraphTextMarkerRangeForTextMarkerAttribute@"AXParagraphTextMarkerRangeForTextMarker"])
3438 return (id)[self textMarkerRangeAtTextMarker:textMarker forUnit:TextUnit::Paragraph];
3439
3440 if ([attribute isEqualToString:NSAccessibilityNextWordEndTextMarkerForTextMarkerAttribute@"AXNextWordEndTextMarkerForTextMarker"])
3441 return (id)[self textMarkerForTextMarker:textMarker atUnit:TextUnit::NextWordEnd];
3442
3443 if ([attribute isEqualToString:NSAccessibilityPreviousWordStartTextMarkerForTextMarkerAttribute@"AXPreviousWordStartTextMarkerForTextMarker"])
3444 return (id)[self textMarkerForTextMarker:textMarker atUnit:TextUnit::PreviousWordStart];
3445
3446 if ([attribute isEqualToString:NSAccessibilityNextLineEndTextMarkerForTextMarkerAttribute@"AXNextLineEndTextMarkerForTextMarker"]) {
3447 if (AXObjectCache::useAXThreadTextApis()) {
3448 AXTextMarker inputMarker { textMarker };
3449 return inputMarker.nextLineEnd().platformData().bridgingAutorelease();
3450 }
3451 return (id)[self textMarkerForTextMarker:textMarker atUnit:TextUnit::NextLineEnd];
3452 }
3453
3454 if ([attribute isEqualToString:NSAccessibilityPreviousLineStartTextMarkerForTextMarkerAttribute@"AXPreviousLineStartTextMarkerForTextMarker"]) {
3455 if (AXObjectCache::useAXThreadTextApis()) {
3456 AXTextMarker inputMarker { textMarker };
3457 return inputMarker.previousLineStart().platformData().bridgingAutorelease();
3458 }
3459 return (id)[self textMarkerForTextMarker:textMarker atUnit:TextUnit::PreviousLineStart];
3460 }
3461
3462 if ([attribute isEqualToString:NSAccessibilityNextSentenceEndTextMarkerForTextMarkerAttribute@"AXNextSentenceEndTextMarkerForTextMarker"])
3463 return (id)[self textMarkerForTextMarker:textMarker atUnit:TextUnit::NextSentenceEnd];
3464
3465 if ([attribute isEqualToString:NSAccessibilityPreviousSentenceStartTextMarkerForTextMarkerAttribute@"AXPreviousSentenceStartTextMarkerForTextMarker"])
3466 return (id)[self textMarkerForTextMarker:textMarker atUnit:TextUnit::PreviousSentenceStart];
3467
3468 if ([attribute isEqualToString:NSAccessibilityNextParagraphEndTextMarkerForTextMarkerAttribute@"AXNextParagraphEndTextMarkerForTextMarker"])
3469 return (id)[self textMarkerForTextMarker:textMarker atUnit:TextUnit::NextParagraphEnd];
3470
3471 if ([attribute isEqualToString:NSAccessibilityPreviousParagraphStartTextMarkerForTextMarkerAttribute@"AXPreviousParagraphStartTextMarkerForTextMarker"])
3472 return (id)[self textMarkerForTextMarker:textMarker atUnit:TextUnit::PreviousParagraphStart];
3473
3474 if ([attribute isEqualToString:NSAccessibilityStyleTextMarkerRangeForTextMarkerAttribute@"AXStyleTextMarkerRangeForTextMarker"]) {
3475 if (AXObjectCache::useAXThreadTextApis())
3476 return AXTextMarker { textMarker }.rangeWithSameStyle().platformData().bridgingAutorelease();
3477
3478 return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([textMarker = retainPtr(textMarker), protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
3479 RefPtr<AXCoreObject> backingObject = protectedSelf.get().axBackingObject;
3480 if (!backingObject)
3481 return nilnullptr;
3482 return AXTextMarkerRange { backingObject->styleRangeForPosition(AXTextMarker { textMarker.get() }) }.platformData().bridgingAutorelease();
3483 });
3484 }
3485
3486 if ([attribute isEqualToString:NSAccessibilityLengthForTextMarkerRangeAttribute@"AXLengthForTextMarkerRange"]) {
3487 if (!isMainThread()) {
3488 AXTextMarkerRange range = { textMarkerRange };
3489 return @(range.toString().length());
3490 }
3491
3492 RefPtr<AXCoreObject> backingObject = self.axBackingObject;
3493 if (!backingObject)
3494 return @(0);
3495
3496 AXTextMarkerRange markerRange { textMarkerRange };
3497 auto range = markerRange.simpleRange();
3498 return @(range ? AXObjectCache::lengthForRange(*range) : 0);
3499 }
3500
3501 if ([attribute isEqualToString:NSAccessibilityIntersectTextMarkerRangesAttribute@"AXIntersectTextMarkerRanges"]) {
3502 if (array.count < 2
3503 || !AXObjectIsTextMarkerRange([array objectAtIndex:0])
3504 || !AXObjectIsTextMarkerRange([array objectAtIndex:1]))
3505 return nilnullptr;
3506
3507 auto range1 = AXTextMarkerRange { (AXTextMarkerRangeRef)[array objectAtIndex:0] };
3508 auto range2 = AXTextMarkerRange { (AXTextMarkerRangeRef)[array objectAtIndex:1] };
3509 auto intersection = range1.intersectionWith(range2);
3510 return intersection ? (*intersection).platformData().bridgingAutorelease() : nilnullptr;
3511 }
3512
3513 if (backingObject->isExposableTable()) {
3514 if ([attribute isEqualToString:NSAccessibilityCellForColumnAndRowParameterizedAttribute]) {
3515 if (array == nilnullptr || [array count] != 2)
3516 return nilnullptr;
3517 RefPtr cell = backingObject->cellForColumnAndRow([[array objectAtIndex:0] unsignedIntValue], [[array objectAtIndex:1] unsignedIntValue]);
3518 return cell ? cell->wrapper() : nilnullptr;
3519 }
3520 }
3521
3522 if (backingObject->isTextControl()) {
3523 if ([attribute isEqualToString: bridge_cast(kAXLineForIndexParameterizedAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXLineForIndex"
""))
)]) {
3524 int lineNumber = backingObject->doAXLineForIndex([number intValue]);
3525 if (lineNumber < 0)
3526 return nilnullptr;
3527 return @(lineNumber);
3528 }
3529
3530 if ([attribute isEqualToString:bridge_cast(kAXRangeForLineParameterizedAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXRangeForLine"
""))
)]) {
3531 auto textRange = backingObject->doAXRangeForLine([number intValue]);
3532 return [NSValue valueWithRange:textRange];
3533 }
3534
3535 if ([attribute isEqualToString:bridge_cast(kAXStringForRangeParameterizedAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXStringForRange"
""))
)])
3536 return rangeSet ? (id)backingObject->doAXStringForRange(range).createNSString().autorelease() : nilnullptr;
3537
3538 if ([attribute isEqualToString:bridge_cast(kAXRangeForPositionParameterizedAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXRangeForPosition"
""))
)]) {
3539 if (!pointSet)
3540 return nilnullptr;
3541
3542 auto webCorePoint = IntPoint(point);
3543 auto textRange = backingObject->characterRangeForPoint(webCorePoint);
3544 return [NSValue valueWithRange:textRange];
3545 }
3546
3547 if ([attribute isEqualToString:bridge_cast(kAXRangeForIndexParameterizedAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXRangeForIndex"
""))
)]) {
3548 auto textRange = backingObject->doAXRangeForIndex([number intValue]);
3549 return [NSValue valueWithRange:textRange];
3550 }
3551
3552 if ([attribute isEqualToString:bridge_cast(kAXBoundsForRangeParameterizedAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXBoundsForRange"
""))
)]) {
3553 if (!rangeSet)
3554 return nilnullptr;
3555
3556 auto bounds = FloatRect(backingObject->doAXBoundsForRangeUsingCharacterOffset(range));
3557 NSRect rect = [self convertRectToSpace:bounds space:AccessibilityConversionSpace::Screen];
3558 return [NSValue valueWithRect:rect];
3559 }
3560
3561 if ([attribute isEqualToString:bridge_cast(kAXRTFForRangeParameterizedAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXRTFForRange"
""))
)])
3562 return rangeSet ? rtfForNSRange(*backingObject, range) : nilnullptr;
3563
3564 if ([attribute isEqualToString:bridge_cast(kAXAttributedStringForRangeParameterizedAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXAttributedStringForRange"
""))
)])
3565 return rangeSet ? attributedStringForNSRange(*backingObject, range) : nilnullptr;
3566
3567 if ([attribute isEqualToString:bridge_cast(kAXStyleRangeForIndexParameterizedAttribute((CFStringRef) __builtin___CFStringMakeConstantString ("" "AXStyleRangeForIndex"
""))
)]) {
3568 auto textRange = backingObject->doAXStyleRangeForIndex([number intValue]);
3569 return [NSValue valueWithRange:textRange];
3570 }
3571 }
3572
3573 if ([attribute isEqualToString:NSAccessibilityConvertRelativeFrameParameterizedAttribute@"AXConvertRelativeFrame"]) {
3574 RefPtr parent = backingObject->parentObject();
3575 return parent ? [NSValue valueWithRect:parent->convertFrameToSpace(FloatRect(rect), AccessibilityConversionSpace::Page)] : nilnullptr;
3576 }
3577
3578 if ([attribute isEqualToString:NSAccessibilityTextMarkerDebugDescriptionAttribute@"AXTextMarkerDebugDescription"])
3579 return AXTextMarker { textMarker }.debugDescription().createNSString().autorelease();
3580
3581 if ([attribute isEqualToString:NSAccessibilityTextMarkerRangeDebugDescriptionAttribute@"AXTextMarkerRangeDebugDescription"])
3582 return AXTextMarkerRange { textMarkerRange }.debugDescription().createNSString().autorelease();
3583
3584#if ENABLE(TREE_DEBUGGING)(defined ENABLE_TREE_DEBUGGING && ENABLE_TREE_DEBUGGING
)
3585 if ([attribute isEqualToString:AXTextMarkerNodeDebugDescriptionAttribute]) {
3586 [self showNodeForTextMarker:textMarker];
3587 return nilnullptr;
3588 }
3589
3590 if ([attribute isEqualToString:AXTextMarkerNodeTreeDebugDescriptionAttribute]) {
3591 [self showNodeTreeForTextMarker:textMarker];
3592 return nilnullptr;
3593 }
3594#endif // ENABLE(TREE_DEBUGGING)
3595
3596 if (AXObjectCache::clientIsInTestMode()) {
3597 if (RetainPtr<id> value = [self parameterizedAttributeValueForTesting:attribute parameter:parameter backingObject:backingObject])
3598 return value.autorelease();
3599 }
3600
3601 // There are some parameters that super handles that are not explicitly returned by the list of the element's attributes.
3602 // In that case it must be passed to super.
3603 return [super accessibilityAttributeValue:attribute forParameter:parameter];
3604}
3605ALLOW_DEPRECATED_IMPLEMENTATIONS_ENDGCC diagnostic pop
3606
3607- (BOOL)accessibilitySupportsOverriddenAttributes
3608{
3609 return YES__objc_yes;
3610}
3611
3612// accessibilityShouldUseUniqueId is an AppKit method we override so that
3613// objects will be given a unique ID, and therefore allow AppKit to know when they
3614// become obsolete (e.g. when the user navigates to a new web page, making this one
3615// unrendered but not deallocated because it is in the back/forward cache).
3616// It is important to call NSAccessibilityUnregisterUniqueIdForUIElement in the
3617// appropriate place (e.g. dealloc) to remove these non-retained references from
3618// AppKit's id mapping tables. We do this in detach by calling unregisterUniqueIdForUIElement.
3619//
3620// Registering an object is also required for observing notifications. Only registered objects can be observed.
3621- (BOOL)accessibilityShouldUseUniqueId
3622{
3623 // All AX object wrappers should use unique ID's because it's faster within AppKit to look them up.
3624 return YES__objc_yes;
3625}
3626
3627// API that AppKit uses for faster access
3628- (NSUInteger)accessibilityIndexOfChild:(id)targetChild
3629{
3630 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
3631 if (!backingObject)
3632 return NSNotFound;
3633
3634 // Tree objects return their rows as their children. We can use the original method
3635 // here, because we won't gain any speed up.
3636 if (backingObject->isTree())
3637 return [super accessibilityIndexOfChild:targetChild];
3638
3639 const auto& children = backingObject->stitchedUnignoredChildren();
3640 if (!children.size()) {
3641 if (RetainPtr widgetChildren = renderWidgetChildren(*backingObject))
3642 return [widgetChildren.get() indexOfObject:targetChild];
3643#if ENABLE(MODEL_ELEMENT_ACCESSIBILITY)(defined 1 && 1)
3644 if (backingObject->isModel())
3645 return backingObject->modelElementChildren().children.find(targetChild);
3646#endif
3647 }
3648
3649 size_t childCount = children.size();
3650 for (size_t i = 0; i < childCount; i++) {
3651 const auto& child = children[i];
3652 RetainPtr childWrapper = child->wrapper();
3653 if (childWrapper == targetChild || (child->isAttachment() && [childWrapper attachmentView] == targetChild)
3654 || (child->isRemoteFrame() && child->remoteFramePlatformElement() == targetChild)) {
3655 return i;
3656 }
3657 }
3658 return NSNotFound;
3659}
3660
3661ALLOW_DEPRECATED_DECLARATIONS_BEGINGCC diagnostic push GCC diagnostic ignored "-W" "deprecated-declarations"
3662- (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute
3663{
3664 AXTRACE(makeString("WebAccessibilityObjectWrapper accessibilityArrayAttributeCount:"_s, String(attribute)))(void)0;
3665
3666 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
3667 if (!backingObject)
3668 return 0;
3669
3670 if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
3671 // Tree items object returns a different set of children than those that are in children()
3672 // because an AXOutline (the mac role is becomes) has some odd stipulations.
3673 if (backingObject->isTree() || backingObject->isTreeItem() || backingObject->isRemoteFrame())
3674 return children(*backingObject).count;
3675
3676 // FIXME: this is duplicating the logic in children(AXCoreObject&) so it should be reworked.
3677 size_t childrenSize = backingObject->stitchedUnignoredChildren().size();
3678 if (!childrenSize) {
3679#if ENABLE(MODEL_ELEMENT_ACCESSIBILITY)(defined 1 && 1)
3680 if (backingObject->isModel())
3681 return backingObject->modelElementChildren().children.size();
3682#endif
3683 if (RetainPtr widgetChildren = renderWidgetChildren(*backingObject))
3684 return [widgetChildren.get() count];
3685 }
3686 return childrenSize;
3687 }
3688
3689 return [super accessibilityArrayAttributeCount:attribute];
3690}
3691ALLOW_DEPRECATED_DECLARATIONS_ENDGCC diagnostic pop
3692
3693// Implement this for performance reasons, as the default AppKit implementation will iterate upwards
3694// until it finds something that responds to this method.
3695- (pid_t)accessibilityPresenterProcessIdentifier
3696{
3697 RefPtr<AXCoreObject> backingObject = self.axBackingObject;
3698 return backingObject ? backingObject->processID() : 0;
3699}
3700
3701- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount
3702{
3703 AXTRACE(makeString("WebAccessibilityObjectWrapper accessibilityArrayAttributeValue:"_s, String(attribute)))(void)0;
3704
3705 if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
3706 return [self _accessibilityChildrenFromIndex:index maxCount:maxCount returnPlatformElements:YES__objc_yes];
3707
3708 return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
3709}
3710
3711- (NSArray *)_accessibilityChildrenFromIndex:(NSUInteger)index maxCount:(NSUInteger)maxCount returnPlatformElements:(BOOL)returnPlatformElements
3712{
3713 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
3714 if (!backingObject)
3715 return nilnullptr;
3716
3717 const auto& unignoredChildren = backingObject->crossFrameUnignoredChildren();
3718 if (unignoredChildren.isEmpty()) {
3719 RetainPtr<NSArray> children = transformSpecialChildrenCases(*backingObject, unignoredChildren);
3720 if (!children)
3721 return nilnullptr;
3722
3723 NSUInteger childCount = [children count];
3724 if (index >= childCount)
3725 return nilnullptr;
3726
3727 NSUInteger arrayLength = std::min(childCount - index, maxCount);
3728 return [children subarrayWithRange:NSMakeRange(index, arrayLength)];
3729 }
3730
3731 if (backingObject->isTree() || backingObject->isTreeItem()) {
3732 // Tree objects return their rows as their children & tree items return their contents sans rows.
3733 // We can use the original method in this case.
3734 return [super accessibilityArrayAttributeValues:NSAccessibilityChildrenAttribute index:index maxCount:maxCount];
3735 }
3736
3737 RetainPtr<NSArray> children = makeNSArray(unignoredChildren, returnPlatformElements);
3738 unsigned childCount = [children count];
3739 if (index >= childCount)
3740 return nilnullptr;
3741
3742 unsigned available = std::min(childCount - index, maxCount);
3743
3744 NSMutableArray *subarray = [NSMutableArray arrayWithCapacity:available];
3745 for (unsigned added = 0; added < available; ++index, ++added) {
3746 RetainPtr<WebAccessibilityObjectWrapper> wrapper = [children objectAtIndex:index];
3747
3748 // The attachment view should be returned, otherwise AX palindrome errors occur.
3749 RetainPtr<id> attachmentView;
3750 if (RefPtr childObject = [wrapper isKindOfClass:[WebAccessibilityObjectWrapper class]] ? wrapper.get().axBackingObject : nullptr) {
3751 if (childObject->isAttachment())
3752 attachmentView = [wrapper attachmentView];
3753 else if (childObject->isRemoteFrame() && returnPlatformElements)
3754 attachmentView = childObject->remoteFramePlatformElement();
3755 }
3756
3757 [subarray addObject:attachmentView ? attachmentView.get() : wrapper.get()];
3758 }
3759
3760 return subarray;
3761}
3762
3763- (NSArray<NSAccessibilityCustomAction *> *)accessibilityCustomActions
3764{
3765 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
3766 if (!backingObject)
3767 return nilnullptr;
3768
3769 auto actionsData = [self baseAccessibilityCustomActionsData];
3770 if (actionsData.isEmpty())
3771 return nilnullptr;
3772
3773 RetainPtr<NSMutableArray<NSAccessibilityCustomAction *>> actions = adoptNS([[NSMutableArray alloc] init]);
3774 for (auto& actionData : actionsData) {
3775 auto action = adoptNS([[NSAccessibilityCustomAction alloc] initWithName:actionData.name.createNSString().autorelease() handler:^BOOL {
3776 return Accessibility::performCustomActionPress(actionData.treeID, actionData.targetID);
3777 }]);
3778 [actions addObject:action.get()];
3779 }
3780
3781 return actions.autorelease();
3782}
3783
3784- (NSString *)debugDescription
3785{
3786 String backingObjectDescription = "null backingObject"_s;
3787 RefPtr<AXCoreObject> backingObject = self.updateObjectBackingStore;
3788 if (backingObject)
3789 backingObjectDescription = backingObject->debugDescription();
3790 return makeString("PID: "_s, getpid(), ", "_s, backingObjectDescription).createNSString().autorelease();
3791}
3792@end
3793
3794#endif // PLATFORM(MAC)