AX ITM: ARIATreeItemContent, ARIATreeRows, and DisclosedRows properties need to be...
[webkit.git] / Source / WebCore / accessibility / mac / WebAccessibilityObjectWrapperMac.mm
blob7222a356530ec2845f1855fc9cf71fa36caa6db3
1 /*
2  * Copyright (C) 2008, 2009, 2010, 2011 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  */
29 #import "config.h"
30 #import "WebAccessibilityObjectWrapperMac.h"
32 #if ENABLE(ACCESSIBILITY) && PLATFORM(MAC)
34 #import "AXLogger.h"
35 #import "AXObjectCache.h"
36 #import "AccessibilityARIAGridRow.h"
37 #import "AccessibilityLabel.h"
38 #import "AccessibilityList.h"
39 #import "AccessibilityListBox.h"
40 #import "AccessibilityProgressIndicator.h"
41 #import "AccessibilityRenderObject.h"
42 #import "AccessibilityScrollView.h"
43 #import "AccessibilitySpinButton.h"
44 #import "AccessibilityTable.h"
45 #import "AccessibilityTableCell.h"
46 #import "AccessibilityTableColumn.h"
47 #import "AccessibilityTableRow.h"
48 #import "Chrome.h"
49 #import "ChromeClient.h"
50 #import "ColorMac.h"
51 #import "ContextMenuController.h"
52 #import "Editing.h"
53 #import "Editor.h"
54 #import "Font.h"
55 #import "FontCascade.h"
56 #import "Frame.h"
57 #import "FrameLoaderClient.h"
58 #import "FrameSelection.h"
59 #import "HTMLAnchorElement.h"
60 #import "HTMLAreaElement.h"
61 #import "HTMLFrameOwnerElement.h"
62 #import "HTMLImageElement.h"
63 #import "HTMLInputElement.h"
64 #import "HTMLNames.h"
65 #import "LocalizedStrings.h"
66 #import "Page.h"
67 #import "PluginDocument.h"
68 #import "PluginViewBase.h"
69 #import "Range.h"
70 #import "RenderInline.h"
71 #import "RenderTextControl.h"
72 #import "RenderView.h"
73 #import "RenderWidget.h"
74 #import "ScrollView.h"
75 #import "TextCheckerClient.h"
76 #import "TextCheckingHelper.h"
77 #import "TextDecorationPainter.h"
78 #import "TextIterator.h"
79 #import "VisibleUnits.h"
80 #import "WebCoreFrameView.h"
81 #import <pal/SessionID.h>
82 #import <pal/spi/cocoa/NSAccessibilitySPI.h>
83 #import <wtf/cocoa/TypeCastsCocoa.h>
84 #import <wtf/cocoa/VectorCocoa.h>
86 using namespace WebCore;
88 // Cell Tables
89 #ifndef NSAccessibilitySelectedCellsAttribute
90 #define NSAccessibilitySelectedCellsAttribute @"AXSelectedCells"
91 #endif
93 #ifndef NSAccessibilityVisibleCellsAttribute
94 #define NSAccessibilityVisibleCellsAttribute @"AXVisibleCells"
95 #endif
97 #ifndef NSAccessibilityRowIndexRangeAttribute
98 #define NSAccessibilityRowIndexRangeAttribute @"AXRowIndexRange"
99 #endif
101 #ifndef NSAccessibilityColumnIndexRangeAttribute
102 #define NSAccessibilityColumnIndexRangeAttribute @"AXColumnIndexRange"
103 #endif
105 #ifndef NSAccessibilityCellForColumnAndRowParameterizedAttribute
106 #define NSAccessibilityCellForColumnAndRowParameterizedAttribute @"AXCellForColumnAndRow"
107 #endif
109 #ifndef NSAccessibilityCellRole
110 #define NSAccessibilityCellRole @"AXCell"
111 #endif
113 #ifndef NSAccessibilityDefinitionListSubrole
114 #define NSAccessibilityDefinitionListSubrole @"AXDefinitionList"
115 #endif
117 // Miscellaneous
118 #ifndef NSAccessibilityBlockQuoteLevelAttribute
119 #define NSAccessibilityBlockQuoteLevelAttribute @"AXBlockQuoteLevel"
120 #endif
122 #ifndef NSAccessibilityAccessKeyAttribute
123 #define NSAccessibilityAccessKeyAttribute @"AXAccessKey"
124 #endif
126 #ifndef NSAccessibilityValueAutofilledAttribute
127 #define NSAccessibilityValueAutofilledAttribute @"AXValueAutofilled"
128 #endif
130 #ifndef NSAccessibilityValueAutofillAvailableAttribute
131 #define NSAccessibilityValueAutofillAvailableAttribute @"AXValueAutofillAvailable"
132 #endif
134 #ifndef NSAccessibilityValueAutofillTypeAttribute
135 #define NSAccessibilityValueAutofillTypeAttribute @"AXValueAutofillType"
136 #endif
138 #ifndef NSAccessibilityLanguageAttribute
139 #define NSAccessibilityLanguageAttribute @"AXLanguage"
140 #endif
142 #ifndef NSAccessibilityRequiredAttribute
143 #define NSAccessibilityRequiredAttribute @"AXRequired"
144 #endif
146 #ifndef NSAccessibilityInvalidAttribute
147 #define NSAccessibilityInvalidAttribute @"AXInvalid"
148 #endif
150 #ifndef NSAccessibilityOwnsAttribute
151 #define NSAccessibilityOwnsAttribute @"AXOwns"
152 #endif
154 #ifndef NSAccessibilityGrabbedAttribute
155 #define NSAccessibilityGrabbedAttribute @"AXGrabbed"
156 #endif
158 #ifndef NSAccessibilityDatetimeValueAttribute
159 #define NSAccessibilityDatetimeValueAttribute @"AXDateTimeValue"
160 #endif
162 #ifndef NSAccessibilityInlineTextAttribute
163 #define NSAccessibilityInlineTextAttribute @"AXInlineText"
164 #endif
166 #ifndef NSAccessibilityDropEffectsAttribute
167 #define NSAccessibilityDropEffectsAttribute @"AXDropEffects"
168 #endif
170 #ifndef NSAccessibilityARIALiveAttribute
171 #define NSAccessibilityARIALiveAttribute @"AXARIALive"
172 #endif
174 #ifndef NSAccessibilityARIAAtomicAttribute
175 #define NSAccessibilityARIAAtomicAttribute @"AXARIAAtomic"
176 #endif
178 #ifndef NSAccessibilityARIARelevantAttribute
179 #define NSAccessibilityARIARelevantAttribute @"AXARIARelevant"
180 #endif
182 #ifndef NSAccessibilityElementBusyAttribute
183 #define NSAccessibilityElementBusyAttribute @"AXElementBusy"
184 #endif
186 #ifndef NSAccessibilityARIAPosInSetAttribute
187 #define NSAccessibilityARIAPosInSetAttribute @"AXARIAPosInSet"
188 #endif
190 #ifndef NSAccessibilityARIASetSizeAttribute
191 #define NSAccessibilityARIASetSizeAttribute @"AXARIASetSize"
192 #endif
194 #ifndef NSAccessibilityLoadingProgressAttribute
195 #define NSAccessibilityLoadingProgressAttribute @"AXLoadingProgress"
196 #endif
198 #ifndef NSAccessibilityHasPopupAttribute
199 #define NSAccessibilityHasPopupAttribute @"AXHasPopup"
200 #endif
202 #ifndef NSAccessibilityPopupValueAttribute
203 #define NSAccessibilityPopupValueAttribute @"AXPopupValue"
204 #endif
206 #ifndef NSAccessibilityPlaceholderValueAttribute
207 #define NSAccessibilityPlaceholderValueAttribute @"AXPlaceholderValue"
208 #endif
210 #define NSAccessibilityTextMarkerIsValidParameterizedAttribute @"AXTextMarkerIsValid"
211 #define NSAccessibilityIndexForTextMarkerParameterizedAttribute @"AXIndexForTextMarker"
212 #define NSAccessibilityTextMarkerForIndexParameterizedAttribute @"AXTextMarkerForIndex"
214 #ifndef NSAccessibilityScrollToVisibleAction
215 #define NSAccessibilityScrollToVisibleAction @"AXScrollToVisible"
216 #endif
218 #ifndef NSAccessibilityPathAttribute
219 #define NSAccessibilityPathAttribute @"AXPath"
220 #endif
222 #ifndef NSAccessibilityExpandedTextValueAttribute
223 #define NSAccessibilityExpandedTextValueAttribute @"AXExpandedTextValue"
224 #endif
226 #ifndef NSAccessibilityIsMultiSelectableAttribute
227 #define NSAccessibilityIsMultiSelectableAttribute @"AXIsMultiSelectable"
228 #endif
230 #ifndef NSAccessibilityDocumentURIAttribute
231 #define NSAccessibilityDocumentURIAttribute @"AXDocumentURI"
232 #endif
234 #ifndef NSAccessibilityDocumentEncodingAttribute
235 #define NSAccessibilityDocumentEncodingAttribute @"AXDocumentEncoding"
236 #endif
238 #ifndef NSAccessibilityAriaControlsAttribute
239 #define NSAccessibilityAriaControlsAttribute @"AXARIAControls"
240 #endif
242 #define NSAccessibilityDOMIdentifierAttribute @"AXDOMIdentifier"
243 #define NSAccessibilityDOMClassListAttribute @"AXDOMClassList"
245 #ifndef NSAccessibilityARIACurrentAttribute
246 #define NSAccessibilityARIACurrentAttribute @"AXARIACurrent"
247 #endif
249 // Table/grid attributes
250 #ifndef NSAccessibilityARIAColumnIndexAttribute
251 #define NSAccessibilityARIAColumnIndexAttribute @"AXARIAColumnIndex"
252 #endif
254 #ifndef NSAccessibilityARIARowIndexAttribute
255 #define NSAccessibilityARIARowIndexAttribute @"AXARIARowIndex"
256 #endif
258 #ifndef NSAccessibilityARIAColumnCountAttribute
259 #define NSAccessibilityARIAColumnCountAttribute @"AXARIAColumnCount"
260 #endif
262 #ifndef NSAccessibilityARIARowCountAttribute
263 #define NSAccessibilityARIARowCountAttribute @"AXARIARowCount"
264 #endif
267 #ifndef NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute
268 #define NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute @"AXUIElementCountForSearchPredicate"
269 #endif
271 #ifndef NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute
272 #define NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute @"AXUIElementsForSearchPredicate"
273 #endif
275 // Text markers
276 #ifndef NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute
277 #define NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute @"AXEndTextMarkerForBounds"
278 #endif
280 #ifndef NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute
281 #define NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute @"AXStartTextMarkerForBounds"
282 #endif
284 #ifndef NSAccessibilityLineTextMarkerRangeForTextMarkerParameterizedAttribute
285 #define NSAccessibilityLineTextMarkerRangeForTextMarkerParameterizedAttribute @"AXLineTextMarkerRangeForTextMarker"
286 #endif
288 #ifndef NSAccessibilityMisspellingTextMarkerRangeParameterizedAttribute
289 #define NSAccessibilityMisspellingTextMarkerRangeParameterizedAttribute @"AXMisspellingTextMarkerRange"
290 #endif
292 // Text selection
293 #ifndef NSAccessibilitySelectTextActivity
294 #define NSAccessibilitySelectTextActivity @"AXSelectTextActivity"
295 #endif
297 #ifndef NSAccessibilitySelectTextActivityFindAndReplace
298 #define NSAccessibilitySelectTextActivityFindAndReplace @"AXSelectTextActivityFindAndReplace"
299 #endif
301 #ifndef NSAccessibilitySelectTextActivityFindAndSelect
302 #define NSAccessibilitySelectTextActivityFindAndSelect @"AXSelectTextActivityFindAndSelect"
303 #endif
305 #ifndef kAXSelectTextActivityFindAndCapitalize
306 #define kAXSelectTextActivityFindAndCapitalize @"AXSelectTextActivityFindAndCapitalize"
307 #endif
309 #ifndef kAXSelectTextActivityFindAndLowercase
310 #define kAXSelectTextActivityFindAndLowercase @"AXSelectTextActivityFindAndLowercase"
311 #endif
313 #ifndef kAXSelectTextActivityFindAndUppercase
314 #define kAXSelectTextActivityFindAndUppercase @"AXSelectTextActivityFindAndUppercase"
315 #endif
317 #ifndef NSAccessibilitySelectTextAmbiguityResolution
318 #define NSAccessibilitySelectTextAmbiguityResolution @"AXSelectTextAmbiguityResolution"
319 #endif
321 #ifndef NSAccessibilitySelectTextAmbiguityResolutionClosestAfterSelection
322 #define NSAccessibilitySelectTextAmbiguityResolutionClosestAfterSelection @"AXSelectTextAmbiguityResolutionClosestAfterSelection"
323 #endif
325 #ifndef NSAccessibilitySelectTextAmbiguityResolutionClosestBeforeSelection
326 #define NSAccessibilitySelectTextAmbiguityResolutionClosestBeforeSelection @"AXSelectTextAmbiguityResolutionClosestBeforeSelection"
327 #endif
329 #ifndef NSAccessibilitySelectTextAmbiguityResolutionClosestToSelection
330 #define NSAccessibilitySelectTextAmbiguityResolutionClosestToSelection @"AXSelectTextAmbiguityResolutionClosestToSelection"
331 #endif
333 #ifndef NSAccessibilitySelectTextReplacementString
334 #define NSAccessibilitySelectTextReplacementString @"AXSelectTextReplacementString"
335 #endif
337 #ifndef NSAccessibilitySelectTextSearchStrings
338 #define NSAccessibilitySelectTextSearchStrings @"AXSelectTextSearchStrings"
339 #endif
341 #ifndef NSAccessibilitySelectTextWithCriteriaParameterizedAttribute
342 #define NSAccessibilitySelectTextWithCriteriaParameterizedAttribute @"AXSelectTextWithCriteria"
343 #endif
345 // Text search
347 #ifndef NSAccessibilitySearchTextWithCriteriaParameterizedAttribute
348 /* Performs a text search with the given parameters.
349  Returns an NSArray of text marker ranges of the search hits.
350  */
351 #define NSAccessibilitySearchTextWithCriteriaParameterizedAttribute @"AXSearchTextWithCriteria"
352 #endif
354 #ifndef NSAccessibilitySearchTextSearchStrings
355 // NSArray of strings to search for.
356 #define NSAccessibilitySearchTextSearchStrings @"AXSearchTextSearchStrings"
357 #endif
359 #ifndef NSAccessibilitySearchTextStartFrom
360 // NSString specifying the start point of the search: selection, begin or end.
361 #define NSAccessibilitySearchTextStartFrom @"AXSearchTextStartFrom"
362 #endif
364 #ifndef NSAccessibilitySearchTextStartFromBegin
365 // Value for SearchTextStartFrom.
366 #define NSAccessibilitySearchTextStartFromBegin @"AXSearchTextStartFromBegin"
367 #endif
369 #ifndef NSAccessibilitySearchTextStartFromSelection
370 // Value for SearchTextStartFrom.
371 #define NSAccessibilitySearchTextStartFromSelection @"AXSearchTextStartFromSelection"
372 #endif
374 #ifndef NSAccessibilitySearchTextStartFromEnd
375 // Value for SearchTextStartFrom.
376 #define NSAccessibilitySearchTextStartFromEnd @"AXSearchTextStartFromEnd"
377 #endif
379 #ifndef NSAccessibilitySearchTextDirection
380 // NSString specifying the direction of the search: forward, backward, closest, all.
381 #define NSAccessibilitySearchTextDirection @"AXSearchTextDirection"
382 #endif
384 #ifndef NSAccessibilitySearchTextDirectionForward
385 // Value for SearchTextDirection.
386 #define NSAccessibilitySearchTextDirectionForward @"AXSearchTextDirectionForward"
387 #endif
389 #ifndef NSAccessibilitySearchTextDirectionBackward
390 // Value for SearchTextDirection.
391 #define NSAccessibilitySearchTextDirectionBackward @"AXSearchTextDirectionBackward"
392 #endif
394 #ifndef NSAccessibilitySearchTextDirectionClosest
395 // Value for SearchTextDirection.
396 #define NSAccessibilitySearchTextDirectionClosest @"AXSearchTextDirectionClosest"
397 #endif
399 #ifndef NSAccessibilitySearchTextDirectionAll
400 // Value for SearchTextDirection.
401 #define NSAccessibilitySearchTextDirectionAll @"AXSearchTextDirectionAll"
402 #endif
404 // Text operations
406 #ifndef NSAccessibilityTextOperationParameterizedAttribute
407 // Performs an operation on the given text.
408 #define NSAccessibilityTextOperationParameterizedAttribute @"AXTextOperation"
409 #endif
411 #ifndef NSAccessibilityTextOperationMarkerRanges
412 // Text on which to perform operation.
413 #define NSAccessibilityTextOperationMarkerRanges @"AXTextOperationMarkerRanges"
414 #endif
416 #ifndef NSAccessibilityTextOperationType
417 // The type of operation to be performed: select, replace, capitalize....
418 #define NSAccessibilityTextOperationType @"AXTextOperationType"
419 #endif
421 #ifndef NSAccessibilityTextOperationSelect
422 // Value for TextOperationType.
423 #define NSAccessibilityTextOperationSelect @"TextOperationSelect"
424 #endif
426 #ifndef NSAccessibilityTextOperationReplace
427 // Value for TextOperationType.
428 #define NSAccessibilityTextOperationReplace @"TextOperationReplace"
429 #endif
431 #ifndef NSAccessibilityTextOperationCapitalize
432 // Value for TextOperationType.
433 #define NSAccessibilityTextOperationCapitalize @"Capitalize"
434 #endif
436 #ifndef NSAccessibilityTextOperationLowercase
437 // Value for TextOperationType.
438 #define NSAccessibilityTextOperationLowercase @"Lowercase"
439 #endif
441 #ifndef NSAccessibilityTextOperationUppercase
442 // Value for TextOperationType.
443 #define NSAccessibilityTextOperationUppercase @"Uppercase"
444 #endif
446 #ifndef NSAccessibilityTextOperationReplacementString
447 // Replacement text for operation replace.
448 #define NSAccessibilityTextOperationReplacementString @"AXTextOperationReplacementString"
449 #endif
451 // Math attributes
452 #define NSAccessibilityMathRootRadicandAttribute @"AXMathRootRadicand"
453 #define NSAccessibilityMathRootIndexAttribute @"AXMathRootIndex"
454 #define NSAccessibilityMathFractionDenominatorAttribute @"AXMathFractionDenominator"
455 #define NSAccessibilityMathFractionNumeratorAttribute @"AXMathFractionNumerator"
456 #define NSAccessibilityMathBaseAttribute @"AXMathBase"
457 #define NSAccessibilityMathSubscriptAttribute @"AXMathSubscript"
458 #define NSAccessibilityMathSuperscriptAttribute @"AXMathSuperscript"
459 #define NSAccessibilityMathUnderAttribute @"AXMathUnder"
460 #define NSAccessibilityMathOverAttribute @"AXMathOver"
461 #define NSAccessibilityMathFencedOpenAttribute @"AXMathFencedOpen"
462 #define NSAccessibilityMathFencedCloseAttribute @"AXMathFencedClose"
463 #define NSAccessibilityMathLineThicknessAttribute @"AXMathLineThickness"
464 #define NSAccessibilityMathPrescriptsAttribute @"AXMathPrescripts"
465 #define NSAccessibilityMathPostscriptsAttribute @"AXMathPostscripts"
467 #ifndef NSAccessibilityPreventKeyboardDOMEventDispatchAttribute
468 #define NSAccessibilityPreventKeyboardDOMEventDispatchAttribute @"AXPreventKeyboardDOMEventDispatch"
469 #endif
471 #ifndef NSAccessibilityCaretBrowsingEnabledAttribute
472 #define NSAccessibilityCaretBrowsingEnabledAttribute @"AXCaretBrowsingEnabled"
473 #endif
475 #ifndef NSAccessibilityWebSessionIDAttribute
476 #define NSAccessibilityWebSessionIDAttribute @"AXWebSessionID"
477 #endif
479 #ifndef NSAccessibilitFocusableAncestorAttribute
480 #define NSAccessibilityFocusableAncestorAttribute @"AXFocusableAncestor"
481 #endif
483 #ifndef NSAccessibilityEditableAncestorAttribute
484 #define NSAccessibilityEditableAncestorAttribute @"AXEditableAncestor"
485 #endif
487 #ifndef NSAccessibilityHighestEditableAncestorAttribute
488 #define NSAccessibilityHighestEditableAncestorAttribute @"AXHighestEditableAncestor"
489 #endif
491 #ifndef NSAccessibilityLinkRelationshipTypeAttribute
492 #define NSAccessibilityLinkRelationshipTypeAttribute @"AXLinkRelationshipType"
493 #endif
495 #ifndef NSAccessibilityRelativeFrameAttribute
496 #define NSAccessibilityRelativeFrameAttribute @"AXRelativeFrame"
497 #endif
499 #ifndef NSAccessibilityBrailleLabelAttribute
500 #define NSAccessibilityBrailleLabelAttribute @"AXBrailleLabel"
501 #endif
503 #ifndef NSAccessibilityBrailleRoleDescriptionAttribute
504 #define NSAccessibilityBrailleRoleDescriptionAttribute @"AXBrailleRoleDescription"
505 #endif
507 #ifndef NSAccessibilityEmbeddedImageDescriptionAttribute
508 #define NSAccessibilityEmbeddedImageDescriptionAttribute @"AXEmbeddedImageDescription"
509 #endif
511 #ifndef NSAccessibilityImageOverlayElementsAttribute
512 #define NSAccessibilityImageOverlayElementsAttribute @"AXImageOverlayElements"
513 #endif
515 #ifndef AXHasDocumentRoleAncestorAttribute
516 #define AXHasDocumentRoleAncestorAttribute @"AXHasDocumentRoleAncestor"
517 #endif
519 #ifndef AXHasWebApplicationAncestorAttribute
520 #define AXHasWebApplicationAncestorAttribute @"AXHasWebApplicationAncestor"
521 #endif
523 extern "C" AXUIElementRef NSAccessibilityCreateAXUIElementRef(id element);
525 @implementation WebAccessibilityObjectWrapper
527 - (void)detach
529     ASSERT(isMainThread());
531     // 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.
532     // The IsolatedObject is capable to tend to some requests after the live object is gone.
533     // In regular mode, UnregisterUniqueIdForUIElement immediately.
534 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
535     if (!m_isolatedObjectInitialized)
536 #endif
537         NSAccessibilityUnregisterUniqueIdForUIElement(self);
539     [super detach];
542 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
543 - (void)detachIsolatedObject:(AccessibilityDetachmentType)detachmentType
545     NSAccessibilityUnregisterUniqueIdForUIElement(self);
546     [super detachIsolatedObject:detachmentType];
548 #endif
550 - (id)attachmentView
552     return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
553         auto* backingObject = protectedSelf.get().axBackingObject;
554         if (!backingObject)
555             return nil;
557         auto* widget = backingObject->widgetForAttachmentView();
558         return widget ? NSAccessibilityUnignoredDescendant(widget->platformWidget()) : nil;
559     });
562 #pragma mark SystemInterface wrappers
564 static inline BOOL AXObjectIsTextMarker(id object)
566     return object && CFGetTypeID((__bridge CFTypeRef)object) == AXTextMarkerGetTypeID();
569 static inline BOOL AXObjectIsTextMarkerRange(id object)
571     return object && CFGetTypeID((__bridge CFTypeRef)object) == AXTextMarkerRangeGetTypeID();
574 #pragma mark Other helpers
576 - (IntRect)screenToContents:(const IntRect&)rect
578     ASSERT(isMainThread());
580     Document* document = self.axBackingObject->document();
581     if (!document)
582         return IntRect();
583     
584     FrameView* frameView = document->view();
585     if (!frameView)
586         return IntRect();
587     
588     IntPoint startPoint = frameView->screenToContents(rect.minXMaxYCorner());
589     IntPoint endPoint = frameView->screenToContents(rect.maxXMinYCorner());
590     return IntRect(startPoint.x(), startPoint.y(), endPoint.x() - startPoint.x(), endPoint.y() - startPoint.y());
593 #pragma mark Select text helpers
595 // To be deprecated.
596 static std::pair<AccessibilitySearchTextCriteria, AccessibilityTextOperation> accessibilityTextCriteriaForParameterizedAttribute(const NSDictionary *parameterizedAttribute)
598     AccessibilitySearchTextCriteria criteria;
599     AccessibilityTextOperation operation;
601     NSString *activityParameter = [parameterizedAttribute objectForKey:NSAccessibilitySelectTextActivity];
602     NSString *ambiguityResolutionParameter = [parameterizedAttribute objectForKey:NSAccessibilitySelectTextAmbiguityResolution];
603     NSString *replacementStringParameter = [parameterizedAttribute objectForKey:NSAccessibilitySelectTextReplacementString];
604     NSArray *searchStringsParameter = [parameterizedAttribute objectForKey:NSAccessibilitySelectTextSearchStrings];
606     if ([activityParameter isKindOfClass:[NSString class]]) {
607         if ([activityParameter isEqualToString:NSAccessibilitySelectTextActivityFindAndReplace])
608             operation.type = AccessibilityTextOperationType::Replace;
609         else if ([activityParameter isEqualToString:kAXSelectTextActivityFindAndCapitalize])
610             operation.type = AccessibilityTextOperationType::Capitalize;
611         else if ([activityParameter isEqualToString:kAXSelectTextActivityFindAndLowercase])
612             operation.type = AccessibilityTextOperationType::Lowercase;
613         else if ([activityParameter isEqualToString:kAXSelectTextActivityFindAndUppercase])
614             operation.type = AccessibilityTextOperationType::Uppercase;
615     }
617     criteria.direction = AccessibilitySearchTextDirection::Closest;
618     if ([ambiguityResolutionParameter isKindOfClass:[NSString class]]) {
619         if ([ambiguityResolutionParameter isEqualToString:NSAccessibilitySelectTextAmbiguityResolutionClosestAfterSelection])
620             criteria.direction = AccessibilitySearchTextDirection::Forward;
621         else if ([ambiguityResolutionParameter isEqualToString:NSAccessibilitySelectTextAmbiguityResolutionClosestBeforeSelection])
622             criteria.direction = AccessibilitySearchTextDirection::Backward;
623     }
625     if ([replacementStringParameter isKindOfClass:[NSString class]])
626         operation.replacementText = replacementStringParameter;
628     if ([searchStringsParameter isKindOfClass:[NSArray class]])
629         criteria.searchStrings = makeVector<String>(searchStringsParameter);
631     return std::make_pair(criteria, operation);
634 static AccessibilitySearchTextCriteria accessibilitySearchTextCriteriaForParameterizedAttribute(const NSDictionary *params)
636     AccessibilitySearchTextCriteria criteria;
638     NSArray *searchStrings = [params objectForKey:NSAccessibilitySearchTextSearchStrings];
639     NSString *start = [params objectForKey:NSAccessibilitySearchTextStartFrom];
640     NSString *direction = [params objectForKey:NSAccessibilitySearchTextDirection];
642     if ([searchStrings isKindOfClass:[NSArray class]])
643         criteria.searchStrings = makeVector<String>(searchStrings);
645     if ([start isKindOfClass:[NSString class]]) {
646         if ([start isEqualToString:NSAccessibilitySearchTextStartFromBegin])
647             criteria.start = AccessibilitySearchTextStartFrom::Begin;
648         else if ([start isEqualToString:NSAccessibilitySearchTextStartFromEnd])
649             criteria.start = AccessibilitySearchTextStartFrom::End;
650     }
652     if ([direction isKindOfClass:[NSString class]]) {
653         if ([direction isEqualToString:NSAccessibilitySearchTextDirectionBackward])
654             criteria.direction = AccessibilitySearchTextDirection::Backward;
655         else if ([direction isEqualToString:NSAccessibilitySearchTextDirectionClosest])
656             criteria.direction = AccessibilitySearchTextDirection::Closest;
657         else if ([direction isEqualToString:NSAccessibilitySearchTextDirectionAll])
658             criteria.direction = AccessibilitySearchTextDirection::All;
659     }
661     return criteria;
664 static AccessibilityTextOperation accessibilityTextOperationForParameterizedAttribute(AXObjectCache* axObjectCache, const NSDictionary *parameterizedAttribute)
666     AccessibilityTextOperation operation;
668     NSArray *markerRanges = [parameterizedAttribute objectForKey:NSAccessibilityTextOperationMarkerRanges];
669     NSString *operationType = [parameterizedAttribute objectForKey:NSAccessibilityTextOperationType];
670     NSString *replacementString = [parameterizedAttribute objectForKey:NSAccessibilityTextOperationReplacementString];
672     if ([markerRanges isKindOfClass:[NSArray class]]) {
673         operation.textRanges = makeVector(markerRanges, [&axObjectCache] (id markerRange) {
674             ASSERT(AXObjectIsTextMarkerRange(markerRange));
675             return rangeForTextMarkerRange(axObjectCache, (AXTextMarkerRangeRef)markerRange);
676         });
677     }
679     if ([operationType isKindOfClass:[NSString class]]) {
680         if ([operationType isEqualToString:NSAccessibilityTextOperationReplace])
681             operation.type = AccessibilityTextOperationType::Replace;
682         else if ([operationType isEqualToString:NSAccessibilityTextOperationCapitalize])
683             operation.type = AccessibilityTextOperationType::Capitalize;
684         else if ([operationType isEqualToString:NSAccessibilityTextOperationLowercase])
685             operation.type = AccessibilityTextOperationType::Lowercase;
686         else if ([operationType isEqualToString:NSAccessibilityTextOperationUppercase])
687             operation.type = AccessibilityTextOperationType::Uppercase;
688     }
690     if ([replacementString isKindOfClass:[NSString class]])
691         operation.replacementText = replacementString;
693     return operation;
696 static std::pair<std::optional<SimpleRange>, AccessibilitySearchDirection> accessibilityMisspellingSearchCriteriaForParameterizedAttribute(AXObjectCache* axObjectCache, const NSDictionary *params)
698     ASSERT(isMainThread());
700     std::pair<std::optional<SimpleRange>, AccessibilitySearchDirection> criteria;
702     ASSERT(AXObjectIsTextMarkerRange([params objectForKey:@"AXStartTextMarkerRange"]));
703     criteria.first = rangeForTextMarkerRange(axObjectCache, (AXTextMarkerRangeRef)[params objectForKey:@"AXStartTextMarkerRange"]);
705     NSNumber *forward = [params objectForKey:NSAccessibilitySearchTextDirection];
706     if ([forward isKindOfClass:[NSNumber class]])
707         criteria.second = [forward boolValue] ? AccessibilitySearchDirection::Next : AccessibilitySearchDirection::Previous;
708     else
709         criteria.second = AccessibilitySearchDirection::Next;
711     return criteria;
714 #pragma mark Text Marker helpers
716 static RetainPtr<AXTextMarkerRef> nextTextMarkerForCharacterOffset(AXObjectCache* cache, CharacterOffset& characterOffset)
718     if (!cache)
719         return nil;
720     
721     TextMarkerData textMarkerData;
722     cache->textMarkerDataForNextCharacterOffset(textMarkerData, characterOffset);
723     if (!textMarkerData.axID)
724         return nil;
725     return adoptCF(AXTextMarkerCreate(kCFAllocatorDefault, (const UInt8*)&textMarkerData, sizeof(textMarkerData)));
728 static RetainPtr<AXTextMarkerRef> previousTextMarkerForCharacterOffset(AXObjectCache* cache, CharacterOffset& characterOffset)
730     if (!cache)
731         return nil;
732     
733     TextMarkerData textMarkerData;
734     cache->textMarkerDataForPreviousCharacterOffset(textMarkerData, characterOffset);
735     if (!textMarkerData.axID)
736         return nil;
737     return adoptCF(AXTextMarkerCreate(kCFAllocatorDefault, (const UInt8*)&textMarkerData, sizeof(textMarkerData)));
740 - (RetainPtr<AXTextMarkerRef>)nextTextMarkerForCharacterOffset:(CharacterOffset&)characterOffset
742     return nextTextMarkerForCharacterOffset(self.axBackingObject->axObjectCache(), characterOffset);
745 - (RetainPtr<AXTextMarkerRef>)previousTextMarkerForCharacterOffset:(CharacterOffset&)characterOffset
747     return previousTextMarkerForCharacterOffset(self.axBackingObject->axObjectCache(), characterOffset);
750 // FIXME: Remove this method since clients should not need to call this method and should not be exposed in the public interface.
751 // Inside WebCore, use WebCore::textMarkerFromVisiblePosition instead.
752 - (id)textMarkerForVisiblePosition:(const VisiblePosition&)position
754     ASSERT(isMainThread());
755     auto *backingObject = self.axBackingObject;
756     return backingObject ? (id)textMarkerForVisiblePosition(backingObject->axObjectCache(), position) : nil;
759 - (RetainPtr<AXTextMarkerRef>)textMarkerForFirstPositionInTextControl:(HTMLTextFormControlElement &)textControl
761     ASSERT(isMainThread());
763     auto* backingObject = self.axBackingObject;
764     if (!backingObject)
765         return nil;
767     auto* cache = backingObject->axObjectCache();
768     if (!cache)
769         return nil;
771     auto textMarkerData = cache->textMarkerDataForFirstPositionInTextControl(textControl);
772     if (!textMarkerData)
773         return nil;
775     return adoptCF(AXTextMarkerCreate(kCFAllocatorDefault, (const UInt8*)&textMarkerData.value(), sizeof(textMarkerData.value())));
778 static void AXAttributeStringSetColor(NSMutableAttributedString* attrString, NSString* attribute, NSColor* color, NSRange range)
780     if (!AXAttributedStringRangeIsValid(attrString, range))
781         return;
783     if (color) {
784         CGColorRef cgColor = color.CGColor;
785         id existingColor = [attrString attribute:attribute atIndex:range.location effectiveRange:nil];
786         if (!existingColor || !CGColorEqualToColor((__bridge CGColorRef)existingColor, cgColor))
787             [attrString addAttribute:attribute value:(__bridge id)cgColor range:range];
788     } else
789         [attrString removeAttribute:attribute range:range];
792 static void AXAttributeStringSetNumber(NSMutableAttributedString* attrString, NSString* attribute, NSNumber* number, NSRange range)
794     if (!AXAttributedStringRangeIsValid(attrString, range))
795         return;
796     
797     if (number)
798         [attrString addAttribute:attribute value:number range:range];
799     else
800         [attrString removeAttribute:attribute range:range];
803 static void AXAttributeStringSetStyle(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
805     const RenderStyle& style = renderer->style();
807     // set basic font info
808     AXAttributedStringSetFont(attrString, style.fontCascade().primaryFont().getCTFont(), range);
810     // set basic colors
811     AXAttributeStringSetColor(attrString, NSAccessibilityForegroundColorTextAttribute, cocoaColor(style.visitedDependentColor(CSSPropertyColor)).get(), range);
812     AXAttributeStringSetColor(attrString, NSAccessibilityBackgroundColorTextAttribute, cocoaColor(style.visitedDependentColor(CSSPropertyBackgroundColor)).get(), range);
813     
814     // set super/sub scripting
815     VerticalAlign alignment = style.verticalAlign();
816     if (alignment == VerticalAlign::Sub)
817         AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, @(-1), range);
818     else if (alignment == VerticalAlign::Super)
819         AXAttributeStringSetNumber(attrString, NSAccessibilitySuperscriptTextAttribute, @(1), range);
820     else
821         [attrString removeAttribute:NSAccessibilitySuperscriptTextAttribute range:range];
822     
823     // set shadow
824     if (style.textShadow())
825         AXAttributeStringSetNumber(attrString, NSAccessibilityShadowTextAttribute, @YES, range);
826     else
827         [attrString removeAttribute:NSAccessibilityShadowTextAttribute range:range];
828     
829     // set underline and strikethrough
830     auto decor = style.textDecorationsInEffect();
831     if (!(decor & TextDecorationLine::Underline)) {
832         [attrString removeAttribute:NSAccessibilityUnderlineTextAttribute range:range];
833         [attrString removeAttribute:NSAccessibilityUnderlineColorTextAttribute range:range];
834     }
835     if (!(decor & TextDecorationLine::LineThrough)) {
836         [attrString removeAttribute:NSAccessibilityStrikethroughTextAttribute range:range];
837         [attrString removeAttribute:NSAccessibilityStrikethroughColorTextAttribute range:range];
838     }
840     if (decor & TextDecorationLine::Underline || decor & TextDecorationLine::LineThrough) {
841         // FIXME: Should the underline style be reported here?
842         auto decorationStyles = TextDecorationPainter::stylesForRenderer(*renderer, decor);
844         if (decor & TextDecorationLine::Underline) {
845             AXAttributeStringSetNumber(attrString, NSAccessibilityUnderlineTextAttribute, @YES, range);
846             AXAttributeStringSetColor(attrString, NSAccessibilityUnderlineColorTextAttribute, cocoaColor(decorationStyles.underlineColor).get(), range);
847         }
849         if (decor & TextDecorationLine::LineThrough) {
850             AXAttributeStringSetNumber(attrString, NSAccessibilityStrikethroughTextAttribute, @YES, range);
851             AXAttributeStringSetColor(attrString, NSAccessibilityStrikethroughColorTextAttribute, cocoaColor(decorationStyles.linethroughColor).get(), range);
852         }
853     }
854     
855     // FIXME: This traversal should be replaced by a flag in AccessibilityObject::m_ancestorFlags (e.g., AXAncestorFlag::HasHTMLMarkAncestor)
856     // Indicate background highlighting.
857     for (Node* node = renderer->node(); node; node = node->parentNode()) {
858         if (node->hasTagName(HTMLNames::markTag))
859             AXAttributeStringSetNumber(attrString, @"AXHighlight", @YES, range);
860     }
863 static void AXAttributeStringSetBlockquoteLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
865     if (!AXAttributedStringRangeIsValid(attrString, range))
866         return;
867     
868     AccessibilityObject* obj = renderer->document().axObjectCache()->getOrCreate(renderer);
869     int quoteLevel = obj->blockquoteLevel();
870     
871     if (quoteLevel)
872         [attrString addAttribute:NSAccessibilityBlockQuoteLevelAttribute value:@(quoteLevel) range:range];
873     else
874         [attrString removeAttribute:NSAccessibilityBlockQuoteLevelAttribute range:range];
877 static void AXAttributeStringSetSpelling(NSMutableAttributedString* attrString, Node* node, StringView text, NSRange range)
879     ASSERT(node);
880     
881     // If this node is not inside editable content, do not run the spell checker on the text.
882     if (!node->document().axObjectCache()->rootAXEditableElement(node))
883         return;
885     if (unifiedTextCheckerEnabled(node->document().frame())) {
886         // Check the spelling directly since document->markersForNode() does not store the misspelled marking when the cursor is in a word.
887         TextCheckerClient* checker = node->document().editor().textChecker();
888         
889         // checkTextOfParagraph is the only spelling/grammar checker implemented in WK1 and WK2
890         Vector<TextCheckingResult> results;
891         checkTextOfParagraph(*checker, text, TextCheckingType::Spelling, results, node->document().frame()->selection().selection());
892         
893         size_t size = results.size();
894         for (unsigned i = 0; i < size; i++) {
895             const TextCheckingResult& result = results[i];
896             AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, @YES, NSMakeRange(result.range.location + range.location, result.range.length));
897 #if PLATFORM(MAC)
898             AXAttributeStringSetNumber(attrString, NSAccessibilityMarkedMisspelledTextAttribute, @YES, NSMakeRange(result.range.location + range.location, result.range.length));
899 #endif
900         }
901         return;
902     }
904     for (unsigned currentPosition = 0; currentPosition < text.length(); ) {
905         int misspellingLocation = -1;
906         int misspellingLength = 0;
907         node->document().editor().textChecker()->checkSpellingOfString(text.substring(currentPosition), &misspellingLocation, &misspellingLength);
908         if (misspellingLocation == -1 || !misspellingLength)
909             break;
910         
911         NSRange spellRange = NSMakeRange(range.location + currentPosition + misspellingLocation, misspellingLength);
912         AXAttributeStringSetNumber(attrString, NSAccessibilityMisspelledTextAttribute, @YES, spellRange);
913 #if PLATFORM(MAC)
914         AXAttributeStringSetNumber(attrString, NSAccessibilityMarkedMisspelledTextAttribute, @YES, spellRange);
915 #endif
917         currentPosition += misspellingLocation + misspellingLength;
918     }
921 static void AXAttributeStringSetExpandedTextValue(NSMutableAttributedString *attrString, RenderObject* renderer, NSRange range)
923     if (!renderer || !AXAttributedStringRangeIsValid(attrString, range))
924         return;
925     AccessibilityObject* axObject = renderer->document().axObjectCache()->getOrCreate(renderer);
926     if (axObject->supportsExpandedTextValue())
927         [attrString addAttribute:NSAccessibilityExpandedTextValueAttribute value:axObject->expandedTextValue() range:range];
928     else
929         [attrString removeAttribute:NSAccessibilityExpandedTextValueAttribute range:range];
932 static void AXAttributeStringSetHeadingLevel(NSMutableAttributedString* attrString, RenderObject* renderer, NSRange range)
934     if (!renderer)
935         return;
936     
937     if (!AXAttributedStringRangeIsValid(attrString, range))
938         return;
939     
940     // Sometimes there are objects between the text and the heading.
941     // In those cases the parent hierarchy should be queried to see if there is a heading level.
942     int parentHeadingLevel = 0;
943     AccessibilityObject* parentObject = renderer->document().axObjectCache()->getOrCreate(renderer->parent());
944     for (; parentObject; parentObject = parentObject->parentObject()) {
945         parentHeadingLevel = parentObject->headingLevel();
946         if (parentHeadingLevel)
947             break;
948     }
949     
950     if (parentHeadingLevel)
951         [attrString addAttribute:@"AXHeadingLevel" value:@(parentHeadingLevel) range:range];
952     else
953         [attrString removeAttribute:@"AXHeadingLevel" range:range];
956 static void AXAttributeStringSetElement(NSMutableAttributedString* attrString, NSString* attribute, AccessibilityObject* object, NSRange range)
958     if (!AXAttributedStringRangeIsValid(attrString, range))
959         return;
960     
961     if (is<AccessibilityRenderObject>(object)) {
962         // make a serializable AX object
963         
964         RenderObject* renderer = downcast<AccessibilityRenderObject>(*object).renderer();
965         if (!renderer)
966             return;
967         
968         AXObjectCache* cache = renderer->document().axObjectCache();
969         if (!cache)
970             return;
971         
972         id objectWrapper = object->wrapper();
973         if ([attribute isEqualToString:NSAccessibilityAttachmentTextAttribute] && object->isAttachment() && [objectWrapper attachmentView])
974             objectWrapper = [objectWrapper attachmentView];
975         
976         if (auto axElement = adoptCF(NSAccessibilityCreateAXUIElementRef(objectWrapper)))
977             [attrString addAttribute:attribute value:(__bridge id)axElement.get() range:range];
978     } else
979         [attrString removeAttribute:attribute range:range];
982 static void AXAttributedStringAppendText(NSMutableAttributedString* attrString, Node* node, StringView text, bool spellCheck)
984     // skip invisible text
985     RenderObject* renderer = node->renderer();
986     if (!renderer || !text.length())
987         return;
988     
989     // easier to calculate the range before appending the string
990     NSRange attrStringRange = NSMakeRange([attrString length], text.length());
991     
992     // append the string from this node
993     [[attrString mutableString] appendString:text.createNSStringWithoutCopying().get()];
994     
995     // add new attributes and remove irrelevant inherited ones
996     // NOTE: color attributes are handled specially because -[NSMutableAttributedString addAttribute: value: range:] does not merge
997     // identical colors.  Workaround is to not replace an existing color attribute if it matches what we are adding.  This also means
998     // we cannot just pre-remove all inherited attributes on the appended string, so we have to remove the irrelevant ones individually.
999     
1000     // remove inherited attachment from prior AXAttributedStringAppendReplaced
1001     [attrString removeAttribute:NSAccessibilityAttachmentTextAttribute range:attrStringRange];
1002     if (spellCheck) {
1003 #if PLATFORM(MAC)
1004         [attrString removeAttribute:NSAccessibilityMarkedMisspelledTextAttribute range:attrStringRange];
1005 #endif
1006         [attrString removeAttribute:NSAccessibilityMisspelledTextAttribute range:attrStringRange];
1007     }
1009     // set new attributes
1010     AXAttributeStringSetStyle(attrString, renderer, attrStringRange);
1011     AXAttributeStringSetHeadingLevel(attrString, renderer, attrStringRange);
1012     AXAttributeStringSetBlockquoteLevel(attrString, renderer, attrStringRange);
1013     AXAttributeStringSetExpandedTextValue(attrString, renderer, attrStringRange);
1014     AXAttributeStringSetElement(attrString, NSAccessibilityLinkTextAttribute, AccessibilityObject::anchorElementForNode(node), attrStringRange);
1015     
1016     // do spelling last because it tends to break up the range
1017     if (spellCheck)
1018         AXAttributeStringSetSpelling(attrString, node, text, attrStringRange);
1021 static NSString* nsStringForReplacedNode(Node* replacedNode)
1023     // we should always be given a rendered node and a replaced node, but be safe
1024     // replaced nodes are either attachments (widgets) or images
1025     if (!replacedNode || !isRendererReplacedElement(replacedNode->renderer()) || replacedNode->isTextNode()) {
1026         ASSERT_NOT_REACHED();
1027         return nil;
1028     }
1029     
1030     // create an AX object, but skip it if it is not supposed to be seen
1031     RefPtr<AccessibilityObject> obj = replacedNode->renderer()->document().axObjectCache()->getOrCreate(replacedNode->renderer());
1032     if (obj->accessibilityIsIgnored())
1033         return nil;
1034     
1035     // use the attachmentCharacter to represent the replaced node
1036     const UniChar attachmentChar = NSAttachmentCharacter;
1037     return [NSString stringWithCharacters:&attachmentChar length:1];
1040 - (NSAttributedString *)doAXAttributedStringForTextMarkerRange:(AXTextMarkerRangeRef)textMarkerRange spellCheck:(BOOL)spellCheck
1042     return Accessibility::retrieveAutoreleasedValueFromMainThread<NSAttributedString *>([&textMarkerRange, &spellCheck, protectedSelf = retainPtr(self)] () -> RetainPtr<NSAttributedString> {
1043         auto* backingObject = protectedSelf.get().axBackingObject;
1044         if (!backingObject)
1045             return nil;
1047         auto range = rangeForTextMarkerRange(backingObject->axObjectCache(), textMarkerRange);
1048         if (!range)
1049             return nil;
1050         auto attrString = adoptNS([[NSMutableAttributedString alloc] init]);
1051         TextIterator it(*range);
1052         while (!it.atEnd()) {
1053             Node& node = it.range().start.container;
1055             // non-zero length means textual node, zero length means replaced node (AKA "attachments" in AX)
1056             if (it.text().length()) {
1057                 // Add the text of the list marker item if necessary.
1058                 String listMarkerText = AccessibilityObject::listMarkerTextForNodeAndPosition(&node, makeContainerOffsetPosition(it.range().start));
1059                 if (!listMarkerText.isEmpty())
1060                     AXAttributedStringAppendText(attrString.get(), &node, listMarkerText, spellCheck);
1061                 AXAttributedStringAppendText(attrString.get(), &node, it.text(), spellCheck);
1062             } else {
1063                 Node* replacedNode = it.node();
1064                 NSString *attachmentString = nsStringForReplacedNode(replacedNode);
1065                 if (attachmentString) {
1066                     NSRange attrStringRange = NSMakeRange([attrString length], [attachmentString length]);
1068                     // append the placeholder string
1069                     [[attrString mutableString] appendString:attachmentString];
1071                     // remove all inherited attributes
1072                     [attrString setAttributes:nil range:attrStringRange];
1074                     // add the attachment attribute
1075                     AccessibilityObject* obj = replacedNode->renderer()->document().axObjectCache()->getOrCreate(replacedNode->renderer());
1076                     AXAttributeStringSetElement(attrString.get(), NSAccessibilityAttachmentTextAttribute, obj, attrStringRange);
1077                 }
1078             }
1079             it.advance();
1080         }
1082         return attrString;
1083     });
1086 // FIXME: Remove this method since clients should not need to call this method and should not be exposed in the public interface.
1087 // Inside WebCore, use WebCore::textMarkerRangeFromVisiblePositions instead.
1088 - (id)textMarkerRangeFromVisiblePositions:(const VisiblePosition&)startPosition endPosition:(const VisiblePosition&)endPosition
1090     return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([&startPosition, &endPosition, protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
1091         auto* backingObject = protectedSelf.get().axBackingObject;
1092         if (!backingObject)
1093             return nil;
1095         return (id)textMarkerRangeFromVisiblePositions(backingObject->axObjectCache(), startPosition, endPosition);
1096     });
1099 ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGIN
1100 - (NSArray*)accessibilityActionNames
1101 ALLOW_DEPRECATED_IMPLEMENTATIONS_END
1103     auto* backingObject = self.updateObjectBackingStore;
1104     if (!backingObject)
1105         return nil;
1107     // All elements should get ShowMenu and ScrollToVisible.
1108     // But certain earlier VoiceOver versions do not support scroll to visible, and it confuses them to see it in the list.
1109     static NeverDestroyed<RetainPtr<NSArray>> defaultElementActions = @[NSAccessibilityShowMenuAction, NSAccessibilityScrollToVisibleAction];
1111     // Action elements allow Press.
1112     // 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.
1113     static NeverDestroyed<RetainPtr<NSArray>> actionElementActions = @[NSAccessibilityPressAction, NSAccessibilityShowMenuAction, NSAccessibilityScrollToVisibleAction];
1115     // Menu elements allow Press and Cancel.
1116     static NeverDestroyed<RetainPtr<NSArray>> menuElementActions = [actionElementActions.get() arrayByAddingObject:NSAccessibilityCancelAction];
1118     // Slider elements allow Increment/Decrement.
1119     static NeverDestroyed<RetainPtr<NSArray>> sliderActions = [defaultElementActions.get() arrayByAddingObjectsFromArray:@[NSAccessibilityIncrementAction, NSAccessibilityDecrementAction]];
1121     NSArray *actions;
1122     if (backingObject->supportsPressAction())
1123         actions = actionElementActions.get().get();
1124     else if (backingObject->isMenuRelated())
1125         actions = menuElementActions.get().get();
1126     else if (backingObject->isSlider())
1127         actions = sliderActions.get().get();
1128     else if (backingObject->isAttachment())
1129         actions = [[self attachmentView] accessibilityActionNames];
1130     else
1131         actions = defaultElementActions.get().get();
1133     return actions;
1136 - (NSArray*)additionalAccessibilityAttributeNames
1138     auto* backingObject = self.axBackingObject;
1139     if (!backingObject)
1140         return nil;
1142     NSMutableArray *additional = [NSMutableArray array];
1143     if (backingObject->supportsARIAOwns())
1144         [additional addObject:NSAccessibilityOwnsAttribute];
1146     if (backingObject->isToggleButton())
1147         [additional addObject:NSAccessibilityValueAttribute];
1149     if (backingObject->supportsExpanded() || backingObject->isSummary())
1150         [additional addObject:NSAccessibilityExpandedAttribute];
1152     if (backingObject->isScrollbar()
1153         || backingObject->isRadioGroup()
1154         || backingObject->isSplitter()
1155         || backingObject->isToolbar())
1156         [additional addObject:NSAccessibilityOrientationAttribute];
1158     if (backingObject->supportsDragging())
1159         [additional addObject:NSAccessibilityGrabbedAttribute];
1161     if (backingObject->supportsDropping())
1162         [additional addObject:NSAccessibilityDropEffectsAttribute];
1164     if (backingObject->isTable() && backingObject->isExposable() && backingObject->supportsSelectedRows())
1165         [additional addObject:NSAccessibilitySelectedRowsAttribute];
1167     if (backingObject->supportsLiveRegion()) {
1168         [additional addObject:NSAccessibilityARIALiveAttribute];
1169         [additional addObject:NSAccessibilityARIARelevantAttribute];
1170     }
1172     if (backingObject->supportsSetSize())
1173         [additional addObject:NSAccessibilityARIASetSizeAttribute];
1175     if (backingObject->supportsPosInSet())
1176         [additional addObject:NSAccessibilityARIAPosInSetAttribute];
1178     AccessibilitySortDirection sortDirection = backingObject->sortDirection();
1179     if (sortDirection != AccessibilitySortDirection::None && sortDirection != AccessibilitySortDirection::Invalid)
1180         [additional addObject:NSAccessibilitySortDirectionAttribute];
1182     // If an object is a child of a live region, then add these
1183     if (backingObject->isInsideLiveRegion())
1184         [additional addObject:NSAccessibilityARIAAtomicAttribute];
1186     // All objects should expose the ARIA busy attribute (ARIA 1.1 with ISSUE-538).
1187     [additional addObject:NSAccessibilityElementBusyAttribute];
1189     // Popup buttons on the Mac expose the value attribute.
1190     if (backingObject->isPopUpButton())
1191         [additional addObject:NSAccessibilityValueAttribute];
1193     if (backingObject->supportsDatetimeAttribute())
1194         [additional addObject:NSAccessibilityDatetimeValueAttribute];
1196     if (backingObject->supportsRequiredAttribute())
1197         [additional addObject:NSAccessibilityRequiredAttribute];
1199     if (backingObject->hasPopup())
1200         [additional addObject:NSAccessibilityHasPopupAttribute];
1202     if (backingObject->isMathRoot()) {
1203         // The index of a square root is always known, so there's no object associated with it.
1204         if (!backingObject->isMathSquareRoot())
1205             [additional addObject:NSAccessibilityMathRootIndexAttribute];
1206         [additional addObject:NSAccessibilityMathRootRadicandAttribute];
1207     } else if (backingObject->isMathFraction()) {
1208         [additional addObject:NSAccessibilityMathFractionNumeratorAttribute];
1209         [additional addObject:NSAccessibilityMathFractionDenominatorAttribute];
1210         [additional addObject:NSAccessibilityMathLineThicknessAttribute];
1211     } else if (backingObject->isMathSubscriptSuperscript()) {
1212         [additional addObject:NSAccessibilityMathBaseAttribute];
1213         [additional addObject:NSAccessibilityMathSubscriptAttribute];
1214         [additional addObject:NSAccessibilityMathSuperscriptAttribute];
1215     } else if (backingObject->isMathUnderOver()) {
1216         [additional addObject:NSAccessibilityMathBaseAttribute];
1217         [additional addObject:NSAccessibilityMathUnderAttribute];
1218         [additional addObject:NSAccessibilityMathOverAttribute];
1219     } else if (backingObject->isMathFenced()) {
1220         [additional addObject:NSAccessibilityMathFencedOpenAttribute];
1221         [additional addObject:NSAccessibilityMathFencedCloseAttribute];
1222     } else if (backingObject->isMathMultiscript()) {
1223         [additional addObject:NSAccessibilityMathBaseAttribute];
1224         [additional addObject:NSAccessibilityMathPrescriptsAttribute];
1225         [additional addObject:NSAccessibilityMathPostscriptsAttribute];
1226     }
1228     if (backingObject->supportsPath())
1229         [additional addObject:NSAccessibilityPathAttribute];
1231     if (backingObject->supportsExpandedTextValue())
1232         [additional addObject:NSAccessibilityExpandedTextValueAttribute];
1234 #if ENABLE(ACCESSIBILITY_ISOLATED_TREE)
1235     if (AXObjectCache::isIsolatedTreeEnabled())
1236         [additional addObject:NSAccessibilityRelativeFrameAttribute];
1237 #endif
1238     
1239     return additional;
1242 ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGIN
1243 - (NSArray*)accessibilityAttributeNames
1244 ALLOW_DEPRECATED_IMPLEMENTATIONS_END
1246     auto* backingObject = self.axBackingObject;
1247     if (!backingObject)
1248         return nil;
1250     if (backingObject->isAttachment())
1251         return [[self attachmentView] accessibilityAttributeNames];
1253     static NeverDestroyed<RetainPtr<NSArray>> attributes = @[
1254         AXHasDocumentRoleAncestorAttribute,
1255         AXHasWebApplicationAncestorAttribute,
1256         NSAccessibilityRoleAttribute,
1257         NSAccessibilitySubroleAttribute,
1258         NSAccessibilityRoleDescriptionAttribute,
1259         NSAccessibilityChildrenAttribute,
1260         NSAccessibilityChildrenInNavigationOrderAttribute,
1261         NSAccessibilityHelpAttribute,
1262         NSAccessibilityParentAttribute,
1263         NSAccessibilityPositionAttribute,
1264         NSAccessibilitySizeAttribute,
1265         NSAccessibilityTitleAttribute,
1266         NSAccessibilityDescriptionAttribute,
1267         NSAccessibilityValueAttribute,
1268         NSAccessibilityFocusedAttribute,
1269         NSAccessibilityEnabledAttribute,
1270         NSAccessibilityWindowAttribute,
1271         @"AXSelectedTextMarkerRange",
1272         @"AXStartTextMarker",
1273         @"AXEndTextMarker",
1274         @"AXVisited",
1275         NSAccessibilityLinkedUIElementsAttribute,
1276         NSAccessibilitySelectedAttribute,
1277         NSAccessibilityBlockQuoteLevelAttribute,
1278         NSAccessibilityTopLevelUIElementAttribute,
1279         NSAccessibilityLanguageAttribute,
1280         NSAccessibilityDOMIdentifierAttribute,
1281         NSAccessibilityDOMClassListAttribute,
1282         NSAccessibilityFocusableAncestorAttribute,
1283         NSAccessibilityEditableAncestorAttribute,
1284         NSAccessibilityHighestEditableAncestorAttribute,
1285     ];
1286     static NeverDestroyed incrementorAttrs = [] {
1287         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
1288         [tempArray addObject:NSAccessibilityIncrementButtonAttribute];
1289         [tempArray addObject:NSAccessibilityDecrementButtonAttribute];
1290         [tempArray addObject:NSAccessibilityValueDescriptionAttribute];
1291         [tempArray addObject:NSAccessibilityMinValueAttribute];
1292         [tempArray addObject:NSAccessibilityMaxValueAttribute];
1293         return tempArray;
1294     }();
1295     static NeverDestroyed anchorAttrs = [] {
1296         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
1297         [tempArray addObject:NSAccessibilityURLAttribute];
1298         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1299         [tempArray addObject:NSAccessibilityLinkRelationshipTypeAttribute];
1300         return tempArray;
1301     }();
1302     static NeverDestroyed<RetainPtr<NSArray>> commonMenuAttrs = @[
1303         NSAccessibilityRoleAttribute,
1304         NSAccessibilityRoleDescriptionAttribute,
1305         NSAccessibilityChildrenAttribute,
1306         NSAccessibilityParentAttribute,
1307         NSAccessibilityEnabledAttribute,
1308         NSAccessibilityPositionAttribute,
1309         NSAccessibilitySizeAttribute,
1310     ];
1311     static NeverDestroyed webAreaAttrs = [] {
1312         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
1313         // WebAreas should not expose AXSubrole.
1314         [tempArray removeObject:NSAccessibilitySubroleAttribute];
1315         // WebAreas should not expose ancestor attributes
1316         [tempArray removeObject:NSAccessibilityFocusableAncestorAttribute];
1317         [tempArray removeObject:NSAccessibilityEditableAncestorAttribute];
1318         [tempArray removeObject:NSAccessibilityHighestEditableAncestorAttribute];
1319         [tempArray addObject:@"AXLinkUIElements"];
1320         [tempArray addObject:@"AXLoaded"];
1321         [tempArray addObject:@"AXLayoutCount"];
1322         [tempArray addObject:NSAccessibilityLoadingProgressAttribute];
1323         [tempArray addObject:NSAccessibilityURLAttribute];
1324         [tempArray addObject:NSAccessibilityCaretBrowsingEnabledAttribute];
1325         [tempArray addObject:NSAccessibilityPreventKeyboardDOMEventDispatchAttribute];
1326         [tempArray addObject:NSAccessibilityWebSessionIDAttribute];
1327         return tempArray;
1328     }();
1329     static NeverDestroyed textAttrs = [] {
1330         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
1331         [tempArray addObject:NSAccessibilityNumberOfCharactersAttribute];
1332         [tempArray addObject:NSAccessibilitySelectedTextAttribute];
1333         [tempArray addObject:NSAccessibilitySelectedTextRangeAttribute];
1334         [tempArray addObject:NSAccessibilityVisibleCharacterRangeAttribute];
1335         [tempArray addObject:NSAccessibilityInsertionPointLineNumberAttribute];
1336         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1337         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1338         [tempArray addObject:NSAccessibilityRequiredAttribute];
1339         [tempArray addObject:NSAccessibilityInvalidAttribute];
1340         [tempArray addObject:NSAccessibilityPlaceholderValueAttribute];
1341         [tempArray addObject:NSAccessibilityValueAutofilledAttribute];
1342         return tempArray;
1343     }();
1344     static NeverDestroyed listAttrs = [] {
1345         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
1346         [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
1347         [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
1348         [tempArray addObject:NSAccessibilityOrientationAttribute];
1349         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1350         return tempArray;
1351     }();
1352     static NeverDestroyed listBoxAttrs = [] {
1353         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:listAttrs.get().get()]);
1354         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1355         [tempArray addObject:NSAccessibilityRequiredAttribute];
1356         [tempArray addObject:NSAccessibilityInvalidAttribute];
1357         [tempArray addObject:NSAccessibilityOrientationAttribute];
1358         return tempArray;
1359     }();
1360     static NeverDestroyed rangeAttrs = [] {
1361         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
1362         [tempArray addObject:NSAccessibilityMinValueAttribute];
1363         [tempArray addObject:NSAccessibilityMaxValueAttribute];
1364         [tempArray addObject:NSAccessibilityOrientationAttribute];
1365         [tempArray addObject:NSAccessibilityValueDescriptionAttribute];
1366         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1367         return tempArray;
1368     }();
1369     static NeverDestroyed menuBarAttrs = [] {
1370         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:commonMenuAttrs.get().get()]);
1371         [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
1372         [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
1373         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1374         [tempArray addObject:NSAccessibilityOrientationAttribute];
1375         return tempArray;
1376     }();
1377     static NeverDestroyed menuAttrs = [] {
1378         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:commonMenuAttrs.get().get()]);
1379         [tempArray addObject:NSAccessibilitySelectedChildrenAttribute];
1380         [tempArray addObject:NSAccessibilityVisibleChildrenAttribute];
1381         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1382         [tempArray addObject:NSAccessibilityOrientationAttribute];
1383         return tempArray;
1384     }();
1385     static NeverDestroyed menuItemAttrs = [] {
1386         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:commonMenuAttrs.get().get()]);
1387         [tempArray addObject:NSAccessibilityTitleAttribute];
1388         [tempArray addObject:NSAccessibilityDescriptionAttribute];
1389         [tempArray addObject:NSAccessibilityHelpAttribute];
1390         [tempArray addObject:NSAccessibilitySelectedAttribute];
1391         [tempArray addObject:NSAccessibilityValueAttribute];
1392         [tempArray addObject:(NSString*)kAXMenuItemCmdCharAttribute];
1393         [tempArray addObject:(NSString*)kAXMenuItemCmdVirtualKeyAttribute];
1394         [tempArray addObject:(NSString*)kAXMenuItemCmdGlyphAttribute];
1395         [tempArray addObject:(NSString*)kAXMenuItemCmdModifiersAttribute];
1396         [tempArray addObject:(NSString*)kAXMenuItemMarkCharAttribute];
1397         [tempArray addObject:(NSString*)kAXMenuItemPrimaryUIElementAttribute];
1398         [tempArray addObject:NSAccessibilityServesAsTitleForUIElementsAttribute];
1399         [tempArray addObject:NSAccessibilityFocusedAttribute];
1400         return tempArray;
1401     }();
1402     static NeverDestroyed<RetainPtr<NSArray>> menuButtonAttrs = @[
1403         NSAccessibilityRoleAttribute,
1404         NSAccessibilityRoleDescriptionAttribute,
1405         NSAccessibilityParentAttribute,
1406         NSAccessibilityPositionAttribute,
1407         NSAccessibilitySizeAttribute,
1408         NSAccessibilityWindowAttribute,
1409         NSAccessibilityEnabledAttribute,
1410         NSAccessibilityFocusedAttribute,
1411         NSAccessibilityTitleAttribute,
1412         NSAccessibilityChildrenAttribute,
1413     ];
1414     static NeverDestroyed controlAttrs = [] {
1415         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
1416         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1417         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1418         [tempArray addObject:NSAccessibilityRequiredAttribute];
1419         [tempArray addObject:NSAccessibilityInvalidAttribute];
1420         return tempArray;
1421     }();
1422     static NeverDestroyed buttonAttrs = [] {
1423         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
1424         // Buttons should not expose AXValue.
1425         [tempArray removeObject:NSAccessibilityValueAttribute];
1426         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1427         [tempArray addObject:NSAccessibilityAccessKeyAttribute];
1428         return tempArray;
1429     }();
1430     static NeverDestroyed comboBoxAttrs = [] {
1431         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:controlAttrs.get().get()]);
1432         [tempArray addObject:NSAccessibilityExpandedAttribute];
1433         [tempArray addObject:NSAccessibilityOrientationAttribute];
1434         return tempArray;
1435     }();
1436     static NeverDestroyed tableAttrs = [] {
1437         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
1438         [tempArray addObject:NSAccessibilityRowsAttribute];
1439         [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
1440         [tempArray addObject:NSAccessibilityColumnsAttribute];
1441         [tempArray addObject:NSAccessibilityVisibleColumnsAttribute];
1442         [tempArray addObject:NSAccessibilityVisibleCellsAttribute];
1443         [tempArray addObject:NSAccessibilityColumnHeaderUIElementsAttribute];
1444         [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute];
1445         [tempArray addObject:NSAccessibilityHeaderAttribute];
1446         [tempArray addObject:NSAccessibilityColumnCountAttribute];
1447         [tempArray addObject:NSAccessibilityRowCountAttribute];
1448         [tempArray addObject:NSAccessibilityARIAColumnCountAttribute];
1449         [tempArray addObject:NSAccessibilityARIARowCountAttribute];
1450         return tempArray;
1451     }();
1452     static NeverDestroyed tableRowAttrs = [] {
1453         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
1454         [tempArray addObject:NSAccessibilityIndexAttribute];
1455         return tempArray;
1456     }();
1457     static NeverDestroyed tableColAttrs = [] {
1458         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
1459         [tempArray addObject:NSAccessibilityIndexAttribute];
1460         [tempArray addObject:NSAccessibilityHeaderAttribute];
1461         [tempArray addObject:NSAccessibilityRowsAttribute];
1462         [tempArray addObject:NSAccessibilityVisibleRowsAttribute];
1463         return tempArray;
1464     }();
1465     static NeverDestroyed tableCellAttrs = [] {
1466         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
1467         [tempArray addObject:NSAccessibilityRowIndexRangeAttribute];
1468         [tempArray addObject:NSAccessibilityColumnIndexRangeAttribute];
1469         [tempArray addObject:NSAccessibilityColumnHeaderUIElementsAttribute];
1470         [tempArray addObject:NSAccessibilityRowHeaderUIElementsAttribute];
1471         [tempArray addObject:NSAccessibilityARIAColumnIndexAttribute];
1472         [tempArray addObject:NSAccessibilityARIARowIndexAttribute];
1473         return tempArray;
1474     }();
1475     static NeverDestroyed groupAttrs = [] {
1476         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
1477         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1478         return tempArray;
1479     }();
1480     static NeverDestroyed inputImageAttrs = [] {
1481         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:buttonAttrs.get().get()]);
1482         [tempArray addObject:NSAccessibilityURLAttribute];
1483         return tempArray;
1484     }();
1485     static NeverDestroyed passwordFieldAttrs = [] {
1486         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
1487         [tempArray addObject:NSAccessibilityTitleUIElementAttribute];
1488         [tempArray addObject:NSAccessibilityRequiredAttribute];
1489         [tempArray addObject:NSAccessibilityInvalidAttribute];
1490         [tempArray addObject:NSAccessibilityPlaceholderValueAttribute];
1491         [tempArray addObject:NSAccessibilityValueAutofilledAttribute];
1492         return tempArray;
1493     }();
1494     static NeverDestroyed tabListAttrs = [] {
1495         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
1496         [tempArray addObject:NSAccessibilityTabsAttribute];
1497         [tempArray addObject:NSAccessibilityContentsAttribute];
1498         [tempArray addObject:NSAccessibilityOrientationAttribute];
1499         return tempArray;
1500     }();
1501     static NeverDestroyed outlineAttrs = [] {
1502         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
1503         [tempArray addObject:NSAccessibilitySelectedRowsAttribute];
1504         [tempArray addObject:NSAccessibilityRowsAttribute];
1505         [tempArray addObject:NSAccessibilityColumnsAttribute];
1506         [tempArray addObject:NSAccessibilityOrientationAttribute];
1507         return tempArray;
1508     }();
1509     static NeverDestroyed outlineRowAttrs = [] {
1510         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:tableRowAttrs.get().get()]);
1511         [tempArray addObject:NSAccessibilityDisclosingAttribute];
1512         [tempArray addObject:NSAccessibilityDisclosedByRowAttribute];
1513         [tempArray addObject:NSAccessibilityDisclosureLevelAttribute];
1514         [tempArray addObject:NSAccessibilityDisclosedRowsAttribute];
1515         [tempArray removeObject:NSAccessibilityValueAttribute];
1516         return tempArray;
1517     }();
1518     static NeverDestroyed scrollViewAttrs = [] {
1519         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
1520         [tempArray addObject:NSAccessibilityContentsAttribute];
1521         [tempArray addObject:NSAccessibilityHorizontalScrollBarAttribute];
1522         [tempArray addObject:NSAccessibilityVerticalScrollBarAttribute];
1523         return tempArray;
1524     }();
1525     static NeverDestroyed imageAttrs = [] {
1526         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
1527         [tempArray addObject:NSAccessibilityImageOverlayElementsAttribute];
1528         [tempArray addObject:NSAccessibilityEmbeddedImageDescriptionAttribute];
1529         [tempArray addObject:NSAccessibilityURLAttribute];
1530         return tempArray;
1531     }();
1532     static NeverDestroyed videoAttrs = [] {
1533         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:attributes.get().get()]);
1534         // This should represent the URL of the video content, not the poster.
1535         [tempArray addObject:NSAccessibilityURLAttribute];
1536         return tempArray;
1537     }();
1539     NSArray *objectAttributes = attributes.get().get();
1541     if (backingObject->isPasswordField())
1542         objectAttributes = passwordFieldAttrs.get().get();
1543     else if (backingObject->isWebArea())
1544         objectAttributes = webAreaAttrs.get().get();
1545     else if (backingObject->isTextControl())
1546         objectAttributes = textAttrs.get().get();
1547     else if (backingObject->isLink())
1548         objectAttributes = anchorAttrs.get().get();
1549     else if (backingObject->isImage())
1550         objectAttributes = imageAttrs.get().get();
1551     else if (backingObject->isTable() && backingObject->isExposable())
1552         objectAttributes = tableAttrs.get().get();
1553     else if (backingObject->isTableColumn())
1554         objectAttributes = tableColAttrs.get().get();
1555     else if (backingObject->isTableCell())
1556         objectAttributes = tableCellAttrs.get().get();
1557     else if (backingObject->isTableRow()) {
1558         // An ARIA table row can be collapsed and expanded, so it needs the extra attributes.
1559         if (backingObject->isARIATreeGridRow())
1560             objectAttributes = outlineRowAttrs.get().get();
1561         else
1562             objectAttributes = tableRowAttrs.get().get();
1563     } else if (backingObject->isTree())
1564         objectAttributes = outlineAttrs.get().get();
1565     else if (backingObject->isTreeItem()) {
1566         if (backingObject->supportsCheckedState())
1567             objectAttributes = [outlineRowAttrs.get() arrayByAddingObject:NSAccessibilityValueAttribute];
1568         else
1569             objectAttributes = outlineRowAttrs.get().get();
1570     }
1571     else if (backingObject->isListBox())
1572         objectAttributes = listBoxAttrs.get().get();
1573     else if (backingObject->isList())
1574         objectAttributes = listAttrs.get().get();
1575     else if (backingObject->isComboBox())
1576         objectAttributes = comboBoxAttrs.get().get();
1577     else if (backingObject->isProgressIndicator() || backingObject->isSlider())
1578         objectAttributes = rangeAttrs.get().get();
1579     // These are processed in order because an input image is a button, and a button is a control.
1580     else if (backingObject->isInputImage())
1581         objectAttributes = inputImageAttrs.get().get();
1582     else if (backingObject->isButton())
1583         objectAttributes = buttonAttrs.get().get();
1584     else if (backingObject->isControl())
1585         objectAttributes = controlAttrs.get().get();
1587     else if (backingObject->isGroup() || backingObject->isListItem())
1588         objectAttributes = groupAttrs.get().get();
1589     else if (backingObject->isTabList())
1590         objectAttributes = tabListAttrs.get().get();
1591     else if (backingObject->isScrollView())
1592         objectAttributes = scrollViewAttrs.get().get();
1593     else if (backingObject->isSpinButton())
1594         objectAttributes = incrementorAttrs.get().get();
1595     else if (backingObject->isMenu())
1596         objectAttributes = menuAttrs.get().get();
1597     else if (backingObject->isMenuBar())
1598         objectAttributes = menuBarAttrs.get().get();
1599     else if (backingObject->isMenuButton())
1600         objectAttributes = menuButtonAttrs.get().get();
1601     else if (backingObject->isMenuItem())
1602         objectAttributes = menuItemAttrs.get().get();
1603     else if (backingObject->isVideo())
1604         objectAttributes = videoAttrs.get().get();
1606     NSArray *additionalAttributes = [self additionalAccessibilityAttributeNames];
1607     if ([additionalAttributes count])
1608         objectAttributes = [objectAttributes arrayByAddingObjectsFromArray:additionalAttributes];
1610     // Only expose AXARIACurrent attribute when the element is set to be current item.
1611     if (backingObject->currentState() != AccessibilityCurrentState::False)
1612         objectAttributes = [objectAttributes arrayByAddingObjectsFromArray:@[ NSAccessibilityARIACurrentAttribute ]];
1614     // AppKit needs to know the screen height in order to do the coordinate conversion.
1615     objectAttributes = [objectAttributes arrayByAddingObjectsFromArray:@[ NSAccessibilityPrimaryScreenHeightAttribute ]];
1617     return objectAttributes;
1620 - (NSArray *)renderWidgetChildren
1622     auto* backingObject = self.axBackingObject;
1623     if (!backingObject || !backingObject->isWidget())
1624         return nil;
1626     id child = Accessibility::retrieveAutoreleasedValueFromMainThread<id>([protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
1627         auto* backingObject = protectedSelf.get().axBackingObject;
1628         if (!backingObject)
1629             return nil;
1631         auto* widget = backingObject->widget();
1632         return widget ? widget->accessibilityObject() : nil;
1633     });
1635     if (child)
1636         return @[child];
1638     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
1639     return [backingObject->platformWidget() accessibilityAttributeValue:NSAccessibilityChildrenAttribute];
1640     ALLOW_DEPRECATED_DECLARATIONS_END
1643 - (id)remoteAccessibilityParentObject
1645     auto* backingObject = self.axBackingObject;
1646     return backingObject ? backingObject->remoteParentObject() : nil;
1649 static void convertToVector(NSArray* array, AccessibilityObject::AccessibilityChildrenVector& vector)
1651     unsigned length = [array count];
1652     vector.reserveInitialCapacity(length);
1653     for (unsigned i = 0; i < length; ++i) {
1654         AXCoreObject* obj = [[array objectAtIndex:i] axBackingObject];
1655         if (obj)
1656             vector.append(obj);
1657     }
1660 - (AXTextMarkerRangeRef)selectedTextMarkerRange
1662     return Accessibility::retrieveAutoreleasedValueFromMainThread<AXTextMarkerRangeRef>([protectedSelf = retainPtr(self)] () -> RetainPtr<AXTextMarkerRangeRef> {
1663         auto* backingObject = protectedSelf.get().axBackingObject;
1664         if (!backingObject)
1665             return nil;
1667         auto selectedVisiblePositionRange = backingObject->selectedVisiblePositionRange();
1668         if (selectedVisiblePositionRange.isNull())
1669             return nil;
1670         return textMarkerRangeFromVisiblePositions(backingObject->axObjectCache(), selectedVisiblePositionRange.start, selectedVisiblePositionRange.end);
1671     });
1674 - (id)associatedPluginParent
1676     return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
1677         auto* backingObject = protectedSelf.get().axBackingObject;
1678         if (!backingObject || !backingObject->hasApplePDFAnnotationAttribute())
1679             return nil;
1681         if (!backingObject->document()->isPluginDocument())
1682             return nil;
1684         Widget* pluginWidget = static_cast<PluginDocument*>(backingObject->document())->pluginWidget();
1685         if (!pluginWidget || !pluginWidget->isPluginViewBase())
1686             return nil;
1688         return static_cast<PluginViewBase*>(pluginWidget)->accessibilityAssociatedPluginParentForElement(backingObject->element());
1689     });
1692 static void WebTransformCGPathToNSBezierPath(void* info, const CGPathElement *element)
1694     NSBezierPath *bezierPath = (__bridge NSBezierPath *)info;
1695     switch (element->type) {
1696     case kCGPathElementMoveToPoint:
1697         [bezierPath moveToPoint:NSPointFromCGPoint(element->points[0])];
1698         break;
1699     case kCGPathElementAddLineToPoint:
1700         [bezierPath lineToPoint:NSPointFromCGPoint(element->points[0])];
1701         break;
1702     case kCGPathElementAddCurveToPoint:
1703         [bezierPath curveToPoint:NSPointFromCGPoint(element->points[0]) controlPoint1:NSPointFromCGPoint(element->points[1]) controlPoint2:NSPointFromCGPoint(element->points[2])];
1704         break;
1705     case kCGPathElementCloseSubpath:
1706         [bezierPath closePath];
1707         break;
1708     default:
1709         break;
1710     }
1713 - (NSBezierPath *)bezierPathFromPath:(CGPathRef)path
1715     NSBezierPath *bezierPath = [NSBezierPath bezierPath];
1716     CGPathApply(path, (__bridge void*)bezierPath, WebTransformCGPathToNSBezierPath);
1717     return bezierPath;
1720 - (NSBezierPath *)path
1722     Path path = self.axBackingObject->elementPath();
1723     if (path.isEmpty())
1724         return NULL;
1725     
1726     CGPathRef transformedPath = [self convertPathToScreenSpace:path];
1727     return [self bezierPathFromPath:transformedPath];
1730 - (NSNumber *)primaryScreenHeight
1732     // The rect for primary screen should not change in normal use. So cache it
1733     // here to avoid hitting the main thread repeatedly.
1734     static FloatRect screenRect = Accessibility::retrieveValueFromMainThread<FloatRect>([] () -> FloatRect {
1735         return screenRectForPrimaryScreen();
1736     });
1737     return [NSNumber numberWithFloat:screenRect.height()];
1740 - (size_t)childrenVectorSize
1742     return self.axBackingObject->children().size();
1745 - (NSArray<WebAccessibilityObjectWrapper *> *)childrenVectorArray
1747     return makeNSArray(self.axBackingObject->children());
1750 - (NSValue *)position
1752     auto* backingObject = self.axBackingObject;
1753     if (!backingObject)
1754         return nil;
1756     auto rect = snappedIntRect(backingObject->elementRect());
1758     // The Cocoa accessibility API wants the lower-left corner.
1759     FloatPoint floatPoint(rect.x(), rect.maxY());
1761     // FIXME: add a function to convert a point, no need to convert a rect when you only need a point.
1762     FloatRect floatRect(floatPoint, FloatSize());
1763     CGRect cgRect(backingObject->convertRectToPlatformSpace(floatRect, AccessibilityConversionSpace::Screen));
1764     return @(cgRect.origin);
1767 - (NSString*)role
1769     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
1770     if (self.axBackingObject->isAttachment())
1771         return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleAttribute];
1772     ALLOW_DEPRECATED_DECLARATIONS_END
1774     NSString *string = self.axBackingObject->rolePlatformString();
1775     if (string.length)
1776         return string;
1777     return NSAccessibilityUnknownRole;
1780 - (BOOL)isEmptyGroup
1782     auto* backingObject = self.axBackingObject;
1783     if (!backingObject)
1784         return false;
1786 #if ENABLE(MODEL_ELEMENT)
1787     if (backingObject->isModel())
1788         return false;
1789 #endif
1791     return [[self role] isEqual:NSAccessibilityGroupRole]
1792         && backingObject->children().isEmpty()
1793         && ![[self renderWidgetChildren] count];
1796 ALLOW_DEPRECATED_DECLARATIONS_BEGIN
1797 - (NSString*)subrole
1799     auto* backingObject = self.axBackingObject;
1800     if (!backingObject)
1801         return nil;
1803     if ([self isEmptyGroup])
1804         return @"AXEmptyGroup";
1806     auto subrole = backingObject->subrolePlatformString();
1807     if (!subrole.isEmpty())
1808         return subrole;
1810     return nil;
1812 ALLOW_DEPRECATED_DECLARATIONS_END
1814 - (NSString*)roleDescription
1816     auto* backingObject = self.axBackingObject;
1817     if (!backingObject)
1818         return nil;
1820     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
1821     // attachments have the AXImage role, but a different subrole
1822     if (backingObject->isAttachment())
1823         return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityRoleDescriptionAttribute];
1824     ALLOW_DEPRECATED_DECLARATIONS_END
1826     String roleDescription = backingObject->roleDescription();
1827     if (!roleDescription.isEmpty())
1828         return roleDescription;
1830     NSString *axRole = backingObject->rolePlatformString();
1831     NSString *subrole = self.subrole;
1832     // Fallback to the system default role description.
1833     // If we get the same string back, then as a last resort, return unknown.
1834     NSString *defaultRoleDescription = NSAccessibilityRoleDescription(axRole, subrole);
1836     // On earlier Mac versions (Lion), using a non-standard subrole would result in a role description
1837     // being returned that looked like AXRole:AXSubrole. To make all platforms have the same role descriptions
1838     // we should fallback on a role description ignoring the subrole in these cases.
1839     if ([defaultRoleDescription isEqualToString:[NSString stringWithFormat:@"%@:%@", axRole, subrole]])
1840         defaultRoleDescription = NSAccessibilityRoleDescription(axRole, nil);
1842     if (![defaultRoleDescription isEqualToString:axRole])
1843         return defaultRoleDescription;
1845     return NSAccessibilityRoleDescription(NSAccessibilityUnknownRole, nil);
1848 - (NSString *)computedRoleString
1850     if (!self.axBackingObject)
1851         return nil;
1852     return self.axBackingObject->computedRoleString();
1855 - (id)scrollViewParent
1857     auto* backingObject = self.axBackingObject;
1858     if (!backingObject || !backingObject->isScrollView())
1859         return nil;
1861     // If this scroll view provides it's parent object (because it's a sub-frame), then
1862     // we should not find the remoteAccessibilityParent.
1863     if (backingObject->parentObject())
1864         return nil;
1866     if (auto platformWidget = backingObject->platformWidget())
1867         return NSAccessibilityUnignoredAncestor(platformWidget);
1869     return backingObject->remoteParentObject();
1872 - (id)windowElement:(NSString*)attributeName
1874     if (id remoteParent = self.remoteAccessibilityParentObject) {
1875         ALLOW_DEPRECATED_DECLARATIONS_BEGIN
1876         return [remoteParent accessibilityAttributeValue:attributeName];
1877         ALLOW_DEPRECATED_DECLARATIONS_END
1878     }
1880     return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
1881         auto* backingObject = protectedSelf.get().axBackingObject;
1882         if (!backingObject)
1883             return nil;
1885         if (auto* fv = backingObject->documentFrameView())
1886             return [fv->platformWidget() window];
1888         return nil;
1889     });
1892 - (void)logMissingBackingObject
1894     TextStream stream;
1895     stream << "No backingObject for wrapper " << &self << "!";
1896     AXLOG(stream.release());
1899 // FIXME: split up this function in a better way.
1900 // suggestions: Use a hash table that maps attribute names to function calls,
1901 // or maybe pointers to member functions
1902 ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGIN
1903 - (id)accessibilityAttributeValue:(NSString*)attributeName
1904 ALLOW_DEPRECATED_IMPLEMENTATIONS_END
1906     AXTRACE(makeString("WebAccessibilityObjectWrapper accessibilityAttributeValue:", String(attributeName)));
1908     auto* backingObject = self.updateObjectBackingStore;
1909     if (!backingObject) {
1910         [self logMissingBackingObject];
1911         return nil;
1912     }
1914     if (backingObject->isDetachedFromParent()) {
1915         AXLOG("backingObject is detached from parent!!!");
1916         AXLOG(backingObject);
1917         return nil;
1918     }
1920     if ([attributeName isEqualToString: NSAccessibilityRoleAttribute])
1921         return [self role];
1923     if ([attributeName isEqualToString: NSAccessibilitySubroleAttribute])
1924         return [self subrole];
1926     if ([attributeName isEqualToString: NSAccessibilityRoleDescriptionAttribute])
1927         return [self roleDescription];
1929     // AXARIARole is only used by DumpRenderTree (so far).
1930     if ([attributeName isEqualToString:@"AXARIARole"])
1931         return [self computedRoleString];
1933     if ([attributeName isEqualToString: NSAccessibilityParentAttribute]) {
1935         // This will return the parent of the AXWebArea, if this is a web area.
1936         id scrollViewParent = [self scrollViewParent];
1937         if (scrollViewParent)
1938             return scrollViewParent;
1940         // Tree item (changed to AXRows) can only report the tree (AXOutline) as its parent.
1941         if (backingObject->isTreeItem()) {
1942             auto parent = backingObject->parentObjectUnignored();
1943             while (parent) {
1944                 if (parent->isTree())
1945                     return parent->wrapper();
1946                 parent = parent->parentObjectUnignored();
1947             }
1948         }
1950         auto parent = backingObject->parentObjectUnignored();
1951         if (!parent)
1952             return nil;
1954         // In WebKit1, the scroll view is provided by the system (the attachment view), so the parent
1955         // should be reported directly as such.
1956         if (backingObject->isWebArea() && parent->isAttachment())
1957             return [parent->wrapper() attachmentView];
1959         return parent->wrapper();
1960     }
1962     if ([attributeName isEqualToString:NSAccessibilityChildrenAttribute] || [attributeName isEqualToString:NSAccessibilityChildrenInNavigationOrderAttribute]) {
1963 #if ENABLE(MODEL_ELEMENT)
1964         if (backingObject->isModel()) {
1965             auto modelChildren = backingObject->modelElementChildren();
1966             if (modelChildren.size()) {
1967                 return createNSArray(modelChildren, [] (auto& child) -> id {
1968                     return child.get();
1969                 }).autorelease();
1970             }
1971         }
1972 #endif
1974         if (!self.childrenVectorSize) {
1975             if (NSArray *children = [self renderWidgetChildren])
1976                 return children;
1977         }
1979         // The tree's (AXOutline) children are supposed to be its rows and columns.
1980         // The ARIA spec doesn't have columns, so we just need rows.
1981         if (backingObject->isTree())
1982             return [self accessibilityAttributeValue:NSAccessibilityRowsAttribute];
1984         // A tree item should only expose its content as its children (not its rows)
1985         if (backingObject->isTreeItem())
1986             return makeNSArray(backingObject->ariaTreeItemContent());
1988         return self.childrenVectorArray;
1989     }
1991     if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute]) {
1992         if (backingObject->canHaveSelectedChildren()) {
1993             AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
1994             backingObject->selectedChildren(selectedChildrenCopy);
1995             return makeNSArray(selectedChildrenCopy);
1996         }
1997         return nil;
1998     }
2000     if ([attributeName isEqualToString: NSAccessibilityVisibleChildrenAttribute]) {
2001         if (backingObject->isListBox()) {
2002             AccessibilityObject::AccessibilityChildrenVector visibleChildrenCopy;
2003             backingObject->visibleChildren(visibleChildrenCopy);
2004             return makeNSArray(visibleChildrenCopy);
2005         }
2007         if (backingObject->isList())
2008             return [self accessibilityAttributeValue:NSAccessibilityChildrenAttribute];
2010         return nil;
2011     }
2014     if (backingObject->isWebArea()) {
2015         if ([attributeName isEqualToString:@"AXLinkUIElements"])
2016             return makeNSArray(backingObject->documentLinks());
2018         if ([attributeName isEqualToString:@"AXLoaded"])
2019             return [NSNumber numberWithBool:backingObject->isLoaded()];
2020         if ([attributeName isEqualToString:@"AXLayoutCount"])
2021             return @(backingObject->layoutCount());
2022         if ([attributeName isEqualToString:NSAccessibilityLoadingProgressAttribute])
2023             return @(backingObject->loadingProgress());
2024         if ([attributeName isEqualToString:NSAccessibilityPreventKeyboardDOMEventDispatchAttribute])
2025             return [NSNumber numberWithBool:backingObject->preventKeyboardDOMEventDispatch()];
2026         if ([attributeName isEqualToString:NSAccessibilityCaretBrowsingEnabledAttribute])
2027             return [NSNumber numberWithBool:backingObject->caretBrowsingEnabled()];
2028         if ([attributeName isEqualToString:NSAccessibilityWebSessionIDAttribute])
2029             return @(backingObject->sessionID().toUInt64());
2030     }
2032     if (backingObject->isTextControl()) {
2033         if ([attributeName isEqualToString: NSAccessibilityNumberOfCharactersAttribute]) {
2034             int length = backingObject->textLength();
2035             if (length < 0)
2036                 return nil;
2037             return @(length);
2038         }
2039         if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
2040             String selectedText = backingObject->selectedText();
2041             if (selectedText.isNull())
2042                 return nil;
2043             return (NSString*)selectedText;
2044         }
2045         if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
2046             PlainTextRange textRange = backingObject->selectedTextRange();
2047             return [NSValue valueWithRange:NSMakeRange(textRange.start, textRange.length)];
2048         }
2049         if ([attributeName isEqualToString:NSAccessibilityInsertionPointLineNumberAttribute]) {
2050             int lineNumber = backingObject->insertionPointLineNumber();
2051             return lineNumber >= 0 ? @(lineNumber) : nil;
2052         }
2053     }
2055     if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) {
2056         if (backingObject->isPasswordField())
2057             return nil;
2058         // TODO: Get actual visible range. <rdar://problem/4712101>
2059         if (backingObject->isTextControl())
2060             return [NSValue valueWithRange:NSMakeRange(0, backingObject->textLength())];
2061         return [NSValue valueWithRange:[self accessibilityVisibleCharacterRange]];
2062     }
2064     if ([attributeName isEqualToString: NSAccessibilityURLAttribute]) {
2065         URL url = backingObject->url();
2066         if (url.isNull())
2067             return nil;
2068         return (NSURL*)url;
2069     }
2071     if ([attributeName isEqualToString:NSAccessibilityIncrementButtonAttribute]) {
2072         auto incrementButton = backingObject->incrementButton();
2073         return incrementButton ? incrementButton->wrapper() : nil;
2074     }
2076     if ([attributeName isEqualToString:NSAccessibilityDecrementButtonAttribute]) {
2077         auto decrementButton = backingObject->decrementButton();
2078         return decrementButton ? decrementButton->wrapper() : nil;
2079     }
2081     if ([attributeName isEqualToString: @"AXVisited"])
2082         return [NSNumber numberWithBool: backingObject->isVisited()];
2084     if ([attributeName isEqualToString: NSAccessibilityTitleAttribute]) {
2085         if (backingObject->isAttachment()) {
2086             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityTitleAttribute])
2087                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityTitleAttribute];
2088         }
2090         return backingObject->titleAttributeValue();
2091     }
2093     if ([attributeName isEqualToString: NSAccessibilityDescriptionAttribute]) {
2094         if (backingObject->isAttachment()) {
2095             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityDescriptionAttribute])
2096                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityDescriptionAttribute];
2097         }
2098         return [self baseAccessibilityDescription];
2099     }
2101     if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
2102         if (backingObject->isAttachment()) {
2103             if ([[[self attachmentView] accessibilityAttributeNames] containsObject:NSAccessibilityValueAttribute])
2104                 return [[self attachmentView] accessibilityAttributeValue:NSAccessibilityValueAttribute];
2105         }
2107         auto value = backingObject->value();
2108         return WTF::switchOn(value,
2109             [] (bool& typedValue) -> id { return @(typedValue); },
2110             [] (unsigned& typedValue) -> id { return @(typedValue); },
2111             [] (float& typedValue) -> id { return @(typedValue); },
2112             [] (String& typedValue) -> id { return (NSString *)typedValue; },
2113             [] (AccessibilityButtonState& typedValue) -> id { return @((unsigned)typedValue); },
2114             [] (AXCoreObject*& typedValue) { return typedValue ? (id)typedValue->wrapper() : nil; },
2115             [] (auto&) { return nil; }
2116         );
2117     }
2119     if ([attributeName isEqualToString:(NSString *)kAXMenuItemMarkCharAttribute]) {
2120         const unichar ch = 0x2713; // âœ“ used on Mac for selected menu items.
2121         return (backingObject->isChecked()) ? [NSString stringWithCharacters:&ch length:1] : nil;
2122     }
2124     if ([attributeName isEqualToString: NSAccessibilityMinValueAttribute]) {
2125         // Indeterminate progress indicator should return 0.
2126         if (backingObject->ariaRoleAttribute() == AccessibilityRole::ProgressIndicator && !backingObject->hasARIAValueNow())
2127             return @0;
2128         return [NSNumber numberWithFloat:backingObject->minValueForRange()];
2129     }
2131     if ([attributeName isEqualToString: NSAccessibilityMaxValueAttribute]) {
2132         // Indeterminate progress indicator should return 0.
2133         if (backingObject->ariaRoleAttribute() == AccessibilityRole::ProgressIndicator && !backingObject->hasARIAValueNow())
2134             return @0;
2135         return [NSNumber numberWithFloat:backingObject->maxValueForRange()];
2136     }
2138     if ([attributeName isEqualToString: NSAccessibilityHelpAttribute])
2139         return [self baseAccessibilityHelpText];
2141     if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
2142         return [NSNumber numberWithBool: backingObject->isFocused()];
2144     if ([attributeName isEqualToString: NSAccessibilityEnabledAttribute])
2145         return [NSNumber numberWithBool: backingObject->isEnabled()];
2147     if ([attributeName isEqualToString: NSAccessibilitySizeAttribute]) {
2148         IntSize s = snappedIntRect(backingObject->elementRect()).size();
2149         return [NSValue valueWithSize: NSMakeSize(s.width(), s.height())];
2150     }
2152     if ([attributeName isEqualToString: NSAccessibilityPrimaryScreenHeightAttribute])
2153         return [self primaryScreenHeight];
2154     if ([attributeName isEqualToString: NSAccessibilityPositionAttribute])
2155         return [self position];
2156     if ([attributeName isEqualToString:NSAccessibilityPathAttribute])
2157         return [self path];
2159     if ([attributeName isEqualToString:@"AXLineRectsAndText"]) {
2160         return Accessibility::retrieveAutoreleasedValueFromMainThread<NSArray *>([protectedSelf = retainPtr(self)] () -> RetainPtr<NSArray> {
2161             return protectedSelf.get().lineRectsAndText;
2162         });
2163     }
2165     if ([attributeName isEqualToString:NSAccessibilityImageOverlayElementsAttribute]) {
2166         auto imageOverlayElements = backingObject->imageOverlayElements();
2167         return imageOverlayElements ? makeNSArray(*imageOverlayElements) : nil;
2168     }
2170     if ([attributeName isEqualToString:NSAccessibilityEmbeddedImageDescriptionAttribute])
2171         return backingObject->embeddedImageDescription();
2173     if ([attributeName isEqualToString:NSAccessibilityWindowAttribute]
2174         || [attributeName isEqualToString:NSAccessibilityTopLevelUIElementAttribute])
2175         return [self windowElement:attributeName];
2177     if ([attributeName isEqualToString:NSAccessibilityAccessKeyAttribute]) {
2178         AtomString accessKey = backingObject->accessKey();
2179         if (accessKey.isNull())
2180             return nil;
2181         return accessKey;
2182     }
2184     if ([attributeName isEqualToString:NSAccessibilityLinkRelationshipTypeAttribute])
2185         return backingObject->linkRelValue();
2187     if ([attributeName isEqualToString:NSAccessibilityTabsAttribute]) {
2188         if (backingObject->isTabList()) {
2189             AccessibilityObject::AccessibilityChildrenVector tabsChildren;
2190             backingObject->tabChildren(tabsChildren);
2191             return makeNSArray(tabsChildren);
2192         }
2193     }
2195     if ([attributeName isEqualToString:NSAccessibilityContentsAttribute])
2196         return makeNSArray(backingObject->contents());
2198     if (backingObject->isTable() && backingObject->isExposable()) {
2199         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute])
2200             return makeNSArray(backingObject->rows());
2202         if ([attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute])
2203             return makeNSArray(backingObject->visibleRows());
2205         // TODO: distinguish between visible and non-visible columns
2206         if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute]
2207             || [attributeName isEqualToString:NSAccessibilityVisibleColumnsAttribute])
2208             return makeNSArray(backingObject->columns());
2210         if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
2211             AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
2212             backingObject->selectedChildren(selectedChildrenCopy);
2213             return makeNSArray(selectedChildrenCopy);
2214         }
2216         // HTML tables don't support these attributes.
2217         if ([attributeName isEqualToString:NSAccessibilitySelectedColumnsAttribute]
2218             || [attributeName isEqualToString:NSAccessibilitySelectedCellsAttribute])
2219             return nil;
2221         if ([attributeName isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute])
2222             return makeNSArray(backingObject->columnHeaders());
2224         if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
2225             auto* headerContainer = backingObject->headerContainer();
2226             return headerContainer ? headerContainer->wrapper() : nil;
2227         }
2229         if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute])
2230             return makeNSArray(backingObject->rowHeaders());
2232         if ([attributeName isEqualToString:NSAccessibilityVisibleCellsAttribute])
2233             return makeNSArray(backingObject->cells());
2235         if ([attributeName isEqualToString:NSAccessibilityColumnCountAttribute])
2236             return @(backingObject->columnCount());
2238         if ([attributeName isEqualToString:NSAccessibilityRowCountAttribute])
2239             return @(backingObject->rowCount());
2241         if ([attributeName isEqualToString:NSAccessibilityARIAColumnCountAttribute])
2242             return @(backingObject->axColumnCount());
2244         if ([attributeName isEqualToString:NSAccessibilityARIARowCountAttribute])
2245             return @(backingObject->axRowCount());
2246     }
2248     if (backingObject->isTableColumn()) {
2249         if ([attributeName isEqualToString:NSAccessibilityIndexAttribute])
2250             return @(backingObject->columnIndex());
2252         // rows attribute for a column is the list of all the elements in that column at each row
2253         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute]
2254             || [attributeName isEqualToString:NSAccessibilityVisibleRowsAttribute])
2255             return makeNSArray(backingObject->children());
2257         if ([attributeName isEqualToString:NSAccessibilityHeaderAttribute]) {
2258             auto* header = backingObject->columnHeader();
2259             return header ? header->wrapper() : nil;
2260         }
2261     }
2263     if (backingObject->isTableCell()) {
2264         if ([attributeName isEqualToString:NSAccessibilityRowIndexRangeAttribute]) {
2265             auto rowRange = backingObject->rowIndexRange();
2266             return [NSValue valueWithRange:NSMakeRange(rowRange.first, rowRange.second)];
2267         }
2269         if ([attributeName isEqualToString:NSAccessibilityColumnIndexRangeAttribute]) {
2270             auto columnRange = backingObject->columnIndexRange();
2271             return [NSValue valueWithRange:NSMakeRange(columnRange.first, columnRange.second)];
2272         }
2274         if ([attributeName isEqualToString:NSAccessibilityColumnHeaderUIElementsAttribute])
2275             return makeNSArray(backingObject->columnHeaders());
2277         if ([attributeName isEqualToString:NSAccessibilityRowHeaderUIElementsAttribute])
2278             return makeNSArray(backingObject->rowHeaders());
2280         if ([attributeName isEqualToString:NSAccessibilityARIAColumnIndexAttribute])
2281             return @(backingObject->axColumnIndex());
2283         if ([attributeName isEqualToString:NSAccessibilityARIARowIndexAttribute])
2284             return @(backingObject->axRowIndex());
2285     }
2287     if (backingObject->isTree()) {
2288         if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
2289             AccessibilityObject::AccessibilityChildrenVector selectedChildrenCopy;
2290             backingObject->selectedChildren(selectedChildrenCopy);
2291             return makeNSArray(selectedChildrenCopy);
2292         }
2293         if ([attributeName isEqualToString:NSAccessibilityRowsAttribute]) {
2294             AccessibilityObject::AccessibilityChildrenVector rowsCopy;
2295             backingObject->ariaTreeRows(rowsCopy);
2296             return makeNSArray(rowsCopy);
2297         }
2299         // TreeRoles do not support columns, but Mac AX expects to be able to ask about columns at the least.
2300         if ([attributeName isEqualToString:NSAccessibilityColumnsAttribute])
2301             return @[];
2302     }
2304     if ([attributeName isEqualToString:NSAccessibilityIndexAttribute]) {
2305         if (backingObject->isTreeItem()) {
2306             AXCoreObject* parent = backingObject->parentObject();
2307             for (; parent && !parent->isTree(); parent = parent->parentObject())
2308             { }
2310             if (!parent)
2311                 return nil;
2313             // Find the index of this item by iterating the parents.
2314             AccessibilityObject::AccessibilityChildrenVector rowsCopy;
2315             parent->ariaTreeRows(rowsCopy);
2316             size_t count = rowsCopy.size();
2317             for (size_t k = 0; k < count; ++k)
2318                 if (rowsCopy[k]->wrapper() == self)
2319                     return @(k);
2321             return nil;
2322         }
2324         if (backingObject->isTableRow())
2325             return @(backingObject->rowIndex());
2326     }
2328     // The rows that are considered inside this row.
2329     if ([attributeName isEqualToString:NSAccessibilityDisclosedRowsAttribute]) {
2330         if (backingObject->isTreeItem() || backingObject->isARIATreeGridRow())
2331             return makeNSArray(backingObject->disclosedRows());
2332     }
2334     // The row that contains this row. It should be the same as the first parent that is a treeitem.
2335     if ([attributeName isEqualToString:NSAccessibilityDisclosedByRowAttribute]) {
2336         if (backingObject->isTreeItem()) {
2337             AXCoreObject* parent = backingObject->parentObject();
2338             while (parent) {
2339                 if (parent->isTreeItem())
2340                     return parent->wrapper();
2341                 // If the parent is the tree itself, then this value == nil.
2342                 if (parent->isTree())
2343                     return nil;
2344                 parent = parent->parentObject();
2345             }
2346             return nil;
2347         }
2349         if (backingObject->isARIATreeGridRow()) {
2350             auto* row = backingObject->disclosedByRow();
2351             return row ? row->wrapper() : nil;
2352         }
2353     }
2355     if ([attributeName isEqualToString:NSAccessibilityDisclosureLevelAttribute]) {
2356         // Convert from 1-based level (from aria-level spec) to 0-based level (Mac)
2357         int level = backingObject->hierarchicalLevel();
2358         if (level > 0)
2359             level -= 1;
2360         return @(level);
2361     }
2362     if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute])
2363         return [NSNumber numberWithBool:backingObject->isExpanded()];
2365     if (backingObject->isList() && [attributeName isEqualToString:NSAccessibilityOrientationAttribute])
2366         return NSAccessibilityVerticalOrientationValue;
2368     if ([attributeName isEqualToString:@"AXSelectedTextMarkerRange"])
2369         return (id)[self selectedTextMarkerRange];
2371     if ([attributeName isEqualToString:@"AXStartTextMarker"]) {
2372         return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
2373             auto* backingObject = protectedSelf.get().axBackingObject;
2374             if (!backingObject)
2375                 return nil;
2377             return (id)textMarkerForVisiblePosition(backingObject->axObjectCache(), startOfDocument(backingObject->document()));
2378         });
2379     }
2381     if ([attributeName isEqualToString:@"AXEndTextMarker"]) {
2382         return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
2383             auto* backingObject = protectedSelf.get().axBackingObject;
2384             if (!backingObject)
2385                 return nil;
2387             return (id)textMarkerForVisiblePosition(backingObject->axObjectCache(), endOfDocument(backingObject->document()));
2388         });
2389     }
2391     if ([attributeName isEqualToString:NSAccessibilityBlockQuoteLevelAttribute])
2392         return @(backingObject->blockquoteLevel());
2393     if ([attributeName isEqualToString:@"AXTableLevel"])
2394         return @(backingObject->tableLevel());
2396     if ([attributeName isEqualToString: NSAccessibilityLinkedUIElementsAttribute]) {
2397         AccessibilityObject::AccessibilityChildrenVector linkedUIElements;
2398         backingObject->linkedUIElements(linkedUIElements);
2399         return makeNSArray(linkedUIElements);
2400     }
2402     if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
2403         return [NSNumber numberWithBool:backingObject->isSelected()];
2405     if ([attributeName isEqualToString: NSAccessibilityARIACurrentAttribute])
2406         return backingObject->currentValue();
2408     if ([attributeName isEqualToString: NSAccessibilityServesAsTitleForUIElementsAttribute] && backingObject->isMenuButton()) {
2409         AccessibilityObject* uiElement = downcast<AccessibilityRenderObject>(*backingObject).menuForMenuButton();
2410         if (uiElement)
2411             return @[uiElement->wrapper()];
2412     }
2414     if ([attributeName isEqualToString:NSAccessibilityTitleUIElementAttribute]) {
2415         auto* object = backingObject->titleUIElement();
2416         return object ? object->wrapper() : nil;
2417     }
2419     if ([attributeName isEqualToString:NSAccessibilityValueDescriptionAttribute])
2420         return backingObject->valueDescription();
2422     if ([attributeName isEqualToString:NSAccessibilityOrientationAttribute]) {
2423         AccessibilityOrientation elementOrientation = backingObject->orientation();
2424         if (elementOrientation == AccessibilityOrientation::Vertical)
2425             return NSAccessibilityVerticalOrientationValue;
2426         if (elementOrientation == AccessibilityOrientation::Horizontal)
2427             return NSAccessibilityHorizontalOrientationValue;
2428         if (elementOrientation == AccessibilityOrientation::Undefined)
2429             return NSAccessibilityUnknownOrientationValue;
2430         return nil;
2431     }
2433     if ([attributeName isEqualToString:NSAccessibilityHorizontalScrollBarAttribute]) {
2434         AXCoreObject* scrollBar = backingObject->scrollBar(AccessibilityOrientation::Horizontal);
2435         if (scrollBar)
2436             return scrollBar->wrapper();
2437         return nil;
2438     }
2439     if ([attributeName isEqualToString:NSAccessibilityVerticalScrollBarAttribute]) {
2440         AXCoreObject* scrollBar = backingObject->scrollBar(AccessibilityOrientation::Vertical);
2441         if (scrollBar)
2442             return scrollBar->wrapper();
2443         return nil;
2444     }
2446     if ([attributeName isEqualToString:NSAccessibilitySortDirectionAttribute]) {
2447         switch (backingObject->sortDirection()) {
2448         case AccessibilitySortDirection::Ascending:
2449             return NSAccessibilityAscendingSortDirectionValue;
2450         case AccessibilitySortDirection::Descending:
2451             return NSAccessibilityDescendingSortDirectionValue;
2452         default:
2453             return NSAccessibilityUnknownSortDirectionValue;
2454         }
2455     }
2457     if ([attributeName isEqualToString:NSAccessibilityLanguageAttribute])
2458         return backingObject->language();
2460     if ([attributeName isEqualToString:NSAccessibilityExpandedAttribute])
2461         return [NSNumber numberWithBool:backingObject->isExpanded()];
2463     if ([attributeName isEqualToString:NSAccessibilityRequiredAttribute])
2464         return [NSNumber numberWithBool:backingObject->isRequired()];
2466     if ([attributeName isEqualToString:NSAccessibilityInvalidAttribute])
2467         return backingObject->invalidStatus();
2469     if ([attributeName isEqualToString:NSAccessibilityOwnsAttribute]) {
2470         AccessibilityObject::AccessibilityChildrenVector ariaOwns;
2471         backingObject->ariaOwnsElements(ariaOwns);
2472         return makeNSArray(ariaOwns);
2473     }
2475     if ([attributeName isEqualToString:NSAccessibilityARIAPosInSetAttribute])
2476         return @(backingObject->posInSet());
2477     if ([attributeName isEqualToString:NSAccessibilityARIASetSizeAttribute])
2478         return @(backingObject->setSize());
2480     if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
2481         return [NSNumber numberWithBool:backingObject->isGrabbed()];
2483     if ([attributeName isEqualToString:NSAccessibilityDropEffectsAttribute])
2484         return createNSArray(backingObject->determineDropEffects()).autorelease();
2486     if ([attributeName isEqualToString:NSAccessibilityPlaceholderValueAttribute])
2487         return backingObject->placeholderValue();
2489     if ([attributeName isEqualToString:NSAccessibilityValueAutofillAvailableAttribute])
2490         return @(backingObject->isValueAutofillAvailable());
2492     if ([attributeName isEqualToString:NSAccessibilityValueAutofillTypeAttribute]) {
2493         switch (backingObject->valueAutofillButtonType()) {
2494         case AutoFillButtonType::None:
2495             return @"none";
2496         case AutoFillButtonType::Credentials:
2497             return @"credentials";
2498         case AutoFillButtonType::Contacts:
2499             return @"contacts";
2500         case AutoFillButtonType::StrongPassword:
2501             return @"strong password";
2502         case AutoFillButtonType::CreditCard:
2503             return @"credit card";
2504         }
2505     }
2507     if ([attributeName isEqualToString:NSAccessibilityValueAutofilledAttribute])
2508         return @(backingObject->isValueAutofilled());
2510     if ([attributeName isEqualToString:NSAccessibilityHasPopupAttribute])
2511         return [NSNumber numberWithBool:backingObject->hasPopup()];
2513     if ([attributeName isEqualToString:NSAccessibilityDatetimeValueAttribute])
2514         return backingObject->datetimeAttributeValue();
2516     if ([attributeName isEqualToString:NSAccessibilityInlineTextAttribute])
2517         return @(backingObject->isInlineText());
2519     // ARIA Live region attributes.
2520     if ([attributeName isEqualToString:NSAccessibilityARIALiveAttribute])
2521         return backingObject->liveRegionStatus();
2522     if ([attributeName isEqualToString:NSAccessibilityARIARelevantAttribute])
2523         return backingObject->liveRegionRelevant();
2524     if ([attributeName isEqualToString:NSAccessibilityARIAAtomicAttribute])
2525         return [NSNumber numberWithBool:backingObject->liveRegionAtomic()];
2526     if ([attributeName isEqualToString:NSAccessibilityElementBusyAttribute])
2527         return [NSNumber numberWithBool:backingObject->isBusy()];
2529     // MathML Attributes.
2530     if (backingObject->isMathElement()) {
2531         if ([attributeName isEqualToString:NSAccessibilityMathRootIndexAttribute]) {
2532             auto* rootIndex = backingObject->mathRootIndexObject();
2533             return rootIndex ? rootIndex->wrapper() : nil;
2534         }
2536         if ([attributeName isEqualToString:NSAccessibilityMathRootRadicandAttribute]) {
2537             auto radicand = backingObject->mathRadicand();
2538             return radicand ? makeNSArray(*radicand) : nil;
2539         }
2541         if ([attributeName isEqualToString:NSAccessibilityMathFractionNumeratorAttribute])
2542             return (backingObject->mathNumeratorObject()) ? backingObject->mathNumeratorObject()->wrapper() : 0;
2543         if ([attributeName isEqualToString:NSAccessibilityMathFractionDenominatorAttribute])
2544             return (backingObject->mathDenominatorObject()) ? backingObject->mathDenominatorObject()->wrapper() : 0;
2545         if ([attributeName isEqualToString:NSAccessibilityMathBaseAttribute])
2546             return (backingObject->mathBaseObject()) ? backingObject->mathBaseObject()->wrapper() : 0;
2547         if ([attributeName isEqualToString:NSAccessibilityMathSubscriptAttribute])
2548             return (backingObject->mathSubscriptObject()) ? backingObject->mathSubscriptObject()->wrapper() : 0;
2549         if ([attributeName isEqualToString:NSAccessibilityMathSuperscriptAttribute])
2550             return (backingObject->mathSuperscriptObject()) ? backingObject->mathSuperscriptObject()->wrapper() : 0;
2551         if ([attributeName isEqualToString:NSAccessibilityMathUnderAttribute])
2552             return (backingObject->mathUnderObject()) ? backingObject->mathUnderObject()->wrapper() : 0;
2553         if ([attributeName isEqualToString:NSAccessibilityMathOverAttribute])
2554             return (backingObject->mathOverObject()) ? backingObject->mathOverObject()->wrapper() : 0;
2555         if ([attributeName isEqualToString:NSAccessibilityMathFencedOpenAttribute])
2556             return backingObject->mathFencedOpenString();
2557         if ([attributeName isEqualToString:NSAccessibilityMathFencedCloseAttribute])
2558             return backingObject->mathFencedCloseString();
2559         if ([attributeName isEqualToString:NSAccessibilityMathLineThicknessAttribute])
2560             return [NSNumber numberWithInteger:backingObject->mathLineThickness()];
2561         if ([attributeName isEqualToString:NSAccessibilityMathPostscriptsAttribute])
2562             return [self accessibilityMathPostscriptPairs];
2563         if ([attributeName isEqualToString:NSAccessibilityMathPrescriptsAttribute])
2564             return [self accessibilityMathPrescriptPairs];
2565     }
2567     if ([attributeName isEqualToString:NSAccessibilityExpandedTextValueAttribute])
2568         return backingObject->expandedTextValue();
2570     if ([attributeName isEqualToString:NSAccessibilityDOMIdentifierAttribute])
2571         return backingObject->identifierAttribute();
2572     if ([attributeName isEqualToString:NSAccessibilityDOMClassListAttribute]) {
2573         Vector<String> classList;
2574         backingObject->classList(classList);
2575         return createNSArray(classList).autorelease();
2576     }
2578     if ([attributeName isEqualToString:@"AXResolvedEditingStyles"])
2579         return [self baseAccessibilityResolvedEditingStyles];
2580     
2581     // This allows us to connect to a plugin that creates a shadow node for editing (like PDFs).
2582     if ([attributeName isEqualToString:@"_AXAssociatedPluginParent"])
2583         return [self associatedPluginParent];
2585     // this is used only by DumpRenderTree for testing
2586     if ([attributeName isEqualToString:@"AXClickPoint"])
2587         return [NSValue valueWithPoint:backingObject->clickPoint()];
2589     // This is used by DRT to verify CSS3 speech works.
2590     if ([attributeName isEqualToString:@"AXDRTSpeechAttribute"])
2591         return [self baseAccessibilitySpeechHint];
2593     if ([attributeName isEqualToString:@"AXAutocompleteValue"])
2594         return backingObject->autoCompleteValue();
2596     if ([attributeName isEqualToString:NSAccessibilityPopupValueAttribute])
2597         return backingObject->popupValue();
2599     if ([attributeName isEqualToString:@"AXKeyShortcutsValue"])
2600         return backingObject->keyShortcutsValue();
2602     if ([attributeName isEqualToString:@"AXARIAPressedIsPresent"])
2603         return [NSNumber numberWithBool:backingObject->pressedIsPresent()];
2605     if ([attributeName isEqualToString:@"AXIsMultiline"])
2606         return [NSNumber numberWithBool:backingObject->ariaIsMultiline()];
2608     if ([attributeName isEqualToString:@"AXReadOnlyValue"])
2609         return backingObject->readOnlyValue();
2611     if ([attributeName isEqualToString:@"AXIsActiveDescendantOfFocusedContainer"])
2612         return [NSNumber numberWithBool:backingObject->isActiveDescendantOfFocusedContainer()];
2614     if ([attributeName isEqualToString:AXHasDocumentRoleAncestorAttribute])
2615         return [NSNumber numberWithBool:backingObject->hasDocumentRoleAncestor()];
2617     if ([attributeName isEqualToString:AXHasWebApplicationAncestorAttribute])
2618         return [NSNumber numberWithBool:backingObject->hasWebApplicationAncestor()];
2620     if ([attributeName isEqualToString:@"AXIsInDescriptionListDetail"])
2621         return [NSNumber numberWithBool:backingObject->isInDescriptionListDetail()];
2623     if ([attributeName isEqualToString:@"AXIsInDescriptionListTerm"])
2624         return [NSNumber numberWithBool:backingObject->isInDescriptionListTerm()];
2626     if ([attributeName isEqualToString:@"AXIsInCell"])
2627         return [NSNumber numberWithBool:backingObject->isInCell()];
2629     if ([attributeName isEqualToString:@"AXDetailsElements"]) {
2630         AccessibilityObject::AccessibilityChildrenVector details;
2631         backingObject->ariaDetailsElements(details);
2632         return makeNSArray(details);
2633     }
2635     if ([attributeName isEqualToString:NSAccessibilityBrailleLabelAttribute])
2636         return backingObject->brailleLabel();
2638     if ([attributeName isEqualToString:NSAccessibilityBrailleRoleDescriptionAttribute])
2639         return backingObject->brailleRoleDescription();
2641     if ([attributeName isEqualToString:NSAccessibilityRelativeFrameAttribute])
2642         return [NSValue valueWithRect:(NSRect)backingObject->relativeFrame()];
2644     if ([attributeName isEqualToString:@"AXErrorMessageElements"]) {
2645         AccessibilityObject::AccessibilityChildrenVector errorMessages;
2646         backingObject->ariaErrorMessageElements(errorMessages);
2647         return makeNSArray(errorMessages);
2648     }
2650     // Multi-selectable
2651     if ([attributeName isEqualToString:NSAccessibilityIsMultiSelectableAttribute])
2652         return [NSNumber numberWithBool:backingObject->isMultiSelectable()];
2654     // Document attributes
2655     if ([attributeName isEqualToString:NSAccessibilityDocumentURIAttribute])
2656         return backingObject->documentURI();
2658     if ([attributeName isEqualToString:NSAccessibilityDocumentEncodingAttribute])
2659         return backingObject->documentEncoding();
2661     // Aria controls element
2662     if ([attributeName isEqualToString:NSAccessibilityAriaControlsAttribute]) {
2663         AccessibilityObject::AccessibilityChildrenVector ariaControls;
2664         backingObject->ariaControlsElements(ariaControls);
2665         return makeNSArray(ariaControls);
2666     }
2668     if ([attributeName isEqualToString:NSAccessibilityFocusableAncestorAttribute]) {
2669         AXCoreObject* object = backingObject->focusableAncestor();
2670         return object ? object->wrapper() : nil;
2671     }
2673     if ([attributeName isEqualToString:NSAccessibilityEditableAncestorAttribute]) {
2674         AXCoreObject* object = backingObject->editableAncestor();
2675         return object ? object->wrapper() : nil;
2676     }
2678     if ([attributeName isEqualToString:NSAccessibilityHighestEditableAncestorAttribute]) {
2679         AXCoreObject* object = backingObject->highestEditableAncestor();
2680         return object ? object->wrapper() : nil;
2681     }
2683     if ([attributeName isEqualToString:@"AXIsOnScreen"])
2684         return [NSNumber numberWithBool:backingObject->isOnScreen()];
2686     return nil;
2689 - (NSString *)accessibilityPlatformMathSubscriptKey
2691     return NSAccessibilityMathSubscriptAttribute;
2694 - (NSString *)accessibilityPlatformMathSuperscriptKey
2696     return NSAccessibilityMathSuperscriptAttribute;
2699 - (id)accessibilityFocusedUIElement
2701     auto* backingObject = self.updateObjectBackingStore;
2702     if (!backingObject)
2703         return nil;
2705     auto focusedObject = backingObject->focusedUIElement();
2706     return focusedObject ? focusedObject->wrapper() : nil;
2709 - (id)accessibilityHitTest:(NSPoint)point
2711     auto* backingObject = self.updateObjectBackingStore;
2712     if (!backingObject)
2713         return nil;
2715     backingObject->updateChildrenIfNecessary();
2716     auto* axObject = backingObject->accessibilityHitTest(IntPoint(point));
2718     id hit = nil;
2719     if (axObject) {
2720         if (axObject->isAttachment() && [axObject->wrapper() attachmentView])
2721             return [axObject->wrapper() attachmentView];
2723         hit = Accessibility::retrieveAutoreleasedValueFromMainThread<id>([&axObject, &point] () -> RetainPtr<id> {
2724             auto* widget = axObject->widget();
2725             if (is<PluginViewBase>(widget))
2726                 return widget->accessibilityHitTest(IntPoint(point));
2727             return nil;
2728         });
2730         if (!hit)
2731             hit = axObject->wrapper();
2732     } else
2733         hit = self;
2735     return NSAccessibilityUnignoredAncestor(hit);
2738 ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGIN
2739 - (BOOL)accessibilityIsAttributeSettable:(NSString*)attributeName
2740 ALLOW_DEPRECATED_IMPLEMENTATIONS_END
2742     auto* backingObject = self.updateObjectBackingStore;
2743     if (!backingObject)
2744         return NO;
2746     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"])
2747         return YES;
2749     if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute])
2750         return backingObject->canSetFocusAttribute();
2752     if ([attributeName isEqualToString: NSAccessibilityValueAttribute])
2753         return backingObject->canSetValueAttribute();
2755     if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute])
2756         return backingObject->canSetSelectedAttribute();
2758     if ([attributeName isEqualToString: NSAccessibilitySelectedChildrenAttribute])
2759         return backingObject->canSetSelectedChildren();
2761     if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute]
2762         || [attributeName isEqualToString:NSAccessibilityExpandedAttribute])
2763         return backingObject->canSetExpandedAttribute();
2765     if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute])
2766         return YES;
2768     if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]
2769         || [attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]
2770         || [attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute])
2771         return backingObject->canSetTextRangeAttributes();
2773     if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
2774         return YES;
2776     if (backingObject->isWebArea()
2777         && ([attributeName isEqualToString:NSAccessibilityPreventKeyboardDOMEventDispatchAttribute]
2778             || [attributeName isEqualToString:NSAccessibilityCaretBrowsingEnabledAttribute]))
2779         return YES;
2781     return NO;
2784 ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGIN
2785 - (BOOL)accessibilityIsIgnored
2786 ALLOW_DEPRECATED_IMPLEMENTATIONS_END
2788     auto* backingObject = self.updateObjectBackingStore;
2789     if (!backingObject)
2790         return YES;
2792     if (backingObject->isAttachment())
2793         return [[self attachmentView] accessibilityIsIgnored];
2794     return backingObject->accessibilityIsIgnored();
2797 ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGIN
2798 - (NSArray* )accessibilityParameterizedAttributeNames
2799 ALLOW_DEPRECATED_IMPLEMENTATIONS_END
2801     auto* backingObject = self.updateObjectBackingStore;
2802     if (!backingObject)
2803         return nil;
2805     if (backingObject->isAttachment())
2806         return nil;
2808     static NSArray *paramAttrs;
2809     static NSArray *textParamAttrs;
2810     static NSArray *tableParamAttrs;
2811     static NSArray *webAreaParamAttrs;
2812     if (paramAttrs == nil) {
2813         paramAttrs = [[NSArray alloc] initWithObjects:
2814             @"AXUIElementForTextMarker",
2815             @"AXTextMarkerRangeForUIElement",
2816             @"AXLineForTextMarker",
2817             @"AXTextMarkerRangeForLine",
2818             @"AXStringForTextMarkerRange",
2819             @"AXTextMarkerForPosition",
2820             @"AXBoundsForTextMarkerRange",
2821             @"AXAttributedStringForTextMarkerRange",
2822             @"AXAttributedStringForTextMarkerRangeWithOptions",
2823             @"AXTextMarkerRangeForTextMarkers",
2824             @"AXTextMarkerRangeForUnorderedTextMarkers",
2825             @"AXNextTextMarkerForTextMarker",
2826             @"AXPreviousTextMarkerForTextMarker",
2827             @"AXLeftWordTextMarkerRangeForTextMarker",
2828             @"AXRightWordTextMarkerRangeForTextMarker",
2829             @"AXLeftLineTextMarkerRangeForTextMarker",
2830             @"AXRightLineTextMarkerRangeForTextMarker",
2831             @"AXSentenceTextMarkerRangeForTextMarker",
2832             @"AXParagraphTextMarkerRangeForTextMarker",
2833             @"AXNextWordEndTextMarkerForTextMarker",
2834             @"AXPreviousWordStartTextMarkerForTextMarker",
2835             @"AXNextLineEndTextMarkerForTextMarker",
2836             @"AXPreviousLineStartTextMarkerForTextMarker",
2837             @"AXNextSentenceEndTextMarkerForTextMarker",
2838             @"AXPreviousSentenceStartTextMarkerForTextMarker",
2839             @"AXNextParagraphEndTextMarkerForTextMarker",
2840             @"AXPreviousParagraphStartTextMarkerForTextMarker",
2841             @"AXStyleTextMarkerRangeForTextMarker",
2842             @"AXLengthForTextMarkerRange",
2843             NSAccessibilityBoundsForRangeParameterizedAttribute,
2844             NSAccessibilityStringForRangeParameterizedAttribute,
2845             NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute,
2846             NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute,
2847             NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute,
2848             NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute,
2849             NSAccessibilityLineTextMarkerRangeForTextMarkerParameterizedAttribute,
2850             NSAccessibilitySelectTextWithCriteriaParameterizedAttribute,
2851             NSAccessibilitySearchTextWithCriteriaParameterizedAttribute,
2852             NSAccessibilityTextOperationParameterizedAttribute,
2853             nil];
2854     }
2856     if (textParamAttrs == nil) {
2857         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:paramAttrs]);
2858         [tempArray addObject:(NSString*)kAXLineForIndexParameterizedAttribute];
2859         [tempArray addObject:(NSString*)kAXRangeForLineParameterizedAttribute];
2860         [tempArray addObject:(NSString*)kAXStringForRangeParameterizedAttribute];
2861         [tempArray addObject:(NSString*)kAXRangeForPositionParameterizedAttribute];
2862         [tempArray addObject:(NSString*)kAXRangeForIndexParameterizedAttribute];
2863         [tempArray addObject:(NSString*)kAXBoundsForRangeParameterizedAttribute];
2864         [tempArray addObject:(NSString*)kAXRTFForRangeParameterizedAttribute];
2865         [tempArray addObject:(NSString*)kAXAttributedStringForRangeParameterizedAttribute];
2866         [tempArray addObject:(NSString*)kAXStyleRangeForIndexParameterizedAttribute];
2867         textParamAttrs = [[NSArray alloc] initWithArray:tempArray.get()];
2868     }
2869     if (tableParamAttrs == nil) {
2870         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:paramAttrs]);
2871         [tempArray addObject:NSAccessibilityCellForColumnAndRowParameterizedAttribute];
2872         tableParamAttrs = [[NSArray alloc] initWithArray:tempArray.get()];
2873     }
2874     if (!webAreaParamAttrs) {
2875         auto tempArray = adoptNS([[NSMutableArray alloc] initWithArray:paramAttrs]);
2876         [tempArray addObject:NSAccessibilityTextMarkerForIndexParameterizedAttribute];
2877         [tempArray addObject:NSAccessibilityTextMarkerIsValidParameterizedAttribute];
2878         [tempArray addObject:NSAccessibilityIndexForTextMarkerParameterizedAttribute];
2879         webAreaParamAttrs = [[NSArray alloc] initWithArray:tempArray.get()];
2880     }
2882     if (backingObject->isPasswordField())
2883         return @[ NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute ];
2885     if (backingObject->isTextControl())
2886         return textParamAttrs;
2888     if (backingObject->isTable() && backingObject->isExposable())
2889         return tableParamAttrs;
2891     if (backingObject->isMenuRelated())
2892         return nil;
2894     if (backingObject->isWebArea())
2895         return webAreaParamAttrs;
2897     return paramAttrs;
2900 ALLOW_DEPRECATED_DECLARATIONS_BEGIN
2902 - (void)accessibilityPerformPressAction
2904     // In case anything we do by performing the press action causes an alert or other modal
2905     // behaviors, we need to return now, so that VoiceOver doesn't hang indefinitely.
2906     RunLoop::main().dispatch([self, protectedSelf = retainPtr(self)] {
2907         [self _accessibilityPerformPressAction];
2908     });
2911 - (void)_accessibilityPerformPressAction
2913     auto* backingObject = self.updateObjectBackingStore;
2914     if (!backingObject)
2915         return;
2917     if (backingObject->isAttachment())
2918         [[self attachmentView] accessibilityPerformAction:NSAccessibilityPressAction];
2919     else
2920         backingObject->press();
2923 - (void)accessibilityPerformIncrementAction
2925     RunLoop::main().dispatch([self, protectedSelf = retainPtr(self)] {
2926         [self _accessibilityPerformIncrementAction];
2927     });
2930 - (void)_accessibilityPerformIncrementAction
2932     auto* backingObject = self.updateObjectBackingStore;
2933     if (!backingObject)
2934         return;
2936     if (backingObject->isAttachment())
2937         [[self attachmentView] accessibilityPerformAction:NSAccessibilityIncrementAction];
2938     else
2939         backingObject->increment();
2942 - (void)accessibilityPerformDecrementAction
2944     RunLoop::main().dispatch([self, protectedSelf = retainPtr(self)] {
2945         [self _accessibilityPerformDecrementAction];
2946     });
2949 - (void)_accessibilityPerformDecrementAction
2951     auto* backingObject = self.updateObjectBackingStore;
2952     if (!backingObject)
2953         return;
2955     if (backingObject->isAttachment())
2956         [[self attachmentView] accessibilityPerformAction:NSAccessibilityDecrementAction];
2957     else
2958         backingObject->decrement();
2961 ALLOW_DEPRECATED_DECLARATIONS_END
2963 - (void)accessibilityPerformShowMenuAction
2965     if (self.axBackingObject->roleValue() == AccessibilityRole::ComboBox)
2966         self.axBackingObject->setIsExpanded(true);
2967     else {
2968         // This needs to be performed in an iteration of the run loop that did not start from an AX call.
2969         // If it's the same run loop iteration, the menu open notification won't be sent
2970         [self performSelector:@selector(accessibilityShowContextMenu) withObject:nil afterDelay:0.0];
2971     }
2974 - (void)accessibilityShowContextMenu
2976     Accessibility::performFunctionOnMainThread([protectedSelf = retainPtr(self)] {
2977         [protectedSelf _accessibilityShowContextMenu];
2978     });
2981 - (void)_accessibilityShowContextMenu
2983     ASSERT(isMainThread());
2984     
2985     if (!self.axBackingObject)
2986         return;
2987     
2988     Page* page = self.axBackingObject->page();
2989     if (!page)
2990         return;
2991     
2992     IntRect rect = snappedIntRect(self.axBackingObject->elementRect());
2993     FrameView* frameView = self.axBackingObject->documentFrameView();
2994     
2995     // On WK2, we need to account for the scroll position with regards to root view.
2996     // On WK1, we need to convert rect to window space to match mouse clicking.
2997     if (frameView) {
2998         // Find the appropriate scroll view to use to convert the contents to the window.
2999         for (auto* parent = self.axBackingObject->parentObject(); parent; parent = parent->parentObject()) {
3000             if (parent->isScrollView()) {
3001                 if (auto* scrollView = parent->scrollView()) {
3002                     if (!frameView->platformWidget())
3003                         rect = scrollView->contentsToRootView(rect);
3004                     else
3005                         rect = scrollView->contentsToWindow(rect);
3006                 }
3007                 break;
3008             }
3009         }
3010     }
3012     page->contextMenuController().showContextMenuAt(page->mainFrame(), rect.center());
3015 - (void)accessibilityScrollToVisible
3017     self.axBackingObject->scrollToMakeVisible();
3020 - (void)_accessibilityScrollToMakeVisibleWithSubFocus:(NSRect)rect
3022     self.axBackingObject->scrollToMakeVisibleWithSubFocus(IntRect(rect));
3025 - (void)_accessibilityScrollToGlobalPoint:(NSPoint)point
3027     self.axBackingObject->scrollToGlobalPoint(IntPoint(point));
3030 ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGIN
3031 - (void)accessibilityPerformAction:(NSString*)action
3032 ALLOW_DEPRECATED_IMPLEMENTATIONS_END
3034     auto* backingObject = self.updateObjectBackingStore;
3035     if (!backingObject)
3036         return;
3038     if ([action isEqualToString:NSAccessibilityPressAction])
3039         [self accessibilityPerformPressAction];
3040     else if ([action isEqualToString:@"AXSyncPressAction"]) {
3041         // Used in layout tests, so that we don't have to wait for the async press action.
3042         [self _accessibilityPerformPressAction];
3043     }
3044     else if ([action isEqualToString:@"AXSyncIncrementAction"])
3045         [self _accessibilityPerformIncrementAction];
3046     else if ([action isEqualToString:@"AXSyncDecrementAction"])
3047         [self _accessibilityPerformDecrementAction];
3048     else if ([action isEqualToString:NSAccessibilityShowMenuAction])
3049         [self accessibilityPerformShowMenuAction];
3050     else if ([action isEqualToString:NSAccessibilityIncrementAction])
3051         [self accessibilityPerformIncrementAction];
3052     else if ([action isEqualToString:NSAccessibilityDecrementAction])
3053         [self accessibilityPerformDecrementAction];
3054     else if ([action isEqualToString:NSAccessibilityScrollToVisibleAction])
3055         [self accessibilityScrollToVisible];
3056     else if ([action isEqualToString:@"AXDismissAction"])
3057         backingObject->performDismissAction();
3060 - (BOOL)accessibilityReplaceRange:(NSRange)range withText:(NSString *)string
3062     auto* backingObject = self.updateObjectBackingStore;
3063     return backingObject ? backingObject->replaceTextInRange(String(string), PlainTextRange(range)) : NO;
3066 - (BOOL)accessibilityInsertText:(NSString *)text
3068     auto* backingObject = self.updateObjectBackingStore;
3069     return backingObject ? backingObject->insertText(String(text)) : NO;
3072 ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGIN
3073 - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attributeName
3074 ALLOW_DEPRECATED_IMPLEMENTATIONS_END
3076 #if PLATFORM(MAC)
3077     // In case anything we do by changing values causes an alert or other modal
3078     // behaviors, we need to return now, so that VoiceOver doesn't hang indefinitely.
3079     callOnMainThread([value = retainPtr(value), attributeName = retainPtr(attributeName), protectedSelf = retainPtr(self)] {
3080         [protectedSelf _accessibilitySetValue:value.get() forAttribute:attributeName.get()];
3081     });
3082 #else
3083     // dispatch_async on earlier versions can cause focus not to track.
3084     [self _accessibilitySetValue:value forAttribute:attributeName];
3085 #endif
3088 - (void)_accessibilitySetValue:(id)value forAttribute:(NSString *)attributeName
3090     AXTRACE(makeString("WebAccessibilityObjectWrapper _accessibilitySetValue: forAttribute:", String(attributeName)));
3092     auto* backingObject = self.updateObjectBackingStore;
3093     if (!backingObject) {
3094         [self logMissingBackingObject];
3095         return;
3096     }
3098     AXTextMarkerRangeRef textMarkerRange = nil;
3099     NSNumber*               number = nil;
3100     NSString*               string = nil;
3101     NSRange                 range = {0, 0};
3102     NSArray*                array = nil;
3104     // decode the parameter
3105     if (AXObjectIsTextMarkerRange(value))
3106         textMarkerRange = (AXTextMarkerRangeRef)value;
3107     else if ([value isKindOfClass:[NSNumber class]])
3108         number = value;
3109     else if ([value isKindOfClass:[NSString class]])
3110         string = value;
3111     else if ([value isKindOfClass:[NSValue class]])
3112         range = [value rangeValue];
3113     else if ([value isKindOfClass:[NSArray class]])
3114         array = value;
3116     // handle the command
3117     if ([attributeName isEqualToString: @"AXSelectedTextMarkerRange"]) {
3118         ASSERT(textMarkerRange);
3119         Accessibility::performFunctionOnMainThread([&textMarkerRange, protectedSelf = retainPtr(self)] {
3120             if (auto* backingObject = protectedSelf.get().axBackingObject)
3121                 backingObject->setSelectedVisiblePositionRange(visiblePositionRangeForTextMarkerRange(backingObject->axObjectCache(), textMarkerRange));
3122         });
3123     } else if ([attributeName isEqualToString: NSAccessibilityFocusedAttribute]) {
3124         backingObject->setFocused([number boolValue]);
3125     } else if ([attributeName isEqualToString: NSAccessibilityValueAttribute]) {
3126         if (number && backingObject->canSetNumericValue())
3127             backingObject->setValue([number floatValue]);
3128         else if (string)
3129             backingObject->setValue(string);
3130     } else if ([attributeName isEqualToString: NSAccessibilitySelectedAttribute]) {
3131         if (!number)
3132             return;
3133         backingObject->setSelected([number boolValue]);
3134     } else if ([attributeName isEqualToString:NSAccessibilitySelectedChildrenAttribute]) {
3135         if (!array || !backingObject->canSetSelectedChildren())
3136             return;
3138         AXCoreObject::AccessibilityChildrenVector selectedChildren;
3139         convertToVector(array, selectedChildren);
3140         backingObject->setSelectedChildren(selectedChildren);
3141     } else if (backingObject->isTextControl()) {
3142         if ([attributeName isEqualToString: NSAccessibilitySelectedTextAttribute]) {
3143             backingObject->setSelectedText(string);
3144         } else if ([attributeName isEqualToString: NSAccessibilitySelectedTextRangeAttribute]) {
3145             backingObject->setSelectedTextRange(PlainTextRange(range.location, range.length));
3146         } else if ([attributeName isEqualToString: NSAccessibilityVisibleCharacterRangeAttribute]) {
3147             backingObject->makeRangeVisible(PlainTextRange(range.location, range.length));
3148         }
3149     } else if ([attributeName isEqualToString:NSAccessibilityDisclosingAttribute] || [attributeName isEqualToString:NSAccessibilityExpandedAttribute])
3150         backingObject->setIsExpanded([number boolValue]);
3151     else if ([attributeName isEqualToString:NSAccessibilitySelectedRowsAttribute]) {
3152         AccessibilityObject::AccessibilityChildrenVector selectedRows;
3153         convertToVector(array, selectedRows);
3154         if (backingObject->isTree() || (backingObject->isTable() && backingObject->isExposable()))
3155             backingObject->setSelectedRows(selectedRows);
3156     } else if ([attributeName isEqualToString:NSAccessibilityGrabbedAttribute])
3157         backingObject->setARIAGrabbed([number boolValue]);
3158     else if (backingObject->isWebArea() && [attributeName isEqualToString:NSAccessibilityPreventKeyboardDOMEventDispatchAttribute])
3159         backingObject->setPreventKeyboardDOMEventDispatch([number boolValue]);
3160     else if (backingObject->isWebArea() && [attributeName isEqualToString:NSAccessibilityCaretBrowsingEnabledAttribute])
3161         backingObject->setCaretBrowsingEnabled([number boolValue]);
3164 static RenderObject* rendererForView(NSView* view)
3166     if (![view conformsToProtocol:@protocol(WebCoreFrameView)])
3167         return nullptr;
3168     
3169     NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
3170     Frame* frame = [frameView _web_frame];
3171     if (!frame)
3172         return nullptr;
3173     
3174     Node* node = frame->document()->ownerElement();
3175     if (!node)
3176         return nullptr;
3177     
3178     return node->renderer();
3181 - (id)_accessibilityParentForSubview:(NSView*)subview
3183     RenderObject* renderer = rendererForView(subview);
3184     if (!renderer)
3185         return nil;
3186     
3187     AccessibilityObject* obj = renderer->document().axObjectCache()->getOrCreate(renderer);
3188     if (obj)
3189         return obj->parentObjectUnignored()->wrapper();
3190     return nil;
3193 ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGIN
3194 - (NSString*)accessibilityActionDescription:(NSString*)action
3195 ALLOW_DEPRECATED_IMPLEMENTATIONS_END
3197     // we have no custom actions
3198     return NSAccessibilityActionDescription(action);
3201 // The CFAttributedStringType representation of the text associated with this accessibility
3202 // object that is specified by the given range.
3203 - (NSAttributedString *)doAXAttributedStringForRange:(NSRange)range
3205     return Accessibility::retrieveAutoreleasedValueFromMainThread<NSAttributedString *>([&range, protectedSelf = retainPtr(self)] () -> RetainPtr<NSAttributedString> {
3206         auto* backingObject = protectedSelf.get().axBackingObject;
3207         if (!backingObject)
3208             return nil;
3210         auto webRange = backingObject->rangeForPlainTextRange(range);
3211         return [protectedSelf doAXAttributedStringForTextMarkerRange:textMarkerRangeFromRange(backingObject->axObjectCache(), webRange) spellCheck:YES];
3212     });
3215 - (NSInteger)_indexForTextMarker:(AXTextMarkerRef)marker
3217     if (!marker)
3218         return NSNotFound;
3220     return Accessibility::retrieveValueFromMainThread<NSInteger>([&marker, protectedSelf = retainPtr(self)] () -> NSInteger {
3221         auto* backingObject = protectedSelf.get().axBackingObject;
3222         if (!backingObject)
3223             return NSNotFound;
3225         if (auto* cache = backingObject->axObjectCache()) {
3226             CharacterOffset characterOffset = characterOffsetForTextMarker(cache, marker);
3227             auto range = cache->rangeForUnorderedCharacterOffsets(characterOffset, characterOffset);
3228             if (!range)
3229                 return NSNotFound;
3231             return makeNSRange(range).location;
3232         }
3234         return NSNotFound;
3235     });
3238 - (AXTextMarkerRef)_textMarkerForIndex:(NSInteger)textIndex
3240     return Accessibility::retrieveAutoreleasedValueFromMainThread<AXTextMarkerRef>([&textIndex, protectedSelf = retainPtr(self)] () -> RetainPtr<AXTextMarkerRef> {
3241         auto* backingObject = protectedSelf.get().axBackingObject;
3242         if (!backingObject)
3243             return nil;
3245         auto* cache = backingObject->axObjectCache();
3246         if (!cache)
3247             return nil;
3249         auto* document = backingObject->document();
3250         if (!document)
3251             return nil;
3253         auto* documentElement = document->documentElement();
3254         if (!documentElement)
3255             return nil;
3257         auto boundary = resolveCharacterLocation(makeRangeSelectingNodeContents(*documentElement), textIndex);
3258         auto characterOffset = cache->startOrEndCharacterOffsetForRange(makeSimpleRange(boundary), true);
3260         return textMarkerForCharacterOffset(cache, characterOffset);
3261     });
3264 // The RTF representation of the text associated with this accessibility object that is
3265 // specified by the given range.
3266 - (NSData*)doAXRTFForRange:(NSRange)range
3268     NSAttributedString* attrString = [self doAXAttributedStringForRange:range];
3269     return [attrString RTFFromRange: NSMakeRange(0, [attrString length]) documentAttributes:@{ }];
3272 #if ENABLE(TREE_DEBUGGING)
3273 - (NSString *)debugDescriptionForTextMarker:(AXTextMarkerRef)textMarker
3275     return visiblePositionForTextMarker(self.axBackingObject->axObjectCache(), textMarker).debugDescription();
3278 - (NSString *)debugDescriptionForTextMarkerRange:(AXTextMarkerRangeRef)textMarkerRange
3280     auto* backingObject = self.axBackingObject;
3281     if (!backingObject)
3282         return @"<null>";
3284     auto visiblePositionRange = visiblePositionRangeForTextMarkerRange(backingObject->axObjectCache(), textMarkerRange);
3285     if (visiblePositionRange.isNull())
3286         return @"<null>";
3288     char description[2048];
3289     formatForDebugger(visiblePositionRange, description, sizeof(description));
3291     return [NSString stringWithUTF8String:description];
3294 - (void)showNodeForTextMarker:(AXTextMarkerRef)textMarker
3296     auto visiblePosition = visiblePositionForTextMarker(self.axBackingObject->axObjectCache(), textMarker);
3297     Node* node = visiblePosition.deepEquivalent().deprecatedNode();
3298     if (!node)
3299         return;
3300     node->showNode();
3301     node->showNodePathForThis();
3304 - (void)showNodeTreeForTextMarker:(AXTextMarkerRef)textMarker
3306     auto visiblePosition = visiblePositionForTextMarker(self.axBackingObject->axObjectCache(), textMarker);
3307     Node* node = visiblePosition.deepEquivalent().deprecatedNode();
3308     if (!node)
3309         return;
3310     node->showTreeForThis();
3313 static void formatForDebugger(const VisiblePositionRange& range, char* buffer, unsigned length)
3315     strlcpy(buffer, makeString("from ", range.start.debugDescription(), " to ", range.end.debugDescription()).utf8().data(), length);
3317 #endif
3319 enum class TextUnit {
3320     LeftWord = 1,
3321     RightWord,
3322     NextWordEnd,
3323     PreviousWordStart,
3324     Sentence,
3325     NextSentenceEnd,
3326     PreviousSentenceStart,
3327     Paragraph,
3328     NextParagraphEnd,
3329     PreviousParagraphStart,
3330     Line,
3331     LeftLine,
3332     RightLine,
3333     NextLineEnd,
3334     PreviousLineStart,
3337 - (AXTextMarkerRangeRef)textMarkerRangeAtTextMarker:(AXTextMarkerRef)textMarker forUnit:(TextUnit)textUnit
3339     return Accessibility::retrieveAutoreleasedValueFromMainThread<AXTextMarkerRangeRef>([&textMarker, &textUnit, protectedSelf = retainPtr(self)] () -> RetainPtr<AXTextMarkerRangeRef> {
3340         auto* backingObject = protectedSelf.get().axBackingObject;
3341         if (!backingObject)
3342             return nil;
3344         auto* cache = backingObject->axObjectCache();
3345         if (!cache)
3346             return nil;
3348         auto characterOffset = characterOffsetForTextMarker(cache, textMarker);
3349         std::optional<SimpleRange> range;
3350         switch (textUnit) {
3351         case TextUnit::LeftWord:
3352             range = cache->leftWordRange(characterOffset);
3353             break;
3354         case TextUnit::RightWord:
3355             range = cache->rightWordRange(characterOffset);
3356             break;
3357         case TextUnit::Sentence:
3358             range = cache->sentenceForCharacterOffset(characterOffset);
3359             break;
3360         case TextUnit::Paragraph:
3361             range = cache->paragraphForCharacterOffset(characterOffset);
3362             break;
3363         default:
3364             ASSERT_NOT_REACHED();
3365             break;
3366         }
3368         return textMarkerRangeFromRange(cache, range);
3369     });
3372 - (AXTextMarkerRangeRef)lineTextMarkerRangeForTextMarker:(AXTextMarkerRef)textMarker forUnit:(TextUnit)textUnit
3374     return Accessibility::retrieveAutoreleasedValueFromMainThread<AXTextMarkerRangeRef>([&textMarker, &textUnit, protectedSelf = retainPtr(self)] () -> RetainPtr<AXTextMarkerRangeRef> {
3375         auto* backingObject = protectedSelf.get().axBackingObject;
3376         if (!backingObject)
3377             return nil;
3379         auto* cache = backingObject->axObjectCache();
3380         if (!cache)
3381             return nil;
3383         auto visiblePosition = visiblePositionForTextMarker(cache, textMarker);
3384         VisiblePositionRange visiblePositionRange;
3385         switch (textUnit) {
3386         case TextUnit::Line:
3387             visiblePositionRange = backingObject->lineRangeForPosition(visiblePosition);
3388             break;
3389         case TextUnit::LeftLine:
3390             visiblePositionRange = backingObject->leftLineVisiblePositionRange(visiblePosition);
3391             break;
3392         case TextUnit::RightLine:
3393             visiblePositionRange = backingObject->rightLineVisiblePositionRange(visiblePosition);
3394             break;
3395         default:
3396             ASSERT_NOT_REACHED();
3397             break;
3398         }
3400         return textMarkerRangeFromVisiblePositions(cache, visiblePositionRange.start, visiblePositionRange.end);
3401     });
3404 - (AXTextMarkerRef)textMarkerForTextMarker:(AXTextMarkerRef)textMarker atUnit:(TextUnit)textUnit
3406     return Accessibility::retrieveAutoreleasedValueFromMainThread<AXTextMarkerRef>([&textMarker, &textUnit, protectedSelf = retainPtr(self)] () -> RetainPtr<AXTextMarkerRef> {
3407         auto* backingObject = protectedSelf.get().axBackingObject;
3408         if (!backingObject)
3409             return nil;
3411         auto* cache = backingObject->axObjectCache();
3412         if (!cache)
3413             return nil;
3415         CharacterOffset oldOffset = characterOffsetForTextMarker(cache, textMarker);
3416         CharacterOffset newOffset;
3417         switch (textUnit) {
3418         case TextUnit::NextWordEnd:
3419             newOffset = cache->nextWordEndCharacterOffset(oldOffset);
3420             break;
3421         case TextUnit::PreviousWordStart:
3422             newOffset = cache->previousWordStartCharacterOffset(oldOffset);
3423             break;
3424         case TextUnit::NextSentenceEnd:
3425             newOffset = cache->nextSentenceEndCharacterOffset(oldOffset);
3426             break;
3427         case TextUnit::PreviousSentenceStart:
3428             newOffset = cache->previousSentenceStartCharacterOffset(oldOffset);
3429             break;
3430         case TextUnit::NextParagraphEnd:
3431             newOffset = cache->nextParagraphEndCharacterOffset(oldOffset);
3432             break;
3433         case TextUnit::PreviousParagraphStart:
3434             newOffset = cache->previousParagraphStartCharacterOffset(oldOffset);
3435             break;
3436         case TextUnit::NextLineEnd: {
3437             auto visiblePosition = visiblePositionForTextMarker(cache, textMarker);
3438             return textMarkerForVisiblePosition(cache, backingObject->nextLineEndPosition(visiblePosition));
3439         }
3440         case TextUnit::PreviousLineStart: {
3441             auto visiblePosition = visiblePositionForTextMarker(cache, textMarker);
3442             return textMarkerForVisiblePosition(cache, backingObject->previousLineStartPosition(visiblePosition));
3443         }
3444         default:
3445             ASSERT_NOT_REACHED();
3446             break;
3447         }
3449         return textMarkerForCharacterOffset(cache, newOffset);
3450     });
3453 static bool isMatchingPlugin(AXCoreObject* axObject, const AccessibilitySearchCriteria& criteria)
3455     if (!axObject->isWidget())
3456         return false;
3458     return Accessibility::retrieveValueFromMainThread<bool>([&axObject, &criteria] () -> bool {
3459         auto* widget = axObject->widget();
3460         if (!is<PluginViewBase>(widget))
3461             return false;
3463         return criteria.searchKeys.contains(AccessibilitySearchKey::AnyType)
3464             && (!criteria.visibleOnly || downcast<PluginViewBase>(widget)->isVisible());
3465     });
3468 ALLOW_DEPRECATED_IMPLEMENTATIONS_BEGIN
3469 - (id)accessibilityAttributeValue:(NSString*)attribute forParameter:(id)parameter
3470 ALLOW_DEPRECATED_IMPLEMENTATIONS_END
3472     AXTRACE(makeString("WebAccessibilityObjectWrapper accessibilityAttributeValue:", String(attribute)));
3473     auto* backingObject = self.updateObjectBackingStore;
3474     if (!backingObject)
3475         return nil;
3477     // Basic parameter validation.
3478     if (!attribute || !parameter)
3479         return nil;
3481     AXTextMarkerRef textMarker = nil;
3482     AXTextMarkerRangeRef textMarkerRange = nil;
3483     NSNumber* number = nil;
3484     NSArray* array = nil;
3485     NSDictionary* dictionary = nil;
3486     RefPtr<AXCoreObject> uiElement;
3487     NSPoint point = NSZeroPoint;
3488     bool pointSet = false;
3489     NSRange range = {0, 0};
3490     bool rangeSet = false;
3491     NSRect rect = NSZeroRect;
3493     // common parameter type check/casting.  Nil checks in handlers catch wrong type case.
3494     // NOTE: This assumes nil is not a valid parameter, because it is indistinguishable from
3495     // a parameter of the wrong type.
3496     if (AXObjectIsTextMarker(parameter))
3497         textMarker = (AXTextMarkerRef)parameter;
3498     else if (AXObjectIsTextMarkerRange(parameter))
3499         textMarkerRange = (AXTextMarkerRangeRef)parameter;
3500     else if ([parameter isKindOfClass:[WebAccessibilityObjectWrapper class]]) {
3501         uiElement = [(WebAccessibilityObjectWrapper*)parameter axBackingObject];
3502         // The parameter wrapper object has lost its AX object since being given to the client, so bail early.
3503         if (!uiElement)
3504             return nil;
3505     }
3506     else if ([parameter isKindOfClass:[NSNumber class]])
3507         number = parameter;
3508     else if ([parameter isKindOfClass:[NSArray class]])
3509         array = parameter;
3510     else if ([parameter isKindOfClass:[NSDictionary class]])
3511         dictionary = parameter;
3512     else if ([parameter isKindOfClass:[NSValue class]] && !strcmp([(NSValue*)parameter objCType], @encode(NSPoint))) {
3513         pointSet = true;
3514         point = [(NSValue*)parameter pointValue];
3515     } else if ([parameter isKindOfClass:[NSValue class]] && !strcmp([(NSValue*)parameter objCType], @encode(NSRange))) {
3516         rangeSet = true;
3517         range = [(NSValue*)parameter rangeValue];
3518     } else if ([parameter isKindOfClass:[NSValue class]] && !strcmp([(NSValue*)parameter objCType], @encode(NSRect)))
3519         rect = [(NSValue*)parameter rectValue];
3520     else {
3521         // Attribute type is not supported. Allow super to handle.
3522         return [super accessibilityAttributeValue:attribute forParameter:parameter];
3523     }
3525     // dispatch
3526     if ([attribute isEqualToString:NSAccessibilitySelectTextWithCriteriaParameterizedAttribute]) {
3527         // To be deprecated.
3528         auto result = Accessibility::retrieveValueFromMainThread<Vector<String>>([dictionary, protectedSelf = retainPtr(self)] () -> Vector<String> {
3529             auto* backingObject = protectedSelf.get().axBackingObject;
3530             if (!backingObject)
3531                 return Vector<String>();
3533             auto criteria = accessibilityTextCriteriaForParameterizedAttribute(dictionary);
3534             criteria.second.textRanges = backingObject->findTextRanges(criteria.first);
3535             ASSERT(criteria.second.textRanges.size() <= 1);
3536             return backingObject->performTextOperation(criteria.second);
3537         });
3538         ASSERT(result.size() <= 1);
3539         if (result.size() > 0)
3540             return result[0];
3541         return String();
3542     }
3544     if ([attribute isEqualToString:NSAccessibilitySearchTextWithCriteriaParameterizedAttribute]) {
3545         auto criteria = accessibilitySearchTextCriteriaForParameterizedAttribute(dictionary);
3546         return Accessibility::retrieveAutoreleasedValueFromMainThread<NSArray *>([&criteria, protectedSelf = retainPtr(self)] () -> RetainPtr<NSArray> {
3547             auto* backingObject = protectedSelf.get().axBackingObject;
3548             if (!backingObject)
3549                 return nil;
3550             auto ranges = backingObject->findTextRanges(criteria);
3551             if (ranges.isEmpty())
3552                 return nil;
3553             return createNSArray(ranges, [&] (auto& range) {
3554                 return (id)textMarkerRangeFromRange(backingObject->axObjectCache(), range);
3555             }).autorelease();
3556         });
3557     }
3559     if ([attribute isEqualToString:NSAccessibilityTextOperationParameterizedAttribute]) {
3560         auto operationResult = Accessibility::retrieveValueFromMainThread<Vector<String>>([dictionary, protectedSelf = retainPtr(self)] () -> Vector<String> {
3561             auto* backingObject = protectedSelf.get().axBackingObject;
3562             if (!backingObject)
3563                 return Vector<String>();
3565             auto textOperation = accessibilityTextOperationForParameterizedAttribute(backingObject->axObjectCache(), dictionary);
3566             return backingObject->performTextOperation(textOperation);
3567         });
3568         if (operationResult.isEmpty())
3569             return nil;
3570         return createNSArray(operationResult).autorelease();
3571     }
3573     if ([attribute isEqualToString:NSAccessibilityUIElementCountForSearchPredicateParameterizedAttribute]) {
3574         AccessibilitySearchCriteria criteria = accessibilitySearchCriteriaForSearchPredicateParameterizedAttribute(dictionary);
3575         NSUInteger widgetChildrenSize = 0;
3576         if (isMatchingPlugin(backingObject, criteria)) {
3577             // FIXME: We should also be searching the tree(s) resulting from `renderWidgetChildren` for matches.
3578             // This is tracked by https://bugs.webkit.org/show_bug.cgi?id=230167.
3579             if (auto* widgetChildren = [self renderWidgetChildren]) {
3580                 widgetChildrenSize = [widgetChildren count];
3581                 if (widgetChildrenSize >= criteria.resultsLimit)
3582                     return @(std::min(widgetChildrenSize, NSUInteger(criteria.resultsLimit)));
3583                 criteria.resultsLimit -= widgetChildrenSize;
3584             }
3585         }
3587         AccessibilityObject::AccessibilityChildrenVector results;
3588         backingObject->findMatchingObjects(&criteria, results);
3589         return @(results.size() + widgetChildrenSize);
3590     }
3592     if ([attribute isEqualToString:NSAccessibilityUIElementsForSearchPredicateParameterizedAttribute]) {
3593         AccessibilitySearchCriteria criteria = accessibilitySearchCriteriaForSearchPredicateParameterizedAttribute(dictionary);
3594         NSArray *widgetChildren = nil;
3595         if (isMatchingPlugin(backingObject, criteria)) {
3596             // FIXME: We should also be searching the tree(s) resulting from `renderWidgetChildren` for matches.
3597             // This is tracked by https://bugs.webkit.org/show_bug.cgi?id=230167.
3598             if (auto* children = [self renderWidgetChildren]) {
3599                 NSUInteger includedChildrenCount = std::min([children count], NSUInteger(criteria.resultsLimit));
3600                 widgetChildren = [children subarrayWithRange:NSMakeRange(0, includedChildrenCount)];
3601                 if ([widgetChildren count] >= criteria.resultsLimit)
3602                     return widgetChildren;
3603                 criteria.resultsLimit -= [widgetChildren count];
3604             }
3605         }
3607         AccessibilityObject::AccessibilityChildrenVector results;
3608         backingObject->findMatchingObjects(&criteria, results);
3609         if (widgetChildren)
3610             return [widgetChildren arrayByAddingObjectsFromArray:makeNSArray(results)];
3611         return makeNSArray(results);
3612     }
3614     // TextMarker attributes.
3616     if ([attribute isEqualToString:NSAccessibilityEndTextMarkerForBoundsParameterizedAttribute]) {
3617         return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([&rect, protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
3618             auto* backingObject = protectedSelf.get().axBackingObject;
3619             if (!backingObject)
3620                 return nil;
3622             auto* cache = backingObject->axObjectCache();
3623             if (!cache)
3624                 return nil;
3626             IntRect webCoreRect = [protectedSelf screenToContents:enclosingIntRect(rect)];
3627             CharacterOffset characterOffset = cache->characterOffsetForBounds(webCoreRect, false);
3629             return (id)textMarkerForCharacterOffset(cache, characterOffset);
3630         });
3631     }
3633     if ([attribute isEqualToString:NSAccessibilityStartTextMarkerForBoundsParameterizedAttribute]) {
3634         return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([&rect, protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
3635             auto* backingObject = protectedSelf.get().axBackingObject;
3636             if (!backingObject)
3637                 return nil;
3639             auto* cache = backingObject->axObjectCache();
3640             if (!cache)
3641                 return nil;
3643             IntRect webCoreRect = [protectedSelf screenToContents:enclosingIntRect(rect)];
3644             CharacterOffset characterOffset = cache->characterOffsetForBounds(webCoreRect, true);
3646             return (id)textMarkerForCharacterOffset(cache, characterOffset);
3647         });
3648     }
3650     // TextMarkerRange attributes.
3651     if ([attribute isEqualToString:@"AXTextMarkerRangeForNSRange"])
3652         return (id)backingObject->textMarkerRangeForNSRange(range);
3654     if ([attribute isEqualToString:NSAccessibilityLineTextMarkerRangeForTextMarkerParameterizedAttribute])
3655         return (id)[self lineTextMarkerRangeForTextMarker:textMarker forUnit:TextUnit::Line];
3657     if ([attribute isEqualToString:NSAccessibilityMisspellingTextMarkerRangeParameterizedAttribute]) {
3658         return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([&dictionary, protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
3659             auto* backingObject = protectedSelf.get().axBackingObject;
3660             if (!backingObject)
3661                 return nil;
3663             auto* cache = backingObject->axObjectCache();
3664             if (!cache)
3665                 return nil;
3667             auto criteria = accessibilityMisspellingSearchCriteriaForParameterizedAttribute(cache, dictionary);
3668             if (auto misspellingRange = backingObject->misspellingRange(*criteria.first, criteria.second))
3669                 return (id)textMarkerRangeFromRange(cache, *misspellingRange);
3671             return nil;
3672         });
3673     }
3675     if ([attribute isEqualToString:NSAccessibilityTextMarkerIsValidParameterizedAttribute]) {
3676         bool result = Accessibility::retrieveValueFromMainThread<bool>([&textMarker, protectedSelf = retainPtr(self)] () -> bool {
3677             auto* backingObject = protectedSelf.get().axBackingObject;
3678             if (!backingObject)
3679                 return false;
3681             return !visiblePositionForTextMarker(backingObject->axObjectCache(), textMarker).isNull();
3682         });
3684         return [NSNumber numberWithBool:result];
3685     }
3687     if ([attribute isEqualToString:NSAccessibilityIndexForTextMarkerParameterizedAttribute])
3688         return [NSNumber numberWithInteger:[self _indexForTextMarker:textMarker]];
3690     if ([attribute isEqualToString:NSAccessibilityTextMarkerForIndexParameterizedAttribute])
3691         return (id)[self _textMarkerForIndex:[number integerValue]];
3693     if ([attribute isEqualToString:@"AXUIElementForTextMarker"]) {
3694         return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([&textMarker, protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
3695             auto* backingObject = protectedSelf.get().axBackingObject;
3696             if (!backingObject)
3697                 return nil;
3699             auto* axObject = accessibilityObjectForTextMarker(backingObject->axObjectCache(), textMarker);
3700             if (!axObject)
3701                 return nil;
3703             if (axObject->isAttachment() && [axObject->wrapper() attachmentView])
3704                 return [axObject->wrapper() attachmentView];
3706             return axObject->wrapper();
3707         });
3708     }
3710     if ([attribute isEqualToString:@"AXTextMarkerRangeForUIElement"]) {
3711         return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([&uiElement] () -> RetainPtr<id> {
3712             return (id)textMarkerRangeFromRange(uiElement.get()->axObjectCache(), uiElement.get()->elementRange());
3713         });
3714     }
3716     if ([attribute isEqualToString:@"AXLineForTextMarker"]) {
3717         int result = Accessibility::retrieveValueFromMainThread<int>([&textMarker, protectedSelf = retainPtr(self)] () -> int {
3718             auto* backingObject = protectedSelf.get().axBackingObject;
3719             if (!backingObject)
3720                 return -1;
3722             auto visiblePos = visiblePositionForTextMarker(backingObject->axObjectCache(), textMarker);
3723             return backingObject->lineForPosition(visiblePos);
3724         });
3725         return @(result);
3726     }
3728     if ([attribute isEqualToString:@"AXTextMarkerRangeForLine"]) {
3729         return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([&number, protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
3730             auto* backingObject = protectedSelf.get().axBackingObject;
3731             if (!backingObject)
3732                 return nil;
3734             VisiblePositionRange vpRange;
3735             if ([number unsignedIntegerValue] != NSNotFound)
3736                 vpRange = backingObject->visiblePositionRangeForLine([number unsignedIntValue]);
3738             return (id)textMarkerRangeFromVisiblePositions(backingObject->axObjectCache(), vpRange.start, vpRange.end);
3739         });
3740     }
3742     if ([attribute isEqualToString:@"AXStringForTextMarkerRange"]) {
3743         return Accessibility::retrieveValueFromMainThread<String>([&textMarkerRange, protectedSelf = retainPtr(self)] () -> String {
3744             auto* backingObject = protectedSelf.get().axBackingObject;
3745             if (!backingObject)
3746                 return String();
3748             auto range = rangeForTextMarkerRange(backingObject->axObjectCache(), textMarkerRange);
3749             return range ? backingObject->stringForRange(*range) : String();
3750         });
3751     }
3753     if ([attribute isEqualToString:@"AXTextMarkerForPosition"]) {
3754         if (!pointSet)
3755             return nil;
3756         IntPoint webCorePoint = IntPoint(point);
3758         return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([&webCorePoint, protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
3759             auto* backingObject = protectedSelf.get().axBackingObject;
3760             if (!backingObject)
3761                 return nil;
3763             return (id)textMarkerForVisiblePosition(backingObject->axObjectCache(), backingObject->visiblePositionForPoint(webCorePoint));
3764         });
3765     }
3767     if ([attribute isEqualToString:@"AXBoundsForTextMarkerRange"]) {
3768         NSRect rect = Accessibility::retrieveValueFromMainThread<NSRect>([&textMarkerRange, protectedSelf = retainPtr(self)] () -> NSRect {
3769             auto* backingObject = protectedSelf.get().axBackingObject;
3770             if (!backingObject)
3771                 return CGRectZero;
3773             auto range = rangeForTextMarkerRange(backingObject->axObjectCache(), textMarkerRange);
3774             if (!range)
3775                 return CGRectZero;
3777             auto bounds = FloatRect(backingObject->boundsForRange(*range));
3778             return [protectedSelf convertRectToSpace:bounds space:AccessibilityConversionSpace::Screen];
3779         });
3780         return [NSValue valueWithRect:rect];
3781     }
3783     if ([attribute isEqualToString:NSAccessibilityBoundsForRangeParameterizedAttribute]) {
3784         NSRect rect = Accessibility::retrieveValueFromMainThread<NSRect>([&range, protectedSelf = retainPtr(self)] () -> NSRect {
3785             auto* backingObject = protectedSelf.get().axBackingObject;
3786             if (!backingObject)
3787                 return CGRectZero;
3789             auto start = backingObject->visiblePositionForIndex(range.location);
3790             auto end = backingObject->visiblePositionForIndex(range.location + range.length);
3791             auto webRange = makeSimpleRange({ start, end });
3792             if (!webRange)
3793                 return CGRectZero;
3795             auto bounds = FloatRect(backingObject->boundsForRange(*webRange));
3796             return [protectedSelf convertRectToSpace:bounds space:AccessibilityConversionSpace::Screen];
3797         });
3798         return [NSValue valueWithRect:rect];
3799     }
3801     if ([attribute isEqualToString:NSAccessibilityStringForRangeParameterizedAttribute]) {
3802         if (backingObject->isTextControl()) {
3803             PlainTextRange plainTextRange = PlainTextRange(range.location, range.length);
3804             return backingObject->doAXStringForRange(plainTextRange);
3805         }
3807         return Accessibility::retrieveValueFromMainThread<String>([&range, protectedSelf = retainPtr(self)] () -> String {
3808             auto* backingObject = protectedSelf.get().axBackingObject;
3809             if (!backingObject)
3810                 return String();
3811             auto* cache = backingObject->axObjectCache();
3812             if (!cache)
3813                 return String();
3814             auto start = cache->characterOffsetForIndex(range.location, backingObject);
3815             auto end = cache->characterOffsetForIndex(range.location + range.length, backingObject);
3816             auto range = cache->rangeForUnorderedCharacterOffsets(start, end);
3817             if (!range)
3818                 return { };
3819             return backingObject->stringForRange(*range);
3820         });
3821     }
3823     if ([attribute isEqualToString:@"AXAttributedStringForTextMarkerRange"])
3824         return [self doAXAttributedStringForTextMarkerRange:textMarkerRange spellCheck:YES];
3826     if ([attribute isEqualToString:@"AXAttributedStringForTextMarkerRangeWithOptions"]) {
3827         if (textMarkerRange)
3828             return [self doAXAttributedStringForTextMarkerRange:textMarkerRange spellCheck:NO];
3830         if (dictionary) {
3831             AXTextMarkerRangeRef textMarkerRange = nil;
3832             id parameter = [dictionary objectForKey:@"AXTextMarkerRange"];
3833             if (AXObjectIsTextMarkerRange(parameter))
3834                 textMarkerRange = (AXTextMarkerRangeRef)parameter;
3836             BOOL spellCheck = NO;
3837             parameter = [dictionary objectForKey:@"AXSpellCheck"];
3838             if ([parameter isKindOfClass:[NSNumber class]])
3839                 spellCheck = [parameter boolValue];
3841             return [self doAXAttributedStringForTextMarkerRange:textMarkerRange spellCheck:spellCheck];
3842         }
3844         return nil;
3845     }
3847     if ([attribute isEqualToString:@"AXTextMarkerRangeForTextMarkers"]) {
3848         if (array.count < 2
3849             || !AXObjectIsTextMarker([array objectAtIndex:0])
3850             || !AXObjectIsTextMarker([array objectAtIndex:1]))
3851             return nil;
3852         return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([&array] () -> RetainPtr<id> {
3853             return (id)textMarkerRangeFromMarkers((AXTextMarkerRef)[array objectAtIndex:0], (AXTextMarkerRef)[array objectAtIndex:1]).get();
3854         });
3855     }
3857     if ([attribute isEqualToString:@"AXTextMarkerRangeForUnorderedTextMarkers"]) {
3858         if (array.count < 2
3859             || !AXObjectIsTextMarker([array objectAtIndex:0])
3860             || !AXObjectIsTextMarker([array objectAtIndex:1]))
3861             return nil;
3863         AXTextMarkerRef textMarker1 = (AXTextMarkerRef)[array objectAtIndex:0];
3864         AXTextMarkerRef textMarker2 = (AXTextMarkerRef)[array objectAtIndex:1];
3866         return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([&textMarker1, &textMarker2, protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
3867             auto* backingObject = protectedSelf.get().axBackingObject;
3868             if (!backingObject)
3869                 return nil;
3871             auto* cache = backingObject->axObjectCache();
3872             if (!cache)
3873                 return nil;
3875             auto characterOffset1 = characterOffsetForTextMarker(cache, textMarker1);
3876             auto characterOffset2 = characterOffsetForTextMarker(cache, textMarker2);
3877             auto range = cache->rangeForUnorderedCharacterOffsets(characterOffset1, characterOffset2);
3879             return (id)textMarkerRangeFromRange(cache, range);
3880         });
3881     }
3883     if ([attribute isEqualToString:@"AXNextTextMarkerForTextMarker"]) {
3884         return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([&textMarker, protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
3885             auto* backingObject = protectedSelf.get().axBackingObject;
3886             if (!backingObject)
3887                 return nil;
3889             auto* cache = backingObject->axObjectCache();
3890             if (!cache)
3891                 return nil;
3893             CharacterOffset characterOffset = characterOffsetForTextMarker(cache, textMarker);
3894             return bridge_id_cast([protectedSelf nextTextMarkerForCharacterOffset:characterOffset]);
3895         });
3896     }
3898     if ([attribute isEqualToString:@"AXPreviousTextMarkerForTextMarker"]) {
3899         return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([&textMarker, protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
3900             auto* backingObject = protectedSelf.get().axBackingObject;
3901             if (!backingObject)
3902                 return nil;
3904             auto* cache = backingObject->axObjectCache();
3905             if (!cache)
3906                 return nil;
3908             CharacterOffset characterOffset = characterOffsetForTextMarker(cache, textMarker);
3909             return bridge_id_cast([protectedSelf previousTextMarkerForCharacterOffset:characterOffset]);
3910         });
3911     }
3913     if ([attribute isEqualToString:@"AXLeftWordTextMarkerRangeForTextMarker"])
3914         return (id)[self textMarkerRangeAtTextMarker:textMarker forUnit:TextUnit::LeftWord];
3916     if ([attribute isEqualToString:@"AXRightWordTextMarkerRangeForTextMarker"])
3917         return (id)[self textMarkerRangeAtTextMarker:textMarker forUnit:TextUnit::RightWord];
3919     if ([attribute isEqualToString:@"AXLeftLineTextMarkerRangeForTextMarker"])
3920         return (id)[self lineTextMarkerRangeForTextMarker:textMarker forUnit:TextUnit::LeftLine];
3922     if ([attribute isEqualToString:@"AXRightLineTextMarkerRangeForTextMarker"])
3923         return (id)[self lineTextMarkerRangeForTextMarker:textMarker forUnit:TextUnit::RightLine];
3925     if ([attribute isEqualToString:@"AXSentenceTextMarkerRangeForTextMarker"])
3926         return (id)[self textMarkerRangeAtTextMarker:textMarker forUnit:TextUnit::Sentence];
3928     if ([attribute isEqualToString:@"AXParagraphTextMarkerRangeForTextMarker"])
3929         return (id)[self textMarkerRangeAtTextMarker:textMarker forUnit:TextUnit::Paragraph];
3931     if ([attribute isEqualToString:@"AXNextWordEndTextMarkerForTextMarker"])
3932         return (id)[self textMarkerForTextMarker:textMarker atUnit:TextUnit::NextWordEnd];
3934     if ([attribute isEqualToString:@"AXPreviousWordStartTextMarkerForTextMarker"])
3935         return (id)[self textMarkerForTextMarker:textMarker atUnit:TextUnit::PreviousWordStart];
3937     if ([attribute isEqualToString:@"AXNextLineEndTextMarkerForTextMarker"])
3938         return (id)[self textMarkerForTextMarker:textMarker atUnit:TextUnit::NextLineEnd];
3940     if ([attribute isEqualToString:@"AXPreviousLineStartTextMarkerForTextMarker"])
3941         return (id)[self textMarkerForTextMarker:textMarker atUnit:TextUnit::PreviousLineStart];
3943     if ([attribute isEqualToString:@"AXNextSentenceEndTextMarkerForTextMarker"])
3944         return (id)[self textMarkerForTextMarker:textMarker atUnit:TextUnit::NextSentenceEnd];
3946     if ([attribute isEqualToString:@"AXPreviousSentenceStartTextMarkerForTextMarker"])
3947         return (id)[self textMarkerForTextMarker:textMarker atUnit:TextUnit::PreviousSentenceStart];
3949     if ([attribute isEqualToString:@"AXNextParagraphEndTextMarkerForTextMarker"])
3950         return (id)[self textMarkerForTextMarker:textMarker atUnit:TextUnit::NextParagraphEnd];
3952     if ([attribute isEqualToString:@"AXPreviousParagraphStartTextMarkerForTextMarker"])
3953         return (id)[self textMarkerForTextMarker:textMarker atUnit:TextUnit::PreviousParagraphStart];
3955     if ([attribute isEqualToString:@"AXStyleTextMarkerRangeForTextMarker"]) {
3956         return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([&textMarker, protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
3957             auto* backingObject = protectedSelf.get().axBackingObject;
3958             if (!backingObject)
3959                 return nil;
3961             auto* cache = backingObject->axObjectCache();
3962             if (!cache)
3963                 return nil;
3965             VisiblePosition visiblePos = visiblePositionForTextMarker(cache, textMarker);
3966             VisiblePositionRange vpRange = backingObject->styleRangeForPosition(visiblePos);
3968             return (id)textMarkerRangeFromVisiblePositions(cache, vpRange.start, vpRange.end);
3969         });
3970     }
3972     if ([attribute isEqualToString:@"AXLengthForTextMarkerRange"]) {
3973         int length = Accessibility::retrieveValueFromMainThread<int>([&textMarkerRange, protectedSelf = retainPtr(self)] () -> int {
3974             auto* backingObject = protectedSelf.get().axBackingObject;
3975             if (!backingObject)
3976                 return 0;
3978             auto range = rangeForTextMarkerRange(backingObject->axObjectCache(), textMarkerRange);
3979             if (!range)
3980                 return 0;
3981             return AXObjectCache::lengthForRange(SimpleRange { *range });
3982         });
3983         if (length < 0)
3984             return nil;
3985         return @(length);
3986     }
3988     // Used only by DumpRenderTree (so far).
3989     if ([attribute isEqualToString:@"AXStartTextMarkerForTextMarkerRange"]) {
3990         return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([&textMarkerRange, protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
3991             auto* backingObject = protectedSelf.get().axBackingObject;
3992             if (!backingObject)
3993                 return nil;
3995             auto range = rangeForTextMarkerRange(backingObject->axObjectCache(), textMarkerRange);
3997             return (id)startOrEndTextMarkerForRange(backingObject->axObjectCache(), range, true);
3998         });
3999     }
4001     if ([attribute isEqualToString:@"AXEndTextMarkerForTextMarkerRange"]) {
4002         return Accessibility::retrieveAutoreleasedValueFromMainThread<id>([&textMarkerRange, protectedSelf = retainPtr(self)] () -> RetainPtr<id> {
4003             auto* backingObject = protectedSelf.get().axBackingObject;
4004             if (!backingObject)
4005                 return nil;
4007             auto range = rangeForTextMarkerRange(backingObject->axObjectCache(), textMarkerRange);
4008             return (id)startOrEndTextMarkerForRange(backingObject->axObjectCache(), range, false);
4009         });
4010     }
4012 #if ENABLE(TREE_DEBUGGING)
4013     if ([attribute isEqualToString:@"AXTextMarkerDebugDescription"])
4014         return [self debugDescriptionForTextMarker:textMarker];
4016     if ([attribute isEqualToString:@"AXTextMarkerRangeDebugDescription"])
4017         return [self debugDescriptionForTextMarkerRange:textMarkerRange];
4019     if ([attribute isEqualToString:@"AXTextMarkerNodeDebugDescription"]) {
4020         [self showNodeForTextMarker:textMarker];
4021         return nil;
4022     }
4024     if ([attribute isEqualToString:@"AXTextMarkerNodeTreeDebugDescription"]) {
4025         [self showNodeTreeForTextMarker:textMarker];
4026         return nil;
4027     }
4028 #endif
4030     if (backingObject->isTable() && backingObject->isExposable()) {
4031         if ([attribute isEqualToString:NSAccessibilityCellForColumnAndRowParameterizedAttribute]) {
4032             if (array == nil || [array count] != 2)
4033                 return nil;
4034             auto* cell = backingObject->cellForColumnAndRow([[array objectAtIndex:0] unsignedIntValue], [[array objectAtIndex:1] unsignedIntValue]);
4035             return cell ? cell->wrapper() : nil;
4036         }
4037     }
4039     if (backingObject->isTextControl()) {
4040         if ([attribute isEqualToString: (NSString *)kAXLineForIndexParameterizedAttribute]) {
4041             int lineNumber = backingObject->doAXLineForIndex([number intValue]);
4042             if (lineNumber < 0)
4043                 return nil;
4044             return @(lineNumber);
4045         }
4047         if ([attribute isEqualToString: (NSString *)kAXRangeForLineParameterizedAttribute]) {
4048             PlainTextRange textRange = backingObject->doAXRangeForLine([number intValue]);
4049             return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
4050         }
4052         if ([attribute isEqualToString: (NSString*)kAXStringForRangeParameterizedAttribute]) {
4053             PlainTextRange plainTextRange = PlainTextRange(range.location, range.length);
4054             return rangeSet ? (id)(backingObject->doAXStringForRange(plainTextRange)) : nil;
4055         }
4057         if ([attribute isEqualToString: (NSString*)kAXRangeForPositionParameterizedAttribute]) {
4058             if (!pointSet)
4059                 return nil;
4060             IntPoint webCorePoint = IntPoint(point);
4061             PlainTextRange textRange = backingObject->doAXRangeForPosition(webCorePoint);
4062             return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
4063         }
4065         if ([attribute isEqualToString: (NSString*)kAXRangeForIndexParameterizedAttribute]) {
4066             PlainTextRange textRange = backingObject->doAXRangeForIndex([number intValue]);
4067             return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
4068         }
4070         if ([attribute isEqualToString: (NSString*)kAXBoundsForRangeParameterizedAttribute]) {
4071             if (!rangeSet)
4072                 return nil;
4073             PlainTextRange plainTextRange = PlainTextRange(range.location, range.length);
4074             auto bounds = FloatRect(backingObject->doAXBoundsForRangeUsingCharacterOffset(plainTextRange));
4075             NSRect rect = [self convertRectToSpace:bounds space:AccessibilityConversionSpace::Screen];
4076             return [NSValue valueWithRect:rect];
4077         }
4079         if ([attribute isEqualToString: (NSString*)kAXRTFForRangeParameterizedAttribute])
4080             return rangeSet ? [self doAXRTFForRange:range] : nil;
4082         if ([attribute isEqualToString: (NSString*)kAXAttributedStringForRangeParameterizedAttribute])
4083             return rangeSet ? [self doAXAttributedStringForRange:range] : nil;
4085         if ([attribute isEqualToString: (NSString*)kAXStyleRangeForIndexParameterizedAttribute]) {
4086             PlainTextRange textRange = backingObject->doAXStyleRangeForIndex([number intValue]);
4087             return [NSValue valueWithRange: NSMakeRange(textRange.start, textRange.length)];
4088         }
4089     }
4091     // There are some parameters that super handles that are not explicitly returned by the list of the element's attributes.
4092     // In that case it must be passed to super.
4093     return [super accessibilityAttributeValue:attribute forParameter:parameter];
4096 - (BOOL)accessibilitySupportsOverriddenAttributes
4098     return YES;
4101 // accessibilityShouldUseUniqueId is an AppKit method we override so that
4102 // objects will be given a unique ID, and therefore allow AppKit to know when they
4103 // become obsolete (e.g. when the user navigates to a new web page, making this one
4104 // unrendered but not deallocated because it is in the back/forward cache).
4105 // It is important to call NSAccessibilityUnregisterUniqueIdForUIElement in the
4106 // appropriate place (e.g. dealloc) to remove these non-retained references from
4107 // AppKit's id mapping tables. We do this in detach by calling unregisterUniqueIdForUIElement.
4109 // Registering an object is also required for observing notifications. Only registered objects can be observed.
4110 - (BOOL)accessibilityShouldUseUniqueId
4112     // All AX object wrappers should use unique ID's because it's faster within AppKit to look them up.
4113     return YES;
4116 // API that AppKit uses for faster access
4117 - (NSUInteger)accessibilityIndexOfChild:(id)child
4119     auto* backingObject = self.updateObjectBackingStore;
4120     if (!backingObject)
4121         return NSNotFound;
4123     // Tree objects return their rows as their children. We can use the original method
4124     // here, because we won't gain any speed up.
4125     if (backingObject->isTree())
4126         return [super accessibilityIndexOfChild:child];
4128     NSArray *children = self.childrenVectorArray;
4129     if (!children.count) {
4130         if (auto *renderWidgetChildren = [self renderWidgetChildren])
4131             return [renderWidgetChildren indexOfObject:child];
4132 #if ENABLE(MODEL_ELEMENT)
4133         if (backingObject->isModel())
4134             return backingObject->modelElementChildren().find(child);
4135 #endif
4136     }
4138     NSUInteger count = [children count];
4139     for (NSUInteger i = 0; i < count; ++i) {
4140         WebAccessibilityObjectWrapper *wrapper = children[i];
4141         auto* object = wrapper.axBackingObject;
4142         if (!object)
4143             continue;
4145         if (wrapper == child || (object->isAttachment() && [wrapper attachmentView] == child))
4146             return i;
4147     }
4149     return NSNotFound;
4152 ALLOW_DEPRECATED_DECLARATIONS_BEGIN
4153 - (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute
4155     auto* backingObject = self.updateObjectBackingStore;
4156     if (!backingObject)
4157         return 0;
4159     if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
4160         // Tree items object returns a different set of children than those that are in children()
4161         // because an AXOutline (the mac role is becomes) has some odd stipulations.
4162         if (backingObject->isTree() || backingObject->isTreeItem())
4163             return [[self accessibilityAttributeValue:NSAccessibilityChildrenAttribute] count];
4165         auto childrenSize = self.childrenVectorSize;
4166         if (!childrenSize) {
4167 #if ENABLE(MODEL_ELEMENT)
4168             if (backingObject->isModel())
4169                 return backingObject->modelElementChildren().size();
4170 #endif
4171             if (NSArray *renderWidgetChildren = [self renderWidgetChildren])
4172                 return [renderWidgetChildren count];
4173         }
4174         return childrenSize;
4175     }
4177     return [super accessibilityArrayAttributeCount:attribute];
4179 ALLOW_DEPRECATED_DECLARATIONS_END
4181 - (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount
4183     AXTRACE(makeString("WebAccessibilityObjectWrapper accessibilityArrayAttributeValue:", String(attribute)));
4184     auto* backingObject = self.updateObjectBackingStore;
4185     if (!backingObject)
4186         return nil;
4188     if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
4189         if (!self.childrenVectorSize) {
4190             NSArray *children = nil;
4191 #if ENABLE(MODEL_ELEMENT)
4192             if (backingObject->isModel()) {
4193                 children = createNSArray(backingObject->modelElementChildren(), [] (auto& child) -> id {
4194                     return child.get();
4195                 }).autorelease();
4196             } else
4197 #endif
4198                 children = [self renderWidgetChildren];
4199             
4200             if (!children)
4201                 return nil;
4203             NSUInteger childCount = [children count];
4204             if (index >= childCount)
4205                 return nil;
4207             NSUInteger arrayLength = std::min(childCount - index, maxCount);
4208             return [children subarrayWithRange:NSMakeRange(index, arrayLength)];
4209         }
4211         if (backingObject->isTree() || backingObject->isTreeItem()) {
4212             // Tree objects return their rows as their children & tree items return their contents sans rows.
4213             // We can use the original method in this case.
4214             return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
4215         }
4217         auto children = self.childrenVectorArray;
4218         unsigned childCount = [children count];
4219         if (index >= childCount)
4220             return nil;
4222         unsigned available = std::min(childCount - index, maxCount);
4224         NSMutableArray *subarray = [NSMutableArray arrayWithCapacity:available];
4225         for (unsigned added = 0; added < available; ++index, ++added) {
4226             WebAccessibilityObjectWrapper* wrapper = children[index];
4227             // The attachment view should be returned, otherwise AX palindrome errors occur.
4228             BOOL isAttachment = [wrapper isKindOfClass:[WebAccessibilityObjectWrapper class]] && wrapper.axBackingObject && wrapper.axBackingObject->isAttachment() && [wrapper attachmentView];
4229             [subarray addObject:isAttachment ? [wrapper attachmentView] : wrapper];
4230         }
4232         return subarray;
4233     }
4235     return [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
4238 @end
4240 #endif // ENABLE(ACCESSIBILITY) && PLATFORM(MAC)